proj/linux-patches:6.6 commit in: /

"Mike Pagano" <[email protected]> Mon, 03 Aug 2026 11:19:43 +0000 (UTC)
Newsgroups gmane.linux.gentoo.cvs
Message-ID <1785755971.38167b754694333598de21ee35f9cb88eb7dc5ad.mpagano@gentoo>
commit:     38167b754694333598de21ee35f9cb88eb7dc5ad
Author:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
AuthorDate: Mon Aug  3 11:19:31 2026 +0000
Commit:     Mike Pagano <mpagano <AT> gentoo <DOT> org>
CommitDate: Mon Aug  3 11:19:31 2026 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=38167b75

Linux patch 6.6.148

Signed-off-by: Mike Pagano <mpagano <AT> gentoo.org>

 0000_README              |     4 +
 1147_linux-6.6.148.patch | 24867 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 24871 insertions(+)

diff --git a/0000_README b/0000_README
index 5a49a62d..76a31215 100644
--- a/0000_README
+++ b/0000_README
@@ -631,6 +631,10 @@ Patch:  1146_linux-6.6.147.patch
 From:   https://www.kernel.org
 Desc:   Linux 6.6.147
 
+Patch:  1147_linux-6.6.148.patch
+From:   https://www.kernel.org
+Desc:   Linux 6.6.148
+
 Patch:  1510_fs-enable-link-security-restrictions-by-default.patch
 From:   http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch
 Desc:   Enable link security restrictions by default.

diff --git a/1147_linux-6.6.148.patch b/1147_linux-6.6.148.patch
new file mode 100644
index 00000000..4a8126cc
--- /dev/null
+++ b/1147_linux-6.6.148.patch
@@ -0,0 +1,24867 @@
+diff --git a/Makefile b/Makefile
+index 02a25b7b265ac0..62de0a92ea104c 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 6
+ PATCHLEVEL = 6
+-SUBLEVEL = 147
++SUBLEVEL = 148
+ EXTRAVERSION =
+ NAME = Pinguïn Aangedreven
+ 
+diff --git a/arch/arm64/boot/dts/nvidia/tegra234.dtsi b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
+index d1d7f6a50e11f2..6decf99af5f089 100644
+--- a/arch/arm64/boot/dts/nvidia/tegra234.dtsi
++++ b/arch/arm64/boot/dts/nvidia/tegra234.dtsi
+@@ -3109,7 +3109,7 @@
+ 		#size-cells = <0>;
+ 
+ 		cpu0_0: cpu@0 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x00000>;
+ 
+@@ -3128,7 +3128,7 @@
+ 		};
+ 
+ 		cpu0_1: cpu@100 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x00100>;
+ 
+@@ -3147,7 +3147,7 @@
+ 		};
+ 
+ 		cpu0_2: cpu@200 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x00200>;
+ 
+@@ -3166,7 +3166,7 @@
+ 		};
+ 
+ 		cpu0_3: cpu@300 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x00300>;
+ 
+@@ -3185,7 +3185,7 @@
+ 		};
+ 
+ 		cpu1_0: cpu@10000 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x10000>;
+ 
+@@ -3204,7 +3204,7 @@
+ 		};
+ 
+ 		cpu1_1: cpu@10100 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x10100>;
+ 
+@@ -3223,7 +3223,7 @@
+ 		};
+ 
+ 		cpu1_2: cpu@10200 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x10200>;
+ 
+@@ -3242,7 +3242,7 @@
+ 		};
+ 
+ 		cpu1_3: cpu@10300 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x10300>;
+ 
+@@ -3261,7 +3261,7 @@
+ 		};
+ 
+ 		cpu2_0: cpu@20000 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x20000>;
+ 
+@@ -3280,7 +3280,7 @@
+ 		};
+ 
+ 		cpu2_1: cpu@20100 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x20100>;
+ 
+@@ -3299,7 +3299,7 @@
+ 		};
+ 
+ 		cpu2_2: cpu@20200 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x20200>;
+ 
+@@ -3318,7 +3318,7 @@
+ 		};
+ 
+ 		cpu2_3: cpu@20300 {
+-			compatible = "arm,cortex-a78";
++			compatible = "arm,cortex-a78ae";
+ 			device_type = "cpu";
+ 			reg = <0x20300>;
+ 
+diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
+index e49ead6d005cc4..d581aedf00190b 100644
+--- a/arch/arm64/kvm/arm.c
++++ b/arch/arm64/kvm/arm.c
+@@ -915,7 +915,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
+ 
+ 	vcpu_load(vcpu);
+ 
+-	if (run->immediate_exit) {
++	if (!vcpu->wants_to_run) {
+ 		ret = -EINTR;
+ 		goto out;
+ 	}
+diff --git a/arch/loongarch/kernel/kgdb.c b/arch/loongarch/kernel/kgdb.c
+index 7be5b4c0c90020..6728b2d67dd325 100644
+--- a/arch/loongarch/kernel/kgdb.c
++++ b/arch/loongarch/kernel/kgdb.c
+@@ -252,7 +252,8 @@ static int kgdb_loongarch_notify(struct notifier_block *self, unsigned long cmd,
+ 	if (atomic_read(&kgdb_active) != -1)
+ 		kgdb_nmicallback(smp_processor_id(), regs);
+ 
+-	if (kgdb_handle_exception(args->trapnr, args->signr, cmd, regs))
++	if (kgdb_handle_exception(regs->csr_era == stepped_address ? 0 : args->trapnr,
++				  args->signr, cmd, regs))
+ 		return NOTIFY_DONE;
+ 
+ 	if (atomic_read(&kgdb_setting_breakpoint))
+diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
+index 231ac052b506b9..f1a99962027a4f 100644
+--- a/arch/mips/kvm/mips.c
++++ b/arch/mips/kvm/mips.c
+@@ -436,7 +436,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
+ 		vcpu->mmio_needed = 0;
+ 	}
+ 
+-	if (vcpu->run->immediate_exit)
++	if (!vcpu->wants_to_run)
+ 		goto out;
+ 
+ 	lose_fpu(1);
+diff --git a/arch/powerpc/include/asm/cputime.h b/arch/powerpc/include/asm/cputime.h
+index 4961fb38e4385f..aff858ca99c05d 100644
+--- a/arch/powerpc/include/asm/cputime.h
++++ b/arch/powerpc/include/asm/cputime.h
+@@ -32,23 +32,10 @@
+ #ifdef CONFIG_PPC64
+ #define get_accounting(tsk)	(&get_paca()->accounting)
+ #define raw_get_accounting(tsk)	(&local_paca->accounting)
+-static inline void arch_vtime_task_switch(struct task_struct *tsk) { }
+ 
+ #else
+ #define get_accounting(tsk)	(&task_thread_info(tsk)->accounting)
+ #define raw_get_accounting(tsk)	get_accounting(tsk)
+-/*
+- * Called from the context switch with interrupts disabled, to charge all
+- * accumulated times to the current process, and to prepare accounting on
+- * the next process.
+- */
+-static inline void arch_vtime_task_switch(struct task_struct *prev)
+-{
+-	struct cpu_accounting_data *acct = get_accounting(current);
+-	struct cpu_accounting_data *acct0 = get_accounting(prev);
+-
+-	acct->starttime = acct0->starttime;
+-}
+ #endif
+ 
+ /*
+diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
+index dda35c404a6761..dce831af31662e 100644
+--- a/arch/powerpc/kernel/time.c
++++ b/arch/powerpc/kernel/time.c
+@@ -354,6 +354,69 @@ void vtime_flush(struct task_struct *tsk)
+ 	acct->hardirq_time = 0;
+ 	acct->softirq_time = 0;
+ }
++
++/*
++ * Called from the context switch with interrupts disabled, to charge all
++ * accumulated times to the current process, and to prepare accounting on
++ * the next process.
++ */
++void vtime_task_switch(struct task_struct *prev)
++{
++	if (is_idle_task(prev))
++		vtime_account_idle(prev);
++	else
++		vtime_account_kernel(prev);
++
++	vtime_flush(prev);
++
++	if (!IS_ENABLED(CONFIG_PPC64)) {
++		struct cpu_accounting_data *acct = get_accounting(current);
++		struct cpu_accounting_data *acct0 = get_accounting(prev);
++
++		acct->starttime = acct0->starttime;
++	}
++}
++
++/**
++ * vtime_reset - Fast forward vtime entry clocks
++ *
++ * Called from dynticks idle IRQ entry to fast-forward the clocks to current time
++ * so that the IRQ time is still accounted by vtime while nohz cputime is paused.
++ */
++void vtime_reset(void)
++{
++	struct cpu_accounting_data *acct = get_accounting(current);
++
++	acct->starttime = mftb();
++#ifdef CONFIG_ARCH_HAS_SCALED_CPUTIME
++	acct->startspurr = read_spurr(acct->starttime);
++#endif
++}
++
++#ifdef CONFIG_NO_HZ_COMMON
++/**
++ * vtime_dyntick_start - Inform vtime about entry to idle-dynticks
++ *
++ * Called when idle enters in dyntick mode. The idle cputime that elapsed so far
++ * is accumulated and the tick subsystem takes over the idle cputime accounting.
++ */
++void vtime_dyntick_start(void)
++{
++	vtime_account_idle(current);
++}
++
++/**
++ * vtime_dyntick_stop - Inform vtime about exit from idle-dynticks
++ *
++ * Called when idle exits from dyntick mode. The vtime entry clocks are
++ * fast-forward to current time so that idle accounting restarts elapsing from
++ * now.
++ */
++void vtime_dyntick_stop(void)
++{
++	vtime_reset();
++}
++#endif /* CONFIG_NO_HZ_COMMON */
+ #endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
+ 
+ void __no_kcsan __delay(unsigned long loops)
+@@ -864,6 +927,7 @@ static void __init set_decrementer_max(void)
+ static void __init init_decrementer_clockevent(void)
+ {
+ 	register_decrementer_clockevent(smp_processor_id());
++	vtime_reset();
+ }
+ 
+ void secondary_cpu_time_init(void)
+@@ -879,6 +943,7 @@ void secondary_cpu_time_init(void)
+ 	/* FIME: Should make unrelated change to move snapshot_timebase
+ 	 * call here ! */
+ 	register_decrementer_clockevent(smp_processor_id());
++	vtime_reset();
+ }
+ 
+ /* This function is only called on the boot processor */
+diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
+index 6cef200c2404df..0e35668b28302f 100644
+--- a/arch/powerpc/kvm/powerpc.c
++++ b/arch/powerpc/kvm/powerpc.c
+@@ -1858,7 +1858,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
+ 
+ 	kvm_sigset_activate(vcpu);
+ 
+-	if (run->immediate_exit)
++	if (!vcpu->wants_to_run)
+ 		r = -EINTR;
+ 	else
+ 		r = kvmppc_vcpu_run(vcpu);
+diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
+index 459e61ad7d2b68..d2d7f9b4f7c043 100644
+--- a/arch/riscv/include/asm/kvm_host.h
++++ b/arch/riscv/include/asm/kvm_host.h
+@@ -202,13 +202,13 @@ struct kvm_vcpu_arch {
+ 	/*
+ 	 * VCPU interrupts
+ 	 *
+-	 * We have a lockless approach for tracking pending VCPU interrupts
+-	 * implemented using atomic bitops. The irqs_pending bitmap represent
+-	 * pending interrupts whereas irqs_pending_mask represent bits changed
+-	 * in irqs_pending. Our approach is modeled around multiple producer
+-	 * and single consumer problem where the consumer is the VCPU itself.
++	 * The irqs_pending bitmap represents pending interrupts whereas
++	 * irqs_pending_mask represents bits changed in irqs_pending. Updates
++	 * to these bitmaps are serialized so vcpu interrupt sync/flush cannot
++	 * drop a newly injected interrupt while syncing guest-visible HVIP.
+ 	 */
+ #define KVM_RISCV_VCPU_NR_IRQS	64
++	raw_spinlock_t irqs_pending_lock;
+ 	DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
+ 	DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
+ 
+diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c
+index 74bb27440527b3..be133090306455 100644
+--- a/arch/riscv/kvm/aia.c
++++ b/arch/riscv/kvm/aia.c
+@@ -71,12 +71,15 @@ void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu)
+ 	struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
+ 	unsigned long mask, val;
+ 
++	lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
++
+ 	if (!kvm_riscv_aia_available())
+ 		return;
+ 
+-	if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) {
+-		mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0);
+-		val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask;
++	mask = vcpu->arch.irqs_pending_mask[1];
++	if (mask) {
++		vcpu->arch.irqs_pending_mask[1] = 0;
++		val = vcpu->arch.irqs_pending[1] & mask;
+ 
+ 		csr->hviph &= ~mask;
+ 		csr->hviph |= val;
+@@ -87,6 +90,8 @@ void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)
+ {
+ 	struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
+ 
++	lockdep_assert_held(&vcpu->arch.irqs_pending_lock);
++
+ 	if (kvm_riscv_aia_available())
+ 		csr->vsieh = csr_read(CSR_VSIEH);
+ }
+@@ -96,13 +101,22 @@ bool kvm_riscv_vcpu_aia_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
+ {
+ 	int hgei;
+ 	unsigned long seip;
++#ifdef CONFIG_32BIT
++	unsigned long flags;
++	bool pending;
++#endif
+ 
+ 	if (!kvm_riscv_aia_available())
+ 		return false;
+ 
+ #ifdef CONFIG_32BIT
+-	if (READ_ONCE(vcpu->arch.irqs_pending[1]) &
+-	    (vcpu->arch.aia_context.guest_csr.vsieh & upper_32_bits(mask)))
++	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++	pending = vcpu->arch.irqs_pending[1] &
++		  (vcpu->arch.aia_context.guest_csr.vsieh &
++		   upper_32_bits(mask));
++	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
++
++	if (pending)
+ 		return true;
+ #endif
+ 
+@@ -190,6 +204,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
+ 			       unsigned long val)
+ {
+ 	struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
++#ifdef CONFIG_32BIT
++	unsigned long flags;
++#endif
+ 
+ 	if (reg_num >= sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long))
+ 		return -ENOENT;
+@@ -198,8 +215,12 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
+ 		((unsigned long *)csr)[reg_num] = val;
+ 
+ #ifdef CONFIG_32BIT
+-		if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph))
+-			WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0);
++		if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) {
++			raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++			vcpu->arch.irqs_pending_mask[1] = 0;
++			raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock,
++						   flags);
++		}
+ #endif
+ 	}
+ 
+diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
+index 9584d62c96ee74..e2c66bf319111b 100644
+--- a/arch/riscv/kvm/vcpu.c
++++ b/arch/riscv/kvm/vcpu.c
+@@ -44,6 +44,7 @@ const struct kvm_stats_header kvm_vcpu_stats_header = {
+ 
+ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu)
+ {
++	unsigned long flags;
+ 	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+ 	struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr;
+ 	struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
+@@ -74,8 +75,10 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu)
+ 
+ 	kvm_riscv_vcpu_aia_reset(vcpu);
+ 
++	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+ 	bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
+ 	bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
++	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+ 
+ 	kvm_riscv_vcpu_pmu_reset(vcpu);
+ 
+@@ -117,6 +120,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
+ 
+ 	/* Setup VCPU hfence queue */
+ 	spin_lock_init(&vcpu->arch.hfence_lock);
++	raw_spin_lock_init(&vcpu->arch.irqs_pending_lock);
+ 
+ 	/* Setup reset state of shadow SSTATUS and HSTATUS CSRs */
+ 	cntx = &vcpu->arch.guest_reset_context;
+@@ -323,10 +327,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
+ {
+ 	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+ 	unsigned long mask, val;
++	unsigned long flags;
+ 
+-	if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) {
+-		mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0);
+-		val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask;
++	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++
++	mask = vcpu->arch.irqs_pending_mask[0];
++	if (mask) {
++		vcpu->arch.irqs_pending_mask[0] = 0;
++		val = vcpu->arch.irqs_pending[0] & mask;
+ 
+ 		csr->hvip &= ~mask;
+ 		csr->hvip |= val;
+@@ -334,11 +342,14 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
+ 
+ 	/* Flush AIA high interrupts */
+ 	kvm_riscv_vcpu_aia_flush_interrupts(vcpu);
++
++	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+ }
+ 
+ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
+ {
+ 	unsigned long hvip;
++	unsigned long flags;
+ 	struct kvm_vcpu_arch *v = &vcpu->arch;
+ 	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
+ 
+@@ -347,27 +358,34 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
+ 
+ 	/* Sync-up HVIP.VSSIP bit changes does by Guest */
+ 	hvip = csr_read(CSR_HVIP);
++
++	raw_spin_lock_irqsave(&v->irqs_pending_lock, flags);
++
+ 	if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) {
+ 		if (hvip & (1UL << IRQ_VS_SOFT)) {
+-			if (!test_and_set_bit(IRQ_VS_SOFT,
+-					      v->irqs_pending_mask))
+-				set_bit(IRQ_VS_SOFT, v->irqs_pending);
++			if (!__test_and_set_bit(IRQ_VS_SOFT,
++						v->irqs_pending_mask))
++				__set_bit(IRQ_VS_SOFT, v->irqs_pending);
+ 		} else {
+-			if (!test_and_set_bit(IRQ_VS_SOFT,
+-					      v->irqs_pending_mask))
+-				clear_bit(IRQ_VS_SOFT, v->irqs_pending);
++			if (!__test_and_set_bit(IRQ_VS_SOFT,
++						v->irqs_pending_mask))
++				__clear_bit(IRQ_VS_SOFT, v->irqs_pending);
+ 		}
+ 	}
+ 
+ 	/* Sync-up AIA high interrupts */
+ 	kvm_riscv_vcpu_aia_sync_interrupts(vcpu);
+ 
++	raw_spin_unlock_irqrestore(&v->irqs_pending_lock, flags);
++
+ 	/* Sync-up timer CSRs */
+ 	kvm_riscv_vcpu_timer_sync(vcpu);
+ }
+ 
+ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
+ {
++	unsigned long flags;
++
+ 	/*
+ 	 * We only allow VS-mode software, timer, and external
+ 	 * interrupts when irq is one of the local interrupts
+@@ -379,9 +397,10 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
+ 	    irq != IRQ_VS_EXT)
+ 		return -EINVAL;
+ 
+-	set_bit(irq, vcpu->arch.irqs_pending);
+-	smp_mb__before_atomic();
+-	set_bit(irq, vcpu->arch.irqs_pending_mask);
++	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++	__set_bit(irq, vcpu->arch.irqs_pending);
++	__set_bit(irq, vcpu->arch.irqs_pending_mask);
++	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+ 
+ 	kvm_vcpu_kick(vcpu);
+ 
+@@ -390,6 +409,8 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
+ 
+ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
+ {
++	unsigned long flags;
++
+ 	/*
+ 	 * We only allow VS-mode software, timer, and external
+ 	 * interrupts when irq is one of the local interrupts
+@@ -401,26 +422,33 @@ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
+ 	    irq != IRQ_VS_EXT)
+ 		return -EINVAL;
+ 
+-	clear_bit(irq, vcpu->arch.irqs_pending);
+-	smp_mb__before_atomic();
+-	set_bit(irq, vcpu->arch.irqs_pending_mask);
++	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++	__clear_bit(irq, vcpu->arch.irqs_pending);
++	__set_bit(irq, vcpu->arch.irqs_pending_mask);
++	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+ 
+ 	return 0;
+ }
+ 
+ bool kvm_riscv_vcpu_has_interrupts(struct kvm_vcpu *vcpu, u64 mask)
+ {
++	unsigned long flags;
+ 	unsigned long ie;
++	bool ret;
+ 
++	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+ 	ie = ((vcpu->arch.guest_csr.vsie & VSIP_VALID_MASK)
+ 		<< VSIP_TO_HVIP_SHIFT) & (unsigned long)mask;
+ 	ie |= vcpu->arch.guest_csr.vsie & ~IRQ_LOCAL_MASK &
+ 		(unsigned long)mask;
+-	if (READ_ONCE(vcpu->arch.irqs_pending[0]) & ie)
+-		return true;
++	ret = vcpu->arch.irqs_pending[0] & ie;
++	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+ 
+ 	/* Check AIA high interrupts */
+-	return kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
++	if (!ret)
++		ret = kvm_riscv_vcpu_aia_has_interrupts(vcpu, mask);
++
++	return ret;
+ }
+ 
+ void __kvm_riscv_vcpu_power_off(struct kvm_vcpu *vcpu)
+@@ -676,7 +704,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
+ 		return ret;
+ 	}
+ 
+-	if (run->immediate_exit) {
++	if (!vcpu->wants_to_run) {
+ 		kvm_vcpu_srcu_read_unlock(vcpu);
+ 		return -EINTR;
+ 	}
+diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
+index d520b25d856167..0e5853186365e2 100644
+--- a/arch/riscv/kvm/vcpu_onereg.c
++++ b/arch/riscv/kvm/vcpu_onereg.c
+@@ -361,6 +361,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
+ 					  unsigned long reg_val)
+ {
+ 	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
++	unsigned long flags;
+ 
+ 	if (reg_num >= sizeof(struct kvm_riscv_csr) / sizeof(unsigned long))
+ 		return -ENOENT;
+@@ -372,8 +373,11 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
+ 
+ 	((unsigned long *)csr)[reg_num] = reg_val;
+ 
+-	if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
+-		WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0);
++	if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
++		raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
++		vcpu->arch.irqs_pending_mask[0] = 0;
++		raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
++	}
+ 
+ 	return 0;
+ }
+diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
+index 890d850f51f076..bccbb84eb1be65 100644
+--- a/arch/s390/kvm/kvm-s390.c
++++ b/arch/s390/kvm/kvm-s390.c
+@@ -5048,7 +5048,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
+ 	if (vcpu->kvm->arch.pv.dumping)
+ 		return -EINVAL;
+ 
+-	if (kvm_run->immediate_exit)
++	if (!vcpu->wants_to_run)
+ 		return -EINTR;
+ 
+ 	if (kvm_run->kvm_valid_regs & ~KVM_SYNC_S390_VALID_FIELDS ||
+diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
+index ba17496fad1b3b..bee3c0151a34f5 100644
+--- a/arch/x86/boot/compressed/Makefile
++++ b/arch/x86/boot/compressed/Makefile
+@@ -36,6 +36,7 @@ targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
+ KBUILD_CFLAGS := -m$(BITS) -O2 $(CLANG_FLAGS)
+ KBUILD_CFLAGS += -std=gnu11
+ KBUILD_CFLAGS += -fno-strict-aliasing -fPIE
++KBUILD_CFLAGS += -fno-jump-tables
+ KBUILD_CFLAGS += -Wundef
+ KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
+ cflags-$(CONFIG_X86_32) := -march=i386
+diff --git a/arch/x86/kernel/cpu/resctrl/rdtgroup.c b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+index d82d5de183b107..1bc8b98e175c18 100644
+--- a/arch/x86/kernel/cpu/resctrl/rdtgroup.c
++++ b/arch/x86/kernel/cpu/resctrl/rdtgroup.c
+@@ -2744,10 +2744,6 @@ static void rmdir_all_sub(void)
+ 		if (rdtgrp == &rdtgroup_default)
+ 			continue;
+ 
+-		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
+-		    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED)
+-			rdtgroup_pseudo_lock_remove(rdtgrp);
+-
+ 		/*
+ 		 * Give any CPUs back to the default group. We cannot copy
+ 		 * cpu_online_mask because a CPU might have executed the
+@@ -2756,7 +2752,13 @@ static void rmdir_all_sub(void)
+ 		cpumask_or(&rdtgroup_default.cpu_mask,
+ 			   &rdtgroup_default.cpu_mask, &rdtgrp->cpu_mask);
+ 
+-		free_rmid(rdtgrp->mon.rmid);
++		if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP ||
++		    rdtgrp->mode == RDT_MODE_PSEUDO_LOCKED) {
++			rdtgroup_pseudo_lock_remove(rdtgrp);
++		} else {
++			/* Pseudo-locked group's RMID is freed during setup. */
++			free_rmid(rdtgrp->mon.rmid);
++		}
+ 
+ 		kernfs_remove(rdtgrp->kn);
+ 		list_del(&rdtgrp->rdtgroup_list);
+diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
+index f5d0fd131b2754..a750ec8057cc9a 100644
+--- a/arch/x86/kvm/lapic.c
++++ b/arch/x86/kvm/lapic.c
+@@ -1912,7 +1912,7 @@ static void apic_timer_expired(struct kvm_lapic *apic, bool from_timer_fn)
+ 	if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use)
+ 		ktimer->expired_tscdeadline = ktimer->tscdeadline;
+ 
+-	if (!from_timer_fn && apic->apicv_active) {
++	if (!from_timer_fn && apic->apicv_active && vcpu->wants_to_run) {
+ 		WARN_ON(kvm_get_running_vcpu() != vcpu);
+ 		kvm_apic_inject_pending_timer_irqs(apic);
+ 		return;
+diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
+index 2453524ea4a1fc..6c4b588d557fcf 100644
+--- a/arch/x86/kvm/mmu/mmu.c
++++ b/arch/x86/kvm/mmu/mmu.c
+@@ -4384,16 +4384,17 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
+ 
+ 	orig_pfn = fault->pfn;
+ 
+-	r = RET_PF_RETRY;
+ 	write_lock(&vcpu->kvm->mmu_lock);
+ 
+-	if (is_page_fault_stale(vcpu, fault))
+-		goto out_unlock;
+-
+ 	r = make_mmu_pages_available(vcpu);
+ 	if (r)
+ 		goto out_unlock;
+ 
++	if (is_page_fault_stale(vcpu, fault)) {
++		r = RET_PF_RETRY;
++		goto out_unlock;
++	}
++
+ 	r = direct_map(vcpu, fault);
+ 
+ out_unlock:
+@@ -6803,7 +6804,9 @@ static struct shrinker mmu_shrinker = {
+ static void mmu_destroy_caches(void)
+ {
+ 	kmem_cache_destroy(pte_list_desc_cache);
++	pte_list_desc_cache = NULL;
+ 	kmem_cache_destroy(mmu_page_header_cache);
++	mmu_page_header_cache = NULL;
+ }
+ 
+ static int get_nx_huge_pages(char *buffer, const struct kernel_param *kp)
+diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h
+index c6b2c52aceaca8..7692b3ce8dd071 100644
+--- a/arch/x86/kvm/mmu/paging_tmpl.h
++++ b/arch/x86/kvm/mmu/paging_tmpl.h
+@@ -838,15 +838,17 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
+ 
+ 	orig_pfn = fault->pfn;
+ 
+-	r = RET_PF_RETRY;
+ 	write_lock(&vcpu->kvm->mmu_lock);
+ 
+-	if (is_page_fault_stale(vcpu, fault))
+-		goto out_unlock;
+-
+ 	r = make_mmu_pages_available(vcpu);
+ 	if (r)
+ 		goto out_unlock;
++
++	if (is_page_fault_stale(vcpu, fault)) {
++		r = RET_PF_RETRY;
++		goto out_unlock;
++	}
++
+ 	r = FNAME(fetch)(vcpu, fault, &walker);
+ 
+ out_unlock:
+diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
+index 31e901661b4e95..62c7e575302162 100644
+--- a/arch/x86/kvm/svm/svm.c
++++ b/arch/x86/kvm/svm/svm.c
+@@ -637,7 +637,12 @@ static int svm_hardware_enable(void)
+ 		return -EBUSY;
+ 
+ 	sd = per_cpu_ptr(&svm_data, me);
+-	sd->asid_generation = 1;
++	/*
++	 * Bump the current asid_generation value to ensure any vCPU that
++	 * previously ran on this CPU sees a stale generation and is forced
++	 * to acquire a new ASID, preventing a latent ASID collision.
++	 */
++	sd->asid_generation++;
+ 	sd->max_asid = cpuid_ebx(SVM_CPUID_FUNC) - 1;
+ 	sd->next_asid = sd->max_asid + 1;
+ 	sd->min_asid = max_sev_asid + 1;
+diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c
+index 377b30212c1914..fb473e36438e21 100644
+--- a/arch/x86/kvm/vmx/nested.c
++++ b/arch/x86/kvm/vmx/nested.c
+@@ -295,6 +295,7 @@ static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs)
+ static void free_nested(struct kvm_vcpu *vcpu)
+ {
+ 	struct vcpu_vmx *vmx = to_vmx(vcpu);
++	struct vmcs *shadow_vmcs;
+ 
+ 	if (WARN_ON_ONCE(vmx->loaded_vmcs != &vmx->vmcs01))
+ 		vmx_switch_vmcs(vcpu, &vmx->vmcs01);
+@@ -312,9 +313,15 @@ static void free_nested(struct kvm_vcpu *vcpu)
+ 	vmx->nested.current_vmptr = INVALID_GPA;
+ 	if (enable_shadow_vmcs) {
+ 		vmx_disable_shadow_vmcs(vmx);
+-		vmcs_clear(vmx->vmcs01.shadow_vmcs);
+-		free_vmcs(vmx->vmcs01.shadow_vmcs);
++
++		/*
++		 * Keep the pointer visible until after VMCLEAR, so migration
++		 * can clear an active shadow VMCS on the old CPU.
++		 */
++		shadow_vmcs = vmx->vmcs01.shadow_vmcs;
++		vmcs_clear(shadow_vmcs);
+ 		vmx->vmcs01.shadow_vmcs = NULL;
++		free_vmcs(shadow_vmcs);
+ 	}
+ 	kfree(vmx->nested.cached_vmcs12);
+ 	vmx->nested.cached_vmcs12 = NULL;
+diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
+index c04277b35e2edf..313fce77e05896 100644
+--- a/arch/x86/kvm/x86.c
++++ b/arch/x86/kvm/x86.c
+@@ -11224,7 +11224,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
+ 
+ 	kvm_vcpu_srcu_read_lock(vcpu);
+ 	if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) {
+-		if (kvm_run->immediate_exit) {
++		if (!vcpu->wants_to_run) {
+ 			r = -EINTR;
+ 			goto out;
+ 		}
+@@ -11302,7 +11302,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
+ 		WARN_ON_ONCE(vcpu->mmio_needed);
+ 	}
+ 
+-	if (kvm_run->immediate_exit) {
++	if (!vcpu->wants_to_run) {
+ 		r = -EINTR;
+ 		goto out;
+ 	}
+diff --git a/crypto/rsa-pkcs1pad.c b/crypto/rsa-pkcs1pad.c
+index d2e5e104f8cfe3..8172f0b0b481d7 100644
+--- a/crypto/rsa-pkcs1pad.c
++++ b/crypto/rsa-pkcs1pad.c
+@@ -534,7 +534,7 @@ static int pkcs1pad_verify(struct akcipher_request *req)
+ 	const unsigned int digest_size = req->dst_len;
+ 	int err;
+ 
+-	if (WARN_ON(req->dst) || WARN_ON(!digest_size) ||
++	if (WARN_ON(req->dst) || !digest_size ||
+ 	    !ctx->key_size || sig_size != ctx->key_size)
+ 		return -EINVAL;
+ 
+diff --git a/drivers/accel/ivpu/ivpu_fw_log.c b/drivers/accel/ivpu/ivpu_fw_log.c
+index 95065cac9fbdc4..ccad9aa99e5d64 100644
+--- a/drivers/accel/ivpu/ivpu_fw_log.c
++++ b/drivers/accel/ivpu/ivpu_fw_log.c
+@@ -43,6 +43,10 @@ static int fw_log_ptr(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *offset,
+ 		ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", log->header_size);
+ 		return -EINVAL;
+ 	}
++	if (log->size < log->header_size) {
++		ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
++		return -EINVAL;
++	}
+ 	if ((char *)log + log->size > (char *)bo->kvaddr + bo->base.size) {
+ 		ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size);
+ 		return -EINVAL;
+diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
+index 07dd04b8d01d16..3992a12b90a2a3 100644
+--- a/drivers/ata/libata-core.c
++++ b/drivers/ata/libata-core.c
+@@ -2794,6 +2794,24 @@ static void ata_dev_config_cpr(struct ata_device *dev)
+ 	if (!nr_cpr)
+ 		goto out;
+ 
++	/*
++	 * The device reports the number of CPR descriptors independently of the
++	 * log size, and that count is also used to emit VPD page B9h into the
++	 * fixed-size rbuf. Reject a count larger than what that buffer can hold
++	 * (ATA_DEV_MAX_CPR) or larger than the log the device actually returned.
++	 */
++	if (nr_cpr > ATA_DEV_MAX_CPR) {
++		ata_dev_warn(dev,
++			     "Too many concurrent positioning ranges\n");
++		goto out;
++	}
++
++	if (buf_len < 64 + (size_t)nr_cpr * 32) {
++		ata_dev_warn(dev,
++			     "Invalid number of concurrent positioning ranges\n");
++		goto out;
++	}
++
+ 	cpr_log = kzalloc(struct_size(cpr_log, cpr, nr_cpr), GFP_KERNEL);
+ 	if (!cpr_log)
+ 		goto out;
+diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
+index 300818cb1478a2..0da8c69dc966cc 100644
+--- a/drivers/ata/libata-scsi.c
++++ b/drivers/ata/libata-scsi.c
+@@ -37,8 +37,6 @@
+ #include "libata.h"
+ #include "libata-transport.h"
+ 
+-#define ATA_SCSI_RBUF_SIZE	2048
+-
+ static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
+ static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE];
+ 
+diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
+index 9927d79e55878b..dc2a4583441cd5 100644
+--- a/drivers/ata/libata.h
++++ b/drivers/ata/libata.h
+@@ -111,6 +111,15 @@ static inline void ata_acpi_bind_dev(struct ata_device *dev) {}
+ #endif
+ 
+ /* libata-scsi.c */
++#define ATA_SCSI_RBUF_SIZE	2048
++
++/*
++ * Maximum number of concurrent positioning ranges (CPR) supported. The ACS
++ * specifications allow up to 255, but we limit this to the number of CPR
++ * descriptors that fit in the rbuf buffer used to emit VPD page B9h.
++ */
++#define ATA_DEV_MAX_CPR		min(255, ((ATA_SCSI_RBUF_SIZE - 64) / 32))
++
+ extern struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
+ 					    const struct scsi_device *scsidev);
+ extern int ata_scsi_add_hosts(struct ata_host *host,
+diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
+index 52f5168e4db542..66db8dd8ec2670 100644
+--- a/drivers/ata/sata_dwc_460ex.c
++++ b/drivers/ata/sata_dwc_460ex.c
+@@ -19,7 +19,6 @@
+ #include <linux/device.h>
+ #include <linux/dmaengine.h>
+ #include <linux/of.h>
+-#include <linux/of_irq.h>
+ #include <linux/platform_device.h>
+ #include <linux/phy/phy.h>
+ #include <linux/libata.h>
+@@ -226,7 +225,6 @@ static int sata_dwc_dma_init_old(struct platform_device *pdev,
+ 				 struct sata_dwc_device *hsdev)
+ {
+ 	struct device *dev = &pdev->dev;
+-	struct device_node *np = dev->of_node;
+ 
+ 	hsdev->dma = devm_kzalloc(dev, sizeof(*hsdev->dma), GFP_KERNEL);
+ 	if (!hsdev->dma)
+@@ -236,11 +234,9 @@ static int sata_dwc_dma_init_old(struct platform_device *pdev,
+ 	hsdev->dma->id = pdev->id;
+ 
+ 	/* Get SATA DMA interrupt number */
+-	hsdev->dma->irq = irq_of_parse_and_map(np, 1);
+-	if (!hsdev->dma->irq) {
+-		dev_err(dev, "no SATA DMA irq\n");
+-		return -ENODEV;
+-	}
++	hsdev->dma->irq = platform_get_irq(pdev, 1);
++	if (hsdev->dma->irq < 0)
++		return hsdev->dma->irq;
+ 
+ 	/* Get physical SATA DMA register base address */
+ 	hsdev->dma->regs = devm_platform_ioremap_resource(pdev, 1);
+@@ -398,8 +394,7 @@ static void clear_serror(struct ata_port *ap)
+ 
+ static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit)
+ {
+-	sata_dwc_writel(&hsdev->sata_dwc_regs->intpr,
+-			sata_dwc_readl(&hsdev->sata_dwc_regs->intpr));
++	sata_dwc_writel(&hsdev->sata_dwc_regs->intpr, bit);
+ }
+ 
+ static u32 qcmd_tag_to_mask(u8 tag)
+@@ -612,14 +607,9 @@ DRVSTILLBUSY:
+ 	status = ap->ops->sff_check_status(ap);
+ 	dev_dbg(ap->dev, "%s ATA status register=0x%x\n", __func__, status);
+ 
+-	tag = 0;
+ 	while (tag_mask) {
+-		while (!(tag_mask & 0x00000001)) {
+-			tag++;
+-			tag_mask <<= 1;
+-		}
+-
+-		tag_mask &= (~0x00000001);
++		tag = __ffs(tag_mask);
++		tag_mask &= ~(1U << tag);
+ 		qc = ata_qc_from_tag(ap, tag);
+ 		if (unlikely(!qc)) {
+ 			dev_err(ap->dev, "failed to get qc");
+@@ -1125,7 +1115,6 @@ static const struct ata_port_info sata_dwc_port_info[] = {
+ static int sata_dwc_probe(struct platform_device *ofdev)
+ {
+ 	struct device *dev = &ofdev->dev;
+-	struct device_node *np = dev->of_node;
+ 	struct sata_dwc_device *hsdev;
+ 	u32 idr, versionr;
+ 	char *ver = (char *)&versionr;
+@@ -1168,18 +1157,13 @@ static int sata_dwc_probe(struct platform_device *ofdev)
+ 	/* Save dev for later use in dev_xxx() routines */
+ 	hsdev->dev = dev;
+ 
+-	/* Enable SATA Interrupts */
+-	sata_dwc_enable_interrupts(hsdev);
+-
+ 	/* Get SATA interrupt number */
+-	irq = irq_of_parse_and_map(np, 0);
+-	if (!irq) {
+-		dev_err(dev, "no SATA DMA irq\n");
+-		return -ENODEV;
+-	}
++	irq = platform_get_irq(ofdev, 0);
++	if (irq < 0)
++		return irq;
+ 
+ #ifdef CONFIG_SATA_DWC_OLD_DMA
+-	if (!of_property_present(np, "dmas")) {
++	if (!of_property_present(dev->of_node, "dmas")) {
+ 		err = sata_dwc_dma_init_old(ofdev, hsdev);
+ 		if (err)
+ 			return err;
+@@ -1203,6 +1187,8 @@ static int sata_dwc_probe(struct platform_device *ofdev)
+ 	if (err)
+ 		dev_err(dev, "failed to activate host");
+ 
++	/* Enable SATA Interrupts */
++	sata_dwc_enable_interrupts(hsdev);
+ 	return 0;
+ 
+ error_out:
+diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
+index a50b946c3934fd..d049e8be5b824c 100644
+--- a/drivers/block/rbd.c
++++ b/drivers/block/rbd.c
+@@ -1957,9 +1957,14 @@ static int rbd_object_map_update_finish(struct rbd_obj_request *obj_req,
+ 	bool has_current_state;
+ 	void *p;
+ 
+-	if (osd_req->r_result)
++	if (osd_req->r_result < 0)
+ 		return osd_req->r_result;
+ 
++	/*
++	 * Writes aren't allowed to return a data payload.
++	 */
++	WARN_ON_ONCE(osd_req->r_result > 0);
++
+ 	/*
+ 	 * Nothing to do for a snapshot object map.
+ 	 */
+diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
+index 5b34da23adce7c..09ef7df5c231bf 100644
+--- a/drivers/bluetooth/btqca.c
++++ b/drivers/bluetooth/btqca.c
+@@ -430,7 +430,7 @@ static int qca_tlv_check_data(struct hci_dev *hdev,
+ 
+ 		idx = 0;
+ 		data = tlv->data;
+-		while (idx < length - sizeof(struct tlv_type_nvm)) {
++		while (idx + sizeof(struct tlv_type_nvm) <= length) {
+ 			tlv_nvm = (struct tlv_type_nvm *)(data + idx);
+ 
+ 			tag_id = le16_to_cpu(tlv_nvm->tag_id);
+diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
+index c3eb668c39943d..08b01d93b86c7f 100644
+--- a/drivers/bluetooth/btusb.c
++++ b/drivers/bluetooth/btusb.c
+@@ -2671,7 +2671,9 @@ static int btusb_setup_realtek(struct hci_dev *hdev)
+ 
+ static int btusb_recv_event_realtek(struct hci_dev *hdev, struct sk_buff *skb)
+ {
+-	if (skb->data[0] == HCI_VENDOR_PKT && skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
++	if (skb->len >= HCI_EVENT_HDR_SIZE + 1 &&
++	    skb->data[0] == HCI_VENDOR_PKT &&
++	    skb->data[2] == RTK_SUB_EVENT_CODE_COREDUMP) {
+ 		struct rtk_dev_coredump_hdr hdr = {
+ 			.code = RTK_DEVCOREDUMP_CODE_MEMDUMP,
+ 		};
+diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
+index 2986b18655a150..47c50a43db0232 100644
+--- a/drivers/bluetooth/hci_qca.c
++++ b/drivers/bluetooth/hci_qca.c
+@@ -1069,6 +1069,10 @@ static void qca_controller_memdump(struct work_struct *work)
+ 			if (!(qca_memdump->ram_dump_size)) {
+ 				bt_dev_err(hu->hdev, "Rx invalid memdump size");
+ 				kfree(qca_memdump);
++				qca->qca_memdump = NULL;
++				qca->memdump_state = QCA_MEMDUMP_COLLECTED;
++				clear_and_wake_up_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
++				clear_bit(QCA_IBS_DISABLED, &qca->flags);
+ 				kfree_skb(skb);
+ 				mutex_unlock(&qca->hci_memdump_lock);
+ 				return;
+diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
+index 2283fd91ff5f87..c638f6a9bc7d67 100644
+--- a/drivers/cdrom/cdrom.c
++++ b/drivers/cdrom/cdrom.c
+@@ -3191,6 +3191,7 @@ static noinline int mmc_ioctl_cdrom_volume(struct cdrom_device_info *cdi,
+ 
+ 	/* set volume */
+ 	cgc->buffer = buffer + offset - 8;
++	cgc->buflen -= offset - 8;
+ 	memset(cgc->buffer, 0, 8);
+ 	return cdrom_mode_select(cdi, cgc);
+ }
+diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
+index 37b84bfa623e99..7dec2138b87445 100644
+--- a/drivers/char/ipmi/ipmi_msghandler.c
++++ b/drivers/char/ipmi/ipmi_msghandler.c
+@@ -2331,6 +2331,10 @@ static int i_ipmi_request(struct ipmi_user     *user,
+ 		if (smi_msg == NULL) {
+ 			if (!supplied_recv)
+ 				ipmi_free_recv_msg(recv_msg);
++			else if (recv_msg->user) {
++				atomic_dec(&recv_msg->user->nr_msgs);
++				kref_put(&recv_msg->user->refcount, free_user);
++			}
+ 			return -ENOMEM;
+ 		}
+ 	}
+@@ -2373,6 +2377,10 @@ out_err:
+ 			ipmi_free_smi_msg(smi_msg);
+ 		if (!supplied_recv)
+ 			ipmi_free_recv_msg(recv_msg);
++		else if (recv_msg->user) {
++			atomic_dec(&recv_msg->user->nr_msgs);
++			kref_put(&recv_msg->user->refcount, free_user);
++		}
+ 	} else {
+ 		dev_dbg(intf->si_dev, "Send: %*ph\n",
+ 			smi_msg->data_size, smi_msg->data);
+diff --git a/drivers/comedi/drivers/comedi_parport.c b/drivers/comedi/drivers/comedi_parport.c
+index 098738a688fe64..db9f58792ab919 100644
+--- a/drivers/comedi/drivers/comedi_parport.c
++++ b/drivers/comedi/drivers/comedi_parport.c
+@@ -211,6 +211,13 @@ static irqreturn_t parport_interrupt(int irq, void *d)
+ 	unsigned int ctrl;
+ 	unsigned short val = 0;
+ 
++	/*
++	 * Check device is fully attached.  Device interrupts should have
++	 * been disabled, but do this in case of bad hardware.
++	 */
++	if (!dev->attached)
++		return IRQ_NONE;
++
+ 	ctrl = inb(dev->iobase + PARPORT_CTRL_REG);
+ 	if (!(ctrl & PARPORT_CTRL_IRQ_ENA))
+ 		return IRQ_NONE;
+@@ -231,6 +238,9 @@ static int parport_attach(struct comedi_device *dev,
+ 	if (ret)
+ 		return ret;
+ 
++	outb(0, dev->iobase + PARPORT_DATA_REG);
++	outb(0, dev->iobase + PARPORT_CTRL_REG);
++
+ 	if (it->options[1]) {
+ 		ret = request_irq(it->options[1], parport_interrupt, 0,
+ 				  dev->board_name, dev);
+@@ -286,9 +296,6 @@ static int parport_attach(struct comedi_device *dev,
+ 		s->cancel	= parport_intr_cancel;
+ 	}
+ 
+-	outb(0, dev->iobase + PARPORT_DATA_REG);
+-	outb(0, dev->iobase + PARPORT_CTRL_REG);
+-
+ 	return 0;
+ }
+ 
+diff --git a/drivers/dma-buf/udmabuf.c b/drivers/dma-buf/udmabuf.c
+index 1f05c486ac32eb..cdb6c30352ae50 100644
+--- a/drivers/dma-buf/udmabuf.c
++++ b/drivers/dma-buf/udmabuf.c
+@@ -100,14 +100,16 @@ static struct sg_table *get_sg_table(struct device *dev, struct dma_buf *buf,
+ 					0, ubuf->pagecount << PAGE_SHIFT,
+ 					GFP_KERNEL);
+ 	if (ret < 0)
+-		goto err;
+-	ret = dma_map_sgtable(dev, sg, direction, 0);
++		goto err_alloc;
++
++	ret = dma_map_sgtable(dev, sg, direction, DMA_ATTR_SKIP_CPU_SYNC);
+ 	if (ret < 0)
+-		goto err;
++		goto err_map;
+ 	return sg;
+ 
+-err:
++err_map:
+ 	sg_free_table(sg);
++err_alloc:
+ 	kfree(sg);
+ 	return ERR_PTR(ret);
+ }
+@@ -115,7 +117,7 @@ err:
+ static void put_sg_table(struct device *dev, struct sg_table *sg,
+ 			 enum dma_data_direction direction)
+ {
+-	dma_unmap_sgtable(dev, sg, direction, 0);
++	dma_unmap_sgtable(dev, sg, direction, DMA_ATTR_SKIP_CPU_SYNC);
+ 	sg_free_table(sg);
+ 	kfree(sg);
+ }
+@@ -153,21 +155,22 @@ static int begin_cpu_udmabuf(struct dma_buf *buf,
+ {
+ 	struct udmabuf *ubuf = buf->priv;
+ 	struct device *dev = ubuf->device->this_device;
+-	int ret = 0;
+ 
+ 	if (!ubuf->sg) {
+ 		ubuf->sg = get_sg_table(dev, buf, direction);
+ 		if (IS_ERR(ubuf->sg)) {
++			int ret;
++
+ 			ret = PTR_ERR(ubuf->sg);
+ 			ubuf->sg = NULL;
++			return ret;
+ 		} else {
+ 			ubuf->sg_dir = direction;
+ 		}
+-	} else {
+-		dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction);
+ 	}
+ 
+-	return ret;
++	dma_sync_sgtable_for_cpu(dev, ubuf->sg, direction);
++	return 0;
+ }
+ 
+ static int end_cpu_udmabuf(struct dma_buf *buf,
+diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
+index 1c6043751dc925..b3f2653862a8a5 100644
+--- a/drivers/dma/dw-edma/dw-edma-pcie.c
++++ b/drivers/dma/dw-edma/dw-edma-pcie.c
+@@ -160,12 +160,19 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
+ 			      const struct pci_device_id *pid)
+ {
+ 	struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;
+-	struct dw_edma_pcie_data vsec_data;
+ 	struct device *dev = &pdev->dev;
+ 	struct dw_edma_chip *chip;
+ 	int err, nr_irqs;
+ 	int i, mask;
+ 
++	if (!pdata)
++		return -ENODEV;
++
++	struct dw_edma_pcie_data *vsec_data __free(kfree) =
++		kmalloc(sizeof(*vsec_data), GFP_KERNEL);
++	if (!vsec_data)
++		return -ENOMEM;
++
+ 	/* Enable PCI device */
+ 	err = pcim_enable_device(pdev);
+ 	if (err) {
+@@ -173,23 +180,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
+ 		return err;
+ 	}
+ 
+-	memcpy(&vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
++	memcpy(vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
+ 
+ 	/*
+ 	 * Tries to find if exists a PCIe Vendor-Specific Extended Capability
+ 	 * for the DMA, if one exists, then reconfigures it.
+ 	 */
+-	dw_edma_pcie_get_vsec_dma_data(pdev, &vsec_data);
++	dw_edma_pcie_get_vsec_dma_data(pdev, vsec_data);
+ 
+ 	/* Mapping PCI BAR regions */
+-	mask = BIT(vsec_data.rg.bar);
+-	for (i = 0; i < vsec_data.wr_ch_cnt; i++) {
+-		mask |= BIT(vsec_data.ll_wr[i].bar);
+-		mask |= BIT(vsec_data.dt_wr[i].bar);
++	mask = BIT(vsec_data->rg.bar);
++	for (i = 0; i < vsec_data->wr_ch_cnt; i++) {
++		mask |= BIT(vsec_data->ll_wr[i].bar);
++		mask |= BIT(vsec_data->dt_wr[i].bar);
+ 	}
+-	for (i = 0; i < vsec_data.rd_ch_cnt; i++) {
+-		mask |= BIT(vsec_data.ll_rd[i].bar);
+-		mask |= BIT(vsec_data.dt_rd[i].bar);
++	for (i = 0; i < vsec_data->rd_ch_cnt; i++) {
++		mask |= BIT(vsec_data->ll_rd[i].bar);
++		mask |= BIT(vsec_data->dt_rd[i].bar);
+ 	}
+ 	err = pcim_iomap_regions(pdev, mask, pci_name(pdev));
+ 	if (err) {
+@@ -212,7 +219,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
+ 		return -ENOMEM;
+ 
+ 	/* IRQs allocation */
+-	nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data.irqs,
++	nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data->irqs,
+ 					PCI_IRQ_MSI | PCI_IRQ_MSIX);
+ 	if (nr_irqs < 1) {
+ 		pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
+@@ -223,22 +230,22 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
+ 	/* Data structure initialization */
+ 	chip->dev = dev;
+ 
+-	chip->mf = vsec_data.mf;
++	chip->mf = vsec_data->mf;
+ 	chip->nr_irqs = nr_irqs;
+ 	chip->ops = &dw_edma_pcie_plat_ops;
+ 
+-	chip->ll_wr_cnt = vsec_data.wr_ch_cnt;
+-	chip->ll_rd_cnt = vsec_data.rd_ch_cnt;
++	chip->ll_wr_cnt = vsec_data->wr_ch_cnt;
++	chip->ll_rd_cnt = vsec_data->rd_ch_cnt;
+ 
+-	chip->reg_base = pcim_iomap_table(pdev)[vsec_data.rg.bar];
++	chip->reg_base = pcim_iomap_table(pdev)[vsec_data->rg.bar];
+ 	if (!chip->reg_base)
+ 		return -ENOMEM;
+ 
+ 	for (i = 0; i < chip->ll_wr_cnt; i++) {
+ 		struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
+ 		struct dw_edma_region *dt_region = &chip->dt_region_wr[i];
+-		struct dw_edma_block *ll_block = &vsec_data.ll_wr[i];
+-		struct dw_edma_block *dt_block = &vsec_data.dt_wr[i];
++		struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];
++		struct dw_edma_block *dt_block = &vsec_data->dt_wr[i];
+ 
+ 		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
+ 		if (!ll_region->vaddr.io)
+@@ -262,8 +269,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
+ 	for (i = 0; i < chip->ll_rd_cnt; i++) {
+ 		struct dw_edma_region *ll_region = &chip->ll_region_rd[i];
+ 		struct dw_edma_region *dt_region = &chip->dt_region_rd[i];
+-		struct dw_edma_block *ll_block = &vsec_data.ll_rd[i];
+-		struct dw_edma_block *dt_block = &vsec_data.dt_rd[i];
++		struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];
++		struct dw_edma_block *dt_block = &vsec_data->dt_rd[i];
+ 
+ 		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
+ 		if (!ll_region->vaddr.io)
+@@ -295,31 +302,31 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
+ 		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
+ 
+ 	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
+-		vsec_data.rg.bar, vsec_data.rg.off, vsec_data.rg.sz,
++		vsec_data->rg.bar, vsec_data->rg.off, vsec_data->rg.sz,
+ 		chip->reg_base);
+ 
+ 
+ 	for (i = 0; i < chip->ll_wr_cnt; i++) {
+ 		pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
+-			i, vsec_data.ll_wr[i].bar,
+-			vsec_data.ll_wr[i].off, chip->ll_region_wr[i].sz,
++			i, vsec_data->ll_wr[i].bar,
++			vsec_data->ll_wr[i].off, chip->ll_region_wr[i].sz,
+ 			chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);
+ 
+ 		pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
+-			i, vsec_data.dt_wr[i].bar,
+-			vsec_data.dt_wr[i].off, chip->dt_region_wr[i].sz,
++			i, vsec_data->dt_wr[i].bar,
++			vsec_data->dt_wr[i].off, chip->dt_region_wr[i].sz,
+ 			chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);
+ 	}
+ 
+ 	for (i = 0; i < chip->ll_rd_cnt; i++) {
+ 		pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
+-			i, vsec_data.ll_rd[i].bar,
+-			vsec_data.ll_rd[i].off, chip->ll_region_rd[i].sz,
++			i, vsec_data->ll_rd[i].bar,
++			vsec_data->ll_rd[i].off, chip->ll_region_rd[i].sz,
+ 			chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);
+ 
+ 		pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
+-			i, vsec_data.dt_rd[i].bar,
+-			vsec_data.dt_rd[i].off, chip->dt_region_rd[i].sz,
++			i, vsec_data->dt_rd[i].bar,
++			vsec_data->dt_rd[i].off, chip->dt_region_rd[i].sz,
+ 			chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);
+ 	}
+ 
+diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c
+index e5d89bc1bb83e7..63bcec46b01d7b 100644
+--- a/drivers/dma/sh/rz-dmac.c
++++ b/drivers/dma/sh/rz-dmac.c
+@@ -777,27 +777,6 @@ static int rz_dmac_chan_probe(struct rz_dmac *dmac,
+ 	channel->index = index;
+ 	channel->mid_rid = -EINVAL;
+ 
+-	/* Request the channel interrupt. */
+-	sprintf(pdev_irqname, "ch%u", index);
+-	channel->irq = platform_get_irq_byname(pdev, pdev_irqname);
+-	if (channel->irq < 0)
+-		return channel->irq;
+-
+-	irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u",
+-				 dev_name(dmac->dev), index);
+-	if (!irqname)
+-		return -ENOMEM;
+-
+-	ret = devm_request_threaded_irq(dmac->dev, channel->irq,
+-					rz_dmac_irq_handler,
+-					rz_dmac_irq_handler_thread, 0,
+-					irqname, channel);
+-	if (ret) {
+-		dev_err(dmac->dev, "failed to request IRQ %u (%d)\n",
+-			channel->irq, ret);
+-		return ret;
+-	}
+-
+ 	/* Set io base address for each channel */
+ 	if (index < 8) {
+ 		channel->ch_base = dmac->base + CHANNEL_0_7_OFFSET +
+@@ -810,9 +789,9 @@ static int rz_dmac_chan_probe(struct rz_dmac *dmac,
+ 	}
+ 
+ 	/* Allocate descriptors */
+-	lmdesc = dma_alloc_coherent(&pdev->dev,
+-				    sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
+-				    &channel->lmdesc.base_dma, GFP_KERNEL);
++	lmdesc = dmam_alloc_coherent(&pdev->dev,
++				     sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
++				     &channel->lmdesc.base_dma, GFP_KERNEL);
+ 	if (!lmdesc) {
+ 		dev_err(&pdev->dev, "Can't allocate memory (lmdesc)\n");
+ 		return -ENOMEM;
+@@ -828,7 +807,26 @@ static int rz_dmac_chan_probe(struct rz_dmac *dmac,
+ 	INIT_LIST_HEAD(&channel->ld_free);
+ 	INIT_LIST_HEAD(&channel->ld_active);
+ 
+-	return 0;
++	/* Request the channel interrupt. */
++	sprintf(pdev_irqname, "ch%u", index);
++	channel->irq = platform_get_irq_byname(pdev, pdev_irqname);
++	if (channel->irq < 0)
++		return channel->irq;
++
++	irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u",
++				 dev_name(dmac->dev), index);
++	if (!irqname)
++		return -ENOMEM;
++
++	ret = devm_request_threaded_irq(dmac->dev, channel->irq,
++					rz_dmac_irq_handler,
++					rz_dmac_irq_handler_thread, 0,
++					irqname, channel);
++	if (ret)
++		dev_err(dmac->dev, "failed to request IRQ %u (%d)\n",
++			channel->irq, ret);
++
++	return ret;
+ }
+ 
+ static int rz_dmac_parse_of(struct device *dev, struct rz_dmac *dmac)
+@@ -855,7 +853,6 @@ static int rz_dmac_probe(struct platform_device *pdev)
+ 	const char *irqname = "error";
+ 	struct dma_device *engine;
+ 	struct rz_dmac *dmac;
+-	int channel_num;
+ 	unsigned int i;
+ 	int ret;
+ 	int irq;
+@@ -885,19 +882,6 @@ static int rz_dmac_probe(struct platform_device *pdev)
+ 	if (IS_ERR(dmac->ext_base))
+ 		return PTR_ERR(dmac->ext_base);
+ 
+-	/* Register interrupt handler for error */
+-	irq = platform_get_irq_byname(pdev, irqname);
+-	if (irq < 0)
+-		return irq;
+-
+-	ret = devm_request_irq(&pdev->dev, irq, rz_dmac_irq_handler, 0,
+-			       irqname, NULL);
+-	if (ret) {
+-		dev_err(&pdev->dev, "failed to request IRQ %u (%d)\n",
+-			irq, ret);
+-		return ret;
+-	}
+-
+ 	/* Initialize the channels. */
+ 	INIT_LIST_HEAD(&dmac->engine.channels);
+ 
+@@ -923,6 +907,21 @@ static int rz_dmac_probe(struct platform_device *pdev)
+ 			goto err;
+ 	}
+ 
++	/* Register interrupt handler for error */
++	irq = platform_get_irq_byname(pdev, irqname);
++	if (irq < 0) {
++		ret = irq;
++		goto err;
++	}
++
++	ret = devm_request_irq(&pdev->dev, irq, rz_dmac_irq_handler, 0,
++			       irqname, NULL);
++	if (ret) {
++		dev_err(&pdev->dev, "failed to request IRQ %u (%d)\n",
++			irq, ret);
++		goto err;
++	}
++
+ 	/* Register the DMAC as a DMA provider for DT. */
+ 	ret = of_dma_controller_register(pdev->dev.of_node, rz_dmac_of_xlate,
+ 					 NULL);
+@@ -961,16 +960,6 @@ static int rz_dmac_probe(struct platform_device *pdev)
+ dma_register_err:
+ 	of_dma_controller_free(pdev->dev.of_node);
+ err:
+-	channel_num = i ? i - 1 : 0;
+-	for (i = 0; i < channel_num; i++) {
+-		struct rz_dmac_chan *channel = &dmac->channels[i];
+-
+-		dma_free_coherent(&pdev->dev,
+-				  sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
+-				  channel->lmdesc.base,
+-				  channel->lmdesc.base_dma);
+-	}
+-
+ 	reset_control_assert(dmac->rstc);
+ err_pm_runtime_put:
+ 	pm_runtime_put(&pdev->dev);
+@@ -983,18 +972,9 @@ err_pm_disable:
+ static int rz_dmac_remove(struct platform_device *pdev)
+ {
+ 	struct rz_dmac *dmac = platform_get_drvdata(pdev);
+-	unsigned int i;
+ 
+ 	dma_async_device_unregister(&dmac->engine);
+ 	of_dma_controller_free(pdev->dev.of_node);
+-	for (i = 0; i < dmac->n_channels; i++) {
+-		struct rz_dmac_chan *channel = &dmac->channels[i];
+-
+-		dma_free_coherent(&pdev->dev,
+-				  sizeof(struct rz_lmdesc) * DMAC_NR_LMDESC,
+-				  channel->lmdesc.base,
+-				  channel->lmdesc.base_dma);
+-	}
+ 	reset_control_assert(dmac->rstc);
+ 	pm_runtime_put(&pdev->dev);
+ 	pm_runtime_disable(&pdev->dev);
+diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
+index 21f3a9dae072a9..2a2dd75120b6e3 100644
+--- a/drivers/firewire/net.c
++++ b/drivers/firewire/net.c
+@@ -298,31 +298,34 @@ static struct fwnet_fragment_info *fwnet_frag_new(
+ 		if (fi->offset + fi->len == offset) {
+ 			/* The new fragment can be tacked on to the end */
+ 			/* Did the new fragment plug a hole? */
+-			fi2 = list_entry(fi->fi_link.next,
+-					 struct fwnet_fragment_info, fi_link);
+-			if (fi->offset + fi->len == fi2->offset) {
+-				/* glue fragments together */
+-				fi->len += len + fi2->len;
+-				list_del(&fi2->fi_link);
+-				kfree(fi2);
+-			} else {
+-				fi->len += len;
++			if (!list_is_last(&fi->fi_link, &pd->fi_list)) {
++				fi2 = list_next_entry(fi, fi_link);
++				if (offset + len == fi2->offset) {
++					/* glue fragments together */
++					fi->len += len + fi2->len;
++					list_del(&fi2->fi_link);
++					kfree(fi2);
++
++					return fi;
++				}
+ 			}
++			fi->len += len;
+ 
+ 			return fi;
+ 		}
+ 		if (offset + len == fi->offset) {
+ 			/* The new fragment can be tacked on to the beginning */
+ 			/* Did the new fragment plug a hole? */
+-			fi2 = list_entry(fi->fi_link.prev,
+-					 struct fwnet_fragment_info, fi_link);
+-			if (fi2->offset + fi2->len == fi->offset) {
+-				/* glue fragments together */
+-				fi2->len += fi->len + len;
+-				list_del(&fi->fi_link);
+-				kfree(fi);
+-
+-				return fi2;
++			if (!list_is_first(&fi->fi_link, &pd->fi_list)) {
++				fi2 = list_prev_entry(fi, fi_link);
++				if (fi2->offset + fi2->len == offset) {
++					/* glue fragments together */
++					fi2->len += fi->len + len;
++					list_del(&fi->fi_link);
++					kfree(fi);
++
++					return fi2;
++				}
+ 			}
+ 			fi->offset = offset;
+ 			fi->len += len;
+diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
+index ece91d8d820b51..2309a31549e25a 100644
+--- a/drivers/firmware/arm_ffa/driver.c
++++ b/drivers/firmware/arm_ffa/driver.c
+@@ -582,7 +582,7 @@ static int ffa_partition_info_get(const char *uuid_str,
+ 	uuid_t uuid;
+ 	struct ffa_partition_info *pbuf;
+ 
+-	if (uuid_parse(uuid_str, &uuid)) {
++	if (!uuid_str || uuid_parse(uuid_str, &uuid)) {
+ 		pr_err("invalid uuid (%s)\n", uuid_str);
+ 		return -ENODEV;
+ 	}
+diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c
+index 4782b115e6ec51..1bc715fe3968c3 100644
+--- a/drivers/firmware/arm_scmi/notify.c
++++ b/drivers/firmware/arm_scmi/notify.c
+@@ -595,9 +595,9 @@ int scmi_notify(const struct scmi_handle *handle, u8 proto_id, u8 evt_id,
+ 		return -EINVAL;
+ 	}
+ 	if (kfifo_avail(&r_evt->proto->equeue.kfifo) < sizeof(eh) + len) {
+-		dev_warn(handle->dev,
+-			 "queue full, dropping proto_id:%d  evt_id:%d  ts:%lld\n",
+-			 proto_id, evt_id, ktime_to_ns(ts));
++		dev_warn_ratelimited(handle->dev,
++				     "queue full, dropping proto_id:%d  evt_id:%d  ts:%lld\n",
++				     proto_id, evt_id, ktime_to_ns(ts));
+ 		return -ENOMEM;
+ 	}
+ 
+diff --git a/drivers/fpga/dfl-afu-main.c b/drivers/fpga/dfl-afu-main.c
+index 7f621e96d3b8d8..dd4107ffa7158c 100644
+--- a/drivers/fpga/dfl-afu-main.c
++++ b/drivers/fpga/dfl-afu-main.c
+@@ -720,6 +720,9 @@ afu_ioctl_dma_map(struct dfl_feature_platform_data *pdata, void __user *arg)
+ 	if (map.argsz < minsz || map.flags)
+ 		return -EINVAL;
+ 
++	if (map.length >> PAGE_SHIFT > (u64)INT_MAX)
++		return -EINVAL;
++
+ 	ret = afu_dma_map_region(pdata, map.user_addr, map.length, &map.iova);
+ 	if (ret)
+ 		return ret;
+diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c
+index 93facbebb80efa..212a5f57cfd2bd 100644
+--- a/drivers/gpio/gpio-mt7621.c
++++ b/drivers/gpio/gpio-mt7621.c
+@@ -156,6 +156,8 @@ mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
+ 	int pin = d->hwirq;
+ 	u32 mask = BIT(pin);
+ 
++	guard(spinlock_irqsave)(&rg->lock);
++
+ 	if (type == IRQ_TYPE_PROBE) {
+ 		if ((rg->rising | rg->falling |
+ 		     rg->hlevel | rg->llevel) & mask)
+diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
+index 9ca659cff43883..f58f835d0acb3c 100644
+--- a/drivers/gpio/gpio-mvebu.c
++++ b/drivers/gpio/gpio-mvebu.c
+@@ -345,7 +345,7 @@ static int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin)
+ 	 * Check with the pinctrl driver whether this pin is usable as
+ 	 * an input GPIO
+ 	 */
+-	ret = pinctrl_gpio_direction_input(chip->base + pin);
++	ret = pinctrl_gpio_direction_input(chip, pin);
+ 	if (ret)
+ 		return ret;
+ 
+@@ -365,7 +365,7 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin,
+ 	 * Check with the pinctrl driver whether this pin is usable as
+ 	 * an output GPIO
+ 	 */
+-	ret = pinctrl_gpio_direction_output(chip->base + pin);
++	ret = pinctrl_gpio_direction_output(chip, pin);
+ 	if (ret)
+ 		return ret;
+ 
+diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
+index cae9661862fe1d..91cea97255fa6d 100644
+--- a/drivers/gpio/gpio-pxa.c
++++ b/drivers/gpio/gpio-pxa.c
+@@ -260,7 +260,7 @@ static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+ 	int ret;
+ 
+ 	if (pxa_gpio_has_pinctrl()) {
+-		ret = pinctrl_gpio_direction_input(chip->base + offset);
++		ret = pinctrl_gpio_direction_input(chip, offset);
+ 		if (ret)
+ 			return ret;
+ 	}
+@@ -289,7 +289,7 @@ static int pxa_gpio_direction_output(struct gpio_chip *chip,
+ 	writel_relaxed(mask, base + (value ? GPSR_OFFSET : GPCR_OFFSET));
+ 
+ 	if (pxa_gpio_has_pinctrl()) {
+-		ret = pinctrl_gpio_direction_output(chip->base + offset);
++		ret = pinctrl_gpio_direction_output(chip, offset);
+ 		if (ret)
+ 			return ret;
+ 	}
+diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
+index dc2a4d3d56a102..1846a2fb3b2eb6 100644
+--- a/drivers/gpio/gpio-tegra.c
++++ b/drivers/gpio/gpio-tegra.c
+@@ -174,18 +174,11 @@ static int tegra_gpio_direction_input(struct gpio_chip *chip,
+ 				      unsigned int offset)
+ {
+ 	struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+-	int ret;
+ 
+ 	tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 0);
+ 	tegra_gpio_enable(tgi, offset);
+ 
+-	ret = pinctrl_gpio_direction_input(chip->base + offset);
+-	if (ret < 0)
+-		dev_err(tgi->dev,
+-			"Failed to set pinctrl input direction of GPIO %d: %d",
+-			 chip->base + offset, ret);
+-
+-	return ret;
++	return 0;
+ }
+ 
+ static int tegra_gpio_direction_output(struct gpio_chip *chip,
+@@ -193,19 +186,12 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip,
+ 				       int value)
+ {
+ 	struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+-	int ret;
+ 
+ 	tegra_gpio_set(chip, offset, value);
+ 	tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 1);
+ 	tegra_gpio_enable(tgi, offset);
+ 
+-	ret = pinctrl_gpio_direction_output(chip->base + offset);
+-	if (ret < 0)
+-		dev_err(tgi->dev,
+-			"Failed to set pinctrl output direction of GPIO %d: %d",
+-			 chip->base + offset, ret);
+-
+-	return ret;
++	return 0;
+ }
+ 
+ static int tegra_gpio_get_direction(struct gpio_chip *chip,
+diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
+index 656d6b1dddb5db..324489ff47a71c 100644
+--- a/drivers/gpio/gpio-vf610.c
++++ b/drivers/gpio/gpio-vf610.c
+@@ -116,7 +116,7 @@ static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+ 		vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
+ 	}
+ 
+-	return pinctrl_gpio_direction_input(chip->base + gpio);
++	return pinctrl_gpio_direction_input(chip, gpio);
+ }
+ 
+ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
+@@ -134,7 +134,7 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
+ 		vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
+ 	}
+ 
+-	return pinctrl_gpio_direction_output(chip->base + gpio);
++	return pinctrl_gpio_direction_output(chip, gpio);
+ }
+ 
+ static void vf610_gpio_irq_handler(struct irq_desc *desc)
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
+index 6d72355ac4928f..31c3aaeb3bb41e 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
+@@ -559,7 +559,9 @@ static int acp_hw_fini(void *handle)
+ 
+ 	mfd_remove_devices(adev->acp.parent);
+ 	kfree(adev->acp.acp_res);
++	pm_genpd_remove(&adev->acp.acp_genpd->gpd);
+ 	kfree(adev->acp.acp_genpd);
++	adev->acp.acp_genpd = NULL;
+ 	kfree(adev->acp.acp_cell);
+ 
+ 	return 0;
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+index f3a09ecb76992b..367787653bc086 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c
+@@ -361,6 +361,45 @@ static bool amdgpu_read_disabled_bios(struct amdgpu_device *adev)
+ }
+ 
+ #ifdef CONFIG_ACPI
++/**
++ * amdgpu_acpi_vfct_match() - Check if a VFCT entry matches the device
++ * @adev: AMDGPU device
++ * @vhdr: VFCT image header to check
++ *
++ * VFCT entries contain the PCI bus number as recorded during BIOS POST.
++ * On systems where the kernel renumbers PCI buses (e.g. pci=realloc or
++ * resource conflicts), the runtime bus number may differ from the POST
++ * value.  Match by device identity (vendor + device + function) and use
++ * the bus number as a preference: exact bus match is preferred, but when
++ * the bus numbers disagree we accept the entry if the device identity
++ * matches.
++ *
++ * Returns: 0 on match, -ENODEV on no match
++ */
++static int amdgpu_acpi_vfct_match(struct amdgpu_device *adev,
++				  VFCT_IMAGE_HEADER *vhdr)
++{
++	/* Vendor and device IDs must always match */
++	if (vhdr->VendorID != adev->pdev->vendor ||
++	    vhdr->DeviceID != adev->pdev->device)
++		return -ENODEV;
++
++	if (vhdr->PCIDevice != PCI_SLOT(adev->pdev->devfn) ||
++	    vhdr->PCIFunction != PCI_FUNC(adev->pdev->devfn))
++		return -ENODEV;
++
++	/* Exact bus number match - preferred */
++	if (vhdr->PCIBus == adev->pdev->bus->number)
++		return 0;
++
++	/* Bus mismatch but device identity matches (PCI renumbering case) */
++	dev_notice(adev->dev,
++		   "VFCT bus number mismatch: table %u != runtime %u, matching by device identity (vendor 0x%04x device 0x%04x)\n",
++		   vhdr->PCIBus, adev->pdev->bus->number,
++		   adev->pdev->vendor, adev->pdev->device);
++	return 0;
++}
++
+ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
+ {
+ 	struct acpi_table_header *hdr;
+@@ -396,11 +435,7 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev)
+ 		}
+ 
+ 		if (vhdr->ImageLength &&
+-		    vhdr->PCIBus == adev->pdev->bus->number &&
+-		    vhdr->PCIDevice == PCI_SLOT(adev->pdev->devfn) &&
+-		    vhdr->PCIFunction == PCI_FUNC(adev->pdev->devfn) &&
+-		    vhdr->VendorID == adev->pdev->vendor &&
+-		    vhdr->DeviceID == adev->pdev->device) {
++		    !amdgpu_acpi_vfct_match(adev, vhdr)) {
+ 			adev->bios = kmemdup(&vbios->VbiosContent,
+ 					     vhdr->ImageLength,
+ 					     GFP_KERNEL);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+index 88ddcbfe43fa3d..2d12bb47c574db 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+@@ -272,13 +272,17 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
+ 				goto free_partial_kdata;
+ 			break;
+ 
++		case AMDGPU_CHUNK_ID_CP_GFX_SHADOW:
++			if (size < sizeof(struct drm_amdgpu_cs_chunk_cp_gfx_shadow))
++				goto free_partial_kdata;
++			break;
++
+ 		case AMDGPU_CHUNK_ID_DEPENDENCIES:
+ 		case AMDGPU_CHUNK_ID_SYNCOBJ_IN:
+ 		case AMDGPU_CHUNK_ID_SYNCOBJ_OUT:
+ 		case AMDGPU_CHUNK_ID_SCHEDULED_DEPENDENCIES:
+ 		case AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_WAIT:
+ 		case AMDGPU_CHUNK_ID_SYNCOBJ_TIMELINE_SIGNAL:
+-		case AMDGPU_CHUNK_ID_CP_GFX_SHADOW:
+ 			break;
+ 
+ 		default:
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+index 8672838fb67cad..5eea14076a9292 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+@@ -3977,8 +3977,6 @@ static void amdgpu_device_unmap_mmio(struct amdgpu_device *adev)
+ 
+ 	iounmap(adev->rmmio);
+ 	adev->rmmio = NULL;
+-	if (adev->mman.aper_base_kaddr)
+-		iounmap(adev->mman.aper_base_kaddr);
+ 	adev->mman.aper_base_kaddr = NULL;
+ 
+ 	/* Memory manager related */
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+index 4e9ae52ef9fdbf..be88c962bc5823 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+@@ -285,10 +285,12 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev,
+ 		goto error_free;
+ 	}
+ 
+-	r = amdgpu_bo_pin(*bo_ptr, domain);
+-	if (r) {
+-		dev_err(adev->dev, "(%d) kernel bo pin failed\n", r);
+-		goto error_unreserve;
++	if (free) {
++		r = amdgpu_bo_pin(*bo_ptr, domain);
++		if (r) {
++			dev_err(adev->dev, "(%d) kernel bo pin failed\n", r);
++			goto error_unreserve;
++		}
+ 	}
+ 
+ 	r = amdgpu_ttm_alloc_gart(&(*bo_ptr)->tbo);
+@@ -311,7 +313,8 @@ int amdgpu_bo_create_reserved(struct amdgpu_device *adev,
+ 	return 0;
+ 
+ error_unpin:
+-	amdgpu_bo_unpin(*bo_ptr);
++	if (free)
++		amdgpu_bo_unpin(*bo_ptr);
+ error_unreserve:
+ 	amdgpu_bo_unreserve(*bo_ptr);
+ 
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+index 96c98417c29ded..052ff38c20495d 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+@@ -479,6 +479,15 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
+ 
+ 	if (new_mem->mem_type == TTM_PL_TT ||
+ 	    new_mem->mem_type == AMDGPU_PL_PREEMPT) {
++		if (old_mem && (old_mem->mem_type == TTM_PL_TT ||
++				old_mem->mem_type == AMDGPU_PL_PREEMPT)) {
++			r = ttm_bo_wait_ctx(bo, ctx);
++			if (r)
++				return r;
++
++			amdgpu_ttm_backend_unbind(bo->bdev, bo->ttm);
++		}
++
+ 		r = amdgpu_ttm_backend_bind(bo->bdev, bo->ttm, new_mem);
+ 		if (r)
+ 			return r;
+@@ -513,6 +522,15 @@ static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
+ 		ttm_bo_assign_mem(bo, new_mem);
+ 		return 0;
+ 	}
++	if ((old_mem->mem_type == TTM_PL_TT ||
++	     old_mem->mem_type == AMDGPU_PL_PREEMPT) &&
++	    (new_mem->mem_type == TTM_PL_TT ||
++	     new_mem->mem_type == AMDGPU_PL_PREEMPT)) {
++		amdgpu_bo_move_notify(bo, evict, new_mem);
++		ttm_resource_free(bo, &bo->resource);
++		ttm_bo_assign_mem(bo, new_mem);
++		return 0;
++	}
+ 
+ 	if (old_mem->mem_type == AMDGPU_PL_GDS ||
+ 	    old_mem->mem_type == AMDGPU_PL_GWS ||
+@@ -1869,18 +1887,23 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
+ 	/* Change the size here instead of the init above so only lpfn is affected */
+ 	amdgpu_ttm_set_buffer_funcs_status(adev, false);
+ #ifdef CONFIG_64BIT
+-#ifdef CONFIG_X86
+-	if (adev->gmc.xgmi.connected_to_cpu)
+-		adev->mman.aper_base_kaddr = ioremap_cache(adev->gmc.aper_base,
+-				adev->gmc.visible_vram_size);
+-
+-	else if (adev->gmc.is_app_apu)
++	if (adev->gmc.xgmi.connected_to_cpu) {
++		void *kaddr = devm_memremap(adev->dev, adev->gmc.aper_base,
++					    adev->gmc.visible_vram_size,
++					    MEMREMAP_WB);
++		if (IS_ERR(kaddr))
++			return PTR_ERR(kaddr);
++		adev->mman.aper_base_kaddr = (__force void __iomem *)kaddr;
++	} else if (adev->gmc.is_app_apu) {
+ 		DRM_DEBUG_DRIVER(
+ 			"No need to ioremap when real vram size is 0\n");
+-	else
+-#endif
+-		adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base,
+-				adev->gmc.visible_vram_size);
++	} else {
++		adev->mman.aper_base_kaddr = devm_ioremap_wc(adev->dev,
++							     adev->gmc.aper_base,
++							     adev->gmc.visible_vram_size);
++		if (!adev->mman.aper_base_kaddr)
++			return -ENOMEM;
++	}
+ #endif
+ 
+ 	/*
+@@ -2015,8 +2038,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev)
+  */
+ void amdgpu_ttm_fini(struct amdgpu_device *adev)
+ {
+-	int idx;
+-
+ 	if (!adev->mman.initialized)
+ 		return;
+ 
+@@ -2039,14 +2060,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev)
+ 	amdgpu_ttm_fw_reserve_vram_fini(adev);
+ 	amdgpu_ttm_drv_reserve_vram_fini(adev);
+ 
+-	if (drm_dev_enter(adev_to_drm(adev), &idx)) {
+-
+-		if (adev->mman.aper_base_kaddr)
+-			iounmap(adev->mman.aper_base_kaddr);
+-		adev->mman.aper_base_kaddr = NULL;
+-
+-		drm_dev_exit(idx);
+-	}
++	adev->mman.aper_base_kaddr = NULL;
+ 
+ 	amdgpu_vram_mgr_fini(adev);
+ 	amdgpu_gtt_mgr_fini(adev);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+index b7441654e6fa73..8c3ab7f0804827 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
+@@ -135,7 +135,7 @@ MODULE_FIRMWARE(FIRMWARE_VEGA12);
+ MODULE_FIRMWARE(FIRMWARE_VEGA20);
+ 
+ static void amdgpu_uvd_idle_work_handler(struct work_struct *work);
+-static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *abo);
++static void amdgpu_uvd_force_into_vcpu_segment(struct amdgpu_bo *abo);
+ 
+ static int amdgpu_uvd_create_msg_bo_helper(struct amdgpu_device *adev,
+ 					   uint32_t size,
+@@ -158,7 +158,7 @@ static int amdgpu_uvd_create_msg_bo_helper(struct amdgpu_device *adev,
+ 	amdgpu_bo_kunmap(bo);
+ 	amdgpu_bo_unpin(bo);
+ 	amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_VRAM);
+-	amdgpu_uvd_force_into_uvd_segment(bo);
++	amdgpu_uvd_force_into_vcpu_segment(bo);
+ 	r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
+ 	if (r)
+ 		goto err;
+@@ -188,6 +188,7 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
+ 	const struct common_firmware_header *hdr;
+ 	unsigned int family_id;
+ 	int i, j, r;
++	u32 vcpu_bo_domain;
+ 
+ 	INIT_DELAYED_WORK(&adev->uvd.idle_work, amdgpu_uvd_idle_work_handler);
+ 
+@@ -319,12 +320,20 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
+ 	if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP)
+ 		bo_size += AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8);
+ 
++	/* UVD 5.0 and newer HW can use 64 bit addressing. */
++	adev->uvd.address_64_bit =
++		!amdgpu_device_ip_block_version_cmp(adev, AMD_IP_BLOCK_TYPE_UVD, 5, 0);
++
++	vcpu_bo_domain = AMDGPU_GEM_DOMAIN_VRAM;
++	if (adev->uvd.address_64_bit)
++		vcpu_bo_domain |= AMDGPU_GEM_DOMAIN_GTT;
++
+ 	for (j = 0; j < adev->uvd.num_uvd_inst; j++) {
+ 		if (adev->uvd.harvest_config & (1 << j))
+ 			continue;
++
+ 		r = amdgpu_bo_create_kernel(adev, bo_size, PAGE_SIZE,
+-					    AMDGPU_GEM_DOMAIN_VRAM |
+-					    AMDGPU_GEM_DOMAIN_GTT,
++					    vcpu_bo_domain,
+ 					    &adev->uvd.inst[j].vcpu_bo,
+ 					    &adev->uvd.inst[j].gpu_addr,
+ 					    &adev->uvd.inst[j].cpu_addr);
+@@ -339,10 +348,6 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev)
+ 		adev->uvd.filp[i] = NULL;
+ 	}
+ 
+-	/* from uvd v5.0 HW addressing capacity increased to 64 bits */
+-	if (!amdgpu_device_ip_block_version_cmp(adev, AMD_IP_BLOCK_TYPE_UVD, 5, 0))
+-		adev->uvd.address_64_bit = true;
+-
+ 	r = amdgpu_uvd_create_msg_bo_helper(adev, 128 << 10, &adev->uvd.ib_bo);
+ 	if (r)
+ 		return r;
+@@ -539,6 +544,24 @@ void amdgpu_uvd_free_handles(struct amdgpu_device *adev, struct drm_file *filp)
+ 	}
+ }
+ 
++static void amdgpu_uvd_force_into_vcpu_segment(struct amdgpu_bo *bo)
++{
++	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
++	struct amdgpu_bo *vcpu_bo = adev->uvd.inst[0].vcpu_bo;
++	struct amdgpu_res_cursor vcpu_cur;
++
++	amdgpu_res_first(vcpu_bo->tbo.resource, 0,
++			 amdgpu_bo_size(vcpu_bo), &vcpu_cur);
++
++	bo->placement.num_placement = 1;
++	bo->placement.placement = &bo->placements[0];
++	bo->placements[0].fpfn = ALIGN_DOWN(vcpu_cur.start, SZ_256M) >> PAGE_SHIFT;
++	bo->placements[0].lpfn = bo->placements[0].fpfn + (SZ_256M >> PAGE_SHIFT);
++	bo->placements[0].mem_type = vcpu_bo->tbo.resource->mem_type;
++	if (bo->placements[0].mem_type == TTM_PL_VRAM)
++		bo->placements[0].flags |= TTM_PL_FLAG_CONTIGUOUS;
++}
++
+ static void amdgpu_uvd_force_into_uvd_segment(struct amdgpu_bo *abo)
+ {
+ 	int i;
+@@ -587,13 +610,10 @@ static int amdgpu_uvd_cs_pass1(struct amdgpu_uvd_cs_ctx *ctx)
+ 	if (!ctx->parser->adev->uvd.address_64_bit) {
+ 		/* check if it's a message or feedback command */
+ 		cmd = amdgpu_ib_get_value(ctx->ib, ctx->idx) >> 1;
+-		if (cmd == 0x0 || cmd == 0x3) {
+-			/* yes, force it into VRAM */
+-			uint32_t domain = AMDGPU_GEM_DOMAIN_VRAM;
+-
+-			amdgpu_bo_placement_from_domain(bo, domain);
+-		}
+-		amdgpu_uvd_force_into_uvd_segment(bo);
++		if (cmd == 0x0 || cmd == 0x3)
++			amdgpu_uvd_force_into_vcpu_segment(bo);
++		else
++			amdgpu_uvd_force_into_uvd_segment(bo);
+ 
+ 		r = ttm_bo_validate(&bo->tbo, &bo->placement, &tctx);
+ 	}
+@@ -627,6 +647,14 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg,
+ 	unsigned int image_size, tmp, min_dpb_size, num_dpb_buffer;
+ 	unsigned int min_ctx_size = ~0;
+ 
++	/* Reject invalid dimensions to prevent division by zero */
++	if (width < 16 || height < 16) {
++		dev_WARN_ONCE(adev->dev, 1,
++			      "Invalid UVD decoding dimensions (%dx%d)!\n",
++			      width, height);
++		return -EINVAL;
++	}
++
+ 	image_size = width * height;
+ 	image_size += image_size / 2;
+ 	image_size = ALIGN(image_size, 1024);
+diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+index d25d444984b34b..a22d7fef21263e 100644
+--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+@@ -852,9 +852,20 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p,
+ 				goto out;
+ 			}
+ 
+-			*size = amdgpu_ib_get_value(ib, idx + 8) *
+-				amdgpu_ib_get_value(ib, idx + 10) *
+-				8 * 3 / 2;
++			uint32_t width, height;
++			width = amdgpu_ib_get_value(ib, idx + 8);
++			height = amdgpu_ib_get_value(ib, idx + 10);
++
++			if (width == 0 || height == 0 ||
++			    width > 4096 || height > 2304) {
++				DRM_ERROR("invalid VCE image size: %ux%u\n",
++					  width, height);
++				r = -EINVAL;
++				goto out;
++			}
++
++			*size = width * height * 8 * 3 / 2;
++
+ 			break;
+ 
+ 		case 0x04000001: /* config extension */
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+index afa9eb70507512..0e3c259c7cc5b3 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c
+@@ -3755,7 +3755,7 @@ static void gfx_v10_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel,
+ 			   WAIT_REG_MEM_ENGINE(eng_sel)));
+ 
+ 	if (mem_space)
+-		BUG_ON(addr0 & 0x3); /* Dword align */
++		WARN_ON(addr0 & 0x3); /* Dword align */
+ 	amdgpu_ring_write(ring, addr0);
+ 	amdgpu_ring_write(ring, addr1);
+ 	amdgpu_ring_write(ring, ref);
+@@ -8311,7 +8311,7 @@ static void gfx_v10_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
+ 		control |= 0x400000;
+ 
+ 	amdgpu_ring_write(ring, header);
+-	BUG_ON(ib->gpu_addr & 0x3); /* Dword align */
++	WARN_ON(ib->gpu_addr & 0x3); /* Dword align */
+ 	amdgpu_ring_write(ring,
+ #ifdef __BIG_ENDIAN
+ 		(2 << 0) |
+@@ -8350,7 +8350,7 @@ static void gfx_v10_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
+ 	}
+ 
+ 	amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
+-	BUG_ON(ib->gpu_addr & 0x3); /* Dword align */
++	WARN_ON(ib->gpu_addr & 0x3); /* Dword align */
+ 	amdgpu_ring_write(ring,
+ #ifdef __BIG_ENDIAN
+ 				(2 << 0) |
+@@ -8383,9 +8383,9 @@ static void gfx_v10_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
+ 	 * aligned if only send 32bit data low (discard data high)
+ 	 */
+ 	if (write64bit)
+-		BUG_ON(addr & 0x7);
++		WARN_ON(addr & 0x7);
+ 	else
+-		BUG_ON(addr & 0x3);
++		WARN_ON(addr & 0x3);
+ 	amdgpu_ring_write(ring, lower_32_bits(addr));
+ 	amdgpu_ring_write(ring, upper_32_bits(addr));
+ 	amdgpu_ring_write(ring, lower_32_bits(seq));
+@@ -8437,9 +8437,6 @@ static void gfx_v10_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr,
+ {
+ 	struct amdgpu_device *adev = ring->adev;
+ 
+-	/* we only allocate 32bit for each seq wb address */
+-	BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
+-
+ 	/* write fence seq to the "addr" */
+ 	amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ 	amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+index ed3e47a7eca1fe..131be358f92071 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
+@@ -310,7 +310,7 @@ static void gfx_v11_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel,
+ 			   WAIT_REG_MEM_ENGINE(eng_sel)));
+ 
+ 	if (mem_space)
+-		BUG_ON(addr0 & 0x3); /* Dword align */
++		WARN_ON(addr0 & 0x3); /* Dword align */
+ 	amdgpu_ring_write(ring, addr0);
+ 	amdgpu_ring_write(ring, addr1);
+ 	amdgpu_ring_write(ring, ref);
+@@ -5306,7 +5306,7 @@ static void gfx_v11_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
+ 		control |= 0x400000;
+ 
+ 	amdgpu_ring_write(ring, header);
+-	BUG_ON(ib->gpu_addr & 0x3); /* Dword align */
++	WARN_ON(ib->gpu_addr & 0x3); /* Dword align */
+ 	amdgpu_ring_write(ring,
+ #ifdef __BIG_ENDIAN
+ 		(2 << 0) |
+@@ -5345,7 +5345,7 @@ static void gfx_v11_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
+ 	}
+ 
+ 	amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
+-	BUG_ON(ib->gpu_addr & 0x3); /* Dword align */
++	WARN_ON(ib->gpu_addr & 0x3); /* Dword align */
+ 	amdgpu_ring_write(ring,
+ #ifdef __BIG_ENDIAN
+ 				(2 << 0) |
+@@ -5382,9 +5382,9 @@ static void gfx_v11_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
+ 	 * aligned if only send 32bit data low (discard data high)
+ 	 */
+ 	if (write64bit)
+-		BUG_ON(addr & 0x7);
++		WARN_ON(addr & 0x7);
+ 	else
+-		BUG_ON(addr & 0x3);
++		WARN_ON(addr & 0x3);
+ 	amdgpu_ring_write(ring, lower_32_bits(addr));
+ 	amdgpu_ring_write(ring, upper_32_bits(addr));
+ 	amdgpu_ring_write(ring, lower_32_bits(seq));
+@@ -5436,9 +5436,6 @@ static void gfx_v11_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr,
+ {
+ 	struct amdgpu_device *adev = ring->adev;
+ 
+-	/* we only allocate 32bit for each seq wb address */
+-	BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
+-
+ 	/* write fence seq to the "addr" */
+ 	amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ 	amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+index 472cb0f9e8f6c0..3632c1589db8fe 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+@@ -6267,9 +6267,6 @@ static void gfx_v8_0_ring_emit_fence_compute(struct amdgpu_ring *ring,
+ static void gfx_v8_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr,
+ 					 u64 seq, unsigned int flags)
+ {
+-	/* we only allocate 32bit for each seq wb address */
+-	BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
+-
+ 	/* write fence seq to the "addr" */
+ 	amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ 	amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+index f923aaa6104ad5..b1b4f75ebad356 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
+@@ -983,7 +983,7 @@ static void gfx_v9_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel,
+ 				 WAIT_REG_MEM_ENGINE(eng_sel)));
+ 
+ 	if (mem_space)
+-		BUG_ON(addr0 & 0x3); /* Dword align */
++		WARN_ON(addr0 & 0x3); /* Dword align */
+ 	amdgpu_ring_write(ring, addr0);
+ 	amdgpu_ring_write(ring, addr1);
+ 	amdgpu_ring_write(ring, ref);
+@@ -5166,7 +5166,7 @@ static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
+ 	}
+ 
+ 	amdgpu_ring_write(ring, header);
+-	BUG_ON(ib->gpu_addr & 0x3); /* Dword align */
++	WARN_ON(ib->gpu_addr & 0x3); /* Dword align */
+ 	amdgpu_ring_write(ring,
+ #ifdef __BIG_ENDIAN
+ 		(2 << 0) |
+@@ -5278,7 +5278,7 @@ static void gfx_v9_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
+ 	}
+ 
+ 	amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
+-	BUG_ON(ib->gpu_addr & 0x3); /* Dword align */
++	WARN_ON(ib->gpu_addr & 0x3); /* Dword align */
+ 	amdgpu_ring_write(ring,
+ #ifdef __BIG_ENDIAN
+ 				(2 << 0) |
+@@ -5319,9 +5319,9 @@ static void gfx_v9_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
+ 	 * aligned if only send 32bit data low (discard data high)
+ 	 */
+ 	if (write64bit)
+-		BUG_ON(addr & 0x7);
++		WARN_ON(addr & 0x7);
+ 	else
+-		BUG_ON(addr & 0x3);
++		WARN_ON(addr & 0x3);
+ 	amdgpu_ring_write(ring, lower_32_bits(addr));
+ 	amdgpu_ring_write(ring, upper_32_bits(addr));
+ 	amdgpu_ring_write(ring, lower_32_bits(seq));
+diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
+index caa04d897c2ded..1164937e8d20be 100644
+--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
++++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
+@@ -236,7 +236,7 @@ static void gfx_v9_4_3_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel,
+ 				 WAIT_REG_MEM_ENGINE(eng_sel)));
+ 
+ 	if (mem_space)
+-		BUG_ON(addr0 & 0x3); /* Dword align */
++		WARN_ON(addr0 & 0x3); /* Dword align */
+ 	amdgpu_ring_write(ring, addr0);
+ 	amdgpu_ring_write(ring, addr1);
+ 	amdgpu_ring_write(ring, ref);
+@@ -2529,7 +2529,7 @@ static void gfx_v9_4_3_ring_emit_ib_compute(struct amdgpu_ring *ring,
+ 	}
+ 
+ 	amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2));
+-	BUG_ON(ib->gpu_addr & 0x3); /* Dword align */
++	WARN_ON(ib->gpu_addr & 0x3); /* Dword align */
+ 	amdgpu_ring_write(ring,
+ #ifdef __BIG_ENDIAN
+ 				(2 << 0) |
+@@ -2563,9 +2563,9 @@ static void gfx_v9_4_3_ring_emit_fence(struct amdgpu_ring *ring, u64 addr,
+ 	 * aligned if only send 32bit data low (discard data high)
+ 	 */
+ 	if (write64bit)
+-		BUG_ON(addr & 0x7);
++		WARN_ON(addr & 0x7);
+ 	else
+-		BUG_ON(addr & 0x3);
++		WARN_ON(addr & 0x3);
+ 	amdgpu_ring_write(ring, lower_32_bits(addr));
+ 	amdgpu_ring_write(ring, upper_32_bits(addr));
+ 	amdgpu_ring_write(ring, lower_32_bits(seq));
+@@ -2625,9 +2625,6 @@ static void gfx_v9_4_3_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr,
+ {
+ 	struct amdgpu_device *adev = ring->adev;
+ 
+-	/* we only allocate 32bit for each seq wb address */
+-	BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT);
+-
+ 	/* write fence seq to the "addr" */
+ 	amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
+ 	amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
+diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
+index 4e8d5e6a65e410..2b9b19b6df5f03 100644
+--- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c
+@@ -393,7 +393,7 @@ static void sdma_v4_4_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64
+ 	/* write the fence */
+ 	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE));
+ 	/* zero in first two bits */
+-	BUG_ON(addr & 0x3);
++	WARN_ON(addr & 0x3);
+ 	amdgpu_ring_write(ring, lower_32_bits(addr));
+ 	amdgpu_ring_write(ring, upper_32_bits(addr));
+ 	amdgpu_ring_write(ring, lower_32_bits(seq));
+@@ -403,7 +403,7 @@ static void sdma_v4_4_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64
+ 		addr += 4;
+ 		amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE));
+ 		/* zero in first two bits */
+-		BUG_ON(addr & 0x3);
++		WARN_ON(addr & 0x3);
+ 		amdgpu_ring_write(ring, lower_32_bits(addr));
+ 		amdgpu_ring_write(ring, upper_32_bits(addr));
+ 		amdgpu_ring_write(ring, upper_32_bits(seq));
+diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
+index 1cc34efb455bb8..f4047f759fcbff 100644
+--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c
+@@ -520,7 +520,7 @@ static void sdma_v5_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
+ 	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) |
+ 			  SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */
+ 	/* zero in first two bits */
+-	BUG_ON(addr & 0x3);
++	WARN_ON(addr & 0x3);
+ 	amdgpu_ring_write(ring, lower_32_bits(addr));
+ 	amdgpu_ring_write(ring, upper_32_bits(addr));
+ 	amdgpu_ring_write(ring, lower_32_bits(seq));
+@@ -531,7 +531,7 @@ static void sdma_v5_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
+ 		amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) |
+ 				  SDMA_PKT_FENCE_HEADER_MTYPE(0x3));
+ 		/* zero in first two bits */
+-		BUG_ON(addr & 0x3);
++		WARN_ON(addr & 0x3);
+ 		amdgpu_ring_write(ring, lower_32_bits(addr));
+ 		amdgpu_ring_write(ring, upper_32_bits(addr));
+ 		amdgpu_ring_write(ring, upper_32_bits(seq));
+diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
+index 47d4840c6275c7..fa42a5017f83f2 100644
+--- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c
+@@ -337,7 +337,7 @@ static void sdma_v5_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
+ 	amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) |
+ 			  SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */
+ 	/* zero in first two bits */
+-	BUG_ON(addr & 0x3);
++	WARN_ON(addr & 0x3);
+ 	amdgpu_ring_write(ring, lower_32_bits(addr));
+ 	amdgpu_ring_write(ring, upper_32_bits(addr));
+ 	amdgpu_ring_write(ring, lower_32_bits(seq));
+@@ -348,7 +348,7 @@ static void sdma_v5_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
+ 		amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) |
+ 				  SDMA_PKT_FENCE_HEADER_MTYPE(0x3));
+ 		/* zero in first two bits */
+-		BUG_ON(addr & 0x3);
++		WARN_ON(addr & 0x3);
+ 		amdgpu_ring_write(ring, lower_32_bits(addr));
+ 		amdgpu_ring_write(ring, upper_32_bits(addr));
+ 		amdgpu_ring_write(ring, upper_32_bits(seq));
+diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
+index 45be0af2570b24..692be0835e29db 100644
+--- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c
+@@ -343,7 +343,7 @@ static void sdma_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
+ 	amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) |
+ 			  SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */
+ 	/* zero in first two bits */
+-	BUG_ON(addr & 0x3);
++	WARN_ON(addr & 0x3);
+ 	amdgpu_ring_write(ring, lower_32_bits(addr));
+ 	amdgpu_ring_write(ring, upper_32_bits(addr));
+ 	amdgpu_ring_write(ring, lower_32_bits(seq));
+@@ -354,7 +354,7 @@ static void sdma_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se
+ 		amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) |
+ 				  SDMA_PKT_FENCE_HEADER_MTYPE(0x3));
+ 		/* zero in first two bits */
+-		BUG_ON(addr & 0x3);
++		WARN_ON(addr & 0x3);
+ 		amdgpu_ring_write(ring, lower_32_bits(addr));
+ 		amdgpu_ring_write(ring, upper_32_bits(addr));
+ 		amdgpu_ring_write(ring, upper_32_bits(seq));
+diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+index d35bc5d01b448c..61f981fe9c5acc 100644
+--- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
++++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
+@@ -1769,14 +1769,17 @@ out:
+ #define RENCODE_IB_PARAM_SESSION_INIT			0x00000003
+ 
+ /* return the offset in ib if id is found, -1 otherwise */
+-static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start)
++static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start, uint32_t *length)
+ {
+ 	int i;
+ 	uint32_t len;
+ 
+ 	for (i = start; (len = amdgpu_ib_get_value(ib, i)) >= 8; i += len / 4) {
+-		if (amdgpu_ib_get_value(ib, i + 1) == id)
++		if (amdgpu_ib_get_value(ib, i + 1) == id) {
++			if (length)
++				*length = len;
+ 			return i;
++		}
+ 	}
+ 	return -1;
+ }
+@@ -1786,14 +1789,14 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
+ 					   struct amdgpu_ib *ib)
+ {
+ 	struct amdgpu_ring *ring = amdgpu_job_ring(job);
+-	uint32_t val;
++	uint32_t val, len;
+ 	int idx = 0, sidx;
+ 
+ 	/* The first instance can decode anything */
+ 	if (!ring->me)
+ 		return 0;
+ 
+-	while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx)) >= 0) {
++	while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx, &len)) >= 0) {
+ 		val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */
+ 		if (val == RADEON_VCN_ENGINE_TYPE_DECODE) {
+ 			uint32_t valid_buf_flag = amdgpu_ib_get_value(ib, idx + 6);
+@@ -1806,12 +1809,12 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,
+ 				amdgpu_ib_get_value(ib, idx + 8);
+ 			return vcn_v4_0_dec_msg(p, job, msg_buffer_addr);
+ 		} else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) {
+-			sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx);
++			sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx, NULL);
+ 			if (sidx >= 0 &&
+ 			    amdgpu_ib_get_value(ib, sidx + 2) == RENCODE_ENCODE_STANDARD_AV1)
+ 				return vcn_v4_0_limit_sched(p, job);
+ 		}
+-		idx += amdgpu_ib_get_value(ib, idx) / 4;
++		idx += len / 4;
+ 	}
+ 	return 0;
+ }
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+index 5ffd17ac8e1cf3..30af6b7dda8ccb 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c
+@@ -106,6 +106,9 @@ static int allocate_event_notification_slot(struct kfd_process *p,
+ 	}
+ 
+ 	if (restore_id) {
++		if (*restore_id >= KFD_SIGNAL_EVENT_LIMIT)
++			return -EINVAL;
++
+ 		id = idr_alloc(&p->event_idr, ev, *restore_id, *restore_id + 1,
+ 				GFP_KERNEL);
+ 	} else {
+diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+index 12f75b2ad664d9..7ae94daa969a2c 100644
+--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+@@ -5180,8 +5180,8 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
+ {
+ 	struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state);
+ 	struct rect *dirty_rects = flip_addrs->dirty_rects;
+-	u32 num_clips;
+-	struct drm_mode_rect *clips;
++	u32 num_clips = 0;
++	struct drm_mode_rect *clips = NULL;
+ 	bool bb_changed;
+ 	bool fb_changed;
+ 	u32 i = 0;
+@@ -5197,8 +5197,10 @@ static void fill_dc_dirty_rects(struct drm_plane *plane,
+ 	if (new_plane_state->rotation != DRM_MODE_ROTATE_0)
+ 		goto ffu;
+ 
+-	num_clips = drm_plane_get_damage_clips_count(new_plane_state);
+-	clips = drm_plane_get_damage_clips(new_plane_state);
++	if (!new_plane_state->ignore_damage_clips) {
++		num_clips = drm_plane_get_damage_clips_count(new_plane_state);
++		clips = drm_plane_get_damage_clips(new_plane_state);
++	}
+ 
+ 	if (!dm_crtc_state->mpo_requested) {
+ 		if (!num_clips || num_clips > DC_MAX_DIRTY_RECTS)
+@@ -9532,6 +9534,7 @@ skip_modeset:
+ 	/* Release extra reference */
+ 	if (new_stream)
+ 		dc_stream_release(new_stream);
++	new_stream = NULL;
+ 
+ 	/*
+ 	 * We want to do dc stream updates that do not require a
+diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+index 1c5ae4d62e37b7..65344d0c7c10d2 100644
+--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c
+@@ -255,13 +255,20 @@ static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,
+ 		struct dtbclk_dto_params dto_params = {0};
+ 
+ 		/* use mask to program DTO once per tg */
+-		if (pipe_ctx->stream_res.tg &&
++		if (pipe_ctx->stream && pipe_ctx->stream_res.tg &&
+ 				!(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) {
+ 			tg_mask |= (1 << pipe_ctx->stream_res.tg->inst);
+ 
+ 			dto_params.otg_inst = pipe_ctx->stream_res.tg->inst;
+ 			dto_params.ref_dtbclk_khz = ref_dtbclk_khz;
+ 
++			if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(pipe_ctx))
++				dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz / 10;
++
++			if (dc_is_hdmi_signal(pipe_ctx->stream->signal) ||
++					dc_is_dvi_signal(pipe_ctx->stream->signal))
++				dto_params.is_hdmi = true;
++
+ 			dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ 			//dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params);
+ 		}
+diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c
+index 0717f69f7c45a1..f3ba8e2a6faec8 100644
+--- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c
++++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c
+@@ -958,8 +958,11 @@ static bool detect_link_and_local_sink(struct dc_link *link,
+ 			    link->link_enc->features.flags.bits.DP_IS_USB_C == 1) {
+ 
+ 				/* if alt mode times out, return false */
+-				if (!wait_for_entering_dp_alt_mode(link))
++				if (!wait_for_entering_dp_alt_mode(link)) {
++					if (prev_sink)
++						dc_sink_release(prev_sink);
+ 					return false;
++				}
+ 			}
+ 
+ 			if (!detect_dp(link, &sink_caps, reason)) {
+diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
+index dbb62b911c75c1..84f9b412a4f117 100644
+--- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
++++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
+@@ -447,8 +447,6 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
+  *
+  *  @stream:      contains data we may need to construct VSIF (i.e. timing_3d_format, etc.)
+  *  @info_packet: output structure where to store VSIF
+- *  @ALLMEnabled: indicates whether ALLM HF-VSIF should be generated
+- *  @ALLMValue:   ALLM bit value to advertise in HF-VSIF
+  */
+ void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
+ 		struct dc_info_packet *info_packet)
+diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+index babb73147adfb3..93fe215986d396 100644
+--- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c
++++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c
+@@ -2055,6 +2055,11 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_
+ 		     gc_ver != IP_VERSION(9, 4, 3)) ||
+ 		    gc_ver < IP_VERSION(9, 0, 0))
+ 			*states = ATTR_STATE_UNSUPPORTED;
++
++		if (adev->scpm_enabled) {
++			dev_attr->attr.mode &= ~S_IWUGO;
++			dev_attr->store = NULL;
++		}
+ 	} else if (DEVICE_ATTR_IS(gpu_metrics)) {
+ 		if (gc_ver < IP_VERSION(9, 1, 0))
+ 			*states = ATTR_STATE_UNSUPPORTED;
+diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
+index 1d6e30269d5679..4d553be56396f3 100644
+--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
++++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/hwmgr.c
+@@ -106,11 +106,8 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr)
+ 		hwmgr->od_enabled = false;
+ 		switch (hwmgr->chip_id) {
+ 		case CHIP_BONAIRE:
+-			/* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM
+-			 * R7 260X cards with old MC ucode: MCLK DPM is unstable
+-			 */
+-			if (adev->pdev->subsystem_vendor == 0x106B ||
+-			    adev->pdev->device == 0x6658) {
++			/* R9 M380 in iMac 2015: SMU hangs when enabling MCLK DPM */
++			if (adev->pdev->subsystem_vendor == 0x106B) {
+ 				dev_info(adev->dev, "disabling MCLK DPM on quirky ASIC");
+ 				adev->pm.pp_feature &= ~PP_MCLK_DPM_MASK;
+ 				hwmgr->feature_mask &= ~PP_MCLK_DPM_MASK;
+diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+index ddfbb2009c8d38..790a559e9549ba 100644
+--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
++++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+@@ -1157,7 +1157,7 @@ static const struct mipi_dsi_host_ops cdns_dsi_ops = {
+ 	.transfer = cdns_dsi_transfer,
+ };
+ 
+-static int __maybe_unused cdns_dsi_resume(struct device *dev)
++static int cdns_dsi_resume(struct device *dev)
+ {
+ 	struct cdns_dsi *dsi = dev_get_drvdata(dev);
+ 
+@@ -1168,7 +1168,7 @@ static int __maybe_unused cdns_dsi_resume(struct device *dev)
+ 	return 0;
+ }
+ 
+-static int __maybe_unused cdns_dsi_suspend(struct device *dev)
++static int cdns_dsi_suspend(struct device *dev)
+ {
+ 	struct cdns_dsi *dsi = dev_get_drvdata(dev);
+ 
+@@ -1178,8 +1178,9 @@ static int __maybe_unused cdns_dsi_suspend(struct device *dev)
+ 	return 0;
+ }
+ 
+-static UNIVERSAL_DEV_PM_OPS(cdns_dsi_pm_ops, cdns_dsi_suspend, cdns_dsi_resume,
+-			    NULL);
++static const struct dev_pm_ops cdns_dsi_pm_ops = {
++	RUNTIME_PM_OPS(cdns_dsi_suspend, cdns_dsi_resume, NULL)
++};
+ 
+ static int cdns_dsi_drm_probe(struct platform_device *pdev)
+ {
+@@ -1326,7 +1327,7 @@ static struct platform_driver cdns_dsi_platform_driver = {
+ 	.driver = {
+ 		.name   = "cdns-dsi",
+ 		.of_match_table = cdns_dsi_of_match,
+-		.pm = &cdns_dsi_pm_ops,
++		.pm = pm_ptr(&cdns_dsi_pm_ops),
+ 	},
+ };
+ module_platform_driver(cdns_dsi_platform_driver);
+diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c
+index d4a5489d010c4d..6482c64079438d 100644
+--- a/drivers/gpu/drm/display/drm_dp_mst_topology.c
++++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c
+@@ -779,6 +779,12 @@ static bool drm_dp_sideband_append_payload(struct drm_dp_sideband_msg_rx *msg,
+ {
+ 	u8 crc4;
+ 
++	/* curchunk_len must be >= 1 (min 1 CRC byte) and fit in chunk[] */
++	if (!msg->curchunk_len ||
++	    msg->curchunk_len > ARRAY_SIZE(msg->chunk) ||
++	    msg->curchunk_idx + replybuflen > ARRAY_SIZE(msg->chunk))
++		return false;
++
+ 	memcpy(&msg->chunk[msg->curchunk_idx], replybuf, replybuflen);
+ 	msg->curchunk_idx += replybuflen;
+ 
+@@ -789,6 +795,9 @@ static bool drm_dp_sideband_append_payload(struct drm_dp_sideband_msg_rx *msg,
+ 			print_hex_dump(KERN_DEBUG, "wrong crc",
+ 				       DUMP_PREFIX_NONE, 16, 1,
+ 				       msg->chunk,  msg->curchunk_len, false);
++		/* Guard against accumulated msg[] overflow */
++		if (msg->curlen + msg->curchunk_len - 1 > ARRAY_SIZE(msg->msg))
++			return false;
+ 		/* copy chunk into bigger msg */
+ 		memcpy(&msg->msg[msg->curlen], msg->chunk, msg->curchunk_len - 1);
+ 		msg->curlen += msg->curchunk_len - 1;
+@@ -861,7 +870,7 @@ static bool drm_dp_sideband_parse_remote_dpcd_read(struct drm_dp_sideband_msg_rx
+ 		goto fail_len;
+ 	repmsg->u.remote_dpcd_read_ack.num_bytes = raw->msg[idx];
+ 	idx++;
+-	if (idx > raw->curlen)
++	if (idx + repmsg->u.remote_dpcd_read_ack.num_bytes > raw->curlen)
+ 		goto fail_len;
+ 
+ 	memcpy(repmsg->u.remote_dpcd_read_ack.bytes, &raw->msg[idx], repmsg->u.remote_dpcd_read_ack.num_bytes);
+@@ -897,7 +906,9 @@ static bool drm_dp_sideband_parse_remote_i2c_read_ack(struct drm_dp_sideband_msg
+ 		goto fail_len;
+ 	repmsg->u.remote_i2c_read_ack.num_bytes = raw->msg[idx];
+ 	idx++;
+-	/* TODO check */
++	if (idx + repmsg->u.remote_i2c_read_ack.num_bytes > raw->curlen)
++		goto fail_len;
++
+ 	memcpy(repmsg->u.remote_i2c_read_ack.bytes, &raw->msg[idx], repmsg->u.remote_i2c_read_ack.num_bytes);
+ 	return true;
+ fail_len:
+@@ -913,16 +924,13 @@ static bool drm_dp_sideband_parse_enum_path_resources_ack(struct drm_dp_sideband
+ 	repmsg->u.path_resources.port_number = (raw->msg[idx] >> 4) & 0xf;
+ 	repmsg->u.path_resources.fec_capable = raw->msg[idx] & 0x1;
+ 	idx++;
+-	if (idx > raw->curlen)
++	if (idx + 2 > raw->curlen)
+ 		goto fail_len;
+ 	repmsg->u.path_resources.full_payload_bw_number = (raw->msg[idx] << 8) | (raw->msg[idx+1]);
+ 	idx += 2;
+-	if (idx > raw->curlen)
++	if (idx + 2 > raw->curlen)
+ 		goto fail_len;
+ 	repmsg->u.path_resources.avail_payload_bw_number = (raw->msg[idx] << 8) | (raw->msg[idx+1]);
+-	idx += 2;
+-	if (idx > raw->curlen)
+-		goto fail_len;
+ 	return true;
+ fail_len:
+ 	DRM_DEBUG_KMS("enum resource parse length fail %d %d\n", idx, raw->curlen);
+@@ -940,12 +948,9 @@ static bool drm_dp_sideband_parse_allocate_payload_ack(struct drm_dp_sideband_ms
+ 		goto fail_len;
+ 	repmsg->u.allocate_payload.vcpi = raw->msg[idx];
+ 	idx++;
+-	if (idx > raw->curlen)
++	if (idx + 2 > raw->curlen)
+ 		goto fail_len;
+ 	repmsg->u.allocate_payload.allocated_pbn = (raw->msg[idx] << 8) | (raw->msg[idx+1]);
+-	idx += 2;
+-	if (idx > raw->curlen)
+-		goto fail_len;
+ 	return true;
+ fail_len:
+ 	DRM_DEBUG_KMS("allocate payload parse length fail %d %d\n", idx, raw->curlen);
+@@ -959,12 +964,9 @@ static bool drm_dp_sideband_parse_query_payload_ack(struct drm_dp_sideband_msg_r
+ 
+ 	repmsg->u.query_payload.port_number = (raw->msg[idx] >> 4) & 0xf;
+ 	idx++;
+-	if (idx > raw->curlen)
++	if (idx + 2 > raw->curlen)
+ 		goto fail_len;
+ 	repmsg->u.query_payload.allocated_pbn = (raw->msg[idx] << 8) | (raw->msg[idx + 1]);
+-	idx += 2;
+-	if (idx > raw->curlen)
+-		goto fail_len;
+ 	return true;
+ fail_len:
+ 	DRM_DEBUG_KMS("query payload parse length fail %d %d\n", idx, raw->curlen);
+@@ -3701,8 +3703,10 @@ void drm_dp_mst_topology_queue_probe(struct drm_dp_mst_topology_mgr *mgr)
+ {
+ 	mutex_lock(&mgr->lock);
+ 
+-	if (drm_WARN_ON(mgr->dev, !mgr->mst_state || !mgr->mst_primary))
++	if (!mgr->mst_state || !mgr->mst_primary) {
++		drm_dbg_kms(mgr->dev, "queue_probe skipped: topology torn down\n");
+ 		goto out_unlock;
++	}
+ 
+ 	drm_dp_mst_topology_mgr_invalidate_mstb(mgr->mst_primary);
+ 	drm_dp_mst_queue_probe_work(mgr);
+diff --git a/drivers/gpu/drm/i915/gem/i915_gem_context.c b/drivers/gpu/drm/i915/gem/i915_gem_context.c
+index e38f06a6e56ebc..d606b2035ed02b 100644
+--- a/drivers/gpu/drm/i915/gem/i915_gem_context.c
++++ b/drivers/gpu/drm/i915/gem/i915_gem_context.c
+@@ -610,6 +610,7 @@ set_proto_ctx_engines_parallel_submit(struct i915_user_extension __user *base,
+ 		return -EINVAL;
+ 	}
+ 
++	slot = array_index_nospec(slot, set->num_engines);
+ 	if (set->engines[slot].type != I915_GEM_ENGINE_TYPE_INVALID) {
+ 		drm_dbg(&i915->drm,
+ 			"Invalid placement[%d], already occupied\n", slot);
+@@ -767,8 +768,8 @@ static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
+ 		struct intel_engine_cs *engine;
+ 
+ 		if (copy_from_user(&ci, &user->engines[n], sizeof(ci))) {
+-			kfree(set.engines);
+-			return -EFAULT;
++			err = -EFAULT;
++			goto err;
+ 		}
+ 
+ 		memset(&set.engines[n], 0, sizeof(set.engines[n]));
+@@ -784,8 +785,8 @@ static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
+ 			drm_dbg(&i915->drm,
+ 				"Invalid engine[%d]: { class:%d, instance:%d }\n",
+ 				n, ci.engine_class, ci.engine_instance);
+-			kfree(set.engines);
+-			return -ENOENT;
++			err = -ENOENT;
++			goto err;
+ 		}
+ 
+ 		set.engines[n].type = I915_GEM_ENGINE_TYPE_PHYSICAL;
+@@ -798,15 +799,21 @@ static int set_proto_ctx_engines(struct drm_i915_file_private *fpriv,
+ 					   set_proto_ctx_engines_extensions,
+ 					   ARRAY_SIZE(set_proto_ctx_engines_extensions),
+ 					   &set);
+-	if (err) {
+-		kfree(set.engines);
+-		return err;
+-	}
++	if (err)
++		goto err_extensions;
+ 
+ 	pc->num_user_engines = set.num_engines;
+ 	pc->user_engines = set.engines;
+ 
+ 	return 0;
++
++err_extensions:
++	for (n = 0; n < set.num_engines; n++)
++		kfree(set.engines[n].siblings);
++err:
++	kfree(set.engines);
++
++	return err;
+ }
+ 
+ static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
+@@ -848,7 +855,7 @@ static int set_proto_ctx_sseu(struct drm_i915_file_private *fpriv,
+ 		pe = &pc->user_engines[idx];
+ 
+ 		/* Only render engine supports RPCS configuration. */
+-		if (pe->engine->class != RENDER_CLASS)
++		if (!pe->engine || pe->engine->class != RENDER_CLASS)
+ 			return -EINVAL;
+ 
+ 		sseu = &pe->sseu;
+diff --git a/drivers/gpu/drm/i915/gt/intel_engine_user.c b/drivers/gpu/drm/i915/gt/intel_engine_user.c
+index d304e0a948f0d1..13b27ee9e7bef2 100644
+--- a/drivers/gpu/drm/i915/gt/intel_engine_user.c
++++ b/drivers/gpu/drm/i915/gt/intel_engine_user.c
+@@ -260,7 +260,7 @@ void intel_engines_driver_register(struct drm_i915_private *i915)
+ 		p = &prev->rb_right;
+ 	}
+ 
+-	if (IS_ENABLED(CONFIG_DRM_I915_SELFTESTS) &&
++	if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST) &&
+ 	    IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) {
+ 		struct intel_engine_cs *engine;
+ 		unsigned int isolation;
+diff --git a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
+index 0971241707ce83..d396fbd55b740b 100644
+--- a/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
++++ b/drivers/gpu/drm/i915/gt/selftest_gt_pm.c
+@@ -16,9 +16,9 @@ static int cmp_u64(const void *A, const void *B)
+ {
+ 	const u64 *a = A, *b = B;
+ 
+-	if (a < b)
++	if (*a < *b)
+ 		return -1;
+-	else if (a > b)
++	else if (*a > *b)
+ 		return 1;
+ 	else
+ 		return 0;
+@@ -28,9 +28,9 @@ static int cmp_u32(const void *A, const void *B)
+ {
+ 	const u32 *a = A, *b = B;
+ 
+-	if (a < b)
++	if (*a < *b)
+ 		return -1;
+-	else if (a > b)
++	else if (*a > *b)
+ 		return 1;
+ 	else
+ 		return 0;
+diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c
+index 5ec293011d9902..40f84d547274a4 100644
+--- a/drivers/gpu/drm/i915/i915_active.c
++++ b/drivers/gpu/drm/i915/i915_active.c
+@@ -319,7 +319,7 @@ active_instance(struct i915_active *ref, u64 idx)
+ 	 */
+ 	node = kmem_cache_alloc(slab_cache, GFP_ATOMIC);
+ 	if (!node)
+-		goto out;
++		goto err;
+ 
+ 	__i915_active_fence_init(&node->base, NULL, node_retire);
+ 	node->ref = ref;
+@@ -333,6 +333,11 @@ out:
+ 	spin_unlock_irq(&ref->tree_lock);
+ 
+ 	return &node->base;
++
++err:
++	spin_unlock_irq(&ref->tree_lock);
++
++	return NULL;
+ }
+ 
+ void __i915_active_init(struct i915_active *ref,
+diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c
+index c1837ba95fb580..5eb41aefc2afa2 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_exec.c
++++ b/drivers/gpu/drm/nouveau/nouveau_exec.c
+@@ -353,10 +353,10 @@ nouveau_exec_ucopy(struct nouveau_exec_job_args *args,
+ 
+ 	return 0;
+ 
+-err_free_pushs:
+-	u_free(args->push.s);
+ err_free_ins:
+ 	u_free(args->in_sync.s);
++err_free_pushs:
++	u_free(args->push.s);
+ 	return ret;
+ }
+ 
+diff --git a/drivers/gpu/drm/nouveau/nouveau_uvmm.c b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
+index 3d41e590d4712d..53a514802d6258 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_uvmm.c
++++ b/drivers/gpu/drm/nouveau/nouveau_uvmm.c
+@@ -1730,10 +1730,10 @@ nouveau_uvmm_vm_bind_ucopy(struct nouveau_uvmm_bind_job_args *args,
+ 
+ 	return 0;
+ 
+-err_free_ops:
+-	u_free(args->op.s);
+ err_free_ins:
+ 	u_free(args->in_sync.s);
++err_free_ops:
++	u_free(args->op.s);
+ 	return ret;
+ }
+ 
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
+index 9b8ca4e898f903..dc82b7d7f27218 100644
+--- a/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/acr/base.c
+@@ -315,6 +315,7 @@ nvkm_acr_oneinit(struct nvkm_subdev *subdev)
+ 					  i, us, fw);
+ 			}
+ 		}
++		nvkm_done(acr->wpr);
+ 		return -EINVAL;
+ 	}
+ 	nvkm_done(acr->wpr);
+diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
+index 54cbfac3605fb3..eea9b9a9a996ef 100644
+--- a/drivers/gpu/drm/radeon/r100.c
++++ b/drivers/gpu/drm/radeon/r100.c
+@@ -905,6 +905,7 @@ struct radeon_fence *r100_copy_blit(struct radeon_device *rdev,
+ {
+ 	struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
+ 	struct radeon_fence *fence;
++	uint64_t cur_src_offset, cur_dst_offset;
+ 	uint32_t cur_pages;
+ 	uint32_t stride_bytes = RADEON_GPU_PAGE_SIZE;
+ 	uint32_t pitch;
+@@ -933,6 +934,10 @@ struct radeon_fence *r100_copy_blit(struct radeon_device *rdev,
+ 			cur_pages = 8191;
+ 		}
+ 		num_gpu_pages -= cur_pages;
++		cur_src_offset = src_offset +
++			(uint64_t)num_gpu_pages * RADEON_GPU_PAGE_SIZE;
++		cur_dst_offset = dst_offset +
++			(uint64_t)num_gpu_pages * RADEON_GPU_PAGE_SIZE;
+ 
+ 		/* pages are in Y direction - height
+ 		   page width in X direction - width */
+@@ -949,13 +954,13 @@ struct radeon_fence *r100_copy_blit(struct radeon_device *rdev,
+ 				  RADEON_DP_SRC_SOURCE_MEMORY |
+ 				  RADEON_GMC_CLR_CMP_CNTL_DIS |
+ 				  RADEON_GMC_WR_MSK_DIS);
+-		radeon_ring_write(ring, (pitch << 22) | (src_offset >> 10));
+-		radeon_ring_write(ring, (pitch << 22) | (dst_offset >> 10));
++		radeon_ring_write(ring, (pitch << 22) | (cur_src_offset >> 10));
++		radeon_ring_write(ring, (pitch << 22) | (cur_dst_offset >> 10));
+ 		radeon_ring_write(ring, (0x1fff) | (0x1fff << 16));
+ 		radeon_ring_write(ring, 0);
+ 		radeon_ring_write(ring, (0x1fff) | (0x1fff << 16));
+-		radeon_ring_write(ring, num_gpu_pages);
+-		radeon_ring_write(ring, num_gpu_pages);
++		radeon_ring_write(ring, 0);
++		radeon_ring_write(ring, 0);
+ 		radeon_ring_write(ring, cur_pages | (stride_pixels << 16));
+ 	}
+ 	radeon_ring_write(ring, PACKET0(RADEON_DSTCACHE_CTLSTAT, 0));
+diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
+index 33fb4d05c50657..7b16c28ba25a63 100644
+--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
++++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
+@@ -683,6 +683,8 @@ int cdn_dp_config_video(struct cdn_dp_device *dp)
+ 	val = div_u64(8 * (symbol + 1), bit_per_pix) - val;
+ 	val += 2;
+ 	ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val);
++	if (ret)
++		goto err_config_video;
+ 
+ 	switch (video->color_depth) {
+ 	case 6:
+diff --git a/drivers/gpu/drm/vc4/vc4_bo.c b/drivers/gpu/drm/vc4/vc4_bo.c
+index 84ad6a952b5d34..cd4f528a93ced9 100644
+--- a/drivers/gpu/drm/vc4/vc4_bo.c
++++ b/drivers/gpu/drm/vc4/vc4_bo.c
+@@ -733,9 +733,13 @@ static int vc4_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct
+ {
+ 	struct vc4_bo *bo = to_vc4_bo(obj);
+ 
+-	if (bo->validated_shader && (vma->vm_flags & VM_WRITE)) {
+-		DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n");
+-		return -EINVAL;
++	if (bo->validated_shader) {
++		if (vma->vm_flags & VM_WRITE) {
++			DRM_DEBUG("mmapping of shader BOs for writing not allowed.\n");
++			return -EINVAL;
++		}
++
++		vm_flags_clear(vma, VM_MAYWRITE);
+ 	}
+ 
+ 	mutex_lock(&bo->madv_lock);
+diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c
+index 5a3b5aaed1f361..c88456bc9fcc00 100644
+--- a/drivers/gpu/drm/virtio/virtgpu_kms.c
++++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
+@@ -48,7 +48,10 @@ static void virtio_gpu_config_changed_work_func(struct work_struct *work)
+ 				virtio_gpu_cmd_get_edids(vgdev);
+ 			virtio_gpu_cmd_get_display_info(vgdev);
+ 			virtio_gpu_notify(vgdev);
+-			drm_helper_hpd_irq_event(vgdev->ddev);
++			wait_event_timeout(vgdev->resp_wq,
++					   !vgdev->display_info_pending,
++					   5 * HZ);
++			drm_kms_helper_hotplug_event(vgdev->ddev);
+ 		}
+ 		events_clear |= VIRTIO_GPU_EVENT_DISPLAY;
+ 	}
+diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
+index b1a00c0c25a70b..a4d1a771032596 100644
+--- a/drivers/gpu/drm/virtio/virtgpu_vq.c
++++ b/drivers/gpu/drm/virtio/virtgpu_vq.c
+@@ -669,9 +669,6 @@ static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev,
+ 	vgdev->display_info_pending = false;
+ 	spin_unlock(&vgdev->display_info_lock);
+ 	wake_up(&vgdev->resp_wq);
+-
+-	if (!drm_helper_hpd_irq_event(vgdev->ddev))
+-		drm_kms_helper_hotplug_event(vgdev->ddev);
+ }
+ 
+ static void virtio_gpu_cmd_get_capset_info_cb(struct virtio_gpu_device *vgdev,
+@@ -726,7 +723,8 @@ static int virtio_get_edid_block(void *data, u8 *buf,
+ 	struct virtio_gpu_resp_edid *resp = data;
+ 	size_t start = block * EDID_LENGTH;
+ 
+-	if (start + len > le32_to_cpu(resp->size))
++	if (start + len > le32_to_cpu(resp->size) ||
++	    start + len > sizeof(resp->edid))
+ 		return -EINVAL;
+ 	memcpy(buf, resp->edid + start, len);
+ 	return 0;
+diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+index 17463aeeef28f2..de133f7d2a6307 100644
+--- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
++++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
+@@ -99,7 +99,7 @@ static int vmw_gb_surface_unbind(struct vmw_resource *res,
+ static int vmw_gb_surface_destroy(struct vmw_resource *res);
+ static int
+ vmw_gb_surface_define_internal(struct drm_device *dev,
+-			       struct drm_vmw_gb_surface_create_ext_req *req,
++			       const  struct drm_vmw_gb_surface_create_ext_req *req,
+ 			       struct drm_vmw_gb_surface_create_rep *rep,
+ 			       struct drm_file *file_priv);
+ static int
+@@ -1417,7 +1417,7 @@ int vmw_gb_surface_reference_ext_ioctl(struct drm_device *dev, void *data,
+  */
+ static int
+ vmw_gb_surface_define_internal(struct drm_device *dev,
+-			       struct drm_vmw_gb_surface_create_ext_req *req,
++			       const  struct drm_vmw_gb_surface_create_ext_req *req,
+ 			       struct drm_vmw_gb_surface_create_rep *rep,
+ 			       struct drm_file *file_priv)
+ {
+@@ -1435,9 +1435,21 @@ vmw_gb_surface_define_internal(struct drm_device *dev,
+ 				req->base.svga3d_flags);
+ 
+ 	/* array_size must be null for non-GL3 host. */
+-	if (req->base.array_size > 0 && !has_sm4_context(dev_priv)) {
+-		VMW_DEBUG_USER("SM4 surface not supported.\n");
+-		return -EINVAL;
++	if (req->base.array_size > 0) {
++		if (has_sm5_context(dev_priv)) {
++			if (req->base.array_size > SVGA3D_SM5_MAX_SURFACE_ARRAYSIZE) {
++				VMW_DEBUG_USER("Invalid Surface Array Size.\n");
++				return -EINVAL;
++			}
++		} else if (has_sm4_context(dev_priv)) {
++			if (req->base.array_size > SVGA3D_SM4_MAX_SURFACE_ARRAYSIZE) {
++				VMW_DEBUG_USER("Invalid Surface Array Size.\n");
++				return -EINVAL;
++			}
++		} else {
++			VMW_DEBUG_USER("SM4+ surface not supported.\n");
++			return -EINVAL;
++		}
+ 	}
+ 
+ 	if (!has_sm4_1_context(dev_priv)) {
+diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
+index 6b8b7395a4189e..8a4e0738014d6c 100644
+--- a/drivers/gpu/host1x/bus.c
++++ b/drivers/gpu/host1x/bus.c
+@@ -1006,10 +1006,10 @@ void host1x_bo_clear_cached_mappings(struct host1x_bo *bo)
+ 		if (WARN_ON(!cache))
+ 			continue;
+ 
+-		mutex_lock(&mapping->cache->lock);
++		mutex_lock(&cache->lock);
+ 		WARN_ON(kref_read(&mapping->ref) != 1);
+ 		__host1x_bo_unpin(&mapping->ref);
+-		mutex_unlock(&mapping->cache->lock);
++		mutex_unlock(&cache->lock);
+ 	}
+ }
+ EXPORT_SYMBOL(host1x_bo_clear_cached_mappings);
+diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c
+index bc2197f1dfb7f5..95bf1670156ed6 100644
+--- a/drivers/hwmon/asus-ec-sensors.c
++++ b/drivers/hwmon/asus-ec-sensors.c
+@@ -574,7 +574,7 @@ struct ec_sensors_data {
+ 	/* sorted list of unique register banks */
+ 	u8 banks[ASUS_EC_MAX_BANK + 1];
+ 	/* in jiffies */
+-	unsigned long last_updated;
++	u64 next_update;
+ 	struct lock_data lock_data;
+ 	/* number of board EC sensors */
+ 	u8 nr_sensors;
+@@ -754,7 +754,7 @@ static int asus_ec_block_read(const struct device *dev,
+ 		}
+ 		for (ireg = 0; ireg < ec->nr_registers; ireg++) {
+ 			reg_bank = register_bank(ec->registers[ireg]);
+-			if (reg_bank < bank) {
++			if (reg_bank != bank) {
+ 				continue;
+ 			}
+ 			ec_read(register_index(ec->registers[ireg]),
+@@ -843,13 +843,12 @@ static int get_cached_value_or_update(const struct device *dev,
+ 				      int sensor_index,
+ 				      struct ec_sensors_data *state, s32 *value)
+ {
+-	if (time_after(jiffies, state->last_updated + HZ)) {
++	if (time_after64(get_jiffies_64(), state->next_update)) {
+ 		if (update_ec_sensors(dev, state)) {
+ 			dev_err(dev, "update_ec_sensors() failure\n");
+ 			return -EIO;
+ 		}
+-
+-		state->last_updated = jiffies;
++		state->next_update = get_jiffies_64() + HZ;
+ 	}
+ 
+ 	*value = state->sensors[sensor_index].cached_value;
+@@ -967,6 +966,7 @@ static int asus_ec_probe(struct platform_device *pdev)
+ 	if (!ec_data)
+ 		return -ENOMEM;
+ 
++	ec_data->next_update = INITIAL_JIFFIES;
+ 	dev_set_drvdata(dev, ec_data);
+ 	ec_data->board_info = pboard_info;
+ 
+@@ -1042,9 +1042,11 @@ static int asus_ec_probe(struct platform_device *pdev)
+ 		if (!nr_count[type])
+ 			continue;
+ 
+-		asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,
+-					     nr_count[type], type,
+-					     hwmon_attributes[type]);
++		status = asus_ec_hwmon_add_chan_info(asus_ec_hwmon_chan, dev,
++						     nr_count[type], type,
++						     hwmon_attributes[type]);
++		if (status)
++			return status;
+ 		*ptr_asus_ec_ci++ = asus_ec_hwmon_chan++;
+ 	}
+ 
+diff --git a/drivers/hwmon/corsair-cpro.c b/drivers/hwmon/corsair-cpro.c
+index b37f36f55f88a5..096e187082b80a 100644
+--- a/drivers/hwmon/corsair-cpro.c
++++ b/drivers/hwmon/corsair-cpro.c
+@@ -558,6 +558,7 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
+ 
+ out_hw_close:
+ 	hid_hw_close(hdev);
++	hid_device_io_stop(hdev);
+ out_hw_stop:
+ 	hid_hw_stop(hdev);
+ 	return ret;
+diff --git a/drivers/hwmon/corsair-psu.c b/drivers/hwmon/corsair-psu.c
+index 93937e1bce196b..4ab73bcef1d125 100644
+--- a/drivers/hwmon/corsair-psu.c
++++ b/drivers/hwmon/corsair-psu.c
+@@ -831,6 +831,7 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id
+ 
+ fail_and_close:
+ 	hid_hw_close(hdev);
++	hid_device_io_stop(hdev);
+ fail_and_stop:
+ 	hid_hw_stop(hdev);
+ 	return ret;
+diff --git a/drivers/hwmon/nzxt-smart2.c b/drivers/hwmon/nzxt-smart2.c
+index 7aa586eb74be15..0ce956954378dd 100644
+--- a/drivers/hwmon/nzxt-smart2.c
++++ b/drivers/hwmon/nzxt-smart2.c
+@@ -774,7 +774,7 @@ static int nzxt_smart2_hid_probe(struct hid_device *hdev,
+ 
+ out_hw_close:
+ 	hid_hw_close(hdev);
+-
++	hid_device_io_stop(hdev);
+ out_hw_stop:
+ 	hid_hw_stop(hdev);
+ 	return ret;
+diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
+index c92d08e9827ac5..d0c8a043445a25 100644
+--- a/drivers/hwmon/occ/common.c
++++ b/drivers/hwmon/occ/common.c
+@@ -1052,32 +1052,49 @@ static int occ_setup_sensor_attrs(struct occ *occ)
+ }
+ 
+ /* only need to do this once at startup, as OCC won't change sensors on us */
+-static void occ_parse_poll_response(struct occ *occ)
++static int occ_parse_poll_response(struct occ *occ)
+ {
+ 	unsigned int i, old_offset, offset = 0, size = 0;
++	u16 data_length;
+ 	struct occ_sensor *sensor;
+-	struct occ_sensors *sensors = &occ->sensors;
++	struct occ_sensors parsed = {};
++	struct occ_sensors *sensors = &parsed;
+ 	struct occ_response *resp = &occ->resp;
+ 	struct occ_poll_response *poll =
+ 		(struct occ_poll_response *)&resp->data[0];
+ 	struct occ_poll_response_header *header = &poll->header;
+ 	struct occ_sensor_data_block *block = &poll->block;
+ 
++	data_length = get_unaligned_be16(&resp->data_length);
++	if (data_length < sizeof(*header) || data_length > OCC_RESP_DATA_BYTES) {
++		dev_err(occ->bus_dev, "invalid OCC poll response length %u\n",
++			data_length);
++		return -EMSGSIZE;
++	}
++
+ 	dev_info(occ->bus_dev, "OCC found, code level: %.16s\n",
+ 		 header->occ_code_level);
+ 
+ 	for (i = 0; i < header->num_sensor_data_blocks; ++i) {
+ 		block = (struct occ_sensor_data_block *)((u8 *)block + offset);
++		if (size + sizeof(*header) + sizeof(block->header) >
++		    data_length) {
++			dev_err(occ->bus_dev,
++				"truncated OCC sensor block header\n");
++			return -EMSGSIZE;
++		}
++
+ 		old_offset = offset;
+ 		offset = (block->header.num_sensors *
+ 			  block->header.sensor_length) + sizeof(block->header);
+-		size += offset;
+ 
+ 		/* validate all the length/size fields */
+-		if ((size + sizeof(*header)) >= OCC_RESP_DATA_BYTES) {
+-			dev_warn(occ->bus_dev, "exceeded response buffer\n");
+-			return;
++		if (size + sizeof(*header) + offset > data_length) {
++			dev_err(occ->bus_dev,
++				"exceeded OCC poll response length\n");
++			return -EMSGSIZE;
+ 		}
++		size += offset;
+ 
+ 		dev_dbg(occ->bus_dev, " %04x..%04x: %.4s (%d sensors)\n",
+ 			old_offset, offset - 1, block->header.eye_catcher,
+@@ -1107,6 +1124,9 @@ static void occ_parse_poll_response(struct occ *occ)
+ 
+ 	dev_dbg(occ->bus_dev, "Max resp size: %u+%zd=%zd\n", size,
+ 		sizeof(*header), size + sizeof(*header));
++	occ->sensors = parsed;
++
++	return 0;
+ }
+ 
+ int occ_active(struct occ *occ, bool active)
+@@ -1138,10 +1158,12 @@ int occ_active(struct occ *occ, bool active)
+ 			goto unlock;
+ 		}
+ 
+-		occ->active = true;
+ 		occ->next_update = jiffies + OCC_UPDATE_FREQUENCY;
+-		occ_parse_poll_response(occ);
++		rc = occ_parse_poll_response(occ);
++		if (rc)
++			goto unlock;
+ 
++		occ->active = true;
+ 		rc = occ_setup_sensor_attrs(occ);
+ 		if (rc) {
+ 			dev_err(occ->bus_dev,
+diff --git a/drivers/hwtracing/intel_th/core.c b/drivers/hwtracing/intel_th/core.c
+index e14163459c3d1e..f6951577f18346 100644
+--- a/drivers/hwtracing/intel_th/core.c
++++ b/drivers/hwtracing/intel_th/core.c
+@@ -843,18 +843,8 @@ out_put_device:
+ 	return err;
+ }
+ 
+-static int intel_th_output_release(struct inode *inode, struct file *file)
+-{
+-	struct intel_th_device *thdev = file->private_data;
+-
+-	put_device(&thdev->dev);
+-
+-	return 0;
+-}
+-
+ static const struct file_operations intel_th_output_fops = {
+ 	.open	= intel_th_output_open,
+-	.release = intel_th_output_release,
+ 	.llseek	= noop_llseek,
+ };
+ 
+diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c
+index 54629458fb710c..8358f5e2b55cab 100644
+--- a/drivers/hwtracing/intel_th/msu.c
++++ b/drivers/hwtracing/intel_th/msu.c
+@@ -1474,8 +1474,10 @@ static int intel_th_msc_release(struct inode *inode, struct file *file)
+ {
+ 	struct msc_iter *iter = file->private_data;
+ 	struct msc *msc = iter->msc;
++	struct intel_th_device *thdev = msc->thdev;
+ 
+ 	msc_iter_remove(iter, msc);
++	put_device(&thdev->dev);
+ 
+ 	return 0;
+ }
+diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
+index 02b3b1160fb062..359cb7732db120 100644
+--- a/drivers/i2c/busses/i2c-davinci.c
++++ b/drivers/i2c/busses/i2c-davinci.c
+@@ -866,13 +866,15 @@ static int davinci_i2c_probe(struct platform_device *pdev)
+ 	adap->nr = pdev->id;
+ 	r = i2c_add_numbered_adapter(adap);
+ 	if (r)
+-		goto err_unuse_clocks;
++		goto err_cpufreq;
+ 
+ 	pm_runtime_mark_last_busy(dev->dev);
+ 	pm_runtime_put_autosuspend(dev->dev);
+ 
+ 	return 0;
+ 
++err_cpufreq:
++	i2c_davinci_cpufreq_deregister(dev);
+ err_unuse_clocks:
+ 	pm_runtime_dont_use_autosuspend(dev->dev);
+ 	pm_runtime_put_sync(dev->dev);
+diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
+index 89fdc75cdcfa54..b0429fa3f57349 100644
+--- a/drivers/i2c/busses/i2c-i801.c
++++ b/drivers/i2c/busses/i2c-i801.c
+@@ -918,13 +918,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
+ 	 */
+ 	if (hwpec)
+ 		outb_p(inb_p(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv));
+-out:
+ 	/*
+ 	 * Unlock the SMBus device for use by BIOS/ACPI,
+ 	 * and clear status flags if not done already.
+ 	 */
+ 	outb_p(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
+ 
++out:
+ 	pm_runtime_mark_last_busy(&priv->pci_dev->dev);
+ 	pm_runtime_put_autosuspend(&priv->pci_dev->dev);
+ 	mutex_unlock(&priv->acpi_lock);
+diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
+index 913823a063c9ae..ad65450aed9148 100644
+--- a/drivers/i2c/busses/i2c-imx.c
++++ b/drivers/i2c/busses/i2c-imx.c
+@@ -1011,6 +1011,43 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
+ 	return i2c_imx_acked(i2c_imx);
+ }
+ 
++static int i2c_imx_prepare_read(struct imx_i2c_struct *i2c_imx,
++				struct i2c_msg *msgs, bool atomic,
++				bool use_dma)
++{
++	int result;
++	unsigned int temp = 0;
++
++	/* write slave address */
++	imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
++	result = i2c_imx_trx_complete(i2c_imx, atomic);
++	if (result)
++		return result;
++	result = i2c_imx_acked(i2c_imx);
++	if (result)
++		return result;
++
++	dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__);
++
++	/* setup bus to read data */
++	temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
++	temp &= ~I2CR_MTX;
++
++	/*
++	 * Reset the I2CR_TXAK flag initially for SMBus block read since the
++	 * length is unknown
++	 */
++	if (msgs->len - 1)
++		temp &= ~I2CR_TXAK;
++	if (use_dma)
++		temp |= I2CR_DMAEN;
++
++	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
++	imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
++
++	return 0;
++}
++
+ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
+ 			struct i2c_msg *msgs, bool is_lastmsg)
+ {
+@@ -1021,6 +1058,11 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
+ 	struct imx_i2c_dma *dma = i2c_imx->dma;
+ 	struct device *dev = &i2c_imx->adapter.dev;
+ 
++	result = i2c_imx_prepare_read(i2c_imx, msgs, false, true);
++	if (result)
++		return result;
++
++	dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__);
+ 
+ 	dma->chan_using = dma->chan_rx;
+ 	dma->dma_transfer_dir = DMA_DEV_TO_MEM;
+@@ -1131,50 +1173,25 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
+ 	return 0;
+ }
+ 
++static int i2c_imx_atomic_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs)
++{
++	return i2c_imx_write(i2c_imx, msgs, true);
++}
++
+ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
+ 			bool is_lastmsg, bool atomic)
+ {
+ 	int i, result;
+ 	unsigned int temp;
+ 	int block_data = msgs->flags & I2C_M_RECV_LEN;
+-	int use_dma = i2c_imx->dma && msgs->flags & I2C_M_DMA_SAFE &&
+-		msgs->len >= DMA_THRESHOLD && !block_data;
+-
+-	dev_dbg(&i2c_imx->adapter.dev,
+-		"<%s> write slave address: addr=0x%x\n",
+-		__func__, i2c_8bit_addr_from_msg(msgs));
++	int block_err = 0;
+ 
+-	/* write slave address */
+-	imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR);
+-	result = i2c_imx_trx_complete(i2c_imx, atomic);
++	result = i2c_imx_prepare_read(i2c_imx, msgs, atomic, false);
+ 	if (result)
+ 		return result;
+-	result = i2c_imx_acked(i2c_imx);
+-	if (result)
+-		return result;
+-
+-	dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__);
+-
+-	/* setup bus to read data */
+-	temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
+-	temp &= ~I2CR_MTX;
+-
+-	/*
+-	 * Reset the I2CR_TXAK flag initially for SMBus block read since the
+-	 * length is unknown
+-	 */
+-	if ((msgs->len - 1) || block_data)
+-		temp &= ~I2CR_TXAK;
+-	if (use_dma)
+-		temp |= I2CR_DMAEN;
+-	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
+-	imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */
+ 
+ 	dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__);
+ 
+-	if (use_dma)
+-		return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg);
+-
+ 	/* read data */
+ 	for (i = 0; i < msgs->len; i++) {
+ 		u8 len = 0;
+@@ -1189,8 +1206,20 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
+ 		 */
+ 		if ((!i) && block_data) {
+ 			len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR);
+-			if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX))
+-				return -EPROTO;
++			if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
++				/*
++				 * SMBus 3.1 6.5.7: support count byte of 0.
++				 * I2C_SMBUS_BLOCK_MAX case should not hold the SDA either.
++				 */
++				if (len > I2C_SMBUS_BLOCK_MAX)
++					block_err = -EPROTO;
++				temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
++				temp |= I2CR_TXAK;
++				imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR);
++				msgs->buf[0] = 0;
++				msgs->len = 2;
++				continue;
++			}
+ 			dev_dbg(&i2c_imx->adapter.dev,
+ 				"<%s> read length: 0x%X\n",
+ 				__func__, len);
+@@ -1238,7 +1267,13 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
+ 			"<%s> read byte: B%d=0x%X\n",
+ 			__func__, i, msgs->buf[i]);
+ 	}
+-	return 0;
++	return block_err;
++}
++
++static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs,
++			       bool is_lastmsg)
++{
++	return i2c_imx_read(i2c_imx, msgs, is_lastmsg, true);
+ }
+ 
+ static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
+@@ -1248,6 +1283,7 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
+ 	int result;
+ 	bool is_lastmsg = false;
+ 	struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter);
++	int use_dma = 0;
+ 
+ 	/* Start I2C transfer */
+ 	result = i2c_imx_start(i2c_imx, atomic);
+@@ -1300,15 +1336,25 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter,
+ 			(temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),
+ 			(temp & I2SR_RXAK ? 1 : 0));
+ #endif
++
++		use_dma = i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD &&
++			msgs[i].flags & I2C_M_DMA_SAFE;
+ 		if (msgs[i].flags & I2C_M_RD) {
+-			result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg, atomic);
++			int block_data = msgs->flags & I2C_M_RECV_LEN;
++
++			if (atomic)
++				result = i2c_imx_atomic_read(i2c_imx, &msgs[i], is_lastmsg);
++			else if (use_dma && !block_data)
++				result = i2c_imx_dma_read(i2c_imx, &msgs[i], is_lastmsg);
++			else
++				result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg, false);
+ 		} else {
+-			if (!atomic &&
+-			    i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD &&
+-				msgs[i].flags & I2C_M_DMA_SAFE)
++			if (atomic)
++				result = i2c_imx_atomic_write(i2c_imx, &msgs[i]);
++			else if (use_dma)
+ 				result = i2c_imx_dma_write(i2c_imx, &msgs[i]);
+ 			else
+-				result = i2c_imx_write(i2c_imx, &msgs[i], atomic);
++				result = i2c_imx_write(i2c_imx, &msgs[i], false);
+ 		}
+ 		if (result)
+ 			goto fail0;
+diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
+index 7db79ff3fa06c3..87164dd745ecb5 100644
+--- a/drivers/infiniband/core/cma.c
++++ b/drivers/infiniband/core/cma.c
+@@ -5215,7 +5215,7 @@ static int cma_netevent_callback(struct notifier_block *self,
+ 
+ 	list_for_each_entry(current_id, &ips_node->id_list, id_list_entry) {
+ 		if (!memcmp(current_id->id.route.addr.dev_addr.dst_dev_addr,
+-			   neigh->ha, ETH_ALEN))
++			   neigh->ha, neigh->dev->addr_len))
+ 			continue;
+ 		cma_id_get(current_id);
+ 		if (!queue_work(cma_wq, &current_id->id.net_work))
+diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
+index 242434c09e8d8f..bddb1c607aff62 100644
+--- a/drivers/infiniband/core/mad.c
++++ b/drivers/infiniband/core/mad.c
+@@ -1778,6 +1778,24 @@ void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr)
+ 			      &mad_send_wr->mad_agent_priv->done_list);
+ }
+ 
++static bool is_kernel_rmpp_data_response(struct ib_mad_agent_private *agent,
++					 struct ib_mad_recv_wc *mad_recv_wc)
++{
++	const struct ib_mad_hdr *mad_hdr = &mad_recv_wc->recv_buf.mad->mad_hdr;
++	struct ib_rmpp_mad *rmpp_mad;
++
++	if (!ib_mad_kernel_rmpp_agent(&agent->agent) ||
++	    !ib_response_mad(mad_hdr) ||
++	    !ib_is_mad_class_rmpp(mad_hdr->mgmt_class))
++		return false;
++
++	rmpp_mad = (struct ib_rmpp_mad *)mad_recv_wc->recv_buf.mad;
++
++	return (ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) &
++		IB_MGMT_RMPP_FLAG_ACTIVE) &&
++	       rmpp_mad->rmpp_hdr.rmpp_type == IB_MGMT_RMPP_TYPE_DATA;
++}
++
+ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
+ 				 struct ib_mad_recv_wc *mad_recv_wc)
+ {
+@@ -1796,6 +1814,18 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
+ 	}
+ 
+ 	list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list);
++	if (is_kernel_rmpp_data_response(mad_agent_priv, mad_recv_wc)) {
++		spin_lock_irqsave(&mad_agent_priv->lock, flags);
++		mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc);
++		spin_unlock_irqrestore(&mad_agent_priv->lock, flags);
++
++		if (!mad_send_wr) {
++			ib_free_recv_mad(mad_recv_wc);
++			deref_mad_agent(mad_agent_priv);
++			return;
++		}
++	}
++
+ 	if (ib_mad_kernel_rmpp_agent(&mad_agent_priv->agent)) {
+ 		mad_recv_wc = ib_process_rmpp_recv_wc(mad_agent_priv,
+ 						      mad_recv_wc);
+diff --git a/drivers/infiniband/core/umem_dmabuf.c b/drivers/infiniband/core/umem_dmabuf.c
+index 66f5760197479d..1206993e2e3e83 100644
+--- a/drivers/infiniband/core/umem_dmabuf.c
++++ b/drivers/infiniband/core/umem_dmabuf.c
+@@ -23,6 +23,9 @@ int ib_umem_dmabuf_map_pages(struct ib_umem_dmabuf *umem_dmabuf)
+ 
+ 	dma_resv_assert_held(umem_dmabuf->attach->dmabuf->resv);
+ 
++	if (umem_dmabuf->revoked)
++		return -EINVAL;
++
+ 	if (umem_dmabuf->sgt)
+ 		goto wait_fence;
+ 
+@@ -110,10 +113,12 @@ void ib_umem_dmabuf_unmap_pages(struct ib_umem_dmabuf *umem_dmabuf)
+ }
+ EXPORT_SYMBOL(ib_umem_dmabuf_unmap_pages);
+ 
+-struct ib_umem_dmabuf *ib_umem_dmabuf_get(struct ib_device *device,
+-					  unsigned long offset, size_t size,
+-					  int fd, int access,
+-					  const struct dma_buf_attach_ops *ops)
++static struct ib_umem_dmabuf *
++ib_umem_dmabuf_get_with_dma_device(struct ib_device *device,
++				   struct device *dma_device,
++				   unsigned long offset, size_t size,
++				   int fd, int access,
++				   const struct dma_buf_attach_ops *ops)
+ {
+ 	struct dma_buf *dmabuf;
+ 	struct ib_umem_dmabuf *umem_dmabuf;
+@@ -152,7 +157,7 @@ struct ib_umem_dmabuf *ib_umem_dmabuf_get(struct ib_device *device,
+ 
+ 	umem_dmabuf->attach = dma_buf_dynamic_attach(
+ 					dmabuf,
+-					device->dma_device,
++					dma_device,
+ 					ops,
+ 					umem_dmabuf);
+ 	if (IS_ERR(umem_dmabuf->attach)) {
+@@ -168,6 +173,15 @@ out_release_dmabuf:
+ 	dma_buf_put(dmabuf);
+ 	return ret;
+ }
++
++struct ib_umem_dmabuf *ib_umem_dmabuf_get(struct ib_device *device,
++					  unsigned long offset, size_t size,
++					  int fd, int access,
++					  const struct dma_buf_attach_ops *ops)
++{
++	return ib_umem_dmabuf_get_with_dma_device(device, device->dma_device,
++						  offset, size, fd, access, ops);
++}
+ EXPORT_SYMBOL(ib_umem_dmabuf_get);
+ 
+ static void
+@@ -184,16 +198,44 @@ static struct dma_buf_attach_ops ib_umem_dmabuf_attach_pinned_ops = {
+ 	.move_notify = ib_umem_dmabuf_unsupported_move_notify,
+ };
+ 
+-struct ib_umem_dmabuf *ib_umem_dmabuf_get_pinned(struct ib_device *device,
+-						 unsigned long offset,
+-						 size_t size, int fd,
+-						 int access)
++static void ib_umem_dmabuf_revoke_locked(struct dma_buf_attachment *attach)
++{
++	struct ib_umem_dmabuf *umem_dmabuf = attach->importer_priv;
++
++	dma_resv_assert_held(attach->dmabuf->resv);
++
++	if (umem_dmabuf->revoked)
++		return;
++
++	if (umem_dmabuf->pinned_revoke)
++		umem_dmabuf->pinned_revoke(umem_dmabuf->private);
++
++	ib_umem_dmabuf_unmap_pages(umem_dmabuf);
++	if (umem_dmabuf->pinned) {
++		dma_buf_unpin(umem_dmabuf->attach);
++		umem_dmabuf->pinned = 0;
++	}
++	umem_dmabuf->revoked = 1;
++}
++
++static struct dma_buf_attach_ops ib_umem_dmabuf_attach_pinned_revocable_ops = {
++	.allow_peer2peer = true,
++	.move_notify = ib_umem_dmabuf_revoke_locked,
++};
++
++static struct ib_umem_dmabuf *
++ib_umem_dmabuf_get_pinned_and_lock(struct ib_device *device,
++				   struct device *dma_device,
++				   unsigned long offset,
++				   size_t size, int fd, int access,
++				   const struct dma_buf_attach_ops *ops)
+ {
+ 	struct ib_umem_dmabuf *umem_dmabuf;
+ 	int err;
+ 
+-	umem_dmabuf = ib_umem_dmabuf_get(device, offset, size, fd, access,
+-					 &ib_umem_dmabuf_attach_pinned_ops);
++	umem_dmabuf =
++		ib_umem_dmabuf_get_with_dma_device(device, dma_device, offset,
++						   size, fd, access, ops);
+ 	if (IS_ERR(umem_dmabuf))
+ 		return umem_dmabuf;
+ 
+@@ -206,7 +248,6 @@ struct ib_umem_dmabuf *ib_umem_dmabuf_get_pinned(struct ib_device *device,
+ 	err = ib_umem_dmabuf_map_pages(umem_dmabuf);
+ 	if (err)
+ 		goto err_release;
+-	dma_resv_unlock(umem_dmabuf->attach->dmabuf->resv);
+ 
+ 	return umem_dmabuf;
+ 
+@@ -215,17 +256,118 @@ err_release:
+ 	ib_umem_release(&umem_dmabuf->umem);
+ 	return ERR_PTR(err);
+ }
++
++struct ib_umem_dmabuf *
++ib_umem_dmabuf_get_pinned_with_dma_device(struct ib_device *device,
++					  struct device *dma_device,
++					  unsigned long offset, size_t size,
++					  int fd, int access)
++{
++	struct ib_umem_dmabuf *umem_dmabuf =
++		ib_umem_dmabuf_get_pinned_and_lock(device, dma_device, offset,
++						   size, fd, access,
++						   &ib_umem_dmabuf_attach_pinned_ops);
++	if (IS_ERR(umem_dmabuf))
++		return umem_dmabuf;
++
++	dma_resv_unlock(umem_dmabuf->attach->dmabuf->resv);
++	return umem_dmabuf;
++}
++EXPORT_SYMBOL(ib_umem_dmabuf_get_pinned_with_dma_device);
++
++/**
++ * ib_umem_dmabuf_get_pinned_revocable_and_lock - Map & pin a revocable dmabuf
++ * @device: IB device.
++ * @offset: Start offset.
++ * @size: Length.
++ * @fd: dmabuf fd.
++ * @access: Access flags.
++ *
++ * Obtains a umem from a dmabuf for drivers/devices that can support revocation.
++ *
++ * Returns with dma_resv_lock held upon success. The driver must set the revoke
++ * callback prior to unlock by calling ib_umem_dmabuf_set_revoke_locked().
++ *
++ * When a revocation occurs, the revoke callback will be called. The driver must
++ * ensure that the region is no longer accessed when the callback returns. Any
++ * subsequent access attempts should also probably cause an AE for MRs.
++ *
++ * If the umem is used for an MR, the driver must ensure that the key remains in
++ * use such that it cannot be obtained by a new region until this region is
++ * fully deregistered (i.e., ibv_dereg_mr). If a driver needs to serialize with
++ * revoke calls, it can use dma_resv_lock.
++ *
++ * If successful, then the revoke callback may be called at any time and will
++ * also be called automatically upon ib_umem_release (serialized). The revoke
++ * callback will be called one time at most.
++ *
++ * Return: A pointer to ib_umem_dmabuf on success, or an ERR_PTR on failure.
++ */
++struct ib_umem_dmabuf *
++ib_umem_dmabuf_get_pinned_revocable_and_lock(struct ib_device *device,
++					     unsigned long offset, size_t size,
++					     int fd, int access)
++{
++	const struct dma_buf_attach_ops *ops =
++		&ib_umem_dmabuf_attach_pinned_revocable_ops;
++
++	return ib_umem_dmabuf_get_pinned_and_lock(device, device->dma_device,
++						  offset, size, fd, access,
++						  ops);
++}
++EXPORT_SYMBOL(ib_umem_dmabuf_get_pinned_revocable_and_lock);
++
++void ib_umem_dmabuf_set_revoke_locked(struct ib_umem_dmabuf *umem_dmabuf,
++				      void (*revoke)(void *priv), void *priv)
++{
++	dma_resv_assert_held(umem_dmabuf->attach->dmabuf->resv);
++
++	umem_dmabuf->pinned_revoke = revoke;
++	umem_dmabuf->private = priv;
++}
++EXPORT_SYMBOL(ib_umem_dmabuf_set_revoke_locked);
++
++struct ib_umem_dmabuf *ib_umem_dmabuf_get_pinned(struct ib_device *device,
++						 unsigned long offset,
++						 size_t size, int fd,
++						 int access)
++{
++	return ib_umem_dmabuf_get_pinned_with_dma_device(device, device->dma_device,
++							 offset, size, fd, access);
++}
+ EXPORT_SYMBOL(ib_umem_dmabuf_get_pinned);
+ 
+-void ib_umem_dmabuf_release(struct ib_umem_dmabuf *umem_dmabuf)
++void ib_umem_dmabuf_revoke_lock(struct ib_umem_dmabuf *umem_dmabuf)
+ {
+ 	struct dma_buf *dmabuf = umem_dmabuf->attach->dmabuf;
+ 
+ 	dma_resv_lock(dmabuf->resv, NULL);
+-	ib_umem_dmabuf_unmap_pages(umem_dmabuf);
+-	if (umem_dmabuf->pinned)
+-		dma_buf_unpin(umem_dmabuf->attach);
++}
++EXPORT_SYMBOL(ib_umem_dmabuf_revoke_lock);
++
++void ib_umem_dmabuf_revoke_unlock(struct ib_umem_dmabuf *umem_dmabuf)
++{
++	struct dma_buf *dmabuf = umem_dmabuf->attach->dmabuf;
++
+ 	dma_resv_unlock(dmabuf->resv);
++}
++EXPORT_SYMBOL(ib_umem_dmabuf_revoke_unlock);
++
++void ib_umem_dmabuf_revoke(struct ib_umem_dmabuf *umem_dmabuf)
++{
++	struct dma_buf *dmabuf = umem_dmabuf->attach->dmabuf;
++
++	dma_resv_lock(dmabuf->resv, NULL);
++	ib_umem_dmabuf_revoke_locked(umem_dmabuf->attach);
++	dma_resv_unlock(dmabuf->resv);
++}
++EXPORT_SYMBOL(ib_umem_dmabuf_revoke);
++
++void ib_umem_dmabuf_release(struct ib_umem_dmabuf *umem_dmabuf)
++{
++	struct dma_buf *dmabuf = umem_dmabuf->attach->dmabuf;
++
++	ib_umem_dmabuf_revoke(umem_dmabuf);
+ 
+ 	dma_buf_detach(dmabuf, umem_dmabuf->attach);
+ 	dma_buf_put(dmabuf);
+diff --git a/drivers/infiniband/hw/erdma/erdma_qp.c b/drivers/infiniband/hw/erdma/erdma_qp.c
+index 6d0330badd68e8..e3a731a45e8861 100644
+--- a/drivers/infiniband/hw/erdma/erdma_qp.c
++++ b/drivers/infiniband/hw/erdma/erdma_qp.c
+@@ -573,7 +573,7 @@ int erdma_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *recv_wr,
+ 	const struct ib_recv_wr *wr = recv_wr;
+ 	struct erdma_qp *qp = to_eqp(ibqp);
+ 	unsigned long flags;
+-	int ret;
++	int ret = 0;
+ 
+ 	spin_lock_irqsave(&qp->lock, flags);
+ 
+diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c
+index d6fcb1a4bd4fca..112248ddf02367 100644
+--- a/drivers/infiniband/hw/hns/hns_roce_hem.c
++++ b/drivers/infiniband/hw/hns/hns_roce_hem.c
+@@ -907,7 +907,7 @@ static void hns_roce_cleanup_mhop_hem_table(struct hns_roce_dev *hr_dev,
+ 					mhop.bt_chunk_size;
+ 
+ 	for (i = 0; i < table->num_hem; ++i) {
+-		obj = i * buf_chunk_size / table->obj_size;
++		obj = (u64)i * buf_chunk_size / table->obj_size;
+ 		if (table->hem[i])
+ 			hns_roce_table_mhop_put(hr_dev, table, obj, 0);
+ 	}
+diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c
+index 8ffbc790c1681e..136e367b40d874 100644
+--- a/drivers/infiniband/hw/irdma/verbs.c
++++ b/drivers/infiniband/hw/irdma/verbs.c
+@@ -2366,7 +2366,7 @@ static bool irdma_check_mem_contiguous(u64 *arr, u32 npages, u32 pg_size)
+ 	u32 pg_idx;
+ 
+ 	for (pg_idx = 0; pg_idx < npages; pg_idx++) {
+-		if ((*arr + (pg_size * pg_idx)) != arr[pg_idx])
++		if ((*arr + ((u64)pg_size * pg_idx)) != arr[pg_idx])
+ 			return false;
+ 	}
+ 
+@@ -2399,7 +2399,7 @@ static bool irdma_check_mr_contiguous(struct irdma_pble_alloc *palloc,
+ 
+ 	for (i = 0; i < lvl2->leaf_cnt; i++, leaf++) {
+ 		arr = leaf->addr;
+-		if ((*start_addr + (i * pg_size * PBLE_PER_PAGE)) != *arr)
++		if ((*start_addr + ((u64)i * pg_size * PBLE_PER_PAGE)) != *arr)
+ 			return false;
+ 		ret = irdma_check_mem_contiguous(arr, leaf->cnt, pg_size);
+ 		if (!ret)
+@@ -3251,6 +3251,9 @@ static struct ib_mr *irdma_rereg_user_mr(struct ib_mr *ib_mr, int flags,
+ 	if (flags & ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS))
+ 		return ERR_PTR(-EOPNOTSUPP);
+ 
++	if (iwmr->type != IRDMA_MEMREG_TYPE_MEM)
++	     return ERR_PTR(-EINVAL);
++
+ 	ret = ib_umem_check_rereg(iwmr->region, flags, new_access);
+ 	if (ret)
+ 		return ERR_PTR(ret);
+diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c
+index 1768b8695c45ad..40e0e0a2486db5 100644
+--- a/drivers/infiniband/sw/siw/siw_verbs.c
++++ b/drivers/infiniband/sw/siw/siw_verbs.c
+@@ -302,6 +302,7 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
+ 	struct siw_ucontext *uctx =
+ 		rdma_udata_to_drv_context(udata, struct siw_ucontext,
+ 					  base_ucontext);
++	struct siw_uresp_create_qp uresp = {};
+ 	unsigned long flags;
+ 	int num_sqe, num_rqe, rv = 0;
+ 	size_t length;
+@@ -336,11 +337,10 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
+ 		goto err_atomic;
+ 	}
+ 	/*
+-	 * NOTE: we allow for zero element SQ and RQ WQE's SGL's
+-	 * but not for a QP unable to hold any WQE (SQ + RQ)
++	 * NOTE: we don't allow for a QP unable to hold any SQ WQE
+ 	 */
+-	if (attrs->cap.max_send_wr + attrs->cap.max_recv_wr == 0) {
+-		siw_dbg(base_dev, "QP must have send or receive queue\n");
++	if (attrs->cap.max_send_wr == 0) {
++		siw_dbg(base_dev, "QP must have send queue\n");
+ 		rv = -EINVAL;
+ 		goto err_atomic;
+ 	}
+@@ -356,25 +356,13 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
+ 	spin_lock_init(&qp->rq_lock);
+ 	spin_lock_init(&qp->orq_lock);
+ 
+-	rv = siw_qp_add(sdev, qp);
+-	if (rv)
+-		goto err_atomic;
+-
+-	num_sqe = attrs->cap.max_send_wr;
+-	num_rqe = attrs->cap.max_recv_wr;
+-
+ 	/* All queue indices are derived from modulo operations
+ 	 * on a free running 'get' (consumer) and 'put' (producer)
+ 	 * unsigned counter. Having queue sizes at power of two
+ 	 * avoids handling counter wrap around.
+ 	 */
+-	if (num_sqe)
+-		num_sqe = roundup_pow_of_two(num_sqe);
+-	else {
+-		/* Zero sized SQ is not supported */
+-		rv = -EINVAL;
+-		goto err_out_xa;
+-	}
++	num_sqe = roundup_pow_of_two(attrs->cap.max_send_wr);
++	num_rqe = attrs->cap.max_recv_wr;
+ 	if (num_rqe)
+ 		num_rqe = roundup_pow_of_two(num_rqe);
+ 
+@@ -385,14 +373,14 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
+ 
+ 	if (qp->sendq == NULL) {
+ 		rv = -ENOMEM;
+-		goto err_out_xa;
++		goto err_out;
+ 	}
+ 	if (attrs->sq_sig_type != IB_SIGNAL_REQ_WR) {
+ 		if (attrs->sq_sig_type == IB_SIGNAL_ALL_WR)
+ 			qp->attrs.flags |= SIW_SIGNAL_ALL_WR;
+ 		else {
+ 			rv = -EINVAL;
+-			goto err_out_xa;
++			goto err_out;
+ 		}
+ 	}
+ 	qp->pd = pd;
+@@ -418,7 +406,7 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
+ 
+ 		if (qp->recvq == NULL) {
+ 			rv = -ENOMEM;
+-			goto err_out_xa;
++			goto err_out;
+ 		}
+ 		qp->attrs.rq_size = num_rqe;
+ 	}
+@@ -433,11 +421,8 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
+ 	qp->attrs.state = SIW_QP_STATE_IDLE;
+ 
+ 	if (udata) {
+-		struct siw_uresp_create_qp uresp = {};
+-
+ 		uresp.num_sqe = num_sqe;
+ 		uresp.num_rqe = num_rqe;
+-		uresp.qp_id = qp_id(qp);
+ 
+ 		if (qp->sendq) {
+ 			length = num_sqe * sizeof(struct siw_sqe);
+@@ -446,7 +431,7 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
+ 						      length, &uresp.sq_key);
+ 			if (!qp->sq_entry) {
+ 				rv = -ENOMEM;
+-				goto err_out_xa;
++				goto err_out;
+ 			}
+ 		}
+ 
+@@ -458,9 +443,23 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
+ 			if (!qp->rq_entry) {
+ 				uresp.sq_key = SIW_INVAL_UOBJ_KEY;
+ 				rv = -ENOMEM;
+-				goto err_out_xa;
++				goto err_out;
+ 			}
+ 		}
++	}
++	qp->tx_cpu = siw_get_tx_cpu(sdev);
++	if (qp->tx_cpu < 0) {
++		rv = -EINVAL;
++		goto err_out;
++	}
++	init_completion(&qp->qp_free);
++
++	rv = siw_qp_add(sdev, qp);
++	if (rv)
++		goto err_out_tx;
++
++	if (udata) {
++		uresp.qp_id = qp_id(qp);
+ 
+ 		if (udata->outlen < sizeof(uresp)) {
+ 			rv = -EINVAL;
+@@ -470,22 +469,19 @@ int siw_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
+ 		if (rv)
+ 			goto err_out_xa;
+ 	}
+-	qp->tx_cpu = siw_get_tx_cpu(sdev);
+-	if (qp->tx_cpu < 0) {
+-		rv = -EINVAL;
+-		goto err_out_xa;
+-	}
++
+ 	INIT_LIST_HEAD(&qp->devq);
+ 	spin_lock_irqsave(&sdev->lock, flags);
+ 	list_add_tail(&qp->devq, &sdev->qp_list);
+ 	spin_unlock_irqrestore(&sdev->lock, flags);
+ 
+-	init_completion(&qp->qp_free);
+-
+ 	return 0;
+ 
+ err_out_xa:
+ 	xa_erase(&sdev->qp_xa, qp_id(qp));
++err_out_tx:
++	siw_put_tx_cpu(qp->tx_cpu);
++err_out:
+ 	if (uctx) {
+ 		rdma_user_mmap_entry_remove(qp->sq_entry);
+ 		rdma_user_mmap_entry_remove(qp->rq_entry);
+diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
+index 2bac9d9c7b0c9c..053bf605199fa7 100644
+--- a/drivers/input/misc/ims-pcu.c
++++ b/drivers/input/misc/ims-pcu.c
+@@ -448,6 +448,14 @@ static void ims_pcu_handle_response(struct ims_pcu *pcu)
+ 	}
+ }
+ 
++static void ims_pcu_reset_packet(struct ims_pcu *pcu)
++{
++	pcu->have_stx = false;
++	pcu->have_dle = false;
++	pcu->read_pos = 0;
++	pcu->check_sum = 0;
++}
++
+ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
+ {
+ 	int i;
+@@ -460,6 +468,14 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
+ 			continue;
+ 
+ 		if (pcu->have_dle) {
++			if (pcu->read_pos >= IMS_PCU_BUF_SIZE) {
++				dev_warn(pcu->dev,
++					 "Packet too long (%d bytes), discarding\n",
++					 pcu->read_pos);
++				ims_pcu_reset_packet(pcu);
++				continue;
++			}
++
+ 			pcu->have_dle = false;
+ 			pcu->read_buf[pcu->read_pos++] = data;
+ 			pcu->check_sum += data;
+@@ -472,10 +488,8 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
+ 				dev_warn(pcu->dev,
+ 					 "Unexpected STX at byte %d, discarding old data\n",
+ 					 pcu->read_pos);
++			ims_pcu_reset_packet(pcu);
+ 			pcu->have_stx = true;
+-			pcu->have_dle = false;
+-			pcu->read_pos = 0;
+-			pcu->check_sum = 0;
+ 			break;
+ 
+ 		case IMS_PCU_PROTOCOL_DLE:
+@@ -495,12 +509,18 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
+ 				ims_pcu_handle_response(pcu);
+ 			}
+ 
+-			pcu->have_stx = false;
+-			pcu->have_dle = false;
+-			pcu->read_pos = 0;
++			ims_pcu_reset_packet(pcu);
+ 			break;
+ 
+ 		default:
++			if (pcu->read_pos >= IMS_PCU_BUF_SIZE) {
++				dev_warn(pcu->dev,
++					 "Packet too long (%d bytes), discarding\n",
++					 pcu->read_pos);
++				ims_pcu_reset_packet(pcu);
++				continue;
++			}
++
+ 			pcu->read_buf[pcu->read_pos++] = data;
+ 			pcu->check_sum += data;
+ 			break;
+@@ -944,9 +964,10 @@ out:
+ 	return retval;
+ }
+ 
+-static void ims_pcu_process_async_firmware(const struct firmware *fw,
++static void ims_pcu_process_async_firmware(const struct firmware *_fw,
+ 					   void *context)
+ {
++	const struct firmware *fw __free(firmware) = _fw;
+ 	struct ims_pcu *pcu = context;
+ 	int error;
+ 
+@@ -967,8 +988,6 @@ static void ims_pcu_process_async_firmware(const struct firmware *fw,
+ 	ims_pcu_handle_firmware_update(pcu, fw);
+ 	mutex_unlock(&pcu->cmd_mutex);
+ 
+-	release_firmware(fw);
+-
+ out:
+ 	complete(&pcu->async_firmware_done);
+ }
+diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
+index e5fee1aae587be..d3dc03fa93c652 100644
+--- a/drivers/iommu/amd/init.c
++++ b/drivers/iommu/amd/init.c
+@@ -3675,6 +3675,12 @@ not_found:
+ 	return 1;
+ 
+ found:
++	if (early_acpihid_map_size == EARLY_MAP_SIZE) {
++		pr_err("Early ACPI HID map overflow - ignoring ivrs_acpihid%s\n",
++		       str);
++		return 1;
++	}
++
+ 	p = acpiid;
+ 	hid = strsep(&p, ":");
+ 	uid = p;
+diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
+index 48cf9e9e15976c..695cfb2e56aa7f 100644
+--- a/drivers/iommu/amd/iommu.c
++++ b/drivers/iommu/amd/iommu.c
+@@ -1212,11 +1212,23 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
+ 	int ret;
+ 	u64 data;
+ 
+-	if (!iommu->need_sync)
+-		return 0;
+-
+ 	raw_spin_lock_irqsave(&iommu->lock, flags);
+ 
++	if (!iommu->need_sync) {
++		/*
++		 * No command has been queued since the last completion-wait.
++		 * A concurrent CPU may have already queued that CWAIT and
++		 * cleared need_sync; need_sync == false only means a covering
++		 * CWAIT is queued, not that all prior commands have completed.
++		 * Wait for the last allocated sequence number so that any
++		 * command queued before this call (possibly on another CPU)
++		 * is guaranteed to have completed before returning.
++		 */
++		data = iommu->cmd_sem_val;
++		raw_spin_unlock_irqrestore(&iommu->lock, flags);
++		return wait_on_sem(iommu, data);
++	}
++
+ 	data = get_cmdsem_val(iommu);
+ 	build_completion_wait(&cmd, iommu, data);
+ 
+@@ -1226,9 +1238,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
+ 	if (ret)
+ 		return ret;
+ 
+-	ret = wait_on_sem(iommu, data);
+-
+-	return ret;
++	return wait_on_sem(iommu, data);
+ }
+ 
+ static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid)
+@@ -1431,7 +1441,8 @@ static void __domain_flush_pages(struct protection_domain *domain,
+ static void domain_flush_pages(struct protection_domain *domain,
+ 			       u64 address, size_t size, int pde)
+ {
+-	if (likely(!amd_iommu_np_cache)) {
++	if (likely(!amd_iommu_np_cache) ||
++		size >= (1ULL<<52)) {
+ 		__domain_flush_pages(domain, address, size, pde);
+ 		return;
+ 	}
+diff --git a/drivers/iommu/intel/perf.c b/drivers/iommu/intel/perf.c
+index ae64e1123f2571..08ffebdbd09cec 100644
+--- a/drivers/iommu/intel/perf.c
++++ b/drivers/iommu/intel/perf.c
+@@ -63,7 +63,7 @@ void dmar_latency_disable(struct intel_iommu *iommu, enum latency_type type)
+ 		return;
+ 
+ 	spin_lock_irqsave(&latency_lock, flags);
+-	memset(&lstat[type], 0, sizeof(*lstat) * DMAR_LATENCY_NUM);
++	memset(&lstat[type], 0, sizeof(*lstat));
+ 	spin_unlock_irqrestore(&latency_lock, flags);
+ }
+ 
+diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
+index 6010b93c514c5c..e30f667782d26b 100644
+--- a/drivers/iommu/intel/svm.c
++++ b/drivers/iommu/intel/svm.c
+@@ -149,7 +149,7 @@ int intel_svm_finish_prq(struct intel_iommu *iommu)
+ 
+ void intel_svm_check(struct intel_iommu *iommu)
+ {
+-	if (!pasid_supported(iommu))
++	if (!pasid_supported(iommu) || !ecap_smpwc(iommu->ecap))
+ 		return;
+ 
+ 	if (cpu_feature_enabled(X86_FEATURE_GBPAGES) &&
+diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
+index 6ae5886566d910..7e877c6adb2eac 100644
+--- a/drivers/md/dm-verity-target.c
++++ b/drivers/md/dm-verity-target.c
+@@ -227,14 +227,16 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
+ 	char *envp[] = { verity_env, NULL };
+ 	const char *type_str = "";
+ 	struct mapped_device *md = dm_table_get_md(v->ti->table);
++	int ce;
+ 
+ 	/* Corruption should be visible in device status in all modes */
+ 	v->hash_failed = true;
+ 
+-	if (v->corrupted_errs >= DM_VERITY_MAX_CORRUPTED_ERRS)
+-		goto out;
+-
+-	v->corrupted_errs++;
++	ce = atomic_read(&v->corrupted_errs);
++	do {
++		if (ce >= DM_VERITY_MAX_CORRUPTED_ERRS)
++			goto out;
++	} while (!atomic_try_cmpxchg(&v->corrupted_errs, &ce, ce + 1));
+ 
+ 	switch (type) {
+ 	case DM_VERITY_BLOCK_TYPE_DATA:
+@@ -250,7 +252,7 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
+ 	DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,
+ 		    type_str, block);
+ 
+-	if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS) {
++	if (ce + 1 == DM_VERITY_MAX_CORRUPTED_ERRS) {
+ 		DMERR("%s: reached maximum errors", v->data_dev->name);
+ 		dm_audit_log_target(DM_MSG_PREFIX, "max-corrupted-errors", v->ti, 0);
+ 	}
+@@ -1172,6 +1174,8 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
+ 			continue;
+ 
+ 		} else if (!strcasecmp(arg_name, DM_VERITY_OPT_TASKLET_VERIFY)) {
++			if (v->use_tasklet)
++				continue;
+ 			v->use_tasklet = true;
+ 			static_branch_inc(&use_tasklet_enabled);
+ 			continue;
+diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
+index db93a91169d5e6..325942fc8f8038 100644
+--- a/drivers/md/dm-verity.h
++++ b/drivers/md/dm-verity.h
+@@ -58,7 +58,7 @@ struct dm_verity {
+ 	unsigned int digest_size;	/* digest size for the current hash algorithm */
+ 	unsigned int ahash_reqsize;/* the size of temporary space for crypto */
+ 	enum verity_mode mode;	/* mode for handling verification errors */
+-	unsigned int corrupted_errs;/* Number of errors for corrupted blocks */
++	atomic_t corrupted_errs;/* Number of errors for corrupted blocks */
+ 
+ 	struct workqueue_struct *verify_wq;
+ 
+diff --git a/drivers/media/cec/platform/seco/seco-cec.c b/drivers/media/cec/platform/seco/seco-cec.c
+index 5d4c5a2cae097e..8f5991cfae5e06 100644
+--- a/drivers/media/cec/platform/seco/seco-cec.c
++++ b/drivers/media/cec/platform/seco/seco-cec.c
+@@ -649,7 +649,7 @@ static int secocec_probe(struct platform_device *pdev)
+ 
+ 	ret = secocec_ir_probe(secocec);
+ 	if (ret)
+-		goto err_notifier;
++		goto err_unregister_adapter;
+ 
+ 	platform_set_drvdata(pdev, secocec);
+ 
+@@ -657,6 +657,10 @@ static int secocec_probe(struct platform_device *pdev)
+ 
+ 	return ret;
+ 
++err_unregister_adapter:
++	cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap);
++	cec_unregister_adapter(secocec->cec_adap);
++	goto err;
+ err_notifier:
+ 	cec_notifier_cec_adap_unregister(secocec->notifier, secocec->cec_adap);
+ err_delete_adapter:
+diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
+index 29bfc2bf796b65..1abf6e08668acd 100644
+--- a/drivers/media/common/videobuf2/videobuf2-core.c
++++ b/drivers/media/common/videobuf2/videobuf2-core.c
+@@ -2769,8 +2769,8 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q)
+  * @nonblock:	mode selector (1 means blocking calls, 0 means nonblocking)
+  * @read:	access mode selector (1 means read, 0 means write)
+  */
+-static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
+-		loff_t *ppos, int nonblock, int read)
++static ssize_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
++				    loff_t *ppos, int nonblock, int read)
+ {
+ 	struct vb2_fileio_data *fileio;
+ 	struct vb2_fileio_buf *buf;
+@@ -2930,15 +2930,15 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
+ 	return ret;
+ }
+ 
+-size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+-		loff_t *ppos, int nonblocking)
++ssize_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
++		 loff_t *ppos, int nonblocking)
+ {
+ 	return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1);
+ }
+ EXPORT_SYMBOL_GPL(vb2_read);
+ 
+-size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
+-		loff_t *ppos, int nonblocking)
++ssize_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
++		  loff_t *ppos, int nonblocking)
+ {
+ 	return __vb2_perform_fileio(q, (char __user *) data, count,
+ 							ppos, nonblocking, 0);
+diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
+index e6a7877a985413..b9565bf03e5c08 100644
+--- a/drivers/media/dvb-frontends/rtl2832.c
++++ b/drivers/media/dvb-frontends/rtl2832.c
+@@ -1115,10 +1115,10 @@ static void rtl2832_remove(struct i2c_client *client)
+ 
+ 	dev_dbg(&client->dev, "\n");
+ 
+-	cancel_delayed_work_sync(&dev->i2c_gate_work);
+-
+ 	i2c_mux_del_adapters(dev->muxc);
+ 
++	cancel_delayed_work_sync(&dev->i2c_gate_work);
++
+ 	regmap_exit(dev->regmap);
+ 
+ 	kfree(dev);
+diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
+index 02c619e51641d9..ebe95f02803385 100644
+--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
++++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
+@@ -399,7 +399,8 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_dev *dev)
+ }
+ 
+ /* Must be called with vb_queue_lock hold */
+-static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev)
++static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev,
++					    enum vb2_buffer_state state)
+ {
+ 	struct platform_device *pdev = dev->pdev;
+ 	unsigned long flags;
+@@ -413,7 +414,7 @@ static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev)
+ 		buf = list_entry(dev->queued_bufs.next,
+ 				struct rtl2832_sdr_frame_buf, list);
+ 		list_del(&buf->list);
+-		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
++		vb2_buffer_done(&buf->vb.vb2_buf, state);
+ 	}
+ 	spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+ }
+@@ -854,11 +855,15 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
+ 
+ 	dev_dbg(&pdev->dev, "\n");
+ 
+-	if (!dev->udev)
++	if (!dev->udev) {
++		rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED);
+ 		return -ENODEV;
++	}
+ 
+-	if (mutex_lock_interruptible(&dev->v4l2_lock))
++	if (mutex_lock_interruptible(&dev->v4l2_lock)) {
++		rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED);
+ 		return -ERESTARTSYS;
++	}
+ 
+ 	if (d->props->power_ctrl)
+ 		d->props->power_ctrl(d, 1);
+@@ -899,7 +904,11 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
+ 	if (ret)
+ 		goto err;
+ 
++	mutex_unlock(&dev->v4l2_lock);
++	return 0;
++
+ err:
++	rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED);
+ 	mutex_unlock(&dev->v4l2_lock);
+ 
+ 	return ret;
+@@ -919,7 +928,7 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
+ 	rtl2832_sdr_kill_urbs(dev);
+ 	rtl2832_sdr_free_urbs(dev);
+ 	rtl2832_sdr_free_stream_bufs(dev);
+-	rtl2832_sdr_cleanup_queued_bufs(dev);
++	rtl2832_sdr_cleanup_queued_bufs(dev, VB2_BUF_STATE_ERROR);
+ 	rtl2832_sdr_unset_adc(dev);
+ 
+ 	/* sleep tuner */
+diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
+index c8705d786cddca..5e639a99cab17b 100644
+--- a/drivers/media/pci/cx23885/cx23885-core.c
++++ b/drivers/media/pci/cx23885/cx23885-core.c
+@@ -990,8 +990,12 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
+ 	}
+ 
+ 	/* PCIe stuff */
+-	dev->lmmio = ioremap(pci_resource_start(dev->pci, 0),
+-			     pci_resource_len(dev->pci, 0));
++	dev->lmmio = pci_ioremap_bar(dev->pci, 0);
++	if (!dev->lmmio) {
++		dev_err(&dev->pci->dev, "CORE %s: can't ioremap MMIO memory\n",
++			dev->name);
++		goto err_release_region;
++	}
+ 
+ 	dev->bmmio = (u8 __iomem *)dev->lmmio;
+ 
+@@ -1096,6 +1100,12 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
+ 	}
+ 
+ 	return 0;
++
++err_release_region:
++	release_mem_region(pci_resource_start(dev->pci, 0),
++			   pci_resource_len(dev->pci, 0));
++	cx23885_devcount--;
++	return -ENODEV;
+ }
+ 
+ static void cx23885_dev_unregister(struct cx23885_dev *dev)
+diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
+index e1185aa669f480..c1d55b98367447 100644
+--- a/drivers/media/pci/dm1105/dm1105.c
++++ b/drivers/media/pci/dm1105/dm1105.c
+@@ -1194,6 +1194,7 @@ static void dm1105_remove(struct pci_dev *pdev)
+ 
+ 	dm1105_hw_exit(dev);
+ 	free_irq(pdev->irq, dev);
++	destroy_workqueue(dev->wq);
+ 	pci_iounmap(pdev, dev->io_mem);
+ 	pci_release_regions(pdev);
+ 	pci_disable_device(pdev);
+diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
+index 56b4481a40e612..75a9a951942f3c 100644
+--- a/drivers/media/pci/saa7134/saa7134-video.c
++++ b/drivers/media/pci/saa7134/saa7134-video.c
+@@ -1716,8 +1716,10 @@ int saa7134_video_init1(struct saa7134_dev *dev)
+ 	q->dev = &dev->pci->dev;
+ 	ret = vb2_queue_init(q);
+ 	if (ret)
+-		return ret;
+-	saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt);
++		goto err_free_ctrl;
++	ret = saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt);
++	if (ret)
++		goto err_free_ctrl;
+ 
+ 	q = &dev->vbi_vbq;
+ 	q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+@@ -1734,11 +1736,24 @@ int saa7134_video_init1(struct saa7134_dev *dev)
+ 	q->lock = &dev->lock;
+ 	q->dev = &dev->pci->dev;
+ 	ret = vb2_queue_init(q);
+-	if (ret)
+-		return ret;
+-	saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt);
++	if (ret) {
++		saa7134_pgtable_free(dev->pci, &dev->video_q.pt);
++		goto err_free_ctrl;
++	}
++
++	ret = saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt);
++	if (ret) {
++		saa7134_pgtable_free(dev->pci, &dev->video_q.pt);
++		goto err_free_ctrl;
++	}
+ 
+ 	return 0;
++
++err_free_ctrl:
++	v4l2_ctrl_handler_free(&dev->ctrl_handler);
++	if (card_has_radio(dev))
++		v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
++	return ret;
+ }
+ 
+ void saa7134_video_fini(struct saa7134_dev *dev)
+diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c
+index a9c2c69b2ed99f..0d0b4f2eda0b15 100644
+--- a/drivers/media/platform/aspeed/aspeed-video.c
++++ b/drivers/media/platform/aspeed/aspeed-video.c
+@@ -2193,6 +2193,7 @@ static int aspeed_video_probe(struct platform_device *pdev)
+ 	rc = aspeed_video_setup_video(video);
+ 	if (rc) {
+ 		aspeed_video_free_buf(video, &video->jpeg);
++		of_reserved_mem_device_release(&pdev->dev);
+ 		clk_unprepare(video->vclk);
+ 		clk_unprepare(video->eclk);
+ 		return rc;
+diff --git a/drivers/media/platform/marvell/cafe-driver.c b/drivers/media/platform/marvell/cafe-driver.c
+index ef810249def61c..29cfdc3d9bd46f 100644
+--- a/drivers/media/platform/marvell/cafe-driver.c
++++ b/drivers/media/platform/marvell/cafe-driver.c
+@@ -609,6 +609,7 @@ static void cafe_pci_remove(struct pci_dev *pdev)
+ 		return;
+ 	}
+ 	cafe_shutdown(cam);
++	pci_disable_device(pdev);
+ 	kfree(cam);
+ }
+ 
+diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
+index a1354d40ad8eac..6a4d62e96090b8 100644
+--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
+@@ -503,6 +503,8 @@ static int mxc_isi_probe(struct platform_device *pdev)
+ 	return 0;
+ 
+ err_xbar:
++	while (i--)
++		mxc_isi_pipe_cleanup(&isi->pipes[i]);
+ 	mxc_isi_crossbar_cleanup(&isi->crossbar);
+ 
+ 	return ret;
+diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
+index 5a4676d5207935..467ce2b877725f 100644
+--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.h
+@@ -11,6 +11,7 @@
+ #define __MXC_ISI_CORE_H__
+ 
+ #include <linux/list.h>
++#include <linux/math.h>
+ #include <linux/mutex.h>
+ #include <linux/spinlock.h>
+ #include <linux/types.h>
+@@ -403,4 +404,19 @@ static inline void mxc_isi_debug_cleanup(struct mxc_isi_dev *isi)
+ }
+ #endif
+ 
++/*
++ * ISI scaling engine works in two parts: it performs pre-decimation of
++ * the image followed by bilinear filtering to achieve the desired
++ * downscaling factor.
++ *
++ * The decimation filter provides a maximum downscaling factor of 8, and
++ * the subsequent bilinear filter provides a maximum downscaling factor
++ * of 2. Combined, the maximum scaling factor can be up to 16.
++ */
++static inline unsigned int
++mxc_isi_clamp_downscale_16(unsigned int val, unsigned int max_val)
++{
++	return clamp(val, max(1U, DIV_ROUND_UP(max_val, 16)), max_val);
++}
++
+ #endif /* __MXC_ISI_CORE_H__ */
+diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
+index c9a4d091b57074..05c3cd161aee14 100644
+--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-crossbar.c
+@@ -490,6 +490,7 @@ err_free:
+ 
+ void mxc_isi_crossbar_cleanup(struct mxc_isi_crossbar *xbar)
+ {
++	v4l2_subdev_cleanup(&xbar->sd);
+ 	media_entity_cleanup(&xbar->sd.entity);
+ 	kfree(xbar->pads);
+ 	kfree(xbar->inputs);
+diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c
+index ece352171b936d..690c65ccf623ef 100644
+--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c
++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c
+@@ -112,7 +112,14 @@ static u32 mxc_isi_channel_scaling_ratio(unsigned int from, unsigned int to,
+ 	else
+ 		*dec = 8;
+ 
+-	return min_t(u32, from * 0x1000 / (to * *dec), ISI_DOWNSCALE_THRESHOLD);
++	/*
++	 * The ISI rounds output dimensions up to the next integer (i.MX93 RM
++	 * section 57.7.8). Calculate the scale factor such that the theoretical
++	 * output (input / scale_factor) rounds up to exactly the desired
++	 * output.
++	 */
++	return min_t(u32, DIV_ROUND_UP(from * 0x1000, to * *dec),
++		     ISI_DOWNSCALE_THRESHOLD);
+ }
+ 
+ static void mxc_isi_channel_set_scaling(struct mxc_isi_pipe *pipe,
+diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
+index 81223d28ee56e8..cb18ce84466d8b 100644
+--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
+@@ -504,9 +504,14 @@ __mxc_isi_m2m_try_fmt_vid(struct mxc_isi_m2m_ctx *ctx,
+ 			  const enum mxc_isi_video_type type)
+ {
+ 	if (type == MXC_ISI_VIDEO_M2M_CAP) {
+-		/* Downscaling only  */
+-		pix->width = min(pix->width, ctx->queues.out.format.width);
+-		pix->height = min(pix->height, ctx->queues.out.format.height);
++		const struct v4l2_pix_format_mplane *format =
++			&ctx->queues.out.format;
++
++		/* Downscaling only, by up to 16. */
++		pix->width = mxc_isi_clamp_downscale_16(pix->width,
++							format->width);
++		pix->height = mxc_isi_clamp_downscale_16(pix->height,
++							 format->height);
+ 	}
+ 
+ 	return mxc_isi_format_try(ctx->m2m->pipe, pix, type);
+diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c
+index 483523327c025f..302ecba1c17f15 100644
+--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c
++++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-pipe.c
+@@ -641,16 +641,19 @@ static int mxc_isi_pipe_set_selection(struct v4l2_subdev *sd,
+ 			/* Composing is supported on the sink only. */
+ 			return -EINVAL;
+ 
+-		/* The sink crop is bound by the sink format downscaling only). */
++		/*
++		 * The ISI supports downscaling only, with a factor up to 16.
++		 * Clamp the compose rectangle size accordingly.
++		 */
+ 		format = mxc_isi_pipe_get_pad_format(pipe, state,
+ 						     MXC_ISI_PIPE_PAD_SINK);
+ 
+ 		sel->r.left = 0;
+ 		sel->r.top = 0;
+-		sel->r.width = clamp(sel->r.width, MXC_ISI_MIN_WIDTH,
+-				     format->width);
+-		sel->r.height = clamp(sel->r.height, MXC_ISI_MIN_HEIGHT,
+-				      format->height);
++		sel->r.width = mxc_isi_clamp_downscale_16(sel->r.width,
++							  format->width);
++		sel->r.height = mxc_isi_clamp_downscale_16(sel->r.height,
++							   format->height);
+ 
+ 		rect = mxc_isi_pipe_get_pad_compose(pipe, state,
+ 						    MXC_ISI_PIPE_PAD_SINK);
+@@ -792,18 +795,20 @@ int mxc_isi_pipe_init(struct mxc_isi_dev *isi, unsigned int id)
+ 	irq = platform_get_irq(to_platform_device(isi->dev), id);
+ 	if (irq < 0) {
+ 		ret = irq;
+-		goto error;
++		goto error_subdev;
+ 	}
+ 
+ 	ret = devm_request_irq(isi->dev, irq, mxc_isi_pipe_irq_handler,
+ 			       0, dev_name(isi->dev), pipe);
+ 	if (ret < 0) {
+ 		dev_err(isi->dev, "failed to request IRQ (%d)\n", ret);
+-		goto error;
++		goto error_subdev;
+ 	}
+ 
+ 	return 0;
+ 
++error_subdev:
++	v4l2_subdev_cleanup(sd);
+ error:
+ 	media_entity_cleanup(&sd->entity);
+ 	mutex_destroy(&pipe->lock);
+@@ -815,6 +820,7 @@ void mxc_isi_pipe_cleanup(struct mxc_isi_pipe *pipe)
+ {
+ 	struct v4l2_subdev *sd = &pipe->sd;
+ 
++	v4l2_subdev_cleanup(sd);
+ 	media_entity_cleanup(&sd->entity);
+ 	mutex_destroy(&pipe->lock);
+ }
+diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
+index 8cb4fdcae1373d..cdb14d9ea62c64 100644
+--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
++++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
+@@ -2077,6 +2077,7 @@ static int dcmi_probe(struct platform_device *pdev)
+ 	return 0;
+ 
+ err_cleanup:
++	v4l2_async_nf_unregister(&dcmi->notifier);
+ 	v4l2_async_nf_cleanup(&dcmi->notifier);
+ err_media_entity_cleanup:
+ 	media_entity_cleanup(&dcmi->vdev->entity);
+diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
+index 95b5633b79149a..2b9b800cd81e2e 100644
+--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
++++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
+@@ -234,8 +234,10 @@ static int sun4i_csi_start_streaming(struct vb2_queue *vq, unsigned int count)
+ 	int ret;
+ 
+ 	csi_fmt = sun4i_csi_find_format(&csi->fmt.pixelformat, NULL);
+-	if (!csi_fmt)
+-		return -EINVAL;
++	if (!csi_fmt) {
++		ret = -EINVAL;
++		goto err_clear_dma_queue;
++	}
+ 
+ 	dev_dbg(csi->dev, "Starting capture\n");
+ 
+diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c
+index 2d8ff91cf803f9..5c2f5ca97a59ff 100644
+--- a/drivers/media/platform/ti/davinci/vpif_capture.c
++++ b/drivers/media/platform/ti/davinci/vpif_capture.c
+@@ -1500,7 +1500,7 @@ vpif_capture_get_pdata(struct platform_device *pdev,
+ 	 * video ports & endpoints data.
+ 	 */
+ 	if (pdev->dev.parent && pdev->dev.parent->of_node)
+-		pdev->dev.of_node = pdev->dev.parent->of_node;
++		device_set_of_node_from_dev(&pdev->dev, pdev->dev.parent);
+ 	if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node)
+ 		return pdev->dev.platform_data;
+ 
+diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c
+index 6848cbc82f5288..a2d938e8050d65 100644
+--- a/drivers/media/platform/ti/vpe/vpe.c
++++ b/drivers/media/platform/ti/vpe/vpe.c
+@@ -2545,7 +2545,8 @@ static int vpe_probe(struct platform_device *pdev)
+ 						"vpe_top");
+ 	if (!dev->res) {
+ 		dev_err(&pdev->dev, "missing 'vpe_top' resources data\n");
+-		return -ENODEV;
++		ret = -ENODEV;
++		goto v4l2_dev_unreg;
+ 	}
+ 
+ 	/*
+diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
+index 6061506159f1b4..6fe526b14de5e6 100644
+--- a/drivers/media/radio/radio-si476x.c
++++ b/drivers/media/radio/radio-si476x.c
+@@ -1495,6 +1495,7 @@ static int si476x_radio_probe(struct platform_device *pdev)
+ 	return 0;
+ exit:
+ 	v4l2_ctrl_handler_free(radio->videodev.ctrl_handler);
++	v4l2_device_unregister(&radio->v4l2dev);
+ 	return rval;
+ }
+ 
+diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
+index a5e774aced4800..3edc25159f2e2b 100644
+--- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c
++++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
+@@ -594,8 +594,10 @@ static int __init vidtv_bridge_init(void)
+ 	int ret;
+ 
+ 	ret = platform_device_register(&vidtv_bridge_dev);
+-	if (ret)
++	if (ret) {
++		platform_device_put(&vidtv_bridge_dev);
+ 		return ret;
++	}
+ 
+ 	ret = platform_driver_register(&vidtv_bridge_driver);
+ 	if (ret)
+diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c
+index af127476e920e6..413c699f716ea1 100644
+--- a/drivers/media/test-drivers/vimc/vimc-core.c
++++ b/drivers/media/test-drivers/vimc/vimc-core.c
+@@ -424,6 +424,7 @@ static int __init vimc_init(void)
+ 	if (ret) {
+ 		dev_err(&vimc_pdev.dev,
+ 			"platform device registration failed (err=%d)\n", ret);
++		platform_device_put(&vimc_pdev);
+ 		return ret;
+ 	}
+ 
+diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c
+index 5ca385a6a13656..8e62e907c59246 100644
+--- a/drivers/media/test-drivers/vivid/vivid-ctrls.c
++++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c
+@@ -542,17 +542,24 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
+ 		break;
+ 	case VIVID_CID_REDUCED_FPS:
+ 		dev->reduced_fps = ctrl->val;
+-		vivid_update_format_cap(dev, true);
++		if (dev->input_type[dev->input] == HDMI)
++			vivid_update_reduced_fps(dev);
+ 		break;
+ 	case VIVID_CID_HAS_CROP_CAP:
++		if (vb2_is_busy(&dev->vb_vid_cap_q))
++			return -EBUSY;
+ 		dev->has_crop_cap = ctrl->val;
+ 		vivid_update_format_cap(dev, true);
+ 		break;
+ 	case VIVID_CID_HAS_COMPOSE_CAP:
++		if (vb2_is_busy(&dev->vb_vid_cap_q))
++			return -EBUSY;
+ 		dev->has_compose_cap = ctrl->val;
+ 		vivid_update_format_cap(dev, true);
+ 		break;
+ 	case VIVID_CID_HAS_SCALER_CAP:
++		if (vb2_is_busy(&dev->vb_vid_cap_q))
++			return -EBUSY;
+ 		dev->has_scaler_cap = ctrl->val;
+ 		vivid_update_format_cap(dev, true);
+ 		break;
+@@ -1037,14 +1044,20 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
+ 
+ 	switch (ctrl->id) {
+ 	case VIVID_CID_HAS_CROP_OUT:
++		if (vb2_is_busy(&dev->vb_vid_out_q))
++			return -EBUSY;
+ 		dev->has_crop_out = ctrl->val;
+ 		vivid_update_format_out(dev);
+ 		break;
+ 	case VIVID_CID_HAS_COMPOSE_OUT:
++		if (vb2_is_busy(&dev->vb_vid_out_q))
++			return -EBUSY;
+ 		dev->has_compose_out = ctrl->val;
+ 		vivid_update_format_out(dev);
+ 		break;
+ 	case VIVID_CID_HAS_SCALER_OUT:
++		if (vb2_is_busy(&dev->vb_vid_out_q))
++			return -EBUSY;
+ 		dev->has_scaler_out = ctrl->val;
+ 		vivid_update_format_out(dev);
+ 		break;
+diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+index 5d1f78c7604dea..703169a8935999 100644
+--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
++++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+@@ -368,6 +368,24 @@ static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev)
+ 	return TPG_PIXEL_ASPECT_SQUARE;
+ }
+ 
++void vivid_update_reduced_fps(struct vivid_dev *dev)
++{
++	struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt;
++	unsigned int size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
++	u64 pixelclock;
++
++	if (dev->reduced_fps && can_reduce_fps(bt)) {
++		pixelclock = div_u64(bt->pixelclock * 1000, 1001);
++		bt->flags |= V4L2_DV_FL_REDUCED_FPS;
++	} else {
++		pixelclock = bt->pixelclock;
++		bt->flags &= ~V4L2_DV_FL_REDUCED_FPS;
++	}
++	dev->timeperframe_vid_cap = (struct v4l2_fract) {
++		size / 100, (u32)pixelclock / 100
++	};
++}
++
+ /*
+  * Called whenever the format has to be reset which can occur when
+  * changing inputs, standard, timings, etc.
+@@ -376,8 +394,12 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
+ {
+ 	struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt;
+ 	u32 dims[V4L2_CTRL_MAX_DIMS] = {};
+-	unsigned size;
+-	u64 pixelclock;
++
++	/*
++	 * This resets the format, so must never be called while vb2_is_busy().
++	 */
++	if (WARN_ON(vb2_is_busy(&dev->vb_vid_cap_q)))
++		return;
+ 
+ 	switch (dev->input_type[dev->input]) {
+ 	case WEBCAM:
+@@ -406,17 +428,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
+ 	case HDMI:
+ 		dev->src_rect.width = bt->width;
+ 		dev->src_rect.height = bt->height;
+-		size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
+-		if (dev->reduced_fps && can_reduce_fps(bt)) {
+-			pixelclock = div_u64(bt->pixelclock * 1000, 1001);
+-			bt->flags |= V4L2_DV_FL_REDUCED_FPS;
+-		} else {
+-			pixelclock = bt->pixelclock;
+-			bt->flags &= ~V4L2_DV_FL_REDUCED_FPS;
+-		}
+-		dev->timeperframe_vid_cap = (struct v4l2_fract) {
+-			size / 100, (u32)pixelclock / 100
+-		};
++		vivid_update_reduced_fps(dev);
+ 		if (bt->interlaced)
+ 			dev->field_cap = V4L2_FIELD_ALTERNATE;
+ 		else
+diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.h b/drivers/media/test-drivers/vivid/vivid-vid-cap.h
+index 949768652d3822..792856aa20d2cc 100644
+--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.h
++++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.h
+@@ -9,6 +9,7 @@
+ #define _VIVID_VID_CAP_H_
+ 
+ void vivid_update_quality(struct vivid_dev *dev);
++void vivid_update_reduced_fps(struct vivid_dev *dev);
+ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls);
+ enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev);
+ 
+diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c
+index d05f547a587cd2..50c47b1d911ab4 100644
+--- a/drivers/media/test-drivers/vivid/vivid-vid-out.c
++++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c
+@@ -222,6 +222,12 @@ void vivid_update_format_out(struct vivid_dev *dev)
+ 	unsigned size, p;
+ 	u64 pixelclock;
+ 
++	/*
++	 * This resets the format, so must never be called while vb2_is_busy().
++	 */
++	if (WARN_ON(vb2_is_busy(&dev->vb_vid_out_q)))
++		return;
++
+ 	switch (dev->output_type[dev->output]) {
+ 	case SVID:
+ 	default:
+diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
+index 462eb84235063a..3c5c0b16370893 100644
+--- a/drivers/media/usb/airspy/airspy.c
++++ b/drivers/media/usb/airspy/airspy.c
+@@ -521,11 +521,13 @@ static int airspy_start_streaming(struct vb2_queue *vq, unsigned int count)
+ 
+ 	dev_dbg(s->dev, "\n");
+ 
+-	if (!s->udev)
+-		return -ENODEV;
+-
+ 	mutex_lock(&s->v4l2_lock);
+ 
++	if (!s->udev) {
++		ret = -ENODEV;
++		goto err_clear_bit;
++	}
++
+ 	s->sequence = 0;
+ 
+ 	set_bit(POWER_ON, &s->flags);
+diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
+index bda729b42d05fe..64c3cb8fc2bf00 100644
+--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
++++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
+@@ -1577,7 +1577,8 @@ static int cx231xx_init_v4l2(struct cx231xx *dev,
+ 		 dev->video_mode.end_point_addr,
+ 		 dev->video_mode.num_alt);
+ 
+-	dev->video_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->video_mode.num_alt, GFP_KERNEL);
++	dev->video_mode.alt_max_pkt_size = devm_kmalloc_array(&interface->dev, 32,
++							      dev->video_mode.num_alt, GFP_KERNEL);
+ 	if (dev->video_mode.alt_max_pkt_size == NULL)
+ 		return -ENOMEM;
+ 
+@@ -1618,7 +1619,8 @@ static int cx231xx_init_v4l2(struct cx231xx *dev,
+ 		 dev->vbi_mode.num_alt);
+ 
+ 	/* compute alternate max packet sizes for vbi */
+-	dev->vbi_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->vbi_mode.num_alt, GFP_KERNEL);
++	dev->vbi_mode.alt_max_pkt_size = devm_kmalloc_array(&interface->dev, 32,
++							    dev->vbi_mode.num_alt, GFP_KERNEL);
+ 	if (dev->vbi_mode.alt_max_pkt_size == NULL)
+ 		return -ENOMEM;
+ 
+@@ -1660,7 +1662,9 @@ static int cx231xx_init_v4l2(struct cx231xx *dev,
+ 		 "sliced CC EndPoint Addr 0x%x, Alternate settings: %i\n",
+ 		 dev->sliced_cc_mode.end_point_addr,
+ 		 dev->sliced_cc_mode.num_alt);
+-	dev->sliced_cc_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->sliced_cc_mode.num_alt, GFP_KERNEL);
++	dev->sliced_cc_mode.alt_max_pkt_size = devm_kmalloc_array(&interface->dev, 32,
++								  dev->sliced_cc_mode.num_alt,
++								  GFP_KERNEL);
+ 	if (dev->sliced_cc_mode.alt_max_pkt_size == NULL)
+ 		return -ENOMEM;
+ 
+@@ -1724,7 +1728,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
+ 	udev = usb_get_dev(interface_to_usbdev(interface));
+ 
+ 	/* allocate memory for our device state and initialize it */
+-	dev = devm_kzalloc(&udev->dev, sizeof(*dev), GFP_KERNEL);
++	dev = devm_kzalloc(&interface->dev, sizeof(*dev), GFP_KERNEL);
+ 	if (dev == NULL) {
+ 		retval = -ENOMEM;
+ 		goto err_if;
+@@ -1854,7 +1858,9 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
+ 			 dev->ts1_mode.end_point_addr,
+ 			 dev->ts1_mode.num_alt);
+ 
+-		dev->ts1_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->ts1_mode.num_alt, GFP_KERNEL);
++		dev->ts1_mode.alt_max_pkt_size = devm_kmalloc_array(&interface->dev, 32,
++								    dev->ts1_mode.num_alt,
++								    GFP_KERNEL);
+ 		if (dev->ts1_mode.alt_max_pkt_size == NULL) {
+ 			retval = -ENOMEM;
+ 			goto err_video_alt;
+diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c
+index 9759996ee6a4cc..856bf295f719b6 100644
+--- a/drivers/media/usb/msi2500/msi2500.c
++++ b/drivers/media/usb/msi2500/msi2500.c
+@@ -541,7 +541,8 @@ static int msi2500_isoc_init(struct msi2500_dev *dev)
+ }
+ 
+ /* Must be called with vb_queue_lock hold */
+-static void msi2500_cleanup_queued_bufs(struct msi2500_dev *dev)
++static void msi2500_cleanup_queued_bufs(struct msi2500_dev *dev,
++					enum vb2_buffer_state state)
+ {
+ 	unsigned long flags;
+ 
+@@ -554,7 +555,7 @@ static void msi2500_cleanup_queued_bufs(struct msi2500_dev *dev)
+ 		buf = list_entry(dev->queued_bufs.next,
+ 				 struct msi2500_frame_buf, list);
+ 		list_del(&buf->list);
+-		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
++		vb2_buffer_done(&buf->vb.vb2_buf, state);
+ 	}
+ 	spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+ }
+@@ -830,25 +831,40 @@ static int msi2500_start_streaming(struct vb2_queue *vq, unsigned int count)
+ 
+ 	dev_dbg(dev->dev, "\n");
+ 
+-	if (!dev->udev)
+-		return -ENODEV;
++	if (!dev->udev) {
++		ret = -ENODEV;
++		goto err_cleanup;
++	}
+ 
+-	if (mutex_lock_interruptible(&dev->v4l2_lock))
+-		return -ERESTARTSYS;
++	if (mutex_lock_interruptible(&dev->v4l2_lock)) {
++		ret = -ERESTARTSYS;
++		goto err_cleanup;
++	}
+ 
+ 	/* wake-up tuner */
+ 	v4l2_subdev_call(dev->v4l2_subdev, core, s_power, 1);
+ 
+ 	ret = msi2500_set_usb_adc(dev);
++	if (ret)
++		goto err_unlock_cleanup;
+ 
+ 	ret = msi2500_isoc_init(dev);
+ 	if (ret)
+-		msi2500_cleanup_queued_bufs(dev);
++		goto err_unlock_cleanup;
+ 
+ 	ret = msi2500_ctrl_msg(dev, CMD_START_STREAMING, 0);
++	if (ret)
++		goto err_isoc_cleanup;
+ 
+ 	mutex_unlock(&dev->v4l2_lock);
++	return 0;
+ 
++err_isoc_cleanup:
++	msi2500_isoc_cleanup(dev);
++err_unlock_cleanup:
++	mutex_unlock(&dev->v4l2_lock);
++err_cleanup:
++	msi2500_cleanup_queued_bufs(dev, VB2_BUF_STATE_QUEUED);
+ 	return ret;
+ }
+ 
+@@ -863,7 +879,7 @@ static void msi2500_stop_streaming(struct vb2_queue *vq)
+ 	if (dev->udev)
+ 		msi2500_isoc_cleanup(dev);
+ 
+-	msi2500_cleanup_queued_bufs(dev);
++	msi2500_cleanup_queued_bufs(dev, VB2_BUF_STATE_ERROR);
+ 
+ 	/* according to tests, at least 700us delay is required  */
+ 	msleep(20);
+diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
+index e342199711d397..0ab96c4c7eccd4 100644
+--- a/drivers/media/usb/pwc/pwc-if.c
++++ b/drivers/media/usb/pwc/pwc-if.c
+@@ -711,11 +711,15 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
+ 	struct pwc_device *pdev = vb2_get_drv_priv(vq);
+ 	int r;
+ 
+-	if (!pdev->udev)
++	if (!pdev->udev) {
++		pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED);
+ 		return -ENODEV;
++	}
+ 
+-	if (mutex_lock_interruptible(&pdev->v4l2_lock))
++	if (mutex_lock_interruptible(&pdev->v4l2_lock)) {
++		pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED);
+ 		return -ERESTARTSYS;
++	}
+ 	/* Turn on camera and set LEDS on */
+ 	pwc_camera_power(pdev, 1);
+ 	pwc_set_leds(pdev, leds[0], leds[1]);
+@@ -727,6 +731,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
+ 		pwc_camera_power(pdev, 0);
+ 		/* And cleanup any queued bufs!! */
+ 		pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED);
++		if (pdev->fill_buf) {
++			vb2_buffer_done(&pdev->fill_buf->vb.vb2_buf,
++					VB2_BUF_STATE_QUEUED);
++			pdev->fill_buf = NULL;
++		}
+ 	}
+ 	mutex_unlock(&pdev->v4l2_lock);
+ 
+diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c
+index a1d3e93a409565..c8d58604deea67 100644
+--- a/drivers/media/v4l2-core/v4l2-ctrls-core.c
++++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c
+@@ -809,6 +809,7 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
+ 	struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
+ 	struct v4l2_ctrl_hevc_sps *p_hevc_sps;
+ 	struct v4l2_ctrl_hevc_pps *p_hevc_pps;
++	struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params;
+ 	struct v4l2_ctrl_hdr10_mastering_display *p_hdr10_mastering;
+ 	struct v4l2_ctrl_hevc_decode_params *p_hevc_decode_params;
+ 	struct v4l2_area *area;
+@@ -1097,6 +1098,18 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
+ 		break;
+ 
+ 	case V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS:
++		p_hevc_slice_params = p;
++
++		if (p_hevc_slice_params->num_ref_idx_l0_active_minus1 >=
++		    V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
++			return -EINVAL;
++
++		if (p_hevc_slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_B)
++			break;
++
++		if (p_hevc_slice_params->num_ref_idx_l1_active_minus1 >=
++		    V4L2_HEVC_DPB_ENTRIES_NUM_MAX)
++			return -EINVAL;
+ 		break;
+ 
+ 	case V4L2_CTRL_TYPE_HDR10_CLL_INFO:
+diff --git a/drivers/media/v4l2-core/v4l2-ctrls-request.c b/drivers/media/v4l2-core/v4l2-ctrls-request.c
+index c637049d7a2b3f..dd6ca914349035 100644
+--- a/drivers/media/v4l2-core/v4l2-ctrls-request.c
++++ b/drivers/media/v4l2-core/v4l2-ctrls-request.c
+@@ -348,13 +348,12 @@ void v4l2_ctrl_request_complete(struct media_request *req,
+ 		ret = v4l2_ctrl_handler_init(hdl, (main_hdl->nr_of_buckets - 1) * 8);
+ 		if (!ret)
+ 			ret = v4l2_ctrl_request_bind(req, hdl, main_hdl);
+-		if (ret) {
+-			v4l2_ctrl_handler_free(hdl);
+-			kfree(hdl);
+-			return;
+-		}
++		if (ret)
++			goto error;
+ 		hdl->request_is_queued = true;
+ 		obj = media_request_object_find(req, &req_ops, main_hdl);
++		if (!obj)
++			goto error;
+ 	}
+ 	hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj);
+ 
+@@ -389,6 +388,11 @@ void v4l2_ctrl_request_complete(struct media_request *req,
+ 	mutex_unlock(main_hdl->lock);
+ 	media_request_object_complete(obj);
+ 	media_request_object_put(obj);
++	return;
++
++error:
++	v4l2_ctrl_handler_free(hdl);
++	kfree(hdl);
+ }
+ EXPORT_SYMBOL(v4l2_ctrl_request_complete);
+ 
+diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
+index b94cf7393fad6a..6875204d422758 100644
+--- a/drivers/misc/mei/bus.c
++++ b/drivers/misc/mei/bus.c
+@@ -4,6 +4,7 @@
+  * Intel Management Engine Interface (Intel MEI) Linux driver
+  */
+ 
++#include <linux/cleanup.h>
+ #include <linux/module.h>
+ #include <linux/device.h>
+ #include <linux/kernel.h>
+@@ -1269,15 +1270,16 @@ static void mei_dev_bus_put(struct mei_device *bus)
+ static void mei_cl_bus_dev_release(struct device *dev)
+ {
+ 	struct mei_cl_device *cldev = to_mei_cl_device(dev);
+-	struct mei_device *mdev = cldev->cl->dev;
++	struct mei_device *bus = cldev->bus;
+ 	struct mei_cl *cl;
+ 
+-	mei_cl_flush_queues(cldev->cl, NULL);
+-	mei_me_cl_put(cldev->me_cl);
+-	mei_dev_bus_put(cldev->bus);
+-
+-	list_for_each_entry(cl, &mdev->file_list, link)
+-		WARN_ON(cl == cldev->cl);
++	scoped_guard(mutex, &bus->device_lock) {
++		mei_cl_flush_queues(cldev->cl, NULL);
++		mei_me_cl_put(cldev->me_cl);
++		list_for_each_entry(cl, &bus->file_list, link)
++			WARN_ON(cl == cldev->cl);
++	}
++	mei_dev_bus_put(bus);
+ 
+ 	kfree(cldev->cl);
+ 	kfree(cldev);
+diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
+index 97ca2a897f1d49..506ebd4ba1b458 100644
+--- a/drivers/mtd/mtdcore.c
++++ b/drivers/mtd/mtdcore.c
+@@ -103,6 +103,15 @@ static void mtd_release(struct device *dev)
+ 	device_destroy(&mtd_class, index + 1);
+ }
+ 
++/*
++ * No-op device release used in add_mtd_device() error paths.
++ * Prevents mtd_release() from being called via device_release(),
++ * which would free the mtd_info that the caller still manages.
++ */
++static void mtd_dev_release_nop(struct device *dev)
++{
++}
++
+ static void mtd_device_release(struct kref *kref)
+ {
+ 	struct mtd_info *mtd = container_of(kref, struct mtd_info, refcnt);
+@@ -745,10 +754,8 @@ int add_mtd_device(struct mtd_info *mtd)
+ 	mtd_check_of_node(mtd);
+ 	of_node_get(mtd_get_of_node(mtd));
+ 	error = device_register(&mtd->dev);
+-	if (error) {
+-		put_device(&mtd->dev);
++	if (error)
+ 		goto fail_added;
+-	}
+ 
+ 	/* Add the nvmem provider */
+ 	error = mtd_nvmem_add(mtd);
+@@ -786,8 +793,16 @@ int add_mtd_device(struct mtd_info *mtd)
+ 	return 0;
+ 
+ fail_nvmem_add:
+-	device_unregister(&mtd->dev);
++	device_del(&mtd->dev);
+ fail_added:
++	/*
++	 * Clear type and set nop release to prevent mtd_release() ->
++	 * release_mtd_partition() -> free_partition() from freeing mtd.
++	 * The caller handles cleanup on failure.
++	 */
++	mtd->dev.type = NULL;
++	mtd->dev.release = mtd_dev_release_nop;
++	put_device(&mtd->dev);
+ 	of_node_put(mtd_get_of_node(mtd));
+ 	idr_remove(&mtd_idr, i);
+ fail_locked:
+diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c
+index 680366616da240..4d695875ea1b23 100644
+--- a/drivers/mtd/mtdswap.c
++++ b/drivers/mtd/mtdswap.c
+@@ -125,6 +125,7 @@ struct mtdswap_dev {
+ 
+ 	char *page_buf;
+ 	char *oob_buf;
++	struct dentry *debugfs_stats;
+ };
+ 
+ struct mtdswap_oobdata {
+@@ -1262,7 +1263,8 @@ static int mtdswap_add_debugfs(struct mtdswap_dev *d)
+ 	if (IS_ERR_OR_NULL(root))
+ 		return -1;
+ 
+-	debugfs_create_file("mtdswap_stats", S_IRUSR, root, d, &mtdswap_fops);
++	d->debugfs_stats = debugfs_create_file("mtdswap_stats", 0400, root,
++					       d, &mtdswap_fops);
+ 
+ 	return 0;
+ }
+@@ -1463,6 +1465,7 @@ static void mtdswap_remove_dev(struct mtd_blktrans_dev *dev)
+ {
+ 	struct mtdswap_dev *d = MTDSWAP_MBD_TO_MTDSWAP(dev);
+ 
++	debugfs_remove(d->debugfs_stats);
+ 	del_mtd_blktrans_dev(dev);
+ 	mtdswap_cleanup(d);
+ 	kfree(d);
+diff --git a/drivers/mtd/nand/ecc-mtk.c b/drivers/mtd/nand/ecc-mtk.c
+index c75bb8b80cc1e1..96703f0a418ea2 100644
+--- a/drivers/mtd/nand/ecc-mtk.c
++++ b/drivers/mtd/nand/ecc-mtk.c
+@@ -123,8 +123,8 @@ static int mt7622_ecc_regs[] = {
+ 	[ECC_DECIRQ_STA] =      0x144,
+ };
+ 
+-static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
+-				     enum mtk_ecc_operation op)
++static inline int mtk_ecc_wait_idle(struct mtk_ecc *ecc,
++				    enum mtk_ecc_operation op)
+ {
+ 	struct device *dev = ecc->dev;
+ 	u32 val;
+@@ -136,6 +136,8 @@ static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc,
+ 	if (ret)
+ 		dev_warn(dev, "%s NOT idle\n",
+ 			 op == ECC_ENCODE ? "encoder" : "decoder");
++
++	return ret;
+ }
+ 
+ static irqreturn_t mtk_ecc_irq(int irq, void *id)
+@@ -312,7 +314,11 @@ int mtk_ecc_enable(struct mtk_ecc *ecc, struct mtk_ecc_config *config)
+ 		return ret;
+ 	}
+ 
+-	mtk_ecc_wait_idle(ecc, op);
++	ret = mtk_ecc_wait_idle(ecc, op);
++	if (ret) {
++		mutex_unlock(&ecc->lock);
++		return ret;
++	}
+ 
+ 	ret = mtk_ecc_config(ecc, config);
+ 	if (ret) {
+@@ -412,7 +418,9 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config,
+ 	if (ret)
+ 		goto timeout;
+ 
+-	mtk_ecc_wait_idle(ecc, ECC_ENCODE);
++	ret = mtk_ecc_wait_idle(ecc, ECC_ENCODE);
++	if (ret)
++		goto timeout;
+ 
+ 	/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
+ 	len = (config->strength * ecc->caps->parity_bits + 7) >> 3;
+diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
+index e9e4ea87116c74..b2f56d89bfd367 100644
+--- a/drivers/mtd/nand/raw/nand_base.c
++++ b/drivers/mtd/nand/raw/nand_base.c
+@@ -1212,21 +1212,36 @@ static int nand_lp_exec_read_page_op(struct nand_chip *chip, unsigned int page,
+ 	return nand_exec_op(chip, &op);
+ }
+ 
++static unsigned int rawnand_last_page_of_block(unsigned int ppb, unsigned int block)
++{
++	/* block is expected to be very small */
++	return (block * ppb) + ppb - 1;
++}
++
+ static void rawnand_cap_cont_reads(struct nand_chip *chip)
+ {
+ 	struct nand_memory_organization *memorg;
+-	unsigned int pages_per_lun, first_lun, last_lun;
++	unsigned int ppb, first_block, last_block;
+ 
+ 	memorg = nanddev_get_memorg(&chip->base);
+-	pages_per_lun = memorg->pages_per_eraseblock * memorg->eraseblocks_per_lun;
+-	first_lun = chip->cont_read.first_page / pages_per_lun;
+-	last_lun = chip->cont_read.last_page / pages_per_lun;
++	ppb = memorg->pages_per_eraseblock;
++	first_block = chip->cont_read.first_page / ppb;
++	last_block = chip->cont_read.last_page / ppb;
+ 
+-	/* Prevent sequential cache reads across LUN boundaries */
+-	if (first_lun != last_lun)
+-		chip->cont_read.pause_page = first_lun * pages_per_lun + pages_per_lun - 1;
++	/* Prevent sequential cache reads across block boundaries */
++	if (first_block != last_block)
++		chip->cont_read.pause_page = rawnand_last_page_of_block(ppb, first_block);
+ 	else
+ 		chip->cont_read.pause_page = chip->cont_read.last_page;
++
++	if (chip->cont_read.first_page == chip->cont_read.pause_page) {
++		chip->cont_read.first_page++;
++		chip->cont_read.pause_page = min(chip->cont_read.last_page,
++						 rawnand_last_page_of_block(ppb, first_block + 1));
++	}
++
++	if (chip->cont_read.first_page >= chip->cont_read.last_page)
++		chip->cont_read.ongoing = false;
+ }
+ 
+ static int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int page,
+@@ -1293,12 +1308,11 @@ static int nand_lp_exec_cont_read_page_op(struct nand_chip *chip, unsigned int p
+ 	if (!chip->cont_read.ongoing)
+ 		return 0;
+ 
+-	if (page == chip->cont_read.pause_page &&
+-	    page != chip->cont_read.last_page) {
+-		chip->cont_read.first_page = chip->cont_read.pause_page + 1;
+-		rawnand_cap_cont_reads(chip);
+-	} else if (page == chip->cont_read.last_page) {
++	if (page == chip->cont_read.last_page) {
+ 		chip->cont_read.ongoing = false;
++	} else if (page == chip->cont_read.pause_page) {
++		chip->cont_read.first_page++;
++		rawnand_cap_cont_reads(chip);
+ 	}
+ 
+ 	return 0;
+@@ -3506,10 +3520,7 @@ static void rawnand_cont_read_skip_first_page(struct nand_chip *chip, unsigned i
+ 		return;
+ 
+ 	chip->cont_read.first_page++;
+-	if (chip->cont_read.first_page == chip->cont_read.pause_page)
+-		chip->cont_read.first_page++;
+-	if (chip->cont_read.first_page >= chip->cont_read.last_page)
+-		chip->cont_read.ongoing = false;
++	rawnand_cap_cont_reads(chip);
+ }
+ 
+ /**
+diff --git a/drivers/net/amt.c b/drivers/net/amt.c
+index f2da0c49171f5d..4799f8fd03c45c 100644
+--- a/drivers/net/amt.c
++++ b/drivers/net/amt.c
+@@ -1206,7 +1206,7 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+ 			data = true;
+ 		}
+ 		v6 = false;
+-		group.ip4 = iph->daddr;
++		group.ip4 = ip_hdr(skb)->daddr;
+ #if IS_ENABLED(CONFIG_IPV6)
+ 	} else if (iph->version == 6) {
+ 		ip6h = ipv6_hdr(skb);
+@@ -1230,7 +1230,7 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+ 			data = true;
+ 		}
+ 		v6 = true;
+-		group.ip6 = ip6h->daddr;
++		group.ip6 = ipv6_hdr(skb)->daddr;
+ #endif
+ 	} else {
+ 		dev->stats.tx_errors++;
+@@ -1273,12 +1273,12 @@ static netdev_tx_t amt_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+ 			hlist_for_each_entry_rcu(gnode, &tunnel->groups[hash],
+ 						 node) {
+ 				if (!v6) {
+-					if (gnode->group_addr.ip4 == iph->daddr)
++					if (gnode->group_addr.ip4 == group.ip4)
+ 						goto found;
+ #if IS_ENABLED(CONFIG_IPV6)
+ 				} else {
+ 					if (ipv6_addr_equal(&gnode->group_addr.ip6,
+-							    &ip6h->daddr))
++							    &group.ip6))
+ 						goto found;
+ #endif
+ 				}
+@@ -1995,14 +1995,18 @@ static void amt_igmpv3_report_handler(struct amt_dev *amt, struct sk_buff *skb,
+ 	struct igmpv3_report *ihrv3 = igmpv3_report_hdr(skb);
+ 	int len = skb_transport_offset(skb) + sizeof(*ihrv3);
+ 	void *zero_grec = (void *)&igmpv3_zero_grec;
+-	struct iphdr *iph = ip_hdr(skb);
+ 	struct amt_group_node *gnode;
+ 	union amt_addr group, host;
+ 	struct igmpv3_grec *grec;
++	__be32 saddr;
+ 	u16 nsrcs;
++	u16 ngrec;
+ 	int i;
+ 
+-	for (i = 0; i < ntohs(ihrv3->ngrec); i++) {
++	saddr = ip_hdr(skb)->saddr;
++	ngrec = ntohs(ihrv3->ngrec);
++
++	for (i = 0; i < ngrec; i++) {
+ 		len += sizeof(*grec);
+ 		if (!ip_mc_may_pull(skb, len))
+ 			break;
+@@ -2014,10 +2018,13 @@ static void amt_igmpv3_report_handler(struct amt_dev *amt, struct sk_buff *skb,
+ 		if (!ip_mc_may_pull(skb, len))
+ 			break;
+ 
++		grec = (void *)(skb->data + len - sizeof(*grec) -
++				nsrcs * sizeof(__be32));
++
+ 		memset(&group, 0, sizeof(union amt_addr));
+ 		group.ip4 = grec->grec_mca;
+ 		memset(&host, 0, sizeof(union amt_addr));
+-		host.ip4 = iph->saddr;
++		host.ip4 = saddr;
+ 		gnode = amt_lookup_group(tunnel, &group, &host, false);
+ 		if (!gnode) {
+ 			gnode = amt_add_group(amt, tunnel, &group, &host,
+@@ -2157,14 +2164,18 @@ static void amt_mldv2_report_handler(struct amt_dev *amt, struct sk_buff *skb,
+ 	struct mld2_report *mld2r = (struct mld2_report *)icmp6_hdr(skb);
+ 	int len = skb_transport_offset(skb) + sizeof(*mld2r);
+ 	void *zero_grec = (void *)&mldv2_zero_grec;
+-	struct ipv6hdr *ip6h = ipv6_hdr(skb);
+ 	struct amt_group_node *gnode;
+ 	union amt_addr group, host;
+ 	struct mld2_grec *grec;
++	struct in6_addr saddr;
+ 	u16 nsrcs;
++	u16 ngrec;
+ 	int i;
+ 
+-	for (i = 0; i < ntohs(mld2r->mld2r_ngrec); i++) {
++	saddr = ipv6_hdr(skb)->saddr;
++	ngrec = ntohs(mld2r->mld2r_ngrec);
++
++	for (i = 0; i < ngrec; i++) {
+ 		len += sizeof(*grec);
+ 		if (!ipv6_mc_may_pull(skb, len))
+ 			break;
+@@ -2176,10 +2187,13 @@ static void amt_mldv2_report_handler(struct amt_dev *amt, struct sk_buff *skb,
+ 		if (!ipv6_mc_may_pull(skb, len))
+ 			break;
+ 
++		grec = (void *)(skb->data + len - sizeof(*grec) -
++				nsrcs * sizeof(struct in6_addr));
++
+ 		memset(&group, 0, sizeof(union amt_addr));
+ 		group.ip6 = grec->grec_mca;
+ 		memset(&host, 0, sizeof(union amt_addr));
+-		host.ip6 = ip6h->saddr;
++		host.ip6 = saddr;
+ 		gnode = amt_lookup_group(tunnel, &group, &host, true);
+ 		if (!gnode) {
+ 			gnode = amt_add_group(amt, tunnel, &group, &host,
+@@ -2300,7 +2314,9 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
+ 	skb_push(skb, sizeof(*eth));
+ 	skb_reset_mac_header(skb);
+ 	skb_pull(skb, sizeof(*eth));
+-	eth = eth_hdr(skb);
++
++	if (skb_cow_head(skb, 0))
++		return true;
+ 
+ 	if (!pskb_may_pull(skb, sizeof(*iph)))
+ 		return true;
+@@ -2310,6 +2326,7 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
+ 		if (!ipv4_is_multicast(iph->daddr))
+ 			return true;
+ 		skb->protocol = htons(ETH_P_IP);
++		eth = eth_hdr(skb);
+ 		eth->h_proto = htons(ETH_P_IP);
+ 		ip_eth_mc_map(iph->daddr, eth->h_dest);
+ #if IS_ENABLED(CONFIG_IPV6)
+@@ -2323,6 +2340,7 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
+ 		if (!ipv6_addr_is_multicast(&ip6h->daddr))
+ 			return true;
+ 		skb->protocol = htons(ETH_P_IPV6);
++		eth = eth_hdr(skb);
+ 		eth->h_proto = htons(ETH_P_IPV6);
+ 		ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
+ #endif
+@@ -2346,10 +2364,12 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
+ 					 struct sk_buff *skb)
+ {
+ 	struct amt_header_membership_query *amtmq;
+-	struct igmpv3_query *ihv3;
+ 	struct ethhdr *eth, *oeth;
++	struct igmpv3_query *ihv3;
++	u8 h_source[ETH_ALEN];
+ 	struct iphdr *iph;
+ 	int hdr_size, len;
++	u64 response_mac;
+ 
+ 	hdr_size = sizeof(*amtmq) + sizeof(struct udphdr);
+ 	if (!pskb_may_pull(skb, hdr_size))
+@@ -2362,6 +2382,8 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
+ 	if (amtmq->nonce != amt->nonce)
+ 		return true;
+ 
++	response_mac = amtmq->response_mac;
++
+ 	hdr_size -= sizeof(*eth);
+ 	if (iptunnel_pull_header(skb, hdr_size, htons(ETH_P_TEB), false))
+ 		return true;
+@@ -2371,6 +2393,9 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
+ 	skb_pull(skb, sizeof(*eth));
+ 	skb_reset_network_header(skb);
+ 	eth = eth_hdr(skb);
++	ether_addr_copy(h_source, oeth->h_source);
++	if (skb_cow_head(skb, 0))
++		return true;
+ 	if (!pskb_may_pull(skb, sizeof(*iph)))
+ 		return true;
+ 
+@@ -2383,6 +2408,7 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
+ 				   sizeof(*ihv3)))
+ 			return true;
+ 
++		iph = ip_hdr(skb);
+ 		if (!ipv4_is_multicast(iph->daddr))
+ 			return true;
+ 
+@@ -2390,10 +2416,11 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
+ 		skb_reset_transport_header(skb);
+ 		skb_push(skb, sizeof(*iph) + AMT_IPHDR_OPTS);
+ 		WRITE_ONCE(amt->ready4, true);
+-		amt->mac = amtmq->response_mac;
++		amt->mac = response_mac;
+ 		amt->req_cnt = 0;
+ 		amt->qi = ihv3->qqic;
+ 		skb->protocol = htons(ETH_P_IP);
++		eth = eth_hdr(skb);
+ 		eth->h_proto = htons(ETH_P_IP);
+ 		ip_eth_mc_map(iph->daddr, eth->h_dest);
+ #if IS_ENABLED(CONFIG_IPV6)
+@@ -2416,10 +2443,11 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
+ 		skb_reset_transport_header(skb);
+ 		skb_push(skb, sizeof(*ip6h) + AMT_IP6HDR_OPTS);
+ 		WRITE_ONCE(amt->ready6, true);
+-		amt->mac = amtmq->response_mac;
++		amt->mac = response_mac;
+ 		amt->req_cnt = 0;
+ 		amt->qi = mld2q->mld2q_qqic;
+ 		skb->protocol = htons(ETH_P_IPV6);
++		eth = eth_hdr(skb);
+ 		eth->h_proto = htons(ETH_P_IPV6);
+ 		ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
+ #endif
+@@ -2427,7 +2455,7 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
+ 		return true;
+ 	}
+ 
+-	ether_addr_copy(eth->h_source, oeth->h_source);
++	ether_addr_copy(eth->h_source, h_source);
+ 	skb->pkt_type = PACKET_MULTICAST;
+ 	skb->ip_summed = CHECKSUM_NONE;
+ 	len = skb->len;
+@@ -2450,8 +2478,11 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
+ 	struct ethhdr *eth;
+ 	struct iphdr *iph;
+ 	int len, hdr_size;
++	u64 response_mac;
++	__be32 saddr;
++	__be32 nonce;
+ 
+-	iph = ip_hdr(skb);
++	saddr = ip_hdr(skb)->saddr;
+ 
+ 	hdr_size = sizeof(*amtmu) + sizeof(struct udphdr);
+ 	if (!pskb_may_pull(skb, hdr_size))
+@@ -2461,15 +2492,18 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
+ 	if (amtmu->reserved || amtmu->version)
+ 		return true;
+ 
++	nonce = amtmu->nonce;
++	response_mac = amtmu->response_mac;
++
+ 	if (iptunnel_pull_header(skb, hdr_size, skb->protocol, false))
+ 		return true;
+ 
+ 	skb_reset_network_header(skb);
+ 
+ 	list_for_each_entry_rcu(tunnel, &amt->tunnel_list, list) {
+-		if (tunnel->ip4 == iph->saddr) {
+-			if ((amtmu->nonce == tunnel->nonce &&
+-			     amtmu->response_mac == tunnel->mac)) {
++		if (tunnel->ip4 == saddr) {
++			if ((nonce == tunnel->nonce &&
++			     response_mac == tunnel->mac)) {
+ 				mod_delayed_work(amt_wq, &tunnel->gc_wq,
+ 						 msecs_to_jiffies(amt_gmi(amt))
+ 								  * 3);
+@@ -2487,6 +2521,9 @@ report:
+ 	if (!pskb_may_pull(skb, sizeof(*iph)))
+ 		return true;
+ 
++	if (skb_cow_head(skb, 0))
++		return true;
++
+ 	iph = ip_hdr(skb);
+ 	if (iph->version == 4) {
+ 		if (ip_mc_check_igmp(skb)) {
+@@ -2503,6 +2540,7 @@ report:
+ 		eth = eth_hdr(skb);
+ 		skb->protocol = htons(ETH_P_IP);
+ 		eth->h_proto = htons(ETH_P_IP);
++		iph = ip_hdr(skb);
+ 		ip_eth_mc_map(iph->daddr, eth->h_dest);
+ #if IS_ENABLED(CONFIG_IPV6)
+ 	} else if (iph->version == 6) {
+@@ -2522,6 +2560,7 @@ report:
+ 		eth = eth_hdr(skb);
+ 		skb->protocol = htons(ETH_P_IPV6);
+ 		eth->h_proto = htons(ETH_P_IPV6);
++		ip6h = ipv6_hdr(skb);
+ 		ipv6_eth_mc_map(&ip6h->daddr, eth->h_dest);
+ #endif
+ 	} else {
+@@ -2767,7 +2806,7 @@ drop:
+ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
+ {
+ 	struct amt_dev *amt;
+-	struct iphdr *iph;
++	__be32 saddr;
+ 	int type;
+ 	bool err;
+ 
+@@ -2780,7 +2819,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
+ 	}
+ 
+ 	skb->dev = amt->dev;
+-	iph = ip_hdr(skb);
++	saddr = ip_hdr(skb)->saddr;
+ 	type = amt_parse_type(skb);
+ 	if (type == -1) {
+ 		err = true;
+@@ -2790,7 +2829,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
+ 	if (amt->mode == AMT_MODE_GATEWAY) {
+ 		switch (type) {
+ 		case AMT_MSG_ADVERTISEMENT:
+-			if (iph->saddr != amt->discovery_ip) {
++			if (saddr != amt->discovery_ip) {
+ 				netdev_dbg(amt->dev, "Invalid Relay IP\n");
+ 				err = true;
+ 				goto drop;
+@@ -2802,7 +2841,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
+ 			}
+ 			goto out;
+ 		case AMT_MSG_MULTICAST_DATA:
+-			if (iph->saddr != amt->remote_ip) {
++			if (saddr != amt->remote_ip) {
+ 				netdev_dbg(amt->dev, "Invalid Relay IP\n");
+ 				err = true;
+ 				goto drop;
+@@ -2813,7 +2852,7 @@ static int amt_rcv(struct sock *sk, struct sk_buff *skb)
+ 			else
+ 				goto out;
+ 		case AMT_MSG_MEMBERSHIP_QUERY:
+-			if (iph->saddr != amt->remote_ip) {
++			if (saddr != amt->remote_ip) {
+ 				netdev_dbg(amt->dev, "Invalid Relay IP\n");
+ 				err = true;
+ 				goto drop;
+diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
+index 6b558aa98c6d2f..09e2ae6739073f 100644
+--- a/drivers/net/bonding/bond_main.c
++++ b/drivers/net/bonding/bond_main.c
+@@ -3431,7 +3431,8 @@ static void bond_send_validate(struct bonding *bond, struct slave *slave)
+ {
+ 	bond_arp_send_all(bond, slave);
+ #if IS_ENABLED(CONFIG_IPV6)
+-	bond_ns_send_all(bond, slave);
++	if (likely(ipv6_mod_enabled()))
++		bond_ns_send_all(bond, slave);
+ #endif
+ }
+ 
+diff --git a/drivers/net/ethernet/amd/pds_core/adminq.c b/drivers/net/ethernet/amd/pds_core/adminq.c
+index 733f133d69e75f..b363d006e044ea 100644
+--- a/drivers/net/ethernet/amd/pds_core/adminq.c
++++ b/drivers/net/ethernet/amd/pds_core/adminq.c
+@@ -18,7 +18,13 @@ static int pdsc_process_notifyq(struct pdsc_qcq *qcq)
+ 	comp = cq_info->comp;
+ 	eid = le64_to_cpu(comp->event.eid);
+ 	while (eid > pdsc->last_eid) {
+-		u16 ecode = le16_to_cpu(comp->event.ecode);
++		u16 ecode;
++
++		/* Order the payload read after the event id, the field the
++		 * driver uses to detect a new completion.
++		 */
++		dma_rmb();
++		ecode = le16_to_cpu(comp->event.ecode);
+ 
+ 		switch (ecode) {
+ 		case PDS_EVENT_LINK_CHANGE:
+@@ -102,6 +108,10 @@ void pdsc_process_adminq(struct pdsc_qcq *qcq)
+ 	spin_lock_irqsave(&pdsc->adminq_lock, irqflags);
+ 	comp = cq->info[cq->tail_idx].comp;
+ 	while (pdsc_color_match(comp->color, cq->done_color)) {
++		/* Order the payload reads after the color bit, the field the
++		 * driver uses to detect a new completion.
++		 */
++		dma_rmb();
+ 		q_info = &q->info[q->tail_idx];
+ 		q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1);
+ 
+diff --git a/drivers/net/ethernet/amd/pds_core/auxbus.c b/drivers/net/ethernet/amd/pds_core/auxbus.c
+index 889a18962270aa..7d7c87fe9e8f27 100644
+--- a/drivers/net/ethernet/amd/pds_core/auxbus.c
++++ b/drivers/net/ethernet/amd/pds_core/auxbus.c
+@@ -177,17 +177,21 @@ void pdsc_auxbus_dev_del(struct pdsc *cf, struct pdsc *pf,
+ {
+ 	struct pds_auxiliary_dev *padev;
+ 
+-	if (!*pd_ptr)
+-		return;
+-
+ 	mutex_lock(&pf->config_lock);
+ 
++	/* A concurrent del may have already torn this device down and
++	 * cleared it.
++	 */
+ 	padev = *pd_ptr;
++	if (!padev)
++		goto out_unlock;
++
+ 	pds_client_unregister(pf, padev->client_id);
+ 	auxiliary_device_delete(&padev->aux_dev);
+ 	auxiliary_device_uninit(&padev->aux_dev);
+ 	*pd_ptr = NULL;
+ 
++out_unlock:
+ 	mutex_unlock(&pf->config_lock);
+ }
+ 
+@@ -210,6 +214,13 @@ int pdsc_auxbus_dev_add(struct pdsc *cf, struct pdsc *pf,
+ 
+ 	mutex_lock(&pf->config_lock);
+ 
++	/* Nothing to do if the aux device is already present.  This also
++	 * guards against a second add overwriting *pd_ptr and leaking the
++	 * first, symmetric with the check in pdsc_auxbus_dev_del().
++	 */
++	if (*pd_ptr)
++		goto out_unlock;
++
+ 	mask = BIT_ULL(PDSC_S_FW_DEAD) |
+ 	       BIT_ULL(PDSC_S_STOPPING_DRIVER);
+ 	if (cf->state & mask) {
+diff --git a/drivers/net/ethernet/amd/pds_core/core.c b/drivers/net/ethernet/amd/pds_core/core.c
+index c2ef55cff6b3ec..cd0c698983debe 100644
+--- a/drivers/net/ethernet/amd/pds_core/core.c
++++ b/drivers/net/ethernet/amd/pds_core/core.c
+@@ -526,6 +526,7 @@ static void pdsc_adminq_wait_and_dec_once_unused(struct pdsc *pdsc)
+ 		dev_dbg_ratelimited(pdsc->dev, "%s: adminq in use\n",
+ 				    __func__);
+ 		cpu_relax();
++		cond_resched();
+ 	}
+ }
+ 
+diff --git a/drivers/net/ethernet/amd/pds_core/devlink.c b/drivers/net/ethernet/amd/pds_core/devlink.c
+index 3144bad75a4df5..9939296145b522 100644
+--- a/drivers/net/ethernet/amd/pds_core/devlink.c
++++ b/drivers/net/ethernet/amd/pds_core/devlink.c
+@@ -88,6 +88,12 @@ int pdsc_dl_flash_update(struct devlink *dl,
+ {
+ 	struct pdsc *pdsc = devlink_priv(dl);
+ 
++	if (params->component) {
++		NL_SET_ERR_MSG_MOD(extack,
++				   "Component update not supported by this device");
++		return -EOPNOTSUPP;
++	}
++
+ 	return pdsc_firmware_update(pdsc, params->fw, extack);
+ }
+ 
+diff --git a/drivers/net/ethernet/amd/pds_core/main.c b/drivers/net/ethernet/amd/pds_core/main.c
+index 76652e0e5b6d9c..93fa7dfd74cbc9 100644
+--- a/drivers/net/ethernet/amd/pds_core/main.c
++++ b/drivers/net/ethernet/amd/pds_core/main.c
+@@ -238,6 +238,10 @@ static int pdsc_init_pf(struct pdsc *pdsc)
+ 	/* General workqueue and timer, but don't start timer yet */
+ 	snprintf(wq_name, sizeof(wq_name), "%s.%d", PDS_CORE_DRV_NAME, pdsc->uid);
+ 	pdsc->wq = create_singlethread_workqueue(wq_name);
++	if (!pdsc->wq) {
++		err = -ENOMEM;
++		goto err_out_unmap_bars;
++	}
+ 	INIT_WORK(&pdsc->health_work, pdsc_health_thread);
+ 	timer_setup(&pdsc->wdtimer, pdsc_wdtimer_cb, 0);
+ 	pdsc->wdtimer_period = PDSC_WATCHDOG_SECS * HZ;
+@@ -252,7 +256,7 @@ static int pdsc_init_pf(struct pdsc *pdsc)
+ 	err = pdsc_setup(pdsc, PDSC_SETUP_INIT);
+ 	if (err) {
+ 		mutex_unlock(&pdsc->config_lock);
+-		goto err_out_unmap_bars;
++		goto err_out_shutdown_timer;
+ 	}
+ 
+ 	err = pdsc_start(pdsc);
+@@ -298,13 +302,14 @@ err_out_stop:
+ 	pdsc_stop(pdsc);
+ err_out_teardown:
+ 	pdsc_teardown(pdsc, PDSC_TEARDOWN_REMOVING);
+-err_out_unmap_bars:
++err_out_shutdown_timer:
+ 	timer_shutdown_sync(&pdsc->wdtimer);
+ 	if (pdsc->wq)
+ 		destroy_workqueue(pdsc->wq);
+ 	mutex_destroy(&pdsc->config_lock);
+ 	mutex_destroy(&pdsc->devcmd_lock);
+ 	pci_free_irq_vectors(pdsc->pdev);
++err_out_unmap_bars:
+ 	pdsc_unmap_bars(pdsc);
+ err_out_release_regions:
+ 	pci_release_regions(pdsc->pdev);
+diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+index 63012119f2c8eb..4e4e0735cb2ada 100644
+--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
++++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+@@ -376,9 +376,14 @@ static void xgbe_an37_set(struct xgbe_prv_data *pdata, bool enable,
+ 
+ 	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_CTRL1, reg);
+ 
+-	reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL);
+-	reg |= XGBE_VEND2_MAC_AUTO_SW;
+-	XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL, reg);
++	if (pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) {
++		reg = XMDIO_READ(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL);
++		if (enable)
++			reg |= XGBE_VEND2_MAC_AUTO_SW;
++		else
++			reg &= ~XGBE_VEND2_MAC_AUTO_SW;
++		XMDIO_WRITE(pdata, MDIO_MMD_VEND2, MDIO_PCS_DIG_CTRL, reg);
++	}
+ }
+ 
+ static void xgbe_an37_restart(struct xgbe_prv_data *pdata)
+diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
+index aac62db4ee1460..399a41a3962f70 100644
+--- a/drivers/net/ethernet/cadence/macb_main.c
++++ b/drivers/net/ethernet/cadence/macb_main.c
+@@ -2582,8 +2582,26 @@ static void macb_free_consistent(struct macb *bp)
+ 	bp->macbgem_ops.mog_free_rx_buffers(bp);
+ 
+ 	for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
+-		kfree(queue->tx_skb);
+-		queue->tx_skb = NULL;
++		if (queue->tx_skb) {
++			unsigned int dropped = 0, tail;
++
++			for (tail = queue->tx_tail; tail != queue->tx_head;
++			     tail++) {
++				if (macb_tx_skb(queue, tail)->skb)
++					dropped++;
++				macb_tx_unmap(bp, macb_tx_skb(queue, tail), 0);
++			}
++
++			queue->stats.tx_dropped += dropped;
++			bp->dev->stats.tx_dropped += dropped;
++
++			kfree(queue->tx_skb);
++			queue->tx_skb = NULL;
++		}
++
++		queue->tx_head = 0;
++		queue->tx_tail = 0;
++
+ 		if (queue->tx_ring) {
+ 			size = TX_RING_BYTES(bp) + bp->tx_bd_rd_prefetch;
+ 			dma_free_coherent(&bp->pdev->dev, size,
+diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+index 61bd2389ef4b54..d77c22d1030a92 100644
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c
+@@ -4720,6 +4720,7 @@ static void dpaa2_eth_disconnect_mac(struct dpaa2_eth_priv *priv)
+ 		dpaa2_mac_disconnect(mac);
+ 
+ 	dpaa2_mac_close(mac);
++	put_device(&mac->mc_dev->dev);
+ 	kfree(mac);
+ }
+ 
+diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+index 0f8b46dccc0971..501e86e9fd487c 100644
+--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
++++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+@@ -1510,6 +1510,7 @@ static void dpaa2_switch_port_disconnect_mac(struct ethsw_port_priv *port_priv)
+ 		dpaa2_mac_disconnect(mac);
+ 
+ 	dpaa2_mac_close(mac);
++	put_device(&mac->mc_dev->dev);
+ 	kfree(mac);
+ }
+ 
+diff --git a/drivers/net/ethernet/freescale/fman/fman_dtsec.c b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
+index 3088da7adf0f84..074ca626a51508 100644
+--- a/drivers/net/ethernet/freescale/fman/fman_dtsec.c
++++ b/drivers/net/ethernet/freescale/fman/fman_dtsec.c
+@@ -900,22 +900,28 @@ static void dtsec_mac_config(struct phylink_config *config, unsigned int mode,
+ {
+ 	struct mac_device *mac_dev = fman_config_to_mac(config);
+ 	struct dtsec_regs __iomem *regs = mac_dev->fman_mac->regs;
+-	u32 tmp;
++	u32 ecntrl, maccfg2;
++
++	maccfg2 = ioread32be(&regs->maccfg2);
++	maccfg2 &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE);
+ 
+ 	switch (state->interface) {
+ 	case PHY_INTERFACE_MODE_RMII:
+-		tmp = DTSEC_ECNTRL_RMM;
++		ecntrl = DTSEC_ECNTRL_RMM;
++		maccfg2 |= MACCFG2_NIBBLE_MODE;
+ 		break;
+ 	case PHY_INTERFACE_MODE_RGMII:
+ 	case PHY_INTERFACE_MODE_RGMII_ID:
+ 	case PHY_INTERFACE_MODE_RGMII_RXID:
+ 	case PHY_INTERFACE_MODE_RGMII_TXID:
+-		tmp = DTSEC_ECNTRL_GMIIM | DTSEC_ECNTRL_RPM;
++		ecntrl = DTSEC_ECNTRL_GMIIM | DTSEC_ECNTRL_RPM;
++		maccfg2 |= MACCFG2_BYTE_MODE;
+ 		break;
+ 	case PHY_INTERFACE_MODE_SGMII:
+ 	case PHY_INTERFACE_MODE_1000BASEX:
+ 	case PHY_INTERFACE_MODE_2500BASEX:
+-		tmp = DTSEC_ECNTRL_TBIM | DTSEC_ECNTRL_SGMIIM;
++		ecntrl = DTSEC_ECNTRL_TBIM | DTSEC_ECNTRL_SGMIIM;
++		maccfg2 |= MACCFG2_BYTE_MODE;
+ 		break;
+ 	default:
+ 		dev_warn(mac_dev->dev, "cannot configure dTSEC for %s\n",
+@@ -923,7 +929,8 @@ static void dtsec_mac_config(struct phylink_config *config, unsigned int mode,
+ 		return;
+ 	}
+ 
+-	iowrite32be(tmp, &regs->ecntrl);
++	iowrite32be(ecntrl, &regs->ecntrl);
++	iowrite32be(maccfg2, &regs->maccfg2);
+ }
+ 
+ static void dtsec_link_up(struct phylink_config *config, struct phy_device *phy,
+diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
+index 4b893d162e85d0..7416fc3534ebaf 100644
+--- a/drivers/net/ethernet/hisilicon/hip04_eth.c
++++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
+@@ -594,7 +594,11 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget)
+ 		skb = build_skb(buf, priv->rx_buf_size);
+ 		if (unlikely(!skb)) {
+ 			net_dbg_ratelimited("build_skb failed\n");
+-			goto refill;
++			/* Retain the slot; return budget so NAPI retries this
++			 * buffer. Refill would overwrite rx_buf[]/rx_phys[]
++			 * and leak them.
++			 */
++			return budget;
+ 		}
+ 
+ 		dma_unmap_single(priv->dev, priv->rx_phys[priv->rx_head],
+@@ -622,14 +626,15 @@ static int hip04_rx_poll(struct napi_struct *napi, int budget)
+ 			rx++;
+ 		}
+ 
+-refill:
+ 		buf = netdev_alloc_frag(priv->rx_buf_size);
+ 		if (!buf)
+ 			goto done;
+ 		phys = dma_map_single(priv->dev, buf,
+ 				      RX_BUF_SIZE, DMA_FROM_DEVICE);
+-		if (dma_mapping_error(priv->dev, phys))
++		if (dma_mapping_error(priv->dev, phys)) {
++			skb_free_frag(buf);
+ 			goto done;
++		}
+ 		priv->rx_buf[priv->rx_head] = buf;
+ 		priv->rx_phys[priv->rx_head] = phys;
+ 		hip04_set_recv_desc(priv, phys);
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_dev.h b/drivers/net/ethernet/huawei/hinic/hinic_dev.h
+index 52ea97c818b8ec..d9ab94910a2a79 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_dev.h
++++ b/drivers/net/ethernet/huawei/hinic/hinic_dev.h
+@@ -104,8 +104,6 @@ struct hinic_dev {
+ 	u16				num_rss;
+ 	u16				rss_limit;
+ 	struct hinic_rss_type		rss_type;
+-	u8				*rss_hkey_user;
+-	s32				*rss_indir_user;
+ 	struct hinic_intr_coal_info	*rx_intr_coalesce;
+ 	struct hinic_intr_coal_info	*tx_intr_coalesce;
+ 	struct hinic_sriov_info sriov_info;
+diff --git a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
+index f4b68028691194..660ab3edf73939 100644
+--- a/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
++++ b/drivers/net/ethernet/huawei/hinic/hinic_ethtool.c
+@@ -1061,17 +1061,6 @@ static int __set_rss_rxfh(struct net_device *netdev,
+ 	int err;
+ 
+ 	if (indir) {
+-		if (!nic_dev->rss_indir_user) {
+-			nic_dev->rss_indir_user =
+-				kzalloc(sizeof(u32) * HINIC_RSS_INDIR_SIZE,
+-					GFP_KERNEL);
+-			if (!nic_dev->rss_indir_user)
+-				return -ENOMEM;
+-		}
+-
+-		memcpy(nic_dev->rss_indir_user, indir,
+-		       sizeof(u32) * HINIC_RSS_INDIR_SIZE);
+-
+ 		err = hinic_rss_set_indir_tbl(nic_dev,
+ 					      nic_dev->rss_tmpl_idx, indir);
+ 		if (err)
+@@ -1079,16 +1068,6 @@ static int __set_rss_rxfh(struct net_device *netdev,
+ 	}
+ 
+ 	if (key) {
+-		if (!nic_dev->rss_hkey_user) {
+-			nic_dev->rss_hkey_user =
+-				kzalloc(HINIC_RSS_KEY_SIZE * 2, GFP_KERNEL);
+-
+-			if (!nic_dev->rss_hkey_user)
+-				return -ENOMEM;
+-		}
+-
+-		memcpy(nic_dev->rss_hkey_user, key, HINIC_RSS_KEY_SIZE);
+-
+ 		err = hinic_rss_set_template_tbl(nic_dev,
+ 						 nic_dev->rss_tmpl_idx, key);
+ 		if (err)
+diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+index a2fca58a91c332..35ce578dd6f350 100644
+--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
++++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+@@ -58,47 +58,6 @@ static struct i40e_veb *i40e_dbg_find_veb(struct i40e_pf *pf, int seid)
+  * setup, adding or removing filters, or other things.  Many of
+  * these will be useful for some forms of unit testing.
+  **************************************************************/
+-static char i40e_dbg_command_buf[256] = "";
+-
+-/**
+- * i40e_dbg_command_read - read for command datum
+- * @filp: the opened file
+- * @buffer: where to write the data for the user to read
+- * @count: the size of the user's buffer
+- * @ppos: file position offset
+- **/
+-static ssize_t i40e_dbg_command_read(struct file *filp, char __user *buffer,
+-				     size_t count, loff_t *ppos)
+-{
+-	struct i40e_pf *pf = filp->private_data;
+-	int bytes_not_copied;
+-	int buf_size = 256;
+-	char *buf;
+-	int len;
+-
+-	/* don't allow partial reads */
+-	if (*ppos != 0)
+-		return 0;
+-	if (count < buf_size)
+-		return -ENOSPC;
+-
+-	buf = kzalloc(buf_size, GFP_KERNEL);
+-	if (!buf)
+-		return -ENOSPC;
+-
+-	len = snprintf(buf, buf_size, "%s: %s\n",
+-		       pf->vsi[pf->lan_vsi]->netdev->name,
+-		       i40e_dbg_command_buf);
+-
+-	bytes_not_copied = copy_to_user(buffer, buf, len);
+-	kfree(buf);
+-
+-	if (bytes_not_copied)
+-		return -EFAULT;
+-
+-	*ppos = len;
+-	return len;
+-}
+ 
+ static char *i40e_filter_state_string[] = {
+ 	"INVALID",
+@@ -1637,7 +1596,6 @@ command_write_done:
+ static const struct file_operations i40e_dbg_command_fops = {
+ 	.owner = THIS_MODULE,
+ 	.open =  simple_open,
+-	.read =  i40e_dbg_command_read,
+ 	.write = i40e_dbg_command_write,
+ };
+ 
+@@ -1646,47 +1604,6 @@ static const struct file_operations i40e_dbg_command_fops = {
+  * The netdev_ops entry in debugfs is for giving the driver commands
+  * to be executed from the netdev operations.
+  **************************************************************/
+-static char i40e_dbg_netdev_ops_buf[256] = "";
+-
+-/**
+- * i40e_dbg_netdev_ops_read - read for netdev_ops datum
+- * @filp: the opened file
+- * @buffer: where to write the data for the user to read
+- * @count: the size of the user's buffer
+- * @ppos: file position offset
+- **/
+-static ssize_t i40e_dbg_netdev_ops_read(struct file *filp, char __user *buffer,
+-					size_t count, loff_t *ppos)
+-{
+-	struct i40e_pf *pf = filp->private_data;
+-	int bytes_not_copied;
+-	int buf_size = 256;
+-	char *buf;
+-	int len;
+-
+-	/* don't allow partal reads */
+-	if (*ppos != 0)
+-		return 0;
+-	if (count < buf_size)
+-		return -ENOSPC;
+-
+-	buf = kzalloc(buf_size, GFP_KERNEL);
+-	if (!buf)
+-		return -ENOSPC;
+-
+-	len = snprintf(buf, buf_size, "%s: %s\n",
+-		       pf->vsi[pf->lan_vsi]->netdev->name,
+-		       i40e_dbg_netdev_ops_buf);
+-
+-	bytes_not_copied = copy_to_user(buffer, buf, len);
+-	kfree(buf);
+-
+-	if (bytes_not_copied)
+-		return -EFAULT;
+-
+-	*ppos = len;
+-	return len;
+-}
+ 
+ /**
+  * i40e_dbg_netdev_ops_write - write into netdev_ops datum
+@@ -1700,35 +1617,36 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ 					 size_t count, loff_t *ppos)
+ {
+ 	struct i40e_pf *pf = filp->private_data;
++	char *cmd_buf, *buf_tmp;
+ 	int bytes_not_copied;
+ 	struct i40e_vsi *vsi;
+-	char *buf_tmp;
+ 	int vsi_seid;
+ 	int i, cnt;
+ 
+ 	/* don't allow partial writes */
+ 	if (*ppos != 0)
+ 		return 0;
+-	if (count >= sizeof(i40e_dbg_netdev_ops_buf))
+-		return -ENOSPC;
+ 
+-	memset(i40e_dbg_netdev_ops_buf, 0, sizeof(i40e_dbg_netdev_ops_buf));
+-	bytes_not_copied = copy_from_user(i40e_dbg_netdev_ops_buf,
+-					  buffer, count);
+-	if (bytes_not_copied)
++	cmd_buf = kzalloc(count + 1, GFP_KERNEL);
++	if (!cmd_buf)
++		return count;
++	bytes_not_copied = copy_from_user(cmd_buf, buffer, count);
++	if (bytes_not_copied) {
++		kfree(cmd_buf);
+ 		return -EFAULT;
+-	i40e_dbg_netdev_ops_buf[count] = '\0';
++	}
++	cmd_buf[count] = '\0';
+ 
+-	buf_tmp = strchr(i40e_dbg_netdev_ops_buf, '\n');
++	buf_tmp = strchr(cmd_buf, '\n');
+ 	if (buf_tmp) {
+ 		*buf_tmp = '\0';
+-		count = buf_tmp - i40e_dbg_netdev_ops_buf + 1;
++		count = buf_tmp - cmd_buf + 1;
+ 	}
+ 
+-	if (strncmp(i40e_dbg_netdev_ops_buf, "change_mtu", 10) == 0) {
++	if (strncmp(cmd_buf, "change_mtu", 10) == 0) {
+ 		int mtu;
+ 
+-		cnt = sscanf(&i40e_dbg_netdev_ops_buf[11], "%i %i",
++		cnt = sscanf(&cmd_buf[11], "%i %i",
+ 			     &vsi_seid, &mtu);
+ 		if (cnt != 2) {
+ 			dev_info(&pf->pdev->dev, "change_mtu <vsi_seid> <mtu>\n");
+@@ -1750,8 +1668,8 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ 			dev_info(&pf->pdev->dev, "Could not acquire RTNL - please try again\n");
+ 		}
+ 
+-	} else if (strncmp(i40e_dbg_netdev_ops_buf, "set_rx_mode", 11) == 0) {
+-		cnt = sscanf(&i40e_dbg_netdev_ops_buf[11], "%i", &vsi_seid);
++	} else if (strncmp(cmd_buf, "set_rx_mode", 11) == 0) {
++		cnt = sscanf(&cmd_buf[11], "%i", &vsi_seid);
+ 		if (cnt != 1) {
+ 			dev_info(&pf->pdev->dev, "set_rx_mode <vsi_seid>\n");
+ 			goto netdev_ops_write_done;
+@@ -1771,8 +1689,8 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ 			dev_info(&pf->pdev->dev, "Could not acquire RTNL - please try again\n");
+ 		}
+ 
+-	} else if (strncmp(i40e_dbg_netdev_ops_buf, "napi", 4) == 0) {
+-		cnt = sscanf(&i40e_dbg_netdev_ops_buf[4], "%i", &vsi_seid);
++	} else if (strncmp(cmd_buf, "napi", 4) == 0) {
++		cnt = sscanf(&cmd_buf[4], "%i", &vsi_seid);
+ 		if (cnt != 1) {
+ 			dev_info(&pf->pdev->dev, "napi <vsi_seid>\n");
+ 			goto netdev_ops_write_done;
+@@ -1790,21 +1708,20 @@ static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+ 			dev_info(&pf->pdev->dev, "napi called\n");
+ 		}
+ 	} else {
+-		dev_info(&pf->pdev->dev, "unknown command '%s'\n",
+-			 i40e_dbg_netdev_ops_buf);
++		dev_info(&pf->pdev->dev, "unknown command '%s'\n", cmd_buf);
+ 		dev_info(&pf->pdev->dev, "available commands\n");
+ 		dev_info(&pf->pdev->dev, "  change_mtu <vsi_seid> <mtu>\n");
+ 		dev_info(&pf->pdev->dev, "  set_rx_mode <vsi_seid>\n");
+ 		dev_info(&pf->pdev->dev, "  napi <vsi_seid>\n");
+ 	}
+ netdev_ops_write_done:
++	kfree(cmd_buf);
+ 	return count;
+ }
+ 
+ static const struct file_operations i40e_dbg_netdev_ops_fops = {
+ 	.owner = THIS_MODULE,
+ 	.open = simple_open,
+-	.read = i40e_dbg_netdev_ops_read,
+ 	.write = i40e_dbg_netdev_ops_write,
+ };
+ 
+diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c
+index 8ed9918ea4e894..dcd4148dff4b0b 100644
+--- a/drivers/net/ethernet/intel/ice/ice_lag.c
++++ b/drivers/net/ethernet/intel/ice/ice_lag.c
+@@ -2004,7 +2004,7 @@ int ice_init_lag(struct ice_pf *pf)
+ 		goto lag_error;
+ 
+ 	/* associate recipes to profiles */
+-	for (n = 0; n < ICE_PROFID_IPV6_GTPU_IPV6_TCP_INNER; n++) {
++	for (n = 0; n < ICE_MAX_NUM_PROFILES; n++) {
+ 		err = ice_aq_get_recipe_to_profile(&pf->hw, n,
+ 						   &recipe_bits, NULL);
+ 		if (err)
+diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c
+index c4270708a76947..0da6b47f5b5272 100644
+--- a/drivers/net/ethernet/intel/ice/ice_ptp.c
++++ b/drivers/net/ethernet/intel/ice/ice_ptp.c
+@@ -595,7 +595,7 @@ static u64 ice_ptp_extend_40b_ts(struct ice_pf *pf, u64 in_tstamp)
+ 		return 0;
+ 	}
+ 
+-	return ice_ptp_extend_32b_ts(pf->ptp.cached_phc_time,
++	return ice_ptp_extend_32b_ts(READ_ONCE(pf->ptp.cached_phc_time),
+ 				     (in_tstamp >> 8) & mask);
+ }
+ 
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+index 760dca4d5bfcb8..7cfb4535f87168 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.c
+@@ -440,7 +440,7 @@ struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc)
+ 		return &rvu->pf[rvu_get_pf(pcifunc)];
+ }
+ 
+-static bool is_pf_func_valid(struct rvu *rvu, u16 pcifunc)
++bool is_pf_func_valid(struct rvu *rvu, u16 pcifunc)
+ {
+ 	int pf, vf, nvfs;
+ 	u64 cfg;
+@@ -2330,7 +2330,7 @@ static inline void rvu_afvf_mbox_up_handler(struct work_struct *work)
+ 	__rvu_mbox_up_handler(mwork, TYPE_AFVF);
+ }
+ 
+-static int rvu_get_mbox_regions(struct rvu *rvu, void **mbox_addr,
++static int rvu_get_mbox_regions(struct rvu *rvu, void __iomem **mbox_addr,
+ 				int num, int type, unsigned long *pf_bmap)
+ {
+ 	struct rvu_hwinfo *hw = rvu->hw;
+@@ -2355,7 +2355,7 @@ static int rvu_get_mbox_regions(struct rvu *rvu, void **mbox_addr,
+ 				bar4 = rvupf_read64(rvu, RVU_PF_VF_BAR4_ADDR);
+ 				bar4 += region * MBOX_SIZE;
+ 			}
+-			mbox_addr[region] = (void *)ioremap_wc(bar4, MBOX_SIZE);
++			mbox_addr[region] = ioremap_wc(bar4, MBOX_SIZE);
+ 			if (!mbox_addr[region])
+ 				goto error;
+ 		}
+@@ -2378,7 +2378,7 @@ static int rvu_get_mbox_regions(struct rvu *rvu, void **mbox_addr,
+ 					  RVU_AF_PF_BAR4_ADDR);
+ 			bar4 += region * MBOX_SIZE;
+ 		}
+-		mbox_addr[region] = (void *)ioremap_wc(bar4, MBOX_SIZE);
++		mbox_addr[region] = ioremap_wc(bar4, MBOX_SIZE);
+ 		if (!mbox_addr[region])
+ 			goto error;
+ 	}
+@@ -2386,7 +2386,7 @@ static int rvu_get_mbox_regions(struct rvu *rvu, void **mbox_addr,
+ 
+ error:
+ 	while (region--)
+-		iounmap((void __iomem *)mbox_addr[region]);
++		iounmap(mbox_addr[region]);
+ 	return -ENOMEM;
+ }
+ 
+@@ -2396,10 +2396,10 @@ static int rvu_mbox_init(struct rvu *rvu, struct mbox_wq_info *mw,
+ 			 void (mbox_up_handler)(struct work_struct *))
+ {
+ 	int err = -EINVAL, i, dir, dir_up;
++	void __iomem **mbox_regions;
+ 	void __iomem *reg_base;
+ 	struct rvu_work *mwork;
+ 	unsigned long *pf_bmap;
+-	void **mbox_regions;
+ 	const char *name;
+ 	u64 cfg;
+ 
+@@ -2422,7 +2422,7 @@ static int rvu_mbox_init(struct rvu *rvu, struct mbox_wq_info *mw,
+ 
+ 	mutex_init(&rvu->mbox_lock);
+ 
+-	mbox_regions = kcalloc(num, sizeof(void *), GFP_KERNEL);
++	mbox_regions = kcalloc(num, sizeof(void __iomem *), GFP_KERNEL);
+ 	if (!mbox_regions) {
+ 		err = -ENOMEM;
+ 		goto free_bitmap;
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+index 11d25404d57166..f26814c4990286 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu.h
+@@ -751,6 +751,7 @@ int rvu_get_pf(u16 pcifunc);
+ struct rvu_pfvf *rvu_get_pfvf(struct rvu *rvu, int pcifunc);
+ void rvu_get_pf_numvfs(struct rvu *rvu, int pf, int *numvfs, int *hwvf);
+ bool is_block_implemented(struct rvu_hwinfo *hw, int blkaddr);
++bool is_pf_func_valid(struct rvu *rvu, u16 pcifunc);
+ bool is_pffunc_map_valid(struct rvu *rvu, u16 pcifunc, int blktype);
+ int rvu_get_lf(struct rvu *rvu, struct rvu_block *block, u16 pcifunc, u16 slot);
+ int rvu_lf_reset(struct rvu *rvu, struct rvu_block *block, int lf);
+diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c
+index 1e4cd4f7d0cfd4..a76deef58af82c 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c
++++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_cn10k.c
+@@ -178,6 +178,15 @@ int rvu_mbox_handler_lmtst_tbl_setup(struct rvu *rvu,
+ 	 * pcifunc (will be the one who is calling this mailbox).
+ 	 */
+ 	if (req->base_pcifunc) {
++		/* A VF is untrusted and must not redirect its LMTLINE to
++		 * another PF's region, so confine VF callers to their own PF.
++		 */
++		if (is_vf(req->hdr.pcifunc) &&
++		    (!is_pf_func_valid(rvu, req->base_pcifunc) ||
++		     rvu_get_pf(req->hdr.pcifunc) !=
++		     rvu_get_pf(req->base_pcifunc)))
++			return -EPERM;
++
+ 		/* Calculating the LMT table index equivalent to primary
+ 		 * pcifunc.
+ 		 */
+diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
+index e6082f90f57a50..99e2391ef947a2 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_flows.c
+@@ -153,6 +153,7 @@ exit:
+ 	if (allocated) {
+ 		pfvf->flags |= OTX2_FLAG_MCAM_ENTRIES_ALLOC;
+ 		pfvf->flags |= OTX2_FLAG_NTUPLE_SUPPORT;
++		pfvf->flags |= OTX2_FLAG_TC_FLOWER_SUPPORT;
+ 	}
+ 
+ 	if (allocated != count)
+diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+index c4f5635284ef6f..caea58f8fd86a2 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+@@ -597,8 +597,7 @@ static int otx2_pfvf_mbox_init(struct otx2_nic *pf, int numvfs)
+ 		base = pci_resource_start(pf->pdev, PCI_MBOX_BAR_NUM) +
+ 		       MBOX_SIZE;
+ 	else
+-		base = readq((void __iomem *)((u64)pf->reg_base +
+-					      RVU_PF_VF_BAR4_ADDR));
++		base = readq(pf->reg_base + RVU_PF_VF_BAR4_ADDR);
+ 
+ 	hwbase = ioremap_wc(base, MBOX_SIZE * pf->total_vfs);
+ 	if (!hwbase) {
+@@ -1028,6 +1027,9 @@ static int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af)
+ 	char *irq_name;
+ 	int err;
+ 
++	/* Clear stale mailbox interrupt state before installing the handler. */
++	otx2_write64(pf, RVU_PF_INT, BIT_ULL(0));
++
+ 	/* Register mailbox interrupt handler */
+ 	irq_name = &hw->irq_name[RVU_PF_INT_VEC_AFPF_MBOX * NAME_SIZE];
+ 	snprintf(irq_name, NAME_SIZE, "RVUPFAF Mbox");
+@@ -1039,10 +1041,7 @@ static int otx2_register_mbox_intr(struct otx2_nic *pf, bool probe_af)
+ 		return err;
+ 	}
+ 
+-	/* Enable mailbox interrupt for msgs coming from AF.
+-	 * First clear to avoid spurious interrupts, if any.
+-	 */
+-	otx2_write64(pf, RVU_PF_INT, BIT_ULL(0));
++	/* Enable mailbox interrupt for msgs coming from AF. */
+ 	otx2_write64(pf, RVU_PF_INT_ENA_W1S, BIT_ULL(0));
+ 
+ 	if (!probe_af)
+@@ -1443,13 +1442,13 @@ static void otx2_free_sq_res(struct otx2_nic *pf)
+ 	otx2_sq_free_sqbs(pf);
+ 	for (qidx = 0; qidx < otx2_get_total_tx_queues(pf); qidx++) {
+ 		sq = &qset->sq[qidx];
+-		/* Skip freeing Qos queues if they are not initialized */
+-		if (!sq->sqe)
+-			continue;
+-		qmem_free(pf->dev, sq->sqe);
+-		qmem_free(pf->dev, sq->tso_hdrs);
+-		qmem_free(pf->dev, sq->timestamps);
+-		kfree(sq->sg);
++		/* sq->sqe is not initialized for unused QoS queues */
++		if (sq->sqe) {
++			qmem_free(pf->dev, sq->sqe);
++			qmem_free(pf->dev, sq->tso_hdrs);
++			qmem_free(pf->dev, sq->timestamps);
++			kfree(sq->sg);
++		}
+ 		kfree(sq->sqb_ptrs);
+ 	}
+ }
+@@ -1575,13 +1574,12 @@ static int otx2_init_hw_resources(struct otx2_nic *pf)
+ 	return err;
+ 
+ err_free_nix_queues:
+-	otx2_free_sq_res(pf);
+ 	otx2_free_cq_res(pf);
+ 	otx2_ctx_disable(mbox, NIX_AQ_CTYPE_RQ, false);
+ err_free_txsch:
+ 	otx2_txschq_stop(pf);
+ err_free_sq_ptrs:
+-	otx2_sq_free_sqbs(pf);
++	otx2_free_sq_res(pf);
+ err_free_rq_ptrs:
+ 	otx2_free_aura_ptr(pf, AURA_NIX_RQ);
+ 	otx2_ctx_disable(mbox, NPA_AQ_CTYPE_POOL, true);
+diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+index cf0aa16d754070..d93b4109a144fb 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_vf.c
+@@ -245,9 +245,15 @@ static int otx2vf_register_mbox_intr(struct otx2_nic *vf, bool probe_pf)
+ {
+ 	struct otx2_hw *hw = &vf->hw;
+ 	struct msg_req *req;
++	u64 mbox_int_mask;
+ 	char *irq_name;
+ 	int err;
+ 
++	mbox_int_mask = BIT_ULL(0);
++
++	/* Clear stale mailbox interrupt state before installing the handler. */
++	otx2_write64(vf, RVU_VF_INT, mbox_int_mask);
++
+ 	/* Register mailbox interrupt handler */
+ 	irq_name = &hw->irq_name[RVU_VF_INT_VEC_MBOX * NAME_SIZE];
+ 	snprintf(irq_name, NAME_SIZE, "RVUVFAF Mbox");
+@@ -259,11 +265,8 @@ static int otx2vf_register_mbox_intr(struct otx2_nic *vf, bool probe_pf)
+ 		return err;
+ 	}
+ 
+-	/* Enable mailbox interrupt for msgs coming from PF.
+-	 * First clear to avoid spurious interrupts, if any.
+-	 */
+-	otx2_write64(vf, RVU_VF_INT, BIT_ULL(0));
+-	otx2_write64(vf, RVU_VF_INT_ENA_W1S, BIT_ULL(0));
++	/* Enable mailbox interrupt for msgs coming from PF. */
++	otx2_write64(vf, RVU_VF_INT_ENA_W1S, mbox_int_mask);
+ 
+ 	if (!probe_pf)
+ 		return 0;
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
+index e29a8ed7e7ac13..1a73fa436a1368 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
+@@ -158,6 +158,13 @@ static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev,
+ 	}
+ 	memcpy(ets->tc_tsa, priv->dcbx.tc_tsa, sizeof(ets->tc_tsa));
+ 
++	/* Report 0 for non ETS TSA */
++	for (i = 0; i < ets->ets_cap; i++) {
++		if (ets->tc_tx_bw[i] == MLX5E_MAX_BW_ALLOC &&
++		    priv->dcbx.tc_tsa[i] != IEEE_8021QAZ_TSA_ETS)
++			ets->tc_tx_bw[i] = 0;
++	}
++
+ 	return err;
+ }
+ 
+@@ -302,6 +309,14 @@ static int mlx5e_dbcnl_validate_ets(struct net_device *netdev,
+ 		}
+ 	}
+ 
++	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
++		if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_CB_SHAPER) {
++			netdev_err(netdev,
++				   "Failed to validate ETS: CB Shaper is not supported\n");
++			return -EOPNOTSUPP;
++		}
++	}
++
+ 	/* Validate Bandwidth Sum */
+ 	for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+ 		if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_ETS) {
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c
+index d599e50af346be..fc545bfb54de76 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/acl/helper.c
+@@ -71,7 +71,7 @@ int esw_egress_acl_vlan_create(struct mlx5_eswitch *esw,
+ 	flow_act.action = flow_action;
+ 	vport->egress.allowed_vlan =
+ 		mlx5_add_flow_rules(vport->egress.acl, spec,
+-				    &flow_act, fwd_dest, 0);
++				    &flow_act, fwd_dest, fwd_dest ? 1 : 0);
+ 	if (IS_ERR(vport->egress.allowed_vlan)) {
+ 		err = PTR_ERR(vport->egress.allowed_vlan);
+ 		esw_warn(esw->dev,
+diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
+index 0249ba7e3b92cd..ec5d38164d41b2 100644
+--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
++++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
+@@ -1739,6 +1739,19 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
+ 	rxbuf_oob = &rxq->rx_oobs[curr];
+ 	WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1);
+ 
++	if (unlikely(pktlen > rxq->datasize)) {
++		/* Increase it even if mana_rx_skb() isn't called. */
++		rxq->rx_cq.work_done++;
++
++		++ndev->stats.rx_dropped;
++		netdev_warn_once(ndev,
++				 "Dropped oversized RX packet: len=%u, datasize=%u\n",
++				 pktlen, rxq->datasize);
++
++		/* Reuse the RX buffer since rxbuf_oob is unchanged. */
++		goto drop;
++	}
++
+ 	mana_refill_rx_oob(dev, rxq, rxbuf_oob, &old_buf, &old_fp);
+ 
+ 	/* Unsuccessful refill will have old_buf == NULL.
+diff --git a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c
+index ce7492a6a98fad..908d99f398b819 100644
+--- a/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c
++++ b/drivers/net/ethernet/netronome/nfp/nfpcore/nfp_resource.c
+@@ -96,6 +96,9 @@ static int nfp_cpp_resource_find(struct nfp_cpp *cpp, struct nfp_resource *res)
+ 		res->mutex =
+ 			nfp_cpp_mutex_alloc(cpp,
+ 					    NFP_RESOURCE_TBL_TARGET, addr, key);
++		if (!res->mutex)
++			return -ENOMEM;
++
+ 		res->cpp_id = NFP_CPP_ID(entry.region.cpp_target,
+ 					 entry.region.cpp_action,
+ 					 entry.region.cpp_token);
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index dea3d66619ce3c..2fc0a87534c72a 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -1009,63 +1009,45 @@ static void stmmac_mac_link_up(struct phylink_config *config,
+ 	old_ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
+ 	ctrl = old_ctrl & ~priv->hw->link.speed_mask;
+ 
+-	if (interface == PHY_INTERFACE_MODE_USXGMII) {
+-		switch (speed) {
+-		case SPEED_10000:
+-			ctrl |= priv->hw->link.xgmii.speed10000;
+-			break;
+-		case SPEED_5000:
+-			ctrl |= priv->hw->link.xgmii.speed5000;
+-			break;
+-		case SPEED_2500:
++	switch (speed) {
++	case SPEED_100000:
++		ctrl |= priv->hw->link.xlgmii.speed100000;
++		break;
++	case SPEED_50000:
++		ctrl |= priv->hw->link.xlgmii.speed50000;
++		break;
++	case SPEED_40000:
++		ctrl |= priv->hw->link.xlgmii.speed40000;
++		break;
++	case SPEED_25000:
++		ctrl |= priv->hw->link.xlgmii.speed25000;
++		break;
++	case SPEED_10000:
++		ctrl |= priv->hw->link.xgmii.speed10000;
++		break;
++	case SPEED_5000:
++		ctrl |= priv->hw->link.xgmii.speed5000;
++		break;
++	case SPEED_2500:
++		if (interface == PHY_INTERFACE_MODE_USXGMII)
+ 			ctrl |= priv->hw->link.xgmii.speed2500;
+-			break;
+-		default:
+-			return;
+-		}
+-	} else if (interface == PHY_INTERFACE_MODE_XLGMII) {
+-		switch (speed) {
+-		case SPEED_100000:
+-			ctrl |= priv->hw->link.xlgmii.speed100000;
+-			break;
+-		case SPEED_50000:
+-			ctrl |= priv->hw->link.xlgmii.speed50000;
+-			break;
+-		case SPEED_40000:
+-			ctrl |= priv->hw->link.xlgmii.speed40000;
+-			break;
+-		case SPEED_25000:
+-			ctrl |= priv->hw->link.xlgmii.speed25000;
+-			break;
+-		case SPEED_10000:
+-			ctrl |= priv->hw->link.xgmii.speed10000;
+-			break;
+-		case SPEED_2500:
+-			ctrl |= priv->hw->link.speed2500;
+-			break;
+-		case SPEED_1000:
+-			ctrl |= priv->hw->link.speed1000;
+-			break;
+-		default:
+-			return;
+-		}
+-	} else {
+-		switch (speed) {
+-		case SPEED_2500:
++		else
+ 			ctrl |= priv->hw->link.speed2500;
+-			break;
+-		case SPEED_1000:
+-			ctrl |= priv->hw->link.speed1000;
+-			break;
+-		case SPEED_100:
+-			ctrl |= priv->hw->link.speed100;
+-			break;
+-		case SPEED_10:
+-			ctrl |= priv->hw->link.speed10;
+-			break;
+-		default:
+-			return;
+-		}
++		break;
++	case SPEED_1000:
++		ctrl |= priv->hw->link.speed1000;
++		break;
++	case SPEED_100:
++		ctrl |= priv->hw->link.speed100;
++		break;
++	case SPEED_10:
++		ctrl |= priv->hw->link.speed10;
++		break;
++	default:
++		netdev_err(priv->dev,
++			   "unsupported speed %s on %s, leaving the MAC disabled\n",
++			   phy_speed_to_str(speed), phy_modes(interface));
++		return;
+ 	}
+ 
+ 	priv->speed = speed;
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+index 97ff2dd8f2aecd..9b58a91cce7e4d 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
+@@ -456,6 +456,7 @@ static int tc_parse_flow_actions(struct stmmac_priv *priv,
+ }
+ 
+ #define ETHER_TYPE_FULL_MASK	cpu_to_be16(~0)
++#define IP_PROTO_FULL_MASK	0xFF
+ 
+ static int tc_add_basic_flow(struct stmmac_priv *priv,
+ 			     struct flow_cls_offload *cls,
+@@ -471,6 +472,37 @@ static int tc_add_basic_flow(struct stmmac_priv *priv,
+ 
+ 	flow_rule_match_basic(rule, &match);
+ 
++	/* Both network proto and transport proto not present in the key */
++	if (!match.mask || !(match.mask->n_proto || match.mask->ip_proto)) {
++		NL_SET_ERR_MSG_MOD(cls->common.extack,
++				   "filter must specify network or transport protocol");
++		return -EOPNOTSUPP;
++	}
++
++	/* If the proto is present in the key and is not full mask */
++	if ((match.mask->n_proto && match.mask->n_proto != ETHER_TYPE_FULL_MASK) ||
++	    (match.mask->ip_proto && match.mask->ip_proto != IP_PROTO_FULL_MASK)) {
++		NL_SET_ERR_MSG_MOD(cls->common.extack,
++				   "only full protocol mask is supported");
++		return -EOPNOTSUPP;
++	}
++
++	/* Network proto is present in the key and is not IPv4 */
++	if (match.mask->n_proto && match.key->n_proto != cpu_to_be16(ETH_P_IP)) {
++		NL_SET_ERR_MSG_MOD(cls->common.extack,
++				   "only IPv4 network protocol is supported");
++		return -EOPNOTSUPP;
++	}
++
++	/* Transport proto is present in the key and is not TCP or UDP */
++	if (match.mask->ip_proto &&
++	    match.key->ip_proto != IPPROTO_TCP &&
++	    match.key->ip_proto != IPPROTO_UDP) {
++		NL_SET_ERR_MSG_MOD(cls->common.extack,
++				   "only TCP and UDP transport protocols are supported");
++		return -EOPNOTSUPP;
++	}
++
+ 	entry->ip_proto = match.key->ip_proto;
+ 	return 0;
+ }
+@@ -608,6 +640,8 @@ static int tc_add_flow(struct stmmac_priv *priv,
+ 		ret = tc_flow_parsers[i].fn(priv, cls, entry);
+ 		if (!ret)
+ 			entry->in_use = true;
++		else if (ret == -EOPNOTSUPP)
++			return ret;
+ 	}
+ 
+ 	if (!entry->in_use)
+@@ -637,6 +671,7 @@ static int tc_del_flow(struct stmmac_priv *priv,
+ 	entry->in_use = false;
+ 	entry->cookie = 0;
+ 	entry->is_l4 = false;
++	entry->action = 0;
+ 	return ret;
+ }
+ 
+diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
+index 33dae09f7fb220..378adeb2d38c90 100644
+--- a/drivers/net/geneve.c
++++ b/drivers/net/geneve.c
+@@ -1755,6 +1755,9 @@ static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],
+ 	struct geneve_config cfg;
+ 	int err;
+ 
++	if (!rtnl_dev_link_net_capable(dev, geneve->net))
++		return -EPERM;
++
+ 	/* If the geneve device is configured for metadata (or externally
+ 	 * controlled, for example, OVS), then nothing can be changed.
+ 	 */
+diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
+index 55160a5fc90fc6..7bb3da8f253635 100644
+--- a/drivers/net/gtp.c
++++ b/drivers/net/gtp.c
+@@ -490,8 +490,9 @@ static int gtp1u_send_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb)
+ 		return -1;
+ 
+ 	/* pull GTP and UDP headers */
+-	skb_pull_data(skb,
+-		      sizeof(struct gtp1_header_long) + sizeof(struct udphdr));
++	if (!skb_pull_data(skb, sizeof(struct gtp1_header_long) +
++				sizeof(struct udphdr)))
++		return -1;
+ 
+ 	gtp_pkt = skb_push(skb, sizeof(struct gtp1u_packet));
+ 	memset(gtp_pkt, 0, sizeof(struct gtp1u_packet));
+diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c
+index cbf3d4761ce357..225d952c01af81 100644
+--- a/drivers/net/ipa/ipa_smp2p.c
++++ b/drivers/net/ipa/ipa_smp2p.c
+@@ -233,19 +233,27 @@ int ipa_smp2p_init(struct ipa *ipa, bool modem_init)
+ 					  &valid_bit);
+ 	if (IS_ERR(valid_state))
+ 		return PTR_ERR(valid_state);
+-	if (valid_bit >= 32)		/* BITS_PER_U32 */
+-		return -EINVAL;
++	if (valid_bit >= 32) {		/* BITS_PER_U32 */
++		ret = -EINVAL;
++		goto err_valid_state_put;
++	}
+ 
+ 	enabled_state = qcom_smem_state_get(dev, "ipa-clock-enabled",
+ 					    &enabled_bit);
+-	if (IS_ERR(enabled_state))
+-		return PTR_ERR(enabled_state);
+-	if (enabled_bit >= 32)		/* BITS_PER_U32 */
+-		return -EINVAL;
++	if (IS_ERR(enabled_state)) {
++		ret = PTR_ERR(enabled_state);
++		goto err_valid_state_put;
++	}
++	if (enabled_bit >= 32) {		/* BITS_PER_U32 */
++		ret = -EINVAL;
++		goto err_enabled_state_put;
++	}
+ 
+ 	smp2p = kzalloc(sizeof(*smp2p), GFP_KERNEL);
+-	if (!smp2p)
+-		return -ENOMEM;
++	if (!smp2p) {
++		ret = -ENOMEM;
++		goto err_enabled_state_put;
++	}
+ 
+ 	smp2p->ipa = ipa;
+ 
+@@ -290,6 +298,10 @@ err_null_smp2p:
+ 	ipa->smp2p = NULL;
+ 	mutex_destroy(&smp2p->mutex);
+ 	kfree(smp2p);
++err_enabled_state_put:
++	qcom_smem_state_put(enabled_state);
++err_valid_state_put:
++	qcom_smem_state_put(valid_state);
+ 
+ 	return ret;
+ }
+@@ -306,6 +318,8 @@ void ipa_smp2p_exit(struct ipa *ipa)
+ 	ipa_smp2p_power_release(ipa);
+ 	ipa->smp2p = NULL;
+ 	mutex_destroy(&smp2p->mutex);
++	qcom_smem_state_put(smp2p->enabled_state);
++	qcom_smem_state_put(smp2p->valid_state);
+ 	kfree(smp2p);
+ }
+ 
+diff --git a/drivers/net/mctp/mctp-serial.c b/drivers/net/mctp/mctp-serial.c
+index 346e6ad36054eb..ad312375474d83 100644
+--- a/drivers/net/mctp/mctp-serial.c
++++ b/drivers/net/mctp/mctp-serial.c
+@@ -316,7 +316,7 @@ static void mctp_serial_push_header(struct mctp_serial *dev, unsigned char c)
+ 		} else {
+ 			dev->rxlen = c;
+ 			dev->rxpos = 0;
+-			dev->rxstate = STATE_DATA;
++			dev->rxstate = c > 0 ? STATE_DATA : STATE_TRAILER;
+ 			dev->rxfcs = crc_ccitt_byte(dev->rxfcs, c);
+ 		}
+ 		break;
+diff --git a/drivers/net/pcs/pcs-xpcs.c b/drivers/net/pcs/pcs-xpcs.c
+index f0f41e86a4fb32..680e2b2610860f 100644
+--- a/drivers/net/pcs/pcs-xpcs.c
++++ b/drivers/net/pcs/pcs-xpcs.c
+@@ -994,6 +994,7 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
+ 
+ 	/* Reset link_state */
+ 	state->link = false;
++	state->an_complete = false;
+ 	state->speed = SPEED_UNKNOWN;
+ 	state->duplex = DUPLEX_UNKNOWN;
+ 	state->pause = 0;
+@@ -1005,6 +1006,8 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
+ 	if (ret < 0)
+ 		return ret;
+ 
++	state->an_complete = ret & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR;
++
+ 	if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) {
+ 		int speed_value;
+ 
+@@ -1023,34 +1026,13 @@ static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
+ 			state->duplex = DUPLEX_FULL;
+ 		else
+ 			state->duplex = DUPLEX_HALF;
+-	} else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
+-		int speed, duplex;
+-
+-		state->link = true;
+-
+-		speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
+-		if (speed < 0)
+-			return speed;
+-
+-		speed &= SGMII_SPEED_SS13 | SGMII_SPEED_SS6;
+-		if (speed == SGMII_SPEED_SS6)
+-			state->speed = SPEED_1000;
+-		else if (speed == SGMII_SPEED_SS13)
+-			state->speed = SPEED_100;
+-		else if (speed == 0)
+-			state->speed = SPEED_10;
+-
+-		duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE);
+-		if (duplex < 0)
+-			return duplex;
+ 
+-		if (duplex & DW_FULL_DUPLEX)
+-			state->duplex = DUPLEX_FULL;
+-		else if (duplex & DW_HALF_DUPLEX)
+-			state->duplex = DUPLEX_HALF;
++		return 0;
++	}
+ 
++	/* Clear AN complete status or interrupt */
++	if (state->an_complete)
+ 		xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
+-	}
+ 
+ 	return 0;
+ }
+diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
+index 2b5843d14cbb84..3c42f131e89f26 100644
+--- a/drivers/net/ppp/ppp_generic.c
++++ b/drivers/net/ppp/ppp_generic.c
+@@ -107,18 +107,6 @@ struct ppp_file {
+ #define PF_TO_PPP(pf)		PF_TO_X(pf, struct ppp)
+ #define PF_TO_CHANNEL(pf)	PF_TO_X(pf, struct channel)
+ 
+-/*
+- * Data structure to hold primary network stats for which
+- * we want to use 64 bit storage.  Other network stats
+- * are stored in dev->stats of the ppp strucute.
+- */
+-struct ppp_link_stats {
+-	u64 rx_packets;
+-	u64 tx_packets;
+-	u64 rx_bytes;
+-	u64 tx_bytes;
+-};
+-
+ /*
+  * Data structure describing one ppp unit.
+  * A ppp unit corresponds to a ppp network interface device
+@@ -162,7 +150,6 @@ struct ppp {
+ 	struct bpf_prog *active_filter; /* filter for pkts to reset idle */
+ #endif /* CONFIG_PPP_FILTER */
+ 	struct net	*ppp_net;	/* the net we belong to */
+-	struct ppp_link_stats stats64;	/* 64 bit network stats */
+ };
+ 
+ /*
+@@ -192,6 +179,7 @@ struct channel {
+ 	struct list_head clist;		/* link in list of channels per unit */
+ 	rwlock_t	upl;		/* protects `ppp' and 'bridge' */
+ 	struct channel __rcu *bridge;	/* "bridged" ppp channel */
++	struct rcu_head rcu;		/* for RCU-deferred free of the channel */
+ #ifdef CONFIG_PPP_MULTILINK
+ 	u8		avail;		/* flag used in multilink stuff */
+ 	u8		had_frag;	/* >= 1 fragments have been sent */
+@@ -823,7 +811,9 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 	case PPPIOCSMRU:
+ 		if (get_user(val, p))
+ 			break;
++		ppp_recv_lock(ppp);
+ 		ppp->mru = val;
++		ppp_recv_unlock(ppp);
+ 		err = 0;
+ 		break;
+ 
+@@ -844,7 +834,9 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 		break;
+ 
+ 	case PPPIOCGFLAGS:
++		ppp_lock(ppp);
+ 		val = ppp->flags | ppp->xstate | ppp->rstate;
++		ppp_unlock(ppp);
+ 		if (put_user(val, p))
+ 			break;
+ 		err = 0;
+@@ -868,7 +860,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 	case PPPIOCSDEBUG:
+ 		if (get_user(val, p))
+ 			break;
+-		ppp->debug = val;
++		WRITE_ONCE(ppp->debug, val);
+ 		err = 0;
+ 		break;
+ 
+@@ -879,16 +871,16 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 		break;
+ 
+ 	case PPPIOCGIDLE32:
+-                idle32.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
+-                idle32.recv_idle = (jiffies - ppp->last_recv) / HZ;
+-                if (copy_to_user(argp, &idle32, sizeof(idle32)))
++		idle32.xmit_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_xmit))) / HZ;
++		idle32.recv_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_recv))) / HZ;
++		if (copy_to_user(argp, &idle32, sizeof(idle32)))
+ 			break;
+ 		err = 0;
+ 		break;
+ 
+ 	case PPPIOCGIDLE64:
+-		idle64.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
+-		idle64.recv_idle = (jiffies - ppp->last_recv) / HZ;
++		idle64.xmit_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_xmit))) / HZ;
++		idle64.recv_idle = max(0L, (long)(jiffies - READ_ONCE(ppp->last_recv))) / HZ;
+ 		if (copy_to_user(argp, &idle64, sizeof(idle64)))
+ 			break;
+ 		err = 0;
+@@ -929,7 +921,7 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+ 			if (copy_to_user(argp, &npi, sizeof(npi)))
+ 				break;
+ 		} else {
+-			ppp->npmode[i] = npi.mode;
++			WRITE_ONCE(ppp->npmode[i], npi.mode);
+ 			/* we may be able to transmit more packets now (??) */
+ 			netif_wake_queue(ppp->dev);
+ 		}
+@@ -1466,7 +1458,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ 		goto outf;
+ 
+ 	/* Drop, accept or reject the packet */
+-	switch (ppp->npmode[npi]) {
++	switch (READ_ONCE(ppp->npmode[npi])) {
+ 	case NPMODE_PASS:
+ 		break;
+ 	case NPMODE_QUEUE:
+@@ -1544,23 +1536,12 @@ ppp_net_siocdevprivate(struct net_device *dev, struct ifreq *ifr,
+ static void
+ ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64)
+ {
+-	struct ppp *ppp = netdev_priv(dev);
+-
+-	ppp_recv_lock(ppp);
+-	stats64->rx_packets = ppp->stats64.rx_packets;
+-	stats64->rx_bytes   = ppp->stats64.rx_bytes;
+-	ppp_recv_unlock(ppp);
+-
+-	ppp_xmit_lock(ppp);
+-	stats64->tx_packets = ppp->stats64.tx_packets;
+-	stats64->tx_bytes   = ppp->stats64.tx_bytes;
+-	ppp_xmit_unlock(ppp);
+-
+ 	stats64->rx_errors        = dev->stats.rx_errors;
+ 	stats64->tx_errors        = dev->stats.tx_errors;
+ 	stats64->rx_dropped       = dev->stats.rx_dropped;
+ 	stats64->tx_dropped       = dev->stats.tx_dropped;
+ 	stats64->rx_length_errors = dev->stats.rx_length_errors;
++	dev_fetch_sw_netstats(stats64, dev->tstats);
+ }
+ 
+ static int ppp_dev_init(struct net_device *dev)
+@@ -1658,6 +1639,9 @@ static void ppp_setup(struct net_device *dev)
+ 	dev->type = ARPHRD_PPP;
+ 	dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
+ 	dev->priv_destructor = ppp_dev_priv_destructor;
++	dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
++	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST;
++	dev->hw_features = dev->features;
+ 	netif_keep_dst(dev);
+ }
+ 
+@@ -1722,6 +1706,10 @@ pad_compress_skb(struct ppp *ppp, struct sk_buff *skb)
+ 		ppp->xcomp->comp_extra + ppp->dev->hard_header_len;
+ 	int compressor_skb_size = ppp->dev->mtu +
+ 		ppp->xcomp->comp_extra + PPP_HDRLEN;
++
++	if (skb_linearize(skb))
++		return NULL;
++
+ 	new_skb = alloc_skb(new_skb_size, GFP_ATOMIC);
+ 	if (!new_skb) {
+ 		if (net_ratelimit())
+@@ -1785,7 +1773,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
+ 		*(__be16 *)skb_push(skb, 2) = htons(PPP_FILTER_OUTBOUND_TAG);
+ 		if (ppp->pass_filter &&
+ 		    bpf_prog_run(ppp->pass_filter, skb) == 0) {
+-			if (ppp->debug & 1)
++			if (READ_ONCE(ppp->debug) & 1)
+ 				netdev_printk(KERN_DEBUG, ppp->dev,
+ 					      "PPP: outbound frame "
+ 					      "not passed\n");
+@@ -1795,21 +1783,24 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
+ 		/* if this packet passes the active filter, record the time */
+ 		if (!(ppp->active_filter &&
+ 		      bpf_prog_run(ppp->active_filter, skb) == 0))
+-			ppp->last_xmit = jiffies;
++			WRITE_ONCE(ppp->last_xmit, jiffies);
+ 		skb_pull(skb, 2);
+ #else
+ 		/* for data packets, record the time */
+-		ppp->last_xmit = jiffies;
++		WRITE_ONCE(ppp->last_xmit, jiffies);
+ #endif /* CONFIG_PPP_FILTER */
+ 	}
+ 
+-	++ppp->stats64.tx_packets;
+-	ppp->stats64.tx_bytes += skb->len - PPP_PROTO_LEN;
++	dev_sw_netstats_tx_add(ppp->dev, 1, skb->len - PPP_PROTO_LEN);
+ 
+ 	switch (proto) {
+ 	case PPP_IP:
+ 		if (!ppp->vj || (ppp->flags & SC_COMP_TCP) == 0)
+ 			break;
++
++		if (skb_linearize(skb))
++			goto drop;
++
+ 		/* try to do VJ TCP header compression */
+ 		new_skb = alloc_skb(skb->len + ppp->dev->hard_header_len - 2,
+ 				    GFP_ATOMIC);
+@@ -1907,19 +1898,26 @@ ppp_push(struct ppp *ppp)
+ 	}
+ 
+ 	if ((ppp->flags & SC_MULTILINK) == 0) {
++		struct ppp_channel *chan;
+ 		/* not doing multilink: send it down the first channel */
+ 		list = list->next;
+ 		pch = list_entry(list, struct channel, clist);
+ 
+ 		spin_lock(&pch->downl);
+-		if (pch->chan) {
+-			if (pch->chan->ops->start_xmit(pch->chan, skb))
+-				ppp->xmit_pending = NULL;
+-		} else {
+-			/* channel got unregistered */
++		chan = pch->chan;
++		if (unlikely(!chan || (!chan->direct_xmit && skb_linearize(skb)))) {
++			/* channel got unregistered, or it requires a linear
++			 * skb but linearization failed
++			 */
+ 			kfree_skb(skb);
+ 			ppp->xmit_pending = NULL;
++			goto out;
+ 		}
++
++		if (chan->ops->start_xmit(chan, skb))
++			ppp->xmit_pending = NULL;
++
++out:
+ 		spin_unlock(&pch->downl);
+ 		return;
+ 	}
+@@ -2004,6 +2002,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
+ 		return 0; /* can't take now, leave it in xmit_pending */
+ 
+ 	/* Do protocol field compression */
++	if (skb_linearize(skb))
++		goto err_linearize;
+ 	p = skb->data;
+ 	len = skb->len;
+ 	if (*p == 0 && mp_protocol_compress) {
+@@ -2162,7 +2162,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
+ 
+  noskb:
+ 	spin_unlock(&pch->downl);
+-	if (ppp->debug & 1)
++ err_linearize:
++	if (READ_ONCE(ppp->debug) & 1)
+ 		netdev_err(ppp->dev, "PPP: no memory (fragment)\n");
+ 	++ppp->dev->stats.tx_errors;
+ 	++ppp->nxseq;
+@@ -2482,8 +2483,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
+ 		break;
+ 	}
+ 
+-	++ppp->stats64.rx_packets;
+-	ppp->stats64.rx_bytes += skb->len - 2;
++	dev_sw_netstats_rx_add(ppp->dev, skb->len - PPP_PROTO_LEN);
+ 
+ 	npi = proto_to_npindex(proto);
+ 	if (npi < 0) {
+@@ -2509,7 +2509,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
+ 			*(__be16 *)skb_push(skb, 2) = htons(PPP_FILTER_INBOUND_TAG);
+ 			if (ppp->pass_filter &&
+ 			    bpf_prog_run(ppp->pass_filter, skb) == 0) {
+-				if (ppp->debug & 1)
++				if (READ_ONCE(ppp->debug) & 1)
+ 					netdev_printk(KERN_DEBUG, ppp->dev,
+ 						      "PPP: inbound frame "
+ 						      "not passed\n");
+@@ -2518,14 +2518,14 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
+ 			}
+ 			if (!(ppp->active_filter &&
+ 			      bpf_prog_run(ppp->active_filter, skb) == 0))
+-				ppp->last_recv = jiffies;
++				WRITE_ONCE(ppp->last_recv, jiffies);
+ 			__skb_pull(skb, 2);
+ 		} else
+ #endif /* CONFIG_PPP_FILTER */
+-			ppp->last_recv = jiffies;
++			WRITE_ONCE(ppp->last_recv, jiffies);
+ 
+ 		if ((ppp->dev->flags & IFF_UP) == 0 ||
+-		    ppp->npmode[npi] != NPMODE_PASS) {
++		    READ_ONCE(ppp->npmode[npi]) != NPMODE_PASS) {
+ 			kfree_skb(skb);
+ 		} else {
+ 			/* chop off protocol */
+@@ -2778,7 +2778,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
+ 			seq = seq_before(minseq, PPP_MP_CB(p)->sequence)?
+ 				minseq + 1: PPP_MP_CB(p)->sequence;
+ 
+-			if (ppp->debug & 1)
++			if (READ_ONCE(ppp->debug) & 1)
+ 				netdev_printk(KERN_DEBUG, ppp->dev,
+ 					      "lost frag %u..%u\n",
+ 					      oldseq, seq-1);
+@@ -2827,7 +2827,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
+ 			struct sk_buff *tmp2;
+ 
+ 			skb_queue_reverse_walk_from_safe(list, p, tmp2) {
+-				if (ppp->debug & 1)
++				if (READ_ONCE(ppp->debug) & 1)
+ 					netdev_printk(KERN_DEBUG, ppp->dev,
+ 						      "discarding frag %u\n",
+ 						      PPP_MP_CB(p)->sequence);
+@@ -2849,7 +2849,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
+ 			skb_queue_walk_safe(list, p, tmp) {
+ 				if (p == head)
+ 					break;
+-				if (ppp->debug & 1)
++				if (READ_ONCE(ppp->debug) & 1)
+ 					netdev_printk(KERN_DEBUG, ppp->dev,
+ 						      "discarding frag %u\n",
+ 						      PPP_MP_CB(p)->sequence);
+@@ -2857,7 +2857,7 @@ ppp_mp_reconstruct(struct ppp *ppp)
+ 				kfree_skb(p);
+ 			}
+ 
+-			if (ppp->debug & 1)
++			if (READ_ONCE(ppp->debug) & 1)
+ 				netdev_printk(KERN_DEBUG, ppp->dev,
+ 					      "  missed pkts %u..%u\n",
+ 					      ppp->nextseq,
+@@ -3167,7 +3167,8 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
+ 			if (!ppp->rc_state)
+ 				break;
+ 			if (ppp->rcomp->decomp_init(ppp->rc_state, dp, len,
+-					ppp->file.index, 0, ppp->mru, ppp->debug)) {
++						ppp->file.index, 0, ppp->mru,
++						READ_ONCE(ppp->debug))) {
+ 				ppp->rstate |= SC_DECOMP_RUN;
+ 				ppp->rstate &= ~(SC_DC_ERROR | SC_DC_FERROR);
+ 			}
+@@ -3176,7 +3177,8 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
+ 			if (!ppp->xc_state)
+ 				break;
+ 			if (ppp->xcomp->comp_init(ppp->xc_state, dp, len,
+-					ppp->file.index, 0, ppp->debug))
++						  ppp->file.index, 0,
++						  READ_ONCE(ppp->debug)))
+ 				ppp->xstate |= SC_COMP_RUN;
+ 		}
+ 		break;
+@@ -3311,14 +3313,25 @@ static void
+ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
+ {
+ 	struct slcompress *vj = ppp->vj;
++	int cpu;
+ 
+ 	memset(st, 0, sizeof(*st));
+-	st->p.ppp_ipackets = ppp->stats64.rx_packets;
++	for_each_possible_cpu(cpu) {
++		struct pcpu_sw_netstats *p = per_cpu_ptr(ppp->dev->tstats, cpu);
++		u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
++
++		rx_packets = u64_stats_read(&p->rx_packets);
++		rx_bytes = u64_stats_read(&p->rx_bytes);
++		tx_packets = u64_stats_read(&p->tx_packets);
++		tx_bytes = u64_stats_read(&p->tx_bytes);
++
++		st->p.ppp_ipackets += rx_packets;
++		st->p.ppp_ibytes += rx_bytes;
++		st->p.ppp_opackets += tx_packets;
++		st->p.ppp_obytes += tx_bytes;
++	}
+ 	st->p.ppp_ierrors = ppp->dev->stats.rx_errors;
+-	st->p.ppp_ibytes = ppp->stats64.rx_bytes;
+-	st->p.ppp_opackets = ppp->stats64.tx_packets;
+ 	st->p.ppp_oerrors = ppp->dev->stats.tx_errors;
+-	st->p.ppp_obytes = ppp->stats64.tx_bytes;
+ 	if (!vj)
+ 		return;
+ 	st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed;
+@@ -3507,6 +3520,10 @@ ppp_connect_channel(struct channel *pch, int unit)
+ 		ret = -ENOTCONN;
+ 		goto outl;
+ 	}
++	if (pch->chan->direct_xmit)
++		ppp->dev->priv_flags |= IFF_NO_QUEUE;
++	else
++		ppp->dev->priv_flags &= ~IFF_NO_QUEUE;
+ 	spin_unlock_bh(&pch->downl);
+ 	if (pch->file.hdrlen > ppp->file.hdrlen)
+ 		ppp->file.hdrlen = pch->file.hdrlen;
+@@ -3555,6 +3572,18 @@ ppp_disconnect_channel(struct channel *pch)
+ 	return err;
+ }
+ 
++/* Purge after the grace period: a late ppp_input() may still queue an
++ * skb on pch->file.rq before the last RCU reader drains.
++ */
++static void ppp_release_channel_free(struct rcu_head *rcu)
++{
++	struct channel *pch = container_of(rcu, struct channel, rcu);
++
++	skb_queue_purge(&pch->file.xq);
++	skb_queue_purge(&pch->file.rq);
++	kfree(pch);
++}
++
+ /*
+  * Free up the resources used by a ppp channel.
+  */
+@@ -3570,9 +3599,7 @@ static void ppp_destroy_channel(struct channel *pch)
+ 		pr_err("ppp: destroying undead channel %p !\n", pch);
+ 		return;
+ 	}
+-	skb_queue_purge(&pch->file.xq);
+-	skb_queue_purge(&pch->file.rq);
+-	kfree(pch);
++	call_rcu(&pch->rcu, ppp_release_channel_free);
+ }
+ 
+ static void __exit ppp_cleanup(void)
+@@ -3585,6 +3612,7 @@ static void __exit ppp_cleanup(void)
+ 	device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
+ 	class_destroy(ppp_class);
+ 	unregister_pernet_device(&ppp_net_ops);
++	rcu_barrier(); /* wait for RCU callbacks before module unload */
+ }
+ 
+ /*
+diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
+index bc726b54ca745d..63c94ad88e5656 100644
+--- a/drivers/net/ppp/pppoe.c
++++ b/drivers/net/ppp/pppoe.c
+@@ -699,6 +699,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
+ 		po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr) - 2;
+ 		po->chan.private = sk;
+ 		po->chan.ops = &pppoe_chan_ops;
++		po->chan.direct_xmit = true;
+ 
+ 		error = ppp_register_net_channel(dev_net(dev), &po->chan);
+ 		if (error) {
+@@ -899,6 +900,7 @@ static int pppoe_sendmsg(struct socket *sock, struct msghdr *m,
+ 	dev_hard_header(skb, dev, ETH_P_PPP_SES,
+ 			po->pppoe_pa.remote, NULL, total_len);
+ 
++	ph = pppoe_hdr(skb);
+ 	memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
+ 
+ 	ph->length = htons(total_len);
+diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
+index 3a10303eb756a8..386e0be78a6a96 100644
+--- a/drivers/net/ppp/pptp.c
++++ b/drivers/net/ppp/pptp.c
+@@ -469,6 +469,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
+ 	po->chan.mtu -= PPTP_HEADER_OVERHEAD;
+ 
+ 	po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
++	po->chan.direct_xmit = true;
+ 	error = ppp_register_channel(&po->chan);
+ 	if (error) {
+ 		pr_err("PPTP: failed to register PPP channel (%d)\n", error);
+diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c
+index e4280e37fec97f..b9e5a56f136efb 100644
+--- a/drivers/net/slip/slip.c
++++ b/drivers/net/slip/slip.c
+@@ -693,6 +693,8 @@ static void slip_receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *fp,
+ 	if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
+ 		return;
+ 
++	spin_lock_bh(&sl->lock);
++
+ 	/* Read the characters out of the buffer */
+ 	while (count--) {
+ 		if (fp && *fp++) {
+@@ -708,6 +710,8 @@ static void slip_receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *fp,
+ #endif
+ 			slip_unesc(sl, *cp++);
+ 	}
++
++	spin_unlock_bh(&sl->lock);
+ }
+ 
+ /************************************
+diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
+index 68b8e458a88f6a..16af7c4f8eda59 100644
+--- a/drivers/net/vmxnet3/vmxnet3_drv.c
++++ b/drivers/net/vmxnet3/vmxnet3_drv.c
+@@ -1457,7 +1457,11 @@ vmxnet3_get_hdr_len(struct vmxnet3_adapter *adapter, struct sk_buff *skb,
+ 		struct ipv6hdr *ipv6;
+ 		struct tcphdr *tcp;
+ 	} hdr;
+-	BUG_ON(gdesc->rcd.tcp == 0);
++
++	/* v4/v6/tcp then describe the inner header, which we can't locate. */
++	if ((le32_to_cpu(gdesc->dword[0]) & (1UL << VMXNET3_RCD_HDR_INNER_SHIFT)) ||
++	    gdesc->rcd.tcp == 0)
++		return 0;
+ 
+ 	maplen = skb_headlen(skb);
+ 	if (unlikely(sizeof(struct iphdr) + sizeof(struct tcphdr) > maplen))
+@@ -1471,15 +1475,21 @@ vmxnet3_get_hdr_len(struct vmxnet3_adapter *adapter, struct sk_buff *skb,
+ 
+ 	hdr.eth = eth_hdr(skb);
+ 	if (gdesc->rcd.v4) {
+-		BUG_ON(hdr.eth->h_proto != htons(ETH_P_IP) &&
+-		       hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IP));
++		if (hdr.eth->h_proto != htons(ETH_P_IP) &&
++		    hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IP))
++			return 0;
++
+ 		hdr.ptr += hlen;
+-		BUG_ON(hdr.ipv4->protocol != IPPROTO_TCP);
++		if (hdr.ipv4->protocol != IPPROTO_TCP)
++			return 0;
++
+ 		hlen = hdr.ipv4->ihl << 2;
+ 		hdr.ptr += hdr.ipv4->ihl << 2;
+ 	} else if (gdesc->rcd.v6) {
+-		BUG_ON(hdr.eth->h_proto != htons(ETH_P_IPV6) &&
+-		       hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IPV6));
++		if (hdr.eth->h_proto != htons(ETH_P_IPV6) &&
++		    hdr.veth->h_vlan_encapsulated_proto != htons(ETH_P_IPV6))
++			return 0;
++
+ 		hdr.ptr += hlen;
+ 		/* Use an estimated value, since we also need to handle
+ 		 * TSO case.
+diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
+index 1a3a00476a9368..4fcf5c123a9d55 100644
+--- a/drivers/net/vxlan/vxlan_core.c
++++ b/drivers/net/vxlan/vxlan_core.c
+@@ -4257,6 +4257,9 @@ static int vxlan_changelink(struct net_device *dev, struct nlattr *tb[],
+ 	struct vxlan_rdst *dst;
+ 	int err;
+ 
++	if (!rtnl_dev_link_net_capable(dev, vxlan->net))
++		return -EPERM;
++
+ 	dst = &vxlan->default_dst;
+ 	err = vxlan_nl2conf(tb, data, dev, &conf, true, extack);
+ 	if (err)
+diff --git a/drivers/net/vxlan/vxlan_mdb.c b/drivers/net/vxlan/vxlan_mdb.c
+index 5e041622261a55..73c128c3d90dee 100644
+--- a/drivers/net/vxlan/vxlan_mdb.c
++++ b/drivers/net/vxlan/vxlan_mdb.c
+@@ -42,6 +42,7 @@ struct vxlan_mdb_remote {
+ };
+ 
+ #define VXLAN_SGRP_F_DELETE	BIT(0)
++#define VXLAN_SGRP_F_NEW	BIT(1)
+ 
+ struct vxlan_mdb_src_entry {
+ 	struct hlist_node node;
+@@ -838,6 +839,7 @@ vxlan_mdb_remote_src_add(const struct vxlan_mdb_config *cfg,
+ 		ent = vxlan_mdb_remote_src_entry_add(remote, &src->addr);
+ 		if (!ent)
+ 			return -ENOMEM;
++		ent->flags |= VXLAN_SGRP_F_NEW;
+ 	} else if (!(cfg->nlflags & NLM_F_REPLACE)) {
+ 		NL_SET_ERR_MSG_MOD(extack, "Source entry already exists");
+ 		return -EEXIST;
+@@ -847,15 +849,16 @@ vxlan_mdb_remote_src_add(const struct vxlan_mdb_config *cfg,
+ 	if (err)
+ 		goto err_src_del;
+ 
+-	/* Clear flags in case source entry was marked for deletion as part of
+-	 * replace flow.
++	/* Clear the deletion mark so the entry survives the replace sweep.
++	 * The new mark is retained until the whole operation succeeds.
+ 	 */
+-	ent->flags = 0;
++	ent->flags &= ~VXLAN_SGRP_F_DELETE;
+ 
+ 	return 0;
+ 
+ err_src_del:
+-	vxlan_mdb_remote_src_entry_del(ent);
++	if (ent->flags & VXLAN_SGRP_F_NEW)
++		vxlan_mdb_remote_src_entry_del(ent);
+ 	return err;
+ }
+ 
+@@ -883,11 +886,19 @@ static int vxlan_mdb_remote_srcs_add(const struct vxlan_mdb_config *cfg,
+ 			goto err_src_del;
+ 	}
+ 
++	hlist_for_each_entry(ent, &remote->src_list, node)
++		ent->flags &= ~VXLAN_SGRP_F_NEW;
++
+ 	return 0;
+ 
+ err_src_del:
+-	hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node)
+-		vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote, ent);
++	hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) {
++		if (ent->flags & VXLAN_SGRP_F_NEW)
++			vxlan_mdb_remote_src_del(cfg->vxlan, &cfg->group, remote,
++						 ent);
++		else
++			ent->flags &= ~VXLAN_SGRP_F_DELETE;
++	}
+ 	return err;
+ }
+ 
+@@ -1053,7 +1064,7 @@ vxlan_mdb_remote_srcs_replace(const struct vxlan_mdb_config *cfg,
+ 
+ 	err = vxlan_mdb_remote_srcs_add(cfg, remote, extack);
+ 	if (err)
+-		goto err_clear_delete;
++		return err;
+ 
+ 	hlist_for_each_entry_safe(ent, tmp, &remote->src_list, node) {
+ 		if (ent->flags & VXLAN_SGRP_F_DELETE)
+@@ -1062,11 +1073,6 @@ vxlan_mdb_remote_srcs_replace(const struct vxlan_mdb_config *cfg,
+ 	}
+ 
+ 	return 0;
+-
+-err_clear_delete:
+-	hlist_for_each_entry(ent, &remote->src_list, node)
+-		ent->flags &= ~VXLAN_SGRP_F_DELETE;
+-	return err;
+ }
+ 
+ static int vxlan_mdb_remote_replace(const struct vxlan_mdb_config *cfg,
+diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
+index 5a9e262188efe1..c38dd741401e13 100644
+--- a/drivers/net/wan/wanxl.c
++++ b/drivers/net/wan/wanxl.c
+@@ -514,7 +514,8 @@ static void wanxl_pci_remove_one(struct pci_dev *pdev)
+ 	if (card->irq)
+ 		free_irq(card->irq, card);
+ 
+-	wanxl_reset(card);
++	if (card->plx)
++		wanxl_reset(card);
+ 
+ 	for (i = 0; i < RX_QUEUE_LENGTH; i++)
+ 		if (card->rx_skbs[i]) {
+diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
+index 31fd92bd9efe8f..23771abb3acec5 100644
+--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
++++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
+@@ -4619,6 +4619,9 @@ static void ath11k_hal_rx_msdu_list_get(struct ath11k *ar,
+ 	msdu_details = &msdu_link->msdu_link[0];
+ 
+ 	for (i = 0; i < HAL_RX_NUM_MSDU_DESC; i++) {
++		if (!i && FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
++				    msdu_details[i].buf_addr_info.info0) == 0)
++			break;
+ 		if (FIELD_GET(BUFFER_ADDR_INFO0_ADDR,
+ 			      msdu_details[i].buf_addr_info.info0) == 0) {
+ 			msdu_desc_info = &msdu_details[i - 1].rx_msdu_info;
+diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
+index 09e65c5e55c4a9..966ba712ff9094 100644
+--- a/drivers/net/wireless/ath/ath11k/pci.c
++++ b/drivers/net/wireless/ath/ath11k/pci.c
+@@ -181,6 +181,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
+ 	val |= PCIE_SOC_GLOBAL_RESET_V;
+ 
+ 	ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
++	/* Flush the posted write to the device */
++	ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
+ 
+ 	/* TODO: exact time to sleep is uncertain */
+ 	delay = 10;
+@@ -190,6 +192,8 @@ static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
+ 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
+ 
+ 	ath11k_pcic_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
++	/* Flush the posted write to the device */
++	ath11k_pcic_read32(ab, PCIE_SOC_GLOBAL_RESET);
+ 
+ 	mdelay(delay);
+ 
+diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c
+index 91e31f30d2c80f..84d214c38f0f47 100644
+--- a/drivers/net/wireless/ath/ath11k/qmi.c
++++ b/drivers/net/wireless/ath/ath11k/qmi.c
+@@ -3276,9 +3276,14 @@ static void ath11k_qmi_driver_event_work(struct work_struct *work)
+ 			clear_bit(ATH11K_FLAG_CRASH_FLUSH,
+ 				  &ab->dev_flags);
+ 			clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);
+-			ath11k_core_qmi_firmware_ready(ab);
+-			set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
+-
++			if (!test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) {
++				ret = ath11k_core_qmi_firmware_ready(ab);
++				if (ret) {
++					set_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags);
++					break;
++				}
++				set_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags);
++			}
+ 			break;
+ 		case ATH11K_QMI_EVENT_COLD_BOOT_CAL_DONE:
+ 			break;
+diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
+index 7dfbabf0637d23..62be78de330011 100644
+--- a/drivers/net/wireless/ath/ath12k/pci.c
++++ b/drivers/net/wireless/ath/ath12k/pci.c
+@@ -211,6 +211,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab)
+ 	val |= PCIE_SOC_GLOBAL_RESET_V;
+ 
+ 	ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
++	/* Flush the posted write to the device */
++	ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
+ 
+ 	/* TODO: exact time to sleep is uncertain */
+ 	delay = 10;
+@@ -220,6 +222,8 @@ static void ath12k_pci_soc_global_reset(struct ath12k_base *ab)
+ 	val &= ~PCIE_SOC_GLOBAL_RESET_V;
+ 
+ 	ath12k_pci_write32(ab, PCIE_SOC_GLOBAL_RESET, val);
++	/* Flush the posted write to the device */
++	ath12k_pci_read32(ab, PCIE_SOC_GLOBAL_RESET);
+ 
+ 	mdelay(delay);
+ 
+diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
+index a56fab6232a9ba..159ec376baff8b 100644
+--- a/drivers/net/wireless/ath/ath6kl/txrx.c
++++ b/drivers/net/wireless/ath/ath6kl/txrx.c
+@@ -1722,13 +1722,15 @@ void aggr_recv_addba_req_evt(struct ath6kl_vif *vif, u8 tid_mux, u16 seq_no,
+ 
+ 	rxtid = &aggr_conn->rx_tid[tid];
+ 
+-	if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX)
+-		ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n",
+-			   __func__, win_sz, tid);
+-
+ 	if (rxtid->aggr)
+ 		aggr_delete_tid_state(aggr_conn, tid);
+ 
++	if (win_sz < AGGR_WIN_SZ_MIN || win_sz > AGGR_WIN_SZ_MAX) {
++		ath6kl_dbg(ATH6KL_DBG_WLAN_RX, "%s: win_sz %d, tid %d\n",
++			   __func__, win_sz, tid);
++		return;
++	}
++
+ 	rxtid->seq_next = seq_no;
+ 	hold_q_size = TID_WINDOW_SZ(win_sz) * sizeof(struct skb_hold_q);
+ 	rxtid->hold_q = kzalloc(hold_q_size, GFP_KERNEL);
+diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
+index 3787b9fb007559..447896b871c3e2 100644
+--- a/drivers/net/wireless/ath/ath6kl/wmi.c
++++ b/drivers/net/wireless/ath/ath6kl/wmi.c
+@@ -484,6 +484,18 @@ static int ath6kl_wmi_tx_complete_event_rx(u8 *datap, int len)
+ 
+ 	evt = (struct wmi_tx_complete_event *) datap;
+ 
++	if (len < sizeof(*evt)) {
++		ath6kl_dbg(ATH6KL_DBG_WMI, "tx complete: invalid len %d\n",
++			   len);
++		return -EINVAL;
++	}
++
++	if (len < sizeof(*evt) + evt->num_msg * sizeof(struct tx_complete_msg_v1)) {
++		ath6kl_dbg(ATH6KL_DBG_WMI, "tx complete: invalid len %d for %u msgs\n",
++			   len, evt->num_msg);
++		return -EINVAL;
++	}
++
+ 	ath6kl_dbg(ATH6KL_DBG_WMI, "comp: %d %d %d\n",
+ 		   evt->num_msg, evt->msg_len, evt->msg_type);
+ 
+@@ -862,6 +874,14 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
+ 
+ 	ev = (struct wmi_connect_event *) datap;
+ 
++	if (len < sizeof(*ev) + ev->beacon_ie_len +
++	    ev->assoc_req_len + ev->assoc_resp_len) {
++		ath6kl_dbg(ATH6KL_DBG_WMI,
++			   "connect event: IE lengths %u+%u+%u exceed buffer %d\n",
++			   ev->beacon_ie_len, ev->assoc_req_len,
++			   ev->assoc_resp_len, len);
++		return -EINVAL;
++	}
+ 	if (vif->nw_type == AP_NETWORK) {
+ 		/* AP mode start/STA connected event */
+ 		struct net_device *dev = vif->ndev;
+diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
+index ab728a70ed2796..110cf65b0f8804 100644
+--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
++++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
+@@ -1225,15 +1225,10 @@ static int ath9k_hif_request_firmware(struct hif_device_usb *hif_dev,
+ 	ret = request_firmware_nowait(THIS_MODULE, true, hif_dev->fw_name,
+ 				      &hif_dev->udev->dev, GFP_KERNEL,
+ 				      hif_dev, ath9k_hif_usb_firmware_cb);
+-	if (ret) {
++	if (ret)
+ 		dev_err(&hif_dev->udev->dev,
+ 			"ath9k_htc: Async request for firmware %s failed\n",
+ 			hif_dev->fw_name);
+-		return ret;
+-	}
+-
+-	dev_info(&hif_dev->udev->dev, "ath9k_htc: Firmware %s requested\n",
+-		 hif_dev->fw_name);
+ 
+ 	return ret;
+ }
+diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
+index 908c4c8b7f8256..bda30b1f940459 100644
+--- a/drivers/net/wireless/ath/carl9170/rx.c
++++ b/drivers/net/wireless/ath/carl9170/rx.c
+@@ -150,7 +150,8 @@ static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
+ 	spin_lock(&ar->cmd_lock);
+ 	if (ar->readbuf) {
+ 		if (len >= 4)
+-			memcpy(ar->readbuf, buffer + 4, len - 4);
++			memcpy(ar->readbuf, buffer + 4,
++			       min_t(u32, len - 4, ar->readlen));
+ 
+ 		ar->readbuf = NULL;
+ 	}
+@@ -917,7 +918,9 @@ static void carl9170_rx_stream(struct ar9170 *ar, void *buf, unsigned int len)
+ 				}
+ 			}
+ 
+-			skb_put_data(ar->rx_failover, tbuf, tlen);
++			skb_put_data(ar->rx_failover, tbuf,
++				     min_t(unsigned int, tlen,
++					   ar->rx_failover_missing));
+ 			ar->rx_failover_missing -= tlen;
+ 
+ 			if (ar->rx_failover_missing <= 0) {
+diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
+index 88ef6e023f8266..d036ebb42c0d24 100644
+--- a/drivers/net/wireless/ath/carl9170/tx.c
++++ b/drivers/net/wireless/ath/carl9170/tx.c
+@@ -693,7 +693,7 @@ void carl9170_tx_process_status(struct ar9170 *ar,
+ 	unsigned int i;
+ 
+ 	for (i = 0;  i < cmd->hdr.ext; i++) {
+-		if (WARN_ON(i > ((cmd->hdr.len / 2) + 1))) {
++		if (WARN_ON(i >= (cmd->hdr.len / 2))) {
+ 			print_hex_dump_bytes("UU:", DUMP_PREFIX_NONE,
+ 					     (void *) cmd, cmd->hdr.len + 4);
+ 			break;
+diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c
+index c1a92c7f0f8e88..8987bc5c5859fb 100644
+--- a/drivers/net/wireless/atmel/at76c50x-usb.c
++++ b/drivers/net/wireless/atmel/at76c50x-usb.c
+@@ -1527,13 +1527,16 @@ static inline int at76_guess_freq(struct at76_priv *priv)
+ 
+ 	if (ieee80211_is_probe_resp(hdr->frame_control)) {
+ 		el_off = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+-		el = ((struct ieee80211_mgmt *)hdr)->u.probe_resp.variable;
+ 	} else if (ieee80211_is_beacon(hdr->frame_control)) {
+ 		el_off = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+-		el = ((struct ieee80211_mgmt *)hdr)->u.beacon.variable;
+ 	} else {
+ 		goto exit;
+ 	}
++
++	if (len < el_off)
++		goto exit;
++
++	el = priv->rx_skb->data + el_off;
+ 	len -= el_off;
+ 
+ 	el = cfg80211_find_ie(WLAN_EID_DS_PARAMS, el, len);
+diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+index c7f62226ebbcc5..7146e32717cfcf 100644
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -2122,7 +2122,7 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
+ 				 sme->crypto.akm_suites[0]);
+ 			return -EINVAL;
+ 		}
+-	} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
++	} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED | WPA2_AUTH_1X_SHA256)) {
+ 		switch (sme->crypto.akm_suites[0]) {
+ 		case WLAN_AKM_SUITE_8021X:
+ 			val = WPA2_AUTH_UNSPECIFIED;
+diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+index a43af82691401e..cbb6d512c43b42 100644
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+@@ -1381,16 +1381,20 @@ fail:
+ static void
+ brcmf_pcie_release_scratchbuffers(struct brcmf_pciedev_info *devinfo)
+ {
+-	if (devinfo->shared.scratch)
++	if (devinfo->shared.scratch) {
+ 		dma_free_coherent(&devinfo->pdev->dev,
+ 				  BRCMF_DMA_D2H_SCRATCH_BUF_LEN,
+ 				  devinfo->shared.scratch,
+ 				  devinfo->shared.scratch_dmahandle);
+-	if (devinfo->shared.ringupd)
++		devinfo->shared.scratch = NULL;
++	}
++	if (devinfo->shared.ringupd) {
+ 		dma_free_coherent(&devinfo->pdev->dev,
+ 				  BRCMF_DMA_D2H_RINGUPD_BUF_LEN,
+ 				  devinfo->shared.ringupd,
+ 				  devinfo->shared.ringupd_dmahandle);
++		devinfo->shared.ringupd = NULL;
++	}
+ }
+ 
+ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo)
+diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+index a4d0db371c8976..1ab0f501017bcf 100644
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+@@ -4458,6 +4458,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
+ 	bus->sdiodev = sdiodev;
+ 	sdiodev->bus = bus;
+ 	skb_queue_head_init(&bus->glom);
++	INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
+ 	bus->txbound = BRCMF_TXBOUND;
+ 	bus->rxbound = BRCMF_RXBOUND;
+ 	bus->txminmax = BRCMF_TXMINMAX;
+@@ -4471,7 +4472,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
+ 		goto fail;
+ 	}
+ 	brcmf_sdiod_freezer_count(sdiodev);
+-	INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
+ 	bus->brcmf_wq = wq;
+ 
+ 	/* attempt to attach to the dongle */
+diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+index 9e9ff0cb724cac..a1eb69efecc6d1 100644
+--- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c
++++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c
+@@ -6172,6 +6172,8 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
+ 	if (err) {
+ 		printk(KERN_WARNING DRV_NAME
+ 		       "Error calling pci_enable_device.\n");
++		free_libipw(dev, 0);
++		pci_iounmap(pci_dev, ioaddr);
+ 		return err;
+ 	}
+ 
+@@ -6184,16 +6186,14 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
+ 	if (err) {
+ 		printk(KERN_WARNING DRV_NAME
+ 		       "Error calling pci_set_dma_mask.\n");
+-		pci_disable_device(pci_dev);
+-		return err;
++		goto fail;
+ 	}
+ 
+ 	err = pci_request_regions(pci_dev, DRV_NAME);
+ 	if (err) {
+ 		printk(KERN_WARNING DRV_NAME
+ 		       "Error calling pci_request_regions.\n");
+-		pci_disable_device(pci_dev);
+-		return err;
++		goto fail;
+ 	}
+ 
+ 	/* We disable the RETRY_TIMEOUT register (0x41) to keep
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+index ac304e21a36727..51abcd20ffbd60 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c
+@@ -2812,7 +2812,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm,
+ 					 struct iwl_wowlan_status_data *status,
+ 					 u32 len)
+ {
+-	u32 data_size, packet_len = le32_to_cpu(notif->wake_packet_length);
++	u32 data_size, packet_len;
+ 
+ 	if (len < sizeof(*notif)) {
+ 		IWL_ERR(mvm, "Invalid WoWLAN wake packet notification!\n");
+@@ -2831,6 +2831,7 @@ static int iwl_mvm_wowlan_store_wake_pkt(struct iwl_mvm *mvm,
+ 		return -EIO;
+ 	}
+ 
++	packet_len = le32_to_cpu(notif->wake_packet_length);
+ 	data_size = len - offsetof(struct iwl_wowlan_wake_pkt_notif, wake_packet);
+ 
+ 	/* data_size got the padding from the notification, remove it. */
+diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+index c597492668fad5..d2ff33366b3c6c 100644
+--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
++++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+@@ -908,12 +908,22 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm)
+ 		return ret;
+ 	}
+ 
++	if (IWL_FW_CHECK(mvm,
++			 iwl_rx_packet_payload_len(cmd.resp_pkt) !=
++			 sizeof(*resp),
++			 "Wrong size for iwl_geo_tx_power_profiles_resp: %d\n",
++			 iwl_rx_packet_payload_len(cmd.resp_pkt))) {
++		ret = -EIO;
++		goto out;
++	}
++
+ 	resp = (void *)cmd.resp_pkt->data;
+ 	ret = le32_to_cpu(resp->profile_idx);
+ 
+ 	if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES_REV3))
+ 		ret = -EIO;
+ 
++out:
+ 	iwl_free_resp(&cmd);
+ 	return ret;
+ }
+diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c
+index 2deb1bb54f24bd..dc7bf54e30bba1 100644
+--- a/drivers/net/wireless/intersil/p54/txrx.c
++++ b/drivers/net/wireless/intersil/p54/txrx.c
+@@ -499,11 +499,19 @@ static void p54_rx_eeprom_readback(struct p54_common *priv,
+ 		if (le16_to_cpu(eeprom->v2.len) != priv->eeprom_slice_size)
+ 			return;
+ 
++		if (eeprom->v2.data + priv->eeprom_slice_size >
++		    skb_tail_pointer(skb))
++			return;
++
+ 		memcpy(priv->eeprom, eeprom->v2.data, priv->eeprom_slice_size);
+ 	} else {
+ 		if (le16_to_cpu(eeprom->v1.len) != priv->eeprom_slice_size)
+ 			return;
+ 
++		if (eeprom->v1.data + priv->eeprom_slice_size >
++		    skb_tail_pointer(skb))
++			return;
++
+ 		memcpy(priv->eeprom, eeprom->v1.data, priv->eeprom_slice_size);
+ 	}
+ 
+diff --git a/drivers/net/wireless/marvell/libertas/firmware.c b/drivers/net/wireless/marvell/libertas/firmware.c
+index f124110944b7e9..9bf7d4c207b9ed 100644
+--- a/drivers/net/wireless/marvell/libertas/firmware.c
++++ b/drivers/net/wireless/marvell/libertas/firmware.c
+@@ -78,6 +78,7 @@ static void helper_firmware_cb(const struct firmware *firmware, void *context)
+ 	} else {
+ 		/* No main firmware needed for this helper --> success! */
+ 		lbs_fw_loaded(priv, 0, firmware, NULL);
++		release_firmware(firmware);
+ 	}
+ }
+ 
+diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c
+index 199d33ed3bb960..96c46f7679d970 100644
+--- a/drivers/net/wireless/marvell/libertas_tf/main.c
++++ b/drivers/net/wireless/marvell/libertas_tf/main.c
+@@ -174,7 +174,7 @@ static void lbtf_free_adapter(struct lbtf_private *priv)
+ {
+ 	lbtf_deb_enter(LBTF_DEB_MAIN);
+ 	lbtf_free_cmd_buffer(priv);
+-	del_timer(&priv->command_timer);
++	timer_delete_sync(&priv->command_timer);
+ 	lbtf_deb_leave(LBTF_DEB_MAIN);
+ }
+ 
+diff --git a/drivers/net/wireless/marvell/mwifiex/tdls.c b/drivers/net/wireless/marvell/mwifiex/tdls.c
+index 6c60621b6cccb5..d503db3789c554 100644
+--- a/drivers/net/wireless/marvell/mwifiex/tdls.c
++++ b/drivers/net/wireless/marvell/mwifiex/tdls.c
+@@ -215,7 +215,7 @@ mwifiex_tdls_add_ht_oper(struct mwifiex_private *priv, const u8 *mac,
+ 
+ 	/* follow AP's channel bandwidth */
+ 	if (ISSUPP_CHANWIDTH40(priv->adapter->hw_dot_11n_dev_cap) &&
+-	    bss_desc->bcn_ht_cap &&
++	    bss_desc->bcn_ht_oper &&
+ 	    ISALLOWED_CHANWIDTH40(bss_desc->bcn_ht_oper->ht_param))
+ 		ht_oper->ht_param = bss_desc->bcn_ht_oper->ht_param;
+ 
+diff --git a/drivers/net/wireless/marvell/mwifiex/uap_event.c b/drivers/net/wireless/marvell/mwifiex/uap_event.c
+index 58ef5020a46a73..c7383abf064f50 100644
+--- a/drivers/net/wireless/marvell/mwifiex/uap_event.c
++++ b/drivers/net/wireless/marvell/mwifiex/uap_event.c
+@@ -123,11 +123,31 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
+ 				len = ETH_ALEN;
+ 
+ 			if (len != -1) {
++				u16 evt_len = le16_to_cpu(event->len);
++
+ 				sinfo->assoc_req_ies = &event->data[len];
+ 				len = (u8 *)sinfo->assoc_req_ies -
+ 				      (u8 *)&event->frame_control;
+-				sinfo->assoc_req_ies_len =
+-					le16_to_cpu(event->len) - (u16)len;
++
++				/*
++				 * event->len is reported by the device firmware
++				 * and is not otherwise validated.  Reject a
++				 * length that underflows the header, or that
++				 * would place the association request IEs
++				 * outside the fixed-size event_body[] buffer the
++				 * event was copied into; otherwise the IE walk
++				 * in mwifiex_set_sta_ht_cap() reads past
++				 * event_body and out of the adapter slab object.
++				 */
++				if (evt_len < len ||
++				    (u8 *)&event->frame_control + evt_len >
++				    adapter->event_body + MAX_EVENT_SIZE) {
++					mwifiex_dbg(adapter, ERROR,
++						    "invalid STA assoc event length\n");
++					kfree(sinfo);
++					return -1;
++				}
++				sinfo->assoc_req_ies_len = evt_len - (u16)len;
+ 			}
+ 		}
+ 		cfg80211_new_sta(priv->netdev, event->sta_addr, sinfo,
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+index 1e473f490b4bd3..4f416ebabe86e9 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+@@ -1612,6 +1612,8 @@ bool mt7615_rx_check(struct mt76_dev *mdev, void *data, int len)
+ 
+ 	switch (type) {
+ 	case PKT_TYPE_TXRX_NOTIFY:
++		if (!mt76_is_mmio(mdev))
++			return false;
+ 		mt7615_mac_tx_free(dev, data, len);
+ 		return false;
+ 	case PKT_TYPE_TXS:
+@@ -1645,6 +1647,10 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ 		dev_kfree_skb(skb);
+ 		break;
+ 	case PKT_TYPE_TXRX_NOTIFY:
++		if (!mt76_is_mmio(mdev)) {
++			dev_kfree_skb(skb);
++			break;
++		}
+ 		mt7615_mac_tx_free(dev, skb->data, skb->len);
+ 		dev_kfree_skb(skb);
+ 		break;
+diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+index a388078cdaa2ca..ef1e68154bb611 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+@@ -1406,6 +1406,8 @@ mt76_connac_mcu_uni_bss_he_tlv(struct mt76_phy *phy, struct ieee80211_vif *vif,
+ 	struct bss_info_uni_he *he;
+ 
+ 	cap = mt76_connac_get_he_phy_cap(phy, vif);
++	if (!cap)
++		return;
+ 
+ 	he = (struct bss_info_uni_he *)tlv;
+ 	he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+index f826089396e489..9ac95f14fdaf9f 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+@@ -545,6 +545,8 @@ mt7915_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ 	struct tlv *tlv;
+ 
+ 	cap = mt76_connac_get_he_phy_cap(phy->mt76, vif);
++	if (!cap)
++		return;
+ 
+ 	tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_HE_BASIC, sizeof(*he));
+ 
+@@ -1125,13 +1127,12 @@ mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
+ }
+ 
+ static void
+-mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+-		       struct mt7915_phy *phy, struct sta_rec_bf *bf)
++mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta,
++		       const struct ieee80211_sta_he_cap *vc,
++		       struct sta_rec_bf *bf)
+ {
+ 	struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap;
+ 	struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
+-	const struct ieee80211_sta_he_cap *vc =
+-		mt76_connac_get_he_phy_cap(phy->mt76, vif);
+ 	const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem;
+ 	u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80);
+ 	u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
+@@ -1190,6 +1191,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+ {
+ 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ 	struct mt7915_phy *phy = mvif->phy;
++	const struct ieee80211_sta_he_cap *vc = NULL;
+ 	int tx_ant = hweight8(phy->mt76->chainmask) - 1;
+ 	struct sta_rec_bf *bf;
+ 	struct tlv *tlv;
+@@ -1208,6 +1210,12 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+ 	if (!ebf && !dev->ibf)
+ 		return;
+ 
++	if (sta->deflink.he_cap.has_he && ebf) {
++		vc = mt76_connac_get_he_phy_cap(phy->mt76, vif);
++		if (!vc)
++			return;
++	}
++
+ 	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));
+ 	bf = (struct sta_rec_bf *)tlv;
+ 
+@@ -1216,7 +1224,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+ 	 * ht: iBF only, since mac80211 lacks of eBF support
+ 	 */
+ 	if (sta->deflink.he_cap.has_he && ebf)
+-		mt7915_mcu_sta_bfer_he(sta, vif, phy, bf);
++		mt7915_mcu_sta_bfer_he(sta, vc, bf);
+ 	else if (sta->deflink.vht_cap.vht_supported)
+ 		mt7915_mcu_sta_bfer_vht(sta, phy, bf, ebf);
+ 	else if (sta->deflink.ht_cap.ht_supported)
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+index 5099e6f79448fc..795b4df4bdb64c 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+@@ -575,8 +575,9 @@ bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len)
+ 
+ 	switch (type) {
+ 	case PKT_TYPE_TXRX_NOTIFY:
+-		/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */
+-		mt7921_mac_tx_free(dev, data, len); /* mmio */
++		if (!mt76_is_mmio(mdev))
++			return false;
++		mt7921_mac_tx_free(dev, data, len);
+ 		return false;
+ 	case PKT_TYPE_TXS:
+ 		for (rxd += 2; rxd + 8 <= end; rxd += 8)
+@@ -605,7 +606,10 @@ void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ 
+ 	switch (type) {
+ 	case PKT_TYPE_TXRX_NOTIFY:
+-		/* PKT_TYPE_TXRX_NOTIFY can be received only by mmio devices */
++		if (!mt76_is_mmio(mdev)) {
++			napi_consume_skb(skb, 1);
++			break;
++		}
+ 		mt7921_mac_tx_free(dev, skb->data, skb->len);
+ 		napi_consume_skb(skb, 1);
+ 		break;
+diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+index 9f8c312b64d75c..2abc8d15ea8522 100644
+--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
++++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+@@ -583,6 +583,8 @@ mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ 	struct tlv *tlv;
+ 
+ 	cap = mt76_connac_get_he_phy_cap(phy->mt76, vif);
++	if (!cap)
++		return;
+ 
+ 	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he));
+ 
+@@ -1293,17 +1295,18 @@ mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+ {
+ 	struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap;
+ 	struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
+-	const struct ieee80211_sta_he_cap *vc =
+-		mt76_connac_get_he_phy_cap(phy->mt76, vif);
+-	const struct ieee80211_he_cap_elem *ve = &vc->he_cap_elem;
+ 	u16 mcs_map = le16_to_cpu(pc->he_mcs_nss_supp.rx_mcs_80);
+ 	u8 nss_mcs = mt7996_mcu_get_sta_nss(mcs_map);
++	const struct ieee80211_he_cap_elem *ve;
++	const struct ieee80211_sta_he_cap *vc;
+ 	u8 snd_dim, sts;
+ 
++	vc = mt76_connac_get_he_phy_cap(phy->mt76, vif);
+ 	if (!vc)
+ 		return;
+ 
+ 	bf->tx_mode = MT_PHY_TYPE_HE_SU;
++	ve = &vc->he_cap_elem;
+ 
+ 	mt7996_mcu_sta_sounding_rate(bf);
+ 
+@@ -1357,14 +1360,18 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+ 	struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap;
+ 	struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
+ 	struct ieee80211_eht_mcs_nss_supp *eht_nss = &pc->eht_mcs_nss_supp;
+-	const struct ieee80211_sta_eht_cap *vc =
+-		mt76_connac_get_eht_phy_cap(phy->mt76, vif);
+-	const struct ieee80211_eht_cap_elem_fixed *ve = &vc->eht_cap_elem;
+ 	u8 nss_mcs = u8_get_bits(eht_nss->bw._80.rx_tx_mcs9_max_nss,
+ 				 IEEE80211_EHT_MCS_NSS_RX) - 1;
++	const struct ieee80211_eht_cap_elem_fixed *ve;
++	const struct ieee80211_sta_eht_cap *vc;
+ 	u8 snd_dim, sts;
+ 
++	vc = mt76_connac_get_eht_phy_cap(phy->mt76, vif);
++	if (!vc)
++		return;
++
+ 	bf->tx_mode = MT_PHY_TYPE_EHT_MU;
++	ve = &vc->eht_cap_elem;
+ 
+ 	mt7996_mcu_sta_sounding_rate(bf);
+ 
+diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c
+index 91122e7be41338..ef162f0f50ba1a 100644
+--- a/drivers/net/wireless/microchip/wilc1000/hif.c
++++ b/drivers/net/wireless/microchip/wilc1000/hif.c
+@@ -597,6 +597,11 @@ static s32 wilc_parse_assoc_resp_info(u8 *buffer, u32 buffer_len,
+ 	u16 ies_len;
+ 	struct wilc_assoc_resp *res = (struct wilc_assoc_resp *)buffer;
+ 
++	if (buffer_len < sizeof(*res)) {
++		ret_conn_info->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
++		return -EINVAL;
++	}
++
+ 	ret_conn_info->status = le16_to_cpu(res->status_code);
+ 	if (ret_conn_info->status == WLAN_STATUS_SUCCESS) {
+ 		ies = &buffer[sizeof(*res)];
+diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c
+index bf12ff0ab06ab3..c9bfea77d0ecae 100644
+--- a/drivers/net/wireless/virtual/mac80211_hwsim.c
++++ b/drivers/net/wireless/virtual/mac80211_hwsim.c
+@@ -6383,6 +6383,7 @@ static void hwsim_virtio_rx_work(struct work_struct *work)
+ 
+ 	skb->data = skb->head;
+ 	skb_reset_tail_pointer(skb);
++	len = min(len, skb_end_offset(skb));
+ 	skb_put(skb, len);
+ 	hwsim_virtio_handle_cmd(skb);
+ 
+diff --git a/drivers/pinctrl/cirrus/pinctrl-cs42l43.c b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
+index 53229faa5cc5b2..bd4a92e77f2a7f 100644
+--- a/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
++++ b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
+@@ -508,7 +508,7 @@ static void cs42l43_gpio_set(struct gpio_chip *chip, unsigned int offset, int va
+ 
+ static int cs42l43_gpio_direction_in(struct gpio_chip *chip, unsigned int offset)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + offset);
++	return pinctrl_gpio_direction_input(chip, offset);
+ }
+ 
+ static int cs42l43_gpio_direction_out(struct gpio_chip *chip,
+@@ -516,7 +516,7 @@ static int cs42l43_gpio_direction_out(struct gpio_chip *chip,
+ {
+ 	cs42l43_gpio_set(chip, offset, value);
+ 
+-	return pinctrl_gpio_direction_output(chip->base + offset);
++	return pinctrl_gpio_direction_output(chip, offset);
+ }
+ 
+ static int cs42l43_gpio_add_pin_ranges(struct gpio_chip *chip)
+diff --git a/drivers/pinctrl/cirrus/pinctrl-lochnagar.c b/drivers/pinctrl/cirrus/pinctrl-lochnagar.c
+index 0b78cf611afe00..014297a3fbd287 100644
+--- a/drivers/pinctrl/cirrus/pinctrl-lochnagar.c
++++ b/drivers/pinctrl/cirrus/pinctrl-lochnagar.c
+@@ -1098,7 +1098,7 @@ static int lochnagar_gpio_direction_out(struct gpio_chip *chip,
+ {
+ 	lochnagar_gpio_set(chip, offset, value);
+ 
+-	return pinctrl_gpio_direction_output(chip->base + offset);
++	return pinctrl_gpio_direction_output(chip, offset);
+ }
+ 
+ static int lochnagar_fill_func_groups(struct lochnagar_pin_priv *priv)
+diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c
+index 7342148c657298..f8d084f9fbfc0b 100644
+--- a/drivers/pinctrl/core.c
++++ b/drivers/pinctrl/core.c
+@@ -874,29 +874,31 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input)
+ 
+ /**
+  * pinctrl_gpio_direction_input() - request a GPIO pin to go into input mode
+- * @gpio: the GPIO pin number from the GPIO subsystem number space
++ * @gc: GPIO chip structure from the GPIO subsystem
++ * @offset: hardware offset of the GPIO relative to the controller
+  *
+  * This function should *ONLY* be used from gpiolib-based GPIO drivers,
+  * as part of their gpio_direction_input() semantics, platforms and individual
+  * drivers shall *NOT* touch pin control GPIO calls.
+  */
+-int pinctrl_gpio_direction_input(unsigned gpio)
++int pinctrl_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+ {
+-	return pinctrl_gpio_direction(gpio, true);
++	return pinctrl_gpio_direction(gc->base + offset, true);
+ }
+ EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_input);
+ 
+ /**
+  * pinctrl_gpio_direction_output() - request a GPIO pin to go into output mode
+- * @gpio: the GPIO pin number from the GPIO subsystem number space
++ * @gc: GPIO chip structure from the GPIO subsystem
++ * @offset: hardware offset of the GPIO relative to the controller
+  *
+  * This function should *ONLY* be used from gpiolib-based GPIO drivers,
+  * as part of their gpio_direction_output() semantics, platforms and individual
+  * drivers shall *NOT* touch pin control GPIO calls.
+  */
+-int pinctrl_gpio_direction_output(unsigned gpio)
++int pinctrl_gpio_direction_output(struct gpio_chip *gc, unsigned int offset)
+ {
+-	return pinctrl_gpio_direction(gpio, false);
++	return pinctrl_gpio_direction(gc->base + offset, false);
+ }
+ EXPORT_SYMBOL_GPL(pinctrl_gpio_direction_output);
+ 
+diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
+index 81ee949b946d55..6ab5953b858ac9 100644
+--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
++++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
+@@ -1172,14 +1172,14 @@ static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+ 
+ static int chv_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + offset);
++	return pinctrl_gpio_direction_input(chip, offset);
+ }
+ 
+ static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
+ 				     int value)
+ {
+ 	chv_gpio_set(chip, offset, value);
+-	return pinctrl_gpio_direction_output(chip->base + offset);
++	return pinctrl_gpio_direction_output(chip, offset);
+ }
+ 
+ static const struct gpio_chip chv_gpio_chip = {
+diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
+index b1ce3daae8e856..0f71f554f79fc2 100644
+--- a/drivers/pinctrl/intel/pinctrl-intel.c
++++ b/drivers/pinctrl/intel/pinctrl-intel.c
+@@ -1026,14 +1026,14 @@ static int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+ 
+ static int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + offset);
++	return pinctrl_gpio_direction_input(chip, offset);
+ }
+ 
+ static int intel_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
+ 				       int value)
+ {
+ 	intel_gpio_set(chip, offset, value);
+-	return pinctrl_gpio_direction_output(chip->base + offset);
++	return pinctrl_gpio_direction_output(chip, offset);
+ }
+ 
+ static const struct gpio_chip intel_gpio_chip = {
+diff --git a/drivers/pinctrl/intel/pinctrl-lynxpoint.c b/drivers/pinctrl/intel/pinctrl-lynxpoint.c
+index c3732a9f065862..42cadb15909782 100644
+--- a/drivers/pinctrl/intel/pinctrl-lynxpoint.c
++++ b/drivers/pinctrl/intel/pinctrl-lynxpoint.c
+@@ -545,7 +545,7 @@ static void lp_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+ 
+ static int lp_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + offset);
++	return pinctrl_gpio_direction_input(chip, offset);
+ }
+ 
+ static int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
+@@ -553,7 +553,7 @@ static int lp_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
+ {
+ 	lp_gpio_set(chip, offset, value);
+ 
+-	return pinctrl_gpio_direction_output(chip->base + offset);
++	return pinctrl_gpio_direction_output(chip, offset);
+ }
+ 
+ static int lp_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+diff --git a/drivers/pinctrl/mediatek/pinctrl-moore.c b/drivers/pinctrl/mediatek/pinctrl-moore.c
+index 8649a2f9d324d9..c3b559cc164431 100644
+--- a/drivers/pinctrl/mediatek/pinctrl-moore.c
++++ b/drivers/pinctrl/mediatek/pinctrl-moore.c
+@@ -509,7 +509,7 @@ static void mtk_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value)
+ 
+ static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + gpio);
++	return pinctrl_gpio_direction_input(chip, gpio);
+ }
+ 
+ static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
+@@ -517,7 +517,7 @@ static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
+ {
+ 	mtk_gpio_set(chip, gpio, value);
+ 
+-	return pinctrl_gpio_direction_output(chip->base + gpio);
++	return pinctrl_gpio_direction_output(chip, gpio);
+ }
+ 
+ static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+index 7066fab7621e93..167df3c7336fbb 100644
+--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
++++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+@@ -811,14 +811,14 @@ static const struct pinmux_ops mtk_pmx_ops = {
+ static int mtk_gpio_direction_input(struct gpio_chip *chip,
+ 					unsigned offset)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + offset);
++	return pinctrl_gpio_direction_input(chip, offset);
+ }
+ 
+ static int mtk_gpio_direction_output(struct gpio_chip *chip,
+ 					unsigned offset, int value)
+ {
+ 	mtk_gpio_set(chip, offset, value);
+-	return pinctrl_gpio_direction_output(chip->base + offset);
++	return pinctrl_gpio_direction_output(chip, offset);
+ }
+ 
+ static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+diff --git a/drivers/pinctrl/mediatek/pinctrl-paris.c b/drivers/pinctrl/mediatek/pinctrl-paris.c
+index 9cd7fe3c3e0df1..2d0b970168a334 100644
+--- a/drivers/pinctrl/mediatek/pinctrl-paris.c
++++ b/drivers/pinctrl/mediatek/pinctrl-paris.c
+@@ -904,7 +904,7 @@ static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned int gpio)
+ 	if (gpio >= hw->soc->npins)
+ 		return -EINVAL;
+ 
+-	return pinctrl_gpio_direction_input(chip->base + gpio);
++	return pinctrl_gpio_direction_input(chip, gpio);
+ }
+ 
+ static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
+@@ -917,7 +917,7 @@ static int mtk_gpio_direction_output(struct gpio_chip *chip, unsigned int gpio,
+ 
+ 	mtk_gpio_set(chip, gpio, value);
+ 
+-	return pinctrl_gpio_direction_output(chip->base + gpio);
++	return pinctrl_gpio_direction_output(chip, gpio);
+ }
+ 
+ static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
+diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
+index 843ffcd9687747..015f97f996c6f1 100644
+--- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
++++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c
+@@ -171,7 +171,7 @@ static int npcmgpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+ 	struct npcm7xx_gpio *bank = gpiochip_get_data(chip);
+ 	int ret;
+ 
+-	ret = pinctrl_gpio_direction_input(offset + chip->base);
++	ret = pinctrl_gpio_direction_input(chip, offset);
+ 	if (ret)
+ 		return ret;
+ 
+@@ -188,7 +188,7 @@ static int npcmgpio_direction_output(struct gpio_chip *chip,
+ 	dev_dbg(chip->parent, "gpio_direction_output: offset%d = %x\n", offset,
+ 		value);
+ 
+-	ret = pinctrl_gpio_direction_output(offset + chip->base);
++	ret = pinctrl_gpio_direction_output(chip, offset);
+ 	if (ret)
+ 		return ret;
+ 
+diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c
+index f0e5d87ac50b92..4151656f6245f5 100644
+--- a/drivers/pinctrl/pinctrl-as3722.c
++++ b/drivers/pinctrl/pinctrl-as3722.c
+@@ -502,14 +502,14 @@ static void as3722_gpio_set(struct gpio_chip *chip, unsigned offset,
+ 
+ static int as3722_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + offset);
++	return pinctrl_gpio_direction_input(chip, offset);
+ }
+ 
+ static int as3722_gpio_direction_output(struct gpio_chip *chip,
+ 		unsigned offset, int value)
+ {
+ 	as3722_gpio_set(chip, offset, value);
+-	return pinctrl_gpio_direction_output(chip->base + offset);
++	return pinctrl_gpio_direction_output(chip, offset);
+ }
+ 
+ static int as3722_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c
+index 9f5b3ab8e184b2..a6eb3b866a2314 100644
+--- a/drivers/pinctrl/pinctrl-axp209.c
++++ b/drivers/pinctrl/pinctrl-axp209.c
+@@ -126,7 +126,7 @@ static int axp20x_gpio_get_reg(unsigned int offset)
+ 
+ static int axp20x_gpio_input(struct gpio_chip *chip, unsigned int offset)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + offset);
++	return pinctrl_gpio_direction_input(chip, offset);
+ }
+ 
+ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset)
+diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c
+index 727f3c5605ced2..910b87973f086e 100644
+--- a/drivers/pinctrl/pinctrl-cy8c95x0.c
++++ b/drivers/pinctrl/pinctrl-cy8c95x0.c
+@@ -557,7 +557,7 @@ out:
+ 
+ static int cy8c95x0_gpio_direction_input(struct gpio_chip *gc, unsigned int off)
+ {
+-	return pinctrl_gpio_direction_input(gc->base + off);
++	return pinctrl_gpio_direction_input(gc, off);
+ }
+ 
+ static int cy8c95x0_gpio_direction_output(struct gpio_chip *gc,
+@@ -574,7 +574,7 @@ static int cy8c95x0_gpio_direction_output(struct gpio_chip *gc,
+ 	if (ret)
+ 		return ret;
+ 
+-	return pinctrl_gpio_direction_output(gc->base + off);
++	return pinctrl_gpio_direction_output(gc, off);
+ }
+ 
+ static int cy8c95x0_gpio_get_value(struct gpio_chip *gc, unsigned int off)
+diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c
+index 2f220a47b74978..ca58c9db5c2cce 100644
+--- a/drivers/pinctrl/pinctrl-ingenic.c
++++ b/drivers/pinctrl/pinctrl-ingenic.c
+@@ -133,6 +133,8 @@ struct ingenic_pinctrl {
+ 	struct pinctrl_pin_desc *pdesc;
+ 
+ 	const struct ingenic_chip_info *info;
++
++	struct gpio_chip *gc;
+ };
+ 
+ struct ingenic_gpio_chip {
+@@ -3561,14 +3563,14 @@ static int ingenic_gpio_get(struct gpio_chip *gc, unsigned int offset)
+ static int ingenic_gpio_direction_input(struct gpio_chip *gc,
+ 		unsigned int offset)
+ {
+-	return pinctrl_gpio_direction_input(gc->base + offset);
++	return pinctrl_gpio_direction_input(gc, offset);
+ }
+ 
+ static int ingenic_gpio_direction_output(struct gpio_chip *gc,
+ 		unsigned int offset, int value)
+ {
+ 	ingenic_gpio_set(gc, offset, value);
+-	return pinctrl_gpio_direction_output(gc->base + offset);
++	return pinctrl_gpio_direction_output(gc, offset);
+ }
+ 
+ static inline void ingenic_config_pin(struct ingenic_pinctrl *jzpc,
+@@ -4052,7 +4054,8 @@ static int ingenic_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ 			break;
+ 
+ 		case PIN_CONFIG_OUTPUT:
+-			ret = pinctrl_gpio_direction_output(pin);
++			ret = pinctrl_gpio_direction_output(jzpc->gc,
++							pin - jzpc->gc->base);
+ 			if (ret)
+ 				return ret;
+ 
+@@ -4172,6 +4175,8 @@ static int __init ingenic_gpio_probe(struct ingenic_pinctrl *jzpc,
+ 	if (!jzgc)
+ 		return -ENOMEM;
+ 
++	jzpc->gc = &jzgc->gc;
++
+ 	jzgc->jzpc = jzpc;
+ 	jzgc->reg_base = bank * jzpc->info->reg_offset;
+ 
+diff --git a/drivers/pinctrl/pinctrl-ocelot.c b/drivers/pinctrl/pinctrl-ocelot.c
+index 8d26c8061c77eb..d518b23e2f91a0 100644
+--- a/drivers/pinctrl/pinctrl-ocelot.c
++++ b/drivers/pinctrl/pinctrl-ocelot.c
+@@ -1779,7 +1779,7 @@ static int ocelot_gpio_get_direction(struct gpio_chip *chip,
+ static int ocelot_gpio_direction_input(struct gpio_chip *chip,
+ 				       unsigned int offset)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + offset);
++	return pinctrl_gpio_direction_input(chip, offset);
+ }
+ 
+ static int ocelot_gpio_direction_output(struct gpio_chip *chip,
+@@ -1795,7 +1795,7 @@ static int ocelot_gpio_direction_output(struct gpio_chip *chip,
+ 		regmap_write(info->map, REG(OCELOT_GPIO_OUT_CLR, info, offset),
+ 			     pin);
+ 
+-	return pinctrl_gpio_direction_output(chip->base + offset);
++	return pinctrl_gpio_direction_output(chip, offset);
+ }
+ 
+ static const struct gpio_chip ocelot_gpiolib_chip = {
+diff --git a/drivers/pinctrl/pinctrl-rk805.c b/drivers/pinctrl/pinctrl-rk805.c
+index 2639a9ee82cd0f..968f066eb9dae2 100644
+--- a/drivers/pinctrl/pinctrl-rk805.c
++++ b/drivers/pinctrl/pinctrl-rk805.c
+@@ -289,14 +289,14 @@ static void rk805_gpio_set(struct gpio_chip *chip,
+ static int rk805_gpio_direction_input(struct gpio_chip *chip,
+ 				      unsigned int offset)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + offset);
++	return pinctrl_gpio_direction_input(chip, offset);
+ }
+ 
+ static int rk805_gpio_direction_output(struct gpio_chip *chip,
+ 				       unsigned int offset, int value)
+ {
+ 	rk805_gpio_set(chip, offset, value);
+-	return pinctrl_gpio_direction_output(chip->base + offset);
++	return pinctrl_gpio_direction_output(chip, offset);
+ }
+ 
+ static int rk805_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
+diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
+index c1f36b164ea5de..db511dbd50e5c7 100644
+--- a/drivers/pinctrl/pinctrl-st.c
++++ b/drivers/pinctrl/pinctrl-st.c
+@@ -719,7 +719,7 @@ static void st_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+ 
+ static int st_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+ {
+-	pinctrl_gpio_direction_input(chip->base + offset);
++	pinctrl_gpio_direction_input(chip, offset);
+ 
+ 	return 0;
+ }
+@@ -730,7 +730,7 @@ static int st_gpio_direction_output(struct gpio_chip *chip,
+ 	struct st_gpio_bank *bank = gpiochip_get_data(chip);
+ 
+ 	__st_gpio_set(bank, offset, value);
+-	pinctrl_gpio_direction_output(chip->base + offset);
++	pinctrl_gpio_direction_output(chip, offset);
+ 
+ 	return 0;
+ }
+diff --git a/drivers/pinctrl/renesas/gpio.c b/drivers/pinctrl/renesas/gpio.c
+index 5758daf94fe2e8..dbe27117a859bf 100644
+--- a/drivers/pinctrl/renesas/gpio.c
++++ b/drivers/pinctrl/renesas/gpio.c
+@@ -164,7 +164,7 @@ static void gpio_pin_set_value(struct sh_pfc_chip *chip, unsigned offset,
+ 
+ static int gpio_pin_direction_input(struct gpio_chip *gc, unsigned offset)
+ {
+-	return pinctrl_gpio_direction_input(gc->base + offset);
++	return pinctrl_gpio_direction_input(gc, offset);
+ }
+ 
+ static int gpio_pin_direction_output(struct gpio_chip *gc, unsigned offset,
+@@ -172,7 +172,7 @@ static int gpio_pin_direction_output(struct gpio_chip *gc, unsigned offset,
+ {
+ 	gpio_pin_set_value(gpiochip_get_data(gc), offset, value);
+ 
+-	return pinctrl_gpio_direction_output(gc->base + offset);
++	return pinctrl_gpio_direction_output(gc, offset);
+ }
+ 
+ static int gpio_pin_get(struct gpio_chip *gc, unsigned offset)
+diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c
+index ac96523e07b8df..bfc10cf9ab9753 100644
+--- a/drivers/pinctrl/stm32/pinctrl-stm32.c
++++ b/drivers/pinctrl/stm32/pinctrl-stm32.c
+@@ -241,7 +241,7 @@ static void stm32_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+ 
+ static int stm32_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + offset);
++	return pinctrl_gpio_direction_input(chip, offset);
+ }
+ 
+ static int stm32_gpio_direction_output(struct gpio_chip *chip,
+@@ -250,7 +250,7 @@ static int stm32_gpio_direction_output(struct gpio_chip *chip,
+ 	struct stm32_gpio_bank *bank = gpiochip_get_data(chip);
+ 
+ 	__stm32_gpio_set(bank, offset, value);
+-	pinctrl_gpio_direction_output(chip->base + offset);
++	pinctrl_gpio_direction_output(chip, offset);
+ 
+ 	return 0;
+ }
+diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
+index 6fac30de1c6a88..639446bba37360 100644
+--- a/drivers/pinctrl/vt8500/pinctrl-wmt.c
++++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
+@@ -528,14 +528,14 @@ static void wmt_gpio_set_value(struct gpio_chip *chip, unsigned offset,
+ 
+ static int wmt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+ {
+-	return pinctrl_gpio_direction_input(chip->base + offset);
++	return pinctrl_gpio_direction_input(chip, offset);
+ }
+ 
+ static int wmt_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ 				     int value)
+ {
+ 	wmt_gpio_set_value(chip, offset, value);
+-	return pinctrl_gpio_direction_output(chip->base + offset);
++	return pinctrl_gpio_direction_output(chip, offset);
+ }
+ 
+ static const struct gpio_chip wmt_gpio_chip = {
+diff --git a/drivers/platform/loongarch/loongson-laptop.c b/drivers/platform/loongarch/loongson-laptop.c
+index 5fcfa3a7970b75..f3adee7515d346 100644
+--- a/drivers/platform/loongarch/loongson-laptop.c
++++ b/drivers/platform/loongarch/loongson-laptop.c
+@@ -189,6 +189,7 @@ static int __init setup_acpi_notify(struct generic_sub_driver *sub_driver)
+ 
+ static int loongson_hotkey_suspend(struct device *dev)
+ {
++	bl_powered = false;
+ 	return 0;
+ }
+ 
+diff --git a/drivers/platform/x86/amd/pmc/pmc.c b/drivers/platform/x86/amd/pmc/pmc.c
+index d5b543f74a22db..bf6c7ca247e243 100644
+--- a/drivers/platform/x86/amd/pmc/pmc.c
++++ b/drivers/platform/x86/amd/pmc/pmc.c
+@@ -811,6 +811,20 @@ static bool amd_pmc_intermediate_wakeup_need_delay(struct amd_pmc_dev *pdev)
+ 
+ static bool amd_pmc_want_suspend_delay(struct amd_pmc_dev *pdev)
+ {
++	/*
++	 * intermediate_wakeup implies that the machine didn't get to deepest sleep
++	 * state before - otherwise this function isn't called in amd_pmc_s2idle_check()
++	 * because amd_pmc_intermediate_wakeup_need_delay() returns true first.
++	 * On some IdeaPads that happens when charging, because the EC seems
++	 * to send lots of messages then that wake the machine.
++	 *
++	 * But even in that case, the sleep here is necessary (on those IdeaPads),
++	 * otherwise they wake up completely (resume) after a few seconds.
++	 * So this variable is only used to avoid spamming dmesg on each
++	 * intermediate wakeup.
++	 */
++	bool intermediate_wakeup = !pdev->is_first_check_after_suspend;
++
+ 	/*
+ 	 * Some Lenovo Laptops (like different IdeaPad 3 Slims) need some
+ 	 * me-time before sleeping or they get uncooperative after waking
+@@ -829,17 +843,20 @@ static bool amd_pmc_want_suspend_delay(struct amd_pmc_dev *pdev)
+ 		 * disabled with disable_workarounds or delay_suspend=0
+ 		 */
+ 		if (delay_suspend == 1 || (delay_suspend == -1 && !disable_workarounds)) {
+-			dev_info(pdev->dev, "Delaying suspend by 2.5s to avoid platform bug\n");
++			if (!intermediate_wakeup)
++				dev_info(pdev->dev, "Delaying suspend by 2.5s to avoid platform bug\n");
+ 			return true;
+ 		}
+-		dev_info(pdev->dev, "Not delaying suspend because of module parameter, even though your device is assumed to need it!\n");
++		if (!intermediate_wakeup)
++			dev_info(pdev->dev, "Not delaying suspend because of module parameter, even though your device is assumed to need it!\n");
+ 	} else if (delay_suspend == 1) {
+-		dev_info(pdev->dev, "Delaying suspend by 2.5s because delay_suspend=1. If this solves problems on your machine, please report this whole line to: [email protected] so it can be automatically detected as affected in the future. System Vendor: \"%s\" Product Name: \"%s\" Product Family: \"%s\" Board Vendor: \"%s\" Board Name: \"%s\"\n",
+-			 dmi_get_system_info(DMI_SYS_VENDOR),
+-			 dmi_get_system_info(DMI_PRODUCT_NAME),
+-			 dmi_get_system_info(DMI_PRODUCT_FAMILY),
+-			 dmi_get_system_info(DMI_BOARD_VENDOR),
+-			 dmi_get_system_info(DMI_BOARD_NAME));
++		if (!intermediate_wakeup)
++			dev_info(pdev->dev, "Delaying suspend by 2.5s because delay_suspend=1. If this solves problems on your machine, please report this whole line to: [email protected] so it can be automatically detected as affected in the future. System Vendor: \"%s\" Product Name: \"%s\" Product Family: \"%s\" Board Vendor: \"%s\" Board Name: \"%s\"\n",
++				 dmi_get_system_info(DMI_SYS_VENDOR) ?: "(Unknown)",
++				 dmi_get_system_info(DMI_PRODUCT_NAME) ?: "(Unknown)",
++				 dmi_get_system_info(DMI_PRODUCT_FAMILY) ?: "(Unknown)",
++				 dmi_get_system_info(DMI_BOARD_VENDOR) ?: "(Unknown)",
++				 dmi_get_system_info(DMI_BOARD_NAME) ?: "(Unknown)");
+ 		return true;
+ 	}
+ 	return false;
+@@ -852,6 +869,9 @@ static void amd_pmc_s2idle_prepare(void)
+ 	u8 msg;
+ 	u32 arg = 1;
+ 
++	/* Reset this variable because this is a fresh suspend */
++	pdev->is_first_check_after_suspend = true;
++
+ 	/* Reset and Start SMU logging - to monitor the s0i3 stats */
+ 	amd_pmc_setup_smu_logging(pdev);
+ 
+@@ -891,6 +911,9 @@ static void amd_pmc_s2idle_check(void)
+ 	rc = amd_pmc_write_stb(pdev, AMD_PMC_STB_S2IDLE_CHECK);
+ 	if (rc)
+ 		dev_err(pdev->dev, "error writing to STB: %d\n", rc);
++
++	/* remember that first check after suspend is done (until next prepare) */
++	pdev->is_first_check_after_suspend = false;
+ }
+ 
+ static int amd_pmc_dump_data(struct amd_pmc_dev *pdev)
+diff --git a/drivers/platform/x86/amd/pmc/pmc.h b/drivers/platform/x86/amd/pmc/pmc.h
+index 5e7b8d5dc5d624..bea65810de5ab6 100644
+--- a/drivers/platform/x86/amd/pmc/pmc.h
++++ b/drivers/platform/x86/amd/pmc/pmc.h
+@@ -37,6 +37,7 @@ struct amd_pmc_dev {
+ 	struct dentry *dbgfs_dir;
+ 	struct quirk_entry *quirks;
+ 	bool disable_8042_wakeup;
++	bool is_first_check_after_suspend;
+ };
+ 
+ void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev);
+diff --git a/drivers/platform/x86/dell/dell-laptop.c b/drivers/platform/x86/dell/dell-laptop.c
+index 6586438356de76..d151202bc99499 100644
+--- a/drivers/platform/x86/dell/dell-laptop.c
++++ b/drivers/platform/x86/dell/dell-laptop.c
+@@ -353,29 +353,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
+ 	{ }
+ };
+ 
+-static void dell_fill_request(struct calling_interface_buffer *buffer,
+-			       u32 arg0, u32 arg1, u32 arg2, u32 arg3)
+-{
+-	memset(buffer, 0, sizeof(struct calling_interface_buffer));
+-	buffer->input[0] = arg0;
+-	buffer->input[1] = arg1;
+-	buffer->input[2] = arg2;
+-	buffer->input[3] = arg3;
+-}
+-
+-static int dell_send_request(struct calling_interface_buffer *buffer,
+-			     u16 class, u16 select)
+-{
+-	int ret;
+-
+-	buffer->cmd_class = class;
+-	buffer->cmd_select = select;
+-	ret = dell_smbios_call(buffer);
+-	if (ret != 0)
+-		return ret;
+-	return dell_smbios_error(buffer->output[0]);
+-}
+-
+ /*
+  * Derived from information in smbios-wireless-ctl:
+  *
+@@ -2318,6 +2295,11 @@ fail_backlight:
+ 	if (mute_led_registered)
+ 		led_classdev_unregister(&mute_led_cdev);
+ fail_led:
++	dell_laptop_unregister_notifier(&dell_laptop_notifier);
++	debugfs_remove_recursive(dell_laptop_dir);
++	kbd_led_exit();
++	if (quirks && quirks->touchpad_led)
++		touchpad_led_exit();
+ 	dell_cleanup_rfkill();
+ fail_rfkill:
+ 	platform_device_del(platform_device);
+diff --git a/drivers/platform/x86/dell/dell-smbios-base.c b/drivers/platform/x86/dell/dell-smbios-base.c
+index 9a9b9feac41664..636d881c947770 100644
+--- a/drivers/platform/x86/dell/dell-smbios-base.c
++++ b/drivers/platform/x86/dell/dell-smbios-base.c
+@@ -320,6 +320,31 @@ out_smbios_call:
+ }
+ EXPORT_SYMBOL_GPL(dell_smbios_call);
+ 
++void dell_fill_request(struct calling_interface_buffer *buffer,
++			       u32 arg0, u32 arg1, u32 arg2, u32 arg3)
++{
++	memset(buffer, 0, sizeof(struct calling_interface_buffer));
++	buffer->input[0] = arg0;
++	buffer->input[1] = arg1;
++	buffer->input[2] = arg2;
++	buffer->input[3] = arg3;
++}
++EXPORT_SYMBOL_GPL(dell_fill_request);
++
++int dell_send_request(struct calling_interface_buffer *buffer,
++			     u16 class, u16 select)
++{
++	int ret;
++
++	buffer->cmd_class = class;
++	buffer->cmd_select = select;
++	ret = dell_smbios_call(buffer);
++	if (ret != 0)
++		return ret;
++	return dell_smbios_error(buffer->output[0]);
++}
++EXPORT_SYMBOL_GPL(dell_send_request);
++
+ struct calling_interface_token *dell_smbios_find_token(int tokenid)
+ {
+ 	int i;
+diff --git a/drivers/platform/x86/dell/dell-smbios.h b/drivers/platform/x86/dell/dell-smbios.h
+index eb341bf000c675..641f18c2f7e6e4 100644
+--- a/drivers/platform/x86/dell/dell-smbios.h
++++ b/drivers/platform/x86/dell/dell-smbios.h
+@@ -64,6 +64,11 @@ int dell_smbios_call_filter(struct device *d,
+ 	struct calling_interface_buffer *buffer);
+ int dell_smbios_call(struct calling_interface_buffer *buffer);
+ 
++void dell_fill_request(struct calling_interface_buffer *buffer,
++			       u32 arg0, u32 arg1, u32 arg2, u32 arg3);
++int dell_send_request(struct calling_interface_buffer *buffer,
++			     u16 class, u16 select);
++
+ struct calling_interface_token *dell_smbios_find_token(int tokenid);
+ 
+ enum dell_laptop_notifier_actions {
+diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
+index 33bb58dc3f78c3..b362e0170a6256 100644
+--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
++++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
+@@ -238,14 +238,19 @@ int uncore_freq_add_entry(struct uncore_data *data, int cpu)
+ 		sprintf(data->name, "package_%02d_die_%02d", data->package_id, data->die_id);
+ 	}
+ 
++	/*
++	 * Set the control CPU before any read path so entry recreation after CPU
++	 * hotplug can populate read-only attributes from the new online CPU.
++	 */
++	data->control_cpu = cpu;
+ 	uncore_read(data, &data->initial_min_freq_khz, &data->initial_max_freq_khz);
+ 
+ 	ret = create_attr_group(data, data->name);
+ 	if (ret) {
++		data->control_cpu = -1;
+ 		if (data->domain_id != UNCORE_DOMAIN_ID_INVALID)
+ 			ida_free(&intel_uncore_ida, data->instance_id);
+ 	} else {
+-		data->control_cpu = cpu;
+ 		data->valid = true;
+ 	}
+ 
+diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c
+index 219185aaa588a4..6efbc7fa6cab63 100644
+--- a/drivers/staging/media/meson/vdec/vdec.c
++++ b/drivers/staging/media/meson/vdec/vdec.c
+@@ -897,7 +897,7 @@ static int vdec_open(struct file *file)
+ 
+ 	ret = vdec_init_ctrls(sess);
+ 	if (ret)
+-		goto err_m2m_release;
++		goto err_m2m_ctx_release;
+ 
+ 	sess->pixfmt_cap = formats[0].pixfmts_cap[0];
+ 	sess->fmt_out = &formats[0];
+@@ -922,6 +922,8 @@ static int vdec_open(struct file *file)
+ 
+ 	return 0;
+ 
++err_m2m_ctx_release:
++	v4l2_m2m_ctx_release(sess->m2m_ctx);
+ err_m2m_release:
+ 	v4l2_m2m_release(sess->m2m_dev);
+ err_free_sess:
+diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c
+index a0f9f4a5b03a12..dc9ed1d0ff3afe 100644
+--- a/drivers/staging/media/sunxi/cedrus/cedrus.c
++++ b/drivers/staging/media/sunxi/cedrus/cedrus.c
+@@ -392,6 +392,7 @@ static int cedrus_open(struct file *file)
+ err_m2m_release:
+ 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ err_free:
++	v4l2_fh_exit(&ctx->fh);
+ 	kfree(ctx);
+ 	mutex_unlock(&dev->dev_mutex);
+ 
+@@ -509,7 +510,7 @@ static int cedrus_probe(struct platform_device *pdev)
+ 	ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
+ 	if (ret) {
+ 		v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+-		goto err_m2m;
++		goto err_media;
+ 	}
+ 
+ 	v4l2_info(&dev->v4l2_dev,
+@@ -535,7 +536,8 @@ err_m2m_mc:
+ 	v4l2_m2m_unregister_media_controller(dev->m2m_dev);
+ err_video:
+ 	video_unregister_device(&dev->vfd);
+-err_m2m:
++err_media:
++	media_device_cleanup(&dev->mdev);
+ 	v4l2_m2m_release(dev->m2m_dev);
+ err_v4l2:
+ 	v4l2_device_unregister(&dev->v4l2_dev);
+diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+index dfb401df138a9e..c509fd5a6cfecd 100644
+--- a/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
++++ b/drivers/staging/media/sunxi/cedrus/cedrus_h264.c
+@@ -210,6 +210,9 @@ static void _cedrus_write_ref_list(struct cedrus_ctx *ctx,
+ 		u8 dpb_idx;
+ 
+ 		dpb_idx = ref_list[i].index;
++		if (dpb_idx >= V4L2_H264_NUM_DPB_ENTRIES)
++			continue;
++
+ 		dpb = &decode->dpb[dpb_idx];
+ 
+ 		if (!(dpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE))
+diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
+index e8ba23e5bcde0f..9c0d4661edf561 100644
+--- a/drivers/staging/media/tegra-video/vi.c
++++ b/drivers/staging/media/tegra-video/vi.c
+@@ -80,8 +80,8 @@ static int tegra_get_format_idx_by_code(struct tegra_vi *vi,
+ static u32 tegra_get_format_fourcc_by_idx(struct tegra_vi *vi,
+ 					  unsigned int index)
+ {
+-	if (index >= vi->soc->nformats)
+-		return -EINVAL;
++	if (WARN_ON_ONCE(index >= vi->soc->nformats))
++		return vi->soc->video_formats[0].fourcc;
+ 
+ 	return vi->soc->video_formats[index].fourcc;
+ }
+diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
+index 05765a3bc200c5..95e4d29242249f 100644
+--- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
++++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c
+@@ -678,7 +678,14 @@ u8 *rtw_get_wps_ie(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
+ 	while (cnt < in_len) {
+ 		eid = in_ie[cnt];
+ 
+-		if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) {
++		if (cnt + 2 > in_len)
++			break;
++
++		if (in_ie[cnt + 1] + 2 > in_len - cnt)
++			break;
++
++		if ((eid == WLAN_EID_VENDOR_SPECIFIC) && (in_ie[cnt + 1] >= 4) &&
++		    (!memcmp(&in_ie[cnt + 2], wps_oui, 4))) {
+ 			wpsie_ptr = &in_ie[cnt];
+ 
+ 			if (wps_ie)
+diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
+index 62a55d0ebd69de..557b9c6513e14a 100644
+--- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
++++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c
+@@ -1967,7 +1967,7 @@ static u8 rtw_get_chan_type(struct adapter *adapter)
+ 		else
+ 			return NL80211_CHAN_NO_HT;
+ 	case CHANNEL_WIDTH_40:
+-		if (mlme_ext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
++		if (mlme_ext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+ 			return NL80211_CHAN_HT40PLUS;
+ 		else
+ 			return NL80211_CHAN_HT40MINUS;
+diff --git a/drivers/tty/serial/8250/8250_mid.c b/drivers/tty/serial/8250/8250_mid.c
+index f88809ff370b73..82656645b8a64b 100644
+--- a/drivers/tty/serial/8250/8250_mid.c
++++ b/drivers/tty/serial/8250/8250_mid.c
+@@ -318,9 +318,11 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ 	if (!uart.port.membase)
+ 		return -ENOMEM;
+ 
+-	ret = mid->board->setup(mid, &uart.port);
+-	if (ret)
+-		return ret;
++	if (mid->board->setup) {
++		ret = mid->board->setup(mid, &uart.port);
++		if (ret)
++			return ret;
++	}
+ 
+ 	ret = mid8250_dma_setup(mid, &uart);
+ 	if (ret)
+@@ -336,7 +338,8 @@ static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+ 	return 0;
+ 
+ err:
+-	mid->board->exit(mid);
++	if (mid->board->exit)
++		mid->board->exit(mid);
+ 	return ret;
+ }
+ 
+@@ -346,7 +349,8 @@ static void mid8250_remove(struct pci_dev *pdev)
+ 
+ 	serial8250_unregister_port(mid->line);
+ 
+-	mid->board->exit(mid);
++	if (mid->board->exit)
++		mid->board->exit(mid);
+ }
+ 
+ static const struct mid8250_board pnw_board = {
+diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
+index e10dcdeeda2d32..1cee4e1f312246 100644
+--- a/drivers/tty/serial/max310x.c
++++ b/drivers/tty/serial/max310x.c
+@@ -1209,7 +1209,7 @@ static int __maybe_unused max310x_resume(struct device *dev)
+ static SIMPLE_DEV_PM_OPS(max310x_pm_ops, max310x_suspend, max310x_resume);
+ 
+ #ifdef CONFIG_GPIOLIB
+-static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
++static int max310x_gpio_get(struct gpio_chip *chip, unsigned int offset)
+ {
+ 	unsigned int val;
+ 	struct max310x_port *s = gpiochip_get_data(chip);
+@@ -1220,7 +1220,7 @@ static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
+ 	return !!((val >> 4) & (1 << (offset % 4)));
+ }
+ 
+-static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
++static void max310x_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+ {
+ 	struct max310x_port *s = gpiochip_get_data(chip);
+ 	struct uart_port *port = &s->p[offset / 4].port;
+@@ -1229,7 +1229,18 @@ static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+ 			    value ? 1 << (offset % 4) : 0);
+ }
+ 
+-static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++static int max310x_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
++{
++	struct max310x_port *s = gpiochip_get_data(chip);
++	struct uart_port *port = &s->p[offset / 4].port;
++	unsigned int val;
++
++	val = max310x_port_read(port, MAX310X_GPIOCFG_REG);
++
++	return val & BIT(offset % 4) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
++}
++
++static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+ {
+ 	struct max310x_port *s = gpiochip_get_data(chip);
+ 	struct uart_port *port = &s->p[offset / 4].port;
+@@ -1240,7 +1251,7 @@ static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+ }
+ 
+ static int max310x_gpio_direction_output(struct gpio_chip *chip,
+-					 unsigned offset, int value)
++					 unsigned int offset, int value)
+ {
+ 	struct max310x_port *s = gpiochip_get_data(chip);
+ 	struct uart_port *port = &s->p[offset / 4].port;
+@@ -1442,6 +1453,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
+ 	s->gpio.owner		= THIS_MODULE;
+ 	s->gpio.parent		= dev;
+ 	s->gpio.label		= devtype->name;
++	s->gpio.get_direction	= max310x_gpio_get_direction;
+ 	s->gpio.direction_input	= max310x_gpio_direction_input;
+ 	s->gpio.get		= max310x_gpio_get;
+ 	s->gpio.direction_output= max310x_gpio_direction_output;
+diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
+index b5f9a40f4a8196..6c9a96a72059ad 100644
+--- a/drivers/tty/serial/sc16is7xx.c
++++ b/drivers/tty/serial/sc16is7xx.c
+@@ -1308,6 +1308,17 @@ static void sc16is7xx_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+ 			      val ? BIT(offset) : 0);
+ }
+ 
++static int sc16is7xx_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
++{
++	struct sc16is7xx_port *s = gpiochip_get_data(chip);
++	struct uart_port *port = &s->p[0].port;
++	unsigned int val;
++
++	val = sc16is7xx_port_read(port, SC16IS7XX_IODIR_REG);
++
++	return val & BIT(offset) ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
++}
++
+ static int sc16is7xx_gpio_direction_input(struct gpio_chip *chip,
+ 					  unsigned offset)
+ {
+@@ -1385,6 +1396,7 @@ static int sc16is7xx_setup_gpio_chip(struct sc16is7xx_port *s)
+ 	s->gpio.parent		 = dev;
+ 	s->gpio.label		 = dev_name(dev);
+ 	s->gpio.init_valid_mask	 = sc16is7xx_gpio_init_valid_mask;
++	s->gpio.get_direction	 = sc16is7xx_gpio_get_direction;
+ 	s->gpio.direction_input	 = sc16is7xx_gpio_direction_input;
+ 	s->gpio.get		 = sc16is7xx_gpio_get;
+ 	s->gpio.direction_output = sc16is7xx_gpio_direction_output;
+diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
+index b41f352769f072..5dfe82a4c130da 100644
+--- a/drivers/usb/atm/ueagle-atm.c
++++ b/drivers/usb/atm/ueagle-atm.c
+@@ -2591,6 +2591,7 @@ static struct usbatm_driver uea_usbatm_driver = {
+ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
+ {
+ 	struct usb_device *usb = interface_to_usbdev(intf);
++	bool single_iface = usb->config->desc.bNumInterfaces == 1;
+ 	int ret;
+ 
+ 	uea_enters(usb);
+@@ -2600,6 +2601,22 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
+ 		le16_to_cpu(usb->descriptor.bcdDevice),
+ 		chip_name[UEA_CHIP_VERSION(id)]);
+ 
++	/*
++	 * uea_probe() decides between the pre-firmware and post-firmware case
++	 * from the USB id and stores a different object as interface data in
++	 * each case: a struct completion for a pre-firmware device, a struct
++	 * usbatm_data for a post-firmware one. uea_disconnect() instead tells
++	 * the two apart by the number of interfaces (a pre-firmware device
++	 * exposes a single interface, ADI930 has 2 and eagle has 3). A crafted
++	 * device advertising a pre-firmware id together with a multi-interface
++	 * descriptor (or the other way around) makes the two disagree, so that
++	 * usbatm_usb_disconnect() treats the small completion object as a
++	 * struct usbatm_data and reads out of bounds. Reject such inconsistent
++	 * descriptors so both paths make the same decision.
++	 */
++	if (UEA_IS_PREFIRM(id) != single_iface)
++		return -ENODEV;
++
+ 	usb_reset_device(usb);
+ 
+ 	if (UEA_IS_PREFIRM(id)) {
+diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
+index 8dcdc3f01103fd..9ebde44c563c3d 100644
+--- a/drivers/usb/chipidea/core.c
++++ b/drivers/usb/chipidea/core.c
+@@ -1265,6 +1265,7 @@ static void ci_hdrc_remove(struct platform_device *pdev)
+ 		usb_role_switch_unregister(ci->role_switch);
+ 
+ 	if (ci->supports_runtime_pm) {
++		pm_runtime_dont_use_autosuspend(&pdev->dev);
+ 		pm_runtime_get_sync(&pdev->dev);
+ 		pm_runtime_disable(&pdev->dev);
+ 		pm_runtime_put_noidle(&pdev->dev);
+diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
+index 6d91d7d7a23f85..680651e91a523d 100644
+--- a/drivers/usb/gadget/function/f_midi.c
++++ b/drivers/usb/gadget/function/f_midi.c
+@@ -1301,6 +1301,7 @@ static void f_midi_free(struct usb_function *f)
+ 	opts = container_of(f->fi, struct f_midi_opts, func_inst);
+ 	mutex_lock(&opts->lock);
+ 	if (!--midi->free_ref) {
++		cancel_work_sync(&midi->work);
+ 		kfree(midi->id);
+ 		kfifo_free(&midi->in_req_fifo);
+ 		kfree(midi);
+diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
+index d8ab1adec63e6d..40e20a0ec47151 100644
+--- a/drivers/usb/gadget/function/f_ncm.c
++++ b/drivers/usb/gadget/function/f_ncm.c
+@@ -1175,6 +1175,10 @@ static int ncm_unwrap_ntb(struct gether *port,
+ 	int		to_process = skb->len;
+ 
+ parse_ntb:
++	if (to_process < (int)opts->nth_size) {
++		INFO(port->func.config->cdev, "Packet too small for headers\n");
++		goto err;
++	}
+ 	tmp = (__le16 *)ntb_ptr;
+ 
+ 	/* dwSignature */
+@@ -1195,8 +1199,12 @@ parse_ntb:
+ 	tmp++; /* skip wSequence */
+ 
+ 	block_len = get_ncm(&tmp, opts->block_length);
++	if (block_len == 0)
++		block_len = to_process;
++
+ 	/* (d)wBlockLength */
+-	if ((block_len < opts->nth_size + opts->ndp_size) || (block_len > ntb_max)) {
++	if ((block_len < opts->nth_size + opts->ndp_size) || (block_len > ntb_max) ||
++			(block_len > to_process)) {
+ 		INFO(port->func.config->cdev, "Bad block length: %#X\n", block_len);
+ 		goto err;
+ 	}
+@@ -1259,7 +1267,7 @@ parse_ntb:
+ 			index = index2;
+ 			/* wDatagramIndex[0] */
+ 			if ((index < opts->nth_size) ||
+-					(index > block_len - opts->dpe_size)) {
++					(index > block_len)) {
+ 				INFO(port->func.config->cdev,
+ 				     "Bad index: %#X\n", index);
+ 				goto err;
+@@ -1271,7 +1279,8 @@ parse_ntb:
+ 			 * ethernet hdr + crc or larger than max frame size
+ 			 */
+ 			if ((dg_len < 14 + crc_len) ||
+-					(dg_len > frame_max)) {
++					(dg_len > frame_max) ||
++					(dg_len > block_len - index)) {
+ 				INFO(port->func.config->cdev,
+ 				     "Bad dgram length: %#X\n", dg_len);
+ 				goto err;
+@@ -1296,7 +1305,7 @@ parse_ntb:
+ 			dg_len2 = get_ncm(&tmp, opts->dgram_item_len);
+ 
+ 			/* wDatagramIndex[1] */
+-			if (index2 > block_len - opts->dpe_size) {
++			if (index2 > block_len) {
+ 				INFO(port->func.config->cdev,
+ 				     "Bad index: %#X\n", index2);
+ 				goto err;
+diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
+index 23bdeee737a3e9..d501be37002a36 100644
+--- a/drivers/usb/gadget/function/f_printer.c
++++ b/drivers/usb/gadget/function/f_printer.c
+@@ -431,7 +431,7 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
+ {
+ 	struct printer_dev		*dev = fd->private_data;
+ 	unsigned long			flags;
+-	size_t				size;
++	size_t				size, not_copied, copied;
+ 	size_t				bytes_copied;
+ 	struct usb_request		*req;
+ 	/* This is a pointer to the current USB rx request. */
+@@ -524,10 +524,12 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
+ 		else
+ 			size = len;
+ 
+-		size -= copy_to_user(buf, current_rx_buf, size);
+-		bytes_copied += size;
+-		len -= size;
+-		buf += size;
++		not_copied = copy_to_user(buf, current_rx_buf, size);
++		copied = size - not_copied;
++
++		bytes_copied += copied;
++		len -= copied;
++		buf += copied;
+ 
+ 		spin_lock_irqsave(&dev->lock, flags);
+ 
+@@ -542,6 +544,17 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
+ 		if (dev->interface < 0)
+ 			goto out_disabled;
+ 
++		if (!copied) {
++			dev->current_rx_req = current_rx_req;
++			dev->current_rx_bytes = current_rx_bytes;
++			dev->current_rx_buf = current_rx_buf;
++			spin_unlock_irqrestore(&dev->lock, flags);
++			mutex_unlock(&dev->lock_printer_io);
++			return bytes_copied ? bytes_copied : -EFAULT;
++		}
++
++		size = copied;
++
+ 		/* If we not returning all the data left in this RX request
+ 		 * buffer then adjust the amount of data left in the buffer.
+ 		 * Othewise if we are done with this RX request buffer then
+diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
+index eda0cd6ad66e94..36aa0b580d0e77 100644
+--- a/drivers/usb/gadget/function/uvc_v4l2.c
++++ b/drivers/usb/gadget/function/uvc_v4l2.c
+@@ -191,6 +191,8 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
+ 		return usb_ep_set_halt(cdev->gadget->ep0);
+ 
+ 	req->length = min_t(unsigned int, uvc->event_length, data->length);
++	if (req->length > sizeof(data->data))
++		req->length = sizeof(data->data);
+ 	req->zero = data->length < uvc->event_length;
+ 
+ 	memcpy(req->buf, data->data, req->length);
+diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c
+index c2e3fa997842ad..e12a211f3d8f4c 100644
+--- a/drivers/usb/gadget/udc/bdc/bdc_core.c
++++ b/drivers/usb/gadget/udc/bdc/bdc_core.c
+@@ -586,9 +586,29 @@ disable_clk:
+ static void bdc_remove(struct platform_device *pdev)
+ {
+ 	struct bdc *bdc;
++	unsigned long flags;
++	u32 temp;
+ 
+ 	bdc  = platform_get_drvdata(pdev);
+ 	dev_dbg(bdc->dev, "%s ()\n", __func__);
++	/*
++	 * Disable the device interrupt source before freeing the IRQ:
++	 * clear BDC_GIE so the controller stops asserting interrupts,
++	 * then free_irq drains any in-flight handler.
++	 */
++	spin_lock_irqsave(&bdc->lock, flags);
++	temp = bdc_readl(bdc->regs, BDC_BDCSC);
++	temp &= ~BDC_GIE;
++	bdc_writel(bdc->regs, BDC_BDCSC, temp);
++	spin_unlock_irqrestore(&bdc->lock, flags);
++	free_irq(bdc->irq, bdc);
++	/*
++	 * Drain func_wake_notify after free_irq: the IRQ handler arms this
++	 * delayed_work via bdc_sr_uspc -> handle_link_state_change ->
++	 * schedule_delayed_work (self-rearmed in bdc_func_wake_timer), so
++	 * the IRQ must be released first to prevent re-arm after cancel.
++	 */
++	cancel_delayed_work_sync(&bdc->func_wake_notify);
+ 	bdc_udc_exit(bdc);
+ 	bdc_hw_exit(bdc);
+ 	bdc_phy_exit(bdc);
+diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c
+index 53ffaf4e2e3762..b5e573f9ef55ed 100644
+--- a/drivers/usb/gadget/udc/bdc/bdc_udc.c
++++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c
+@@ -530,8 +530,8 @@ int bdc_udc_init(struct bdc *bdc)
+ 
+ 
+ 	bdc->gadget.name = BRCM_BDC_NAME;
+-	ret = devm_request_irq(bdc->dev, bdc->irq, bdc_udc_interrupt,
+-				IRQF_SHARED, BRCM_BDC_NAME, bdc);
++	ret = request_irq(bdc->irq, bdc_udc_interrupt, IRQF_SHARED,
++			  BRCM_BDC_NAME, bdc);
+ 	if (ret) {
+ 		dev_err(bdc->dev,
+ 			"failed to request irq #%d %d\n",
+@@ -542,7 +542,7 @@ int bdc_udc_init(struct bdc *bdc)
+ 	ret = bdc_init_ep(bdc);
+ 	if (ret) {
+ 		dev_err(bdc->dev, "bdc init ep fail: %d\n", ret);
+-		return ret;
++		goto err0;
+ 	}
+ 
+ 	ret = usb_add_gadget_udc(bdc->dev, &bdc->gadget);
+@@ -571,6 +571,7 @@ int bdc_udc_init(struct bdc *bdc)
+ err1:
+ 	usb_del_gadget_udc(&bdc->gadget);
+ err0:
++	free_irq(bdc->irq, bdc);
+ 	bdc_free_ep(bdc);
+ 
+ 	return ret;
+diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
+index 1221c49300ad46..0947746790be70 100644
+--- a/drivers/usb/gadget/udc/dummy_hcd.c
++++ b/drivers/usb/gadget/udc/dummy_hcd.c
+@@ -277,6 +277,7 @@ struct dummy {
+ 	unsigned			ints_enabled:1;
+ 	unsigned			udc_suspended:1;
+ 	unsigned			pullup:1;
++	unsigned			fifo_req_busy:1;
+ 
+ 	/*
+ 	 * HOST side support
+@@ -328,6 +329,26 @@ static inline struct dummy *gadget_dev_to_dummy(struct device *dev)
+ 
+ /* DEVICE/GADGET SIDE UTILITY ROUTINES */
+ 
++/*
++ * Give back a gadget request with dum->lock dropped around the callback.
++ * If @req is the shared fifo_req, clear fifo_req_busy afterward: the flag
++ * was set in dummy_queue() when the shared request was taken and must stay
++ * set until its completion callback has returned; list_del_init() alone
++ * makes the request look idle while the callback is still running.
++ * Caller holds dum->lock and has already done list_del_init() + status.
++ */
++static void dummy_giveback(struct dummy *dum, struct usb_ep *_ep,
++			   struct dummy_request *req)
++{
++	bool fifo = req == &dum->fifo_req;
++
++	spin_unlock(&dum->lock);
++	usb_gadget_giveback_request(_ep, &req->req);
++	spin_lock(&dum->lock);
++	if (fifo)
++		dum->fifo_req_busy = 0;
++}
++
+ /* called with spinlock held */
+ static void nuke(struct dummy *dum, struct dummy_ep *ep)
+ {
+@@ -338,9 +359,7 @@ static void nuke(struct dummy *dum, struct dummy_ep *ep)
+ 		list_del_init(&req->queue);
+ 		req->req.status = -ESHUTDOWN;
+ 
+-		spin_unlock(&dum->lock);
+-		usb_gadget_giveback_request(&ep->ep, &req->req);
+-		spin_lock(&dum->lock);
++		dummy_giveback(dum, &ep->ep, req);
+ 	}
+ }
+ 
+@@ -727,10 +746,11 @@ static int dummy_queue(struct usb_ep *_ep, struct usb_request *_req,
+ 
+ 	/* implement an emulated single-request FIFO */
+ 	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
+-			list_empty(&dum->fifo_req.queue) &&
++			!dum->fifo_req_busy &&
+ 			list_empty(&ep->queue) &&
+ 			_req->length <= FIFO_SIZE) {
+ 		req = &dum->fifo_req;
++		dum->fifo_req_busy = 1;
+ 		req->req = *_req;
+ 		req->req.buf = dum->fifo_buf;
+ 		memcpy(dum->fifo_buf, _req->buf, _req->length);
+@@ -784,9 +804,7 @@ static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+ 		dev_dbg(udc_dev(dum),
+ 				"dequeued req %p from %s, len %d buf %p\n",
+ 				req, _ep->name, _req->length, _req->buf);
+-		spin_unlock(&dum->lock);
+-		usb_gadget_giveback_request(_ep, _req);
+-		spin_lock(&dum->lock);
++		dummy_giveback(dum, _ep, req);
+ 	}
+ 	spin_unlock_irqrestore(&dum->lock, flags);
+ 	return retval;
+@@ -1522,9 +1540,7 @@ top:
+ 		if (req->req.status != -EINPROGRESS) {
+ 			list_del_init(&req->queue);
+ 
+-			spin_unlock(&dum->lock);
+-			usb_gadget_giveback_request(&ep->ep, &req->req);
+-			spin_lock(&dum->lock);
++			dummy_giveback(dum, &ep->ep, req);
+ 
+ 			/* requests might have been unlinked... */
+ 			rescan = 1;
+@@ -1908,9 +1924,7 @@ restart:
+ 				dev_dbg(udc_dev(dum), "stale req = %p\n",
+ 						req);
+ 
+-				spin_unlock(&dum->lock);
+-				usb_gadget_giveback_request(&ep->ep, &req->req);
+-				spin_lock(&dum->lock);
++				dummy_giveback(dum, &ep->ep, req);
+ 				ep->already_seen = 0;
+ 				goto restart;
+ 			}
+diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
+index 10a82527626eb6..28d6d1017c2a5e 100644
+--- a/drivers/usb/gadget/udc/fsl_udc_core.c
++++ b/drivers/usb/gadget/udc/fsl_udc_core.c
+@@ -2465,7 +2465,6 @@ static int fsl_udc_probe(struct platform_device *pdev)
+ 	udc_controller->gadget.name = driver_name;
+ 
+ 	/* Setup gadget.dev and register with kernel */
+-	dev_set_name(&udc_controller->gadget.dev, "gadget");
+ 	udc_controller->gadget.dev.of_node = pdev->dev.of_node;
+ 
+ 	if (!IS_ERR_OR_NULL(udc_controller->transceiver))
+diff --git a/drivers/usb/gadget/udc/snps_udc_core.c b/drivers/usb/gadget/udc/snps_udc_core.c
+index 2fc5d4d277bc4a..fcb58b0d5c4e48 100644
+--- a/drivers/usb/gadget/udc/snps_udc_core.c
++++ b/drivers/usb/gadget/udc/snps_udc_core.c
+@@ -3133,7 +3133,6 @@ int udc_probe(struct udc *dev)
+ 	/* device struct setup */
+ 	dev->gadget.ops = &udc_ops;
+ 
+-	dev_set_name(&dev->gadget.dev, "gadget");
+ 	dev->gadget.name = name;
+ 	dev->gadget.max_speed = USB_SPEED_HIGH;
+ 
+diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
+index 5abc48f148dcbc..d5ba5a34625bef 100644
+--- a/drivers/usb/host/xhci-pci.c
++++ b/drivers/usb/host/xhci-pci.c
+@@ -510,6 +510,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
+ 	if (pdev->vendor == PCI_VENDOR_ID_VIA && pdev->device == PCI_DEVICE_ID_VIA_VL805) {
+ 		xhci->quirks |= XHCI_LPM_SUPPORT;
+ 		xhci->quirks |= XHCI_TRB_OVERFETCH;
++		xhci->dma_mask_bits = 36;
+ 	}
+ 
+ 	if (pdev->vendor == PCI_VENDOR_ID_ASMEDIA &&
+diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
+index 31509845594e9f..210b5727d1a632 100644
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -5267,6 +5267,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
+ 	if (xhci->hci_version > 0x100)
+ 		xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2);
+ 
++	xhci->dma_mask_bits = 64;
+ 	/* xhci-plat or xhci-pci might have set max_interrupters already */
+ 	if ((!xhci->max_interrupters) ||
+ 	    xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1))
+@@ -5308,12 +5309,16 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
+ 	if (xhci->quirks & XHCI_NO_64BIT_SUPPORT)
+ 		xhci->hcc_params &= ~BIT(0);
+ 
+-	/* Set dma_mask and coherent_dma_mask to 64-bits,
+-	 * if xHC supports 64-bit addressing */
++	/*
++	 * Set dma_mask and coherent_dma_mask to 64-bits if xHC supports
++	 * 64-bit addressing, unless a controller-specific quirk callback
++	 * limits the usable address width.
++	 */
+ 	if (HCC_64BIT_ADDR(xhci->hcc_params) &&
+-			!dma_set_mask(dev, DMA_BIT_MASK(64))) {
+-		xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
+-		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
++	    !dma_set_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits))) {
++		xhci_dbg(xhci, "Enabling %u-bit DMA addresses.\n",
++			 xhci->dma_mask_bits);
++		dma_set_coherent_mask(dev, DMA_BIT_MASK(xhci->dma_mask_bits));
+ 	} else {
+ 		/*
+ 		 * This is to avoid error in cases where a 32-bit USB
+diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
+index 849a83e4013cca..bb7e73df297abc 100644
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1538,6 +1538,7 @@ struct xhci_hcd {
+ 	int		event_ring_max;
+ 	/* 4KB min, 128MB max */
+ 	int		page_size;
++	unsigned int	dma_mask_bits;
+ 	/* Valid values are 12 to 20, inclusive */
+ 	int		page_shift;
+ 	/* msi-x vectors */
+diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
+index 02c738a6e511e5..0b54f64e27fdd1 100644
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -1075,6 +1075,8 @@ static const struct usb_device_id id_table_combined[] = {
+ 	{ USB_DEVICE_INTERFACE_NUMBER(ALTERA_VID, ALTERA_UB3_602E_PID, 3) },
+ 	/* Abacus Electrics */
+ 	{ USB_DEVICE(FTDI_VID, ABACUS_OPTICAL_PROBE_PID) },
++	/* Endress+Hauser AG devices */
++	{ USB_DEVICE(FTDI_VID, FTDI_EH_FXA291_PID) },
+ 	{ }					/* Terminating entry */
+ };
+ 
+diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
+index 6c76cfebfd0e42..9c83c17853c871 100644
+--- a/drivers/usb/serial/ftdi_sio_ids.h
++++ b/drivers/usb/serial/ftdi_sio_ids.h
+@@ -313,6 +313,11 @@
+ #define FTDI_ELV_UDF77_PID	0xFB5E	/* USB DCF Funkuhr (UDF 77) */
+ #define FTDI_ELV_UIO88_PID	0xFB5F	/* USB-I/O Interface (UIO 88) */
+ 
++/*
++ * Endress+Hauser AG product ids (FTDI_VID)
++ */
++#define FTDI_EH_FXA291_PID	0xE510
++
+ /*
+  * EVER Eco Pro UPS (http://www.ever.com.pl/)
+  */
+diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
+index 179c02f5209e40..ab29c867956bba 100644
+--- a/drivers/usb/serial/io_edgeport.c
++++ b/drivers/usb/serial/io_edgeport.c
+@@ -646,7 +646,8 @@ static void edge_interrupt_callback(struct urb *urb)
+ 				if (edge_port && edge_port->open) {
+ 					spin_lock_irqsave(&edge_port->ep_lock,
+ 							  flags);
+-					edge_port->txCredits += txCredits;
++					edge_port->txCredits = min(edge_port->txCredits + txCredits,
++								   edge_port->maxTxCredits);
+ 					spin_unlock_irqrestore(&edge_port->ep_lock,
+ 							       flags);
+ 					dev_dbg(dev, "%s - txcredits for port%d = %d\n",
+diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
+index 40e5448ffcb5cf..b3964f20b25477 100644
+--- a/drivers/usb/serial/keyspan_pda.c
++++ b/drivers/usb/serial/keyspan_pda.c
+@@ -35,6 +35,8 @@ struct keyspan_pda_private {
+ 	struct work_struct	unthrottle_work;
+ 	struct usb_serial	*serial;
+ 	struct usb_serial_port	*port;
++	bool			throttled;
++	bool			throttle_req;
+ };
+ 
+ static int keyspan_pda_write_start(struct usb_serial_port *port);
+@@ -150,6 +152,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
+ 	int retval;
+ 	int status = urb->status;
+ 	struct keyspan_pda_private *priv;
++	bool throttled = false;
+ 	unsigned long flags;
+ 
+ 	priv = usb_get_serial_port_data(port);
+@@ -211,16 +214,24 @@ static void keyspan_pda_rx_interrupt(struct urb *urb)
+ 	}
+ 
+ exit:
+-	retval = usb_submit_urb(urb, GFP_ATOMIC);
+-	if (retval)
+-		dev_err(&port->dev,
+-			"%s - usb_submit_urb failed with result %d\n",
+-			__func__, retval);
++	spin_lock_irqsave(&port->lock, flags);
++	if (priv->throttle_req) {
++		priv->throttled = true;
++		throttled = true;
++	}
++	spin_unlock_irqrestore(&port->lock, flags);
++
++	if (!throttled) {
++		retval = usb_submit_urb(urb, GFP_ATOMIC);
++		if (retval)
++			dev_err(&port->dev, "failed to resubmit in urb: %d\n", retval);
++	}
+ }
+ 
+ static void keyspan_pda_rx_throttle(struct tty_struct *tty)
+ {
+ 	struct usb_serial_port *port = tty->driver_data;
++	struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
+ 
+ 	/*
+ 	 * Stop receiving characters. We just turn off the URB request, and
+@@ -230,16 +241,29 @@ static void keyspan_pda_rx_throttle(struct tty_struct *tty)
+ 	 * send an XOFF, although it might make sense to foist that off upon
+ 	 * the device too.
+ 	 */
+-	usb_kill_urb(port->interrupt_in_urb);
++	spin_lock_irq(&port->lock);
++	priv->throttle_req = true;
++	spin_unlock_irq(&port->lock);
+ }
+ 
+ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
+ {
+ 	struct usb_serial_port *port = tty->driver_data;
++	struct keyspan_pda_private *priv = usb_get_serial_port_data(port);
++	bool throttled;
++	int ret;
+ 
+-	/* just restart the receive interrupt URB */
+-	if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
+-		dev_dbg(&port->dev, "usb_submit_urb(read urb) failed\n");
++	spin_lock_irq(&port->lock);
++	throttled = priv->throttled;
++	priv->throttled = false;
++	priv->throttle_req = false;
++	spin_unlock_irq(&port->lock);
++
++	if (throttled) {
++		ret = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
++		if (ret)
++			dev_err(&port->dev, "failed to submit in urb: %d\n", ret);
++	}
+ }
+ 
+ static speed_t keyspan_pda_setbaud(struct usb_serial *serial, speed_t baud)
+@@ -579,6 +603,8 @@ static int keyspan_pda_open(struct tty_struct *tty,
+ 
+ 	spin_lock_irq(&port->lock);
+ 	priv->tx_room = rc;
++	priv->throttled = false;
++	priv->throttle_req = false;
+ 	spin_unlock_irq(&port->lock);
+ 
+ 	rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
+index 974fc6d2c0fbf9..c211fcff075a9c 100644
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -2497,6 +2497,7 @@ static const struct usb_device_id option_ids[] = {
+ 	  .driver_info = RSVD(5) },
+ 	{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff),			/* Rolling RW135R-GL (laptop MBIM) */
+ 	  .driver_info = RSVD(5) },
++	{ USB_DEVICE_INTERFACE_CLASS(0x3466, 0x3301, 0xff) },			/* TDTECH MT5710-CN */
+ 	{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) },	/* NetPrisma LCUK54-WWD for Global */
+ 	{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) },
+ 	{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) },
+diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
+index 255968f9ca42ae..ac22fa31873439 100644
+--- a/drivers/usb/storage/unusual_devs.h
++++ b/drivers/usb/storage/unusual_devs.h
+@@ -395,6 +395,13 @@ UNUSUAL_DEV(  0x04b3, 0x4001, 0x0110, 0x0110,
+ 		USB_SC_DEVICE, USB_PR_CB, NULL,
+ 		US_FL_MAX_SECTORS_MIN),
+ 
++/* Reported by Ai Chao <aichao-UOlijcLmZ/[email protected]> */
++UNUSUAL_DEV(  0x04b4, 0xb708, 0x0000, 0xffff,
++		"Longmai Technologies",
++		"USB Key",
++		USB_SC_SCSI, USB_PR_BULK, NULL,
++		US_FL_NO_ATA_1X),
++
+ /*
+  * Reported by Simon Levitt <simon-V/[email protected]>
+  * This entry needs Sub and Proto fields
+diff --git a/drivers/vdpa/vdpa_user/iova_domain.c b/drivers/vdpa/vdpa_user/iova_domain.c
+index 5e4a77b9bae6be..cc8d26b97187ea 100644
+--- a/drivers/vdpa/vdpa_user/iova_domain.c
++++ b/drivers/vdpa/vdpa_user/iova_domain.c
+@@ -103,19 +103,38 @@ void vduse_domain_clear_map(struct vduse_iova_domain *domain,
+ static int vduse_domain_map_bounce_page(struct vduse_iova_domain *domain,
+ 					 u64 iova, u64 size, u64 paddr)
+ {
+-	struct vduse_bounce_map *map;
++	struct vduse_bounce_map *map, *head_map;
++	struct page *tmp_page;
+ 	u64 last = iova + size - 1;
+ 
+ 	while (iova <= last) {
+-		map = &domain->bounce_maps[iova >> PAGE_SHIFT];
++		/*
++		 * When PAGE_SIZE is larger than 4KB, multiple adjacent bounce_maps will
++		 * point to the same memory page of PAGE_SIZE. Since bounce_maps originate
++		 * from IO requests, we may not be able to guarantee that the orig_phys
++		 * values of all IO requests within the same 64KB memory page are contiguous.
++		 * Therefore, we need to store them separately.
++		 *
++		 * Bounce pages are allocated on demand. As a result, it may occur that
++		 * multiple bounce pages corresponding to the same 64KB memory page attempt
++		 * to allocate memory simultaneously, so we use cmpxchg to handle this
++		 * concurrency.
++		 */
++		map = &domain->bounce_maps[iova >> BOUNCE_MAP_SHIFT];
+ 		if (!map->bounce_page) {
+-			map->bounce_page = alloc_page(GFP_ATOMIC);
+-			if (!map->bounce_page)
+-				return -ENOMEM;
++			head_map = &domain->bounce_maps[(iova & PAGE_MASK) >> BOUNCE_MAP_SHIFT];
++			if (!head_map->bounce_page) {
++				tmp_page = alloc_page(GFP_ATOMIC | __GFP_ZERO);
++				if (!tmp_page)
++					return -ENOMEM;
++				if (cmpxchg(&head_map->bounce_page, NULL, tmp_page))
++					__free_page(tmp_page);
++			}
++			map->bounce_page = head_map->bounce_page;
+ 		}
+ 		map->orig_phys = paddr;
+-		paddr += PAGE_SIZE;
+-		iova += PAGE_SIZE;
++		paddr += BOUNCE_MAP_SIZE;
++		iova += BOUNCE_MAP_SIZE;
+ 	}
+ 	return 0;
+ }
+@@ -127,12 +146,17 @@ static void vduse_domain_unmap_bounce_page(struct vduse_iova_domain *domain,
+ 	u64 last = iova + size - 1;
+ 
+ 	while (iova <= last) {
+-		map = &domain->bounce_maps[iova >> PAGE_SHIFT];
++		map = &domain->bounce_maps[iova >> BOUNCE_MAP_SHIFT];
+ 		map->orig_phys = INVALID_PHYS_ADDR;
+-		iova += PAGE_SIZE;
++		iova += BOUNCE_MAP_SIZE;
+ 	}
+ }
+ 
++static unsigned int offset_in_bounce_page(dma_addr_t addr)
++{
++	return (addr & ~BOUNCE_MAP_MASK);
++}
++
+ static void do_bounce(phys_addr_t orig, void *addr, size_t size,
+ 		      enum dma_data_direction dir)
+ {
+@@ -162,7 +186,7 @@ static void vduse_domain_bounce(struct vduse_iova_domain *domain,
+ 				enum dma_data_direction dir)
+ {
+ 	struct vduse_bounce_map *map;
+-	unsigned int offset;
++	unsigned int offset, head_offset;
+ 	void *addr;
+ 	size_t sz;
+ 
+@@ -170,16 +194,17 @@ static void vduse_domain_bounce(struct vduse_iova_domain *domain,
+ 		return;
+ 
+ 	while (size) {
+-		map = &domain->bounce_maps[iova >> PAGE_SHIFT];
+-		offset = offset_in_page(iova);
+-		sz = min_t(size_t, PAGE_SIZE - offset, size);
++		map = &domain->bounce_maps[iova >> BOUNCE_MAP_SHIFT];
++		head_offset = offset_in_page(iova);
++		offset = offset_in_bounce_page(iova);
++		sz = min_t(size_t, BOUNCE_MAP_SIZE - offset, size);
+ 
+ 		if (WARN_ON(!map->bounce_page ||
+ 			    map->orig_phys == INVALID_PHYS_ADDR))
+ 			return;
+ 
+ 		addr = kmap_local_page(map->bounce_page);
+-		do_bounce(map->orig_phys + offset, addr + offset, sz, dir);
++		do_bounce(map->orig_phys + offset, addr + head_offset, sz, dir);
+ 		kunmap_local(addr);
+ 		size -= sz;
+ 		iova += sz;
+@@ -214,7 +239,7 @@ vduse_domain_get_bounce_page(struct vduse_iova_domain *domain, u64 iova)
+ 	struct page *page = NULL;
+ 
+ 	read_lock(&domain->bounce_lock);
+-	map = &domain->bounce_maps[iova >> PAGE_SHIFT];
++	map = &domain->bounce_maps[iova >> BOUNCE_MAP_SHIFT];
+ 	if (domain->user_bounce_pages || !map->bounce_page)
+ 		goto out;
+ 
+@@ -232,7 +257,7 @@ vduse_domain_free_kernel_bounce_pages(struct vduse_iova_domain *domain)
+ 	struct vduse_bounce_map *map;
+ 	unsigned long pfn, bounce_pfns;
+ 
+-	bounce_pfns = domain->bounce_size >> PAGE_SHIFT;
++	bounce_pfns = domain->bounce_size >> BOUNCE_MAP_SHIFT;
+ 
+ 	for (pfn = 0; pfn < bounce_pfns; pfn++) {
+ 		map = &domain->bounce_maps[pfn];
+@@ -242,7 +267,8 @@ vduse_domain_free_kernel_bounce_pages(struct vduse_iova_domain *domain)
+ 		if (!map->bounce_page)
+ 			continue;
+ 
+-		__free_page(map->bounce_page);
++		if (!((pfn << BOUNCE_MAP_SHIFT) & ~PAGE_MASK))
++			__free_page(map->bounce_page);
+ 		map->bounce_page = NULL;
+ 	}
+ }
+@@ -250,8 +276,12 @@ vduse_domain_free_kernel_bounce_pages(struct vduse_iova_domain *domain)
+ int vduse_domain_add_user_bounce_pages(struct vduse_iova_domain *domain,
+ 				       struct page **pages, int count)
+ {
+-	struct vduse_bounce_map *map;
+-	int i, ret;
++	struct vduse_bounce_map *map, *head_map;
++	int i, j, ret;
++	int inner_pages = PAGE_SIZE / BOUNCE_MAP_SIZE;
++	int bounce_pfns = domain->bounce_size >> BOUNCE_MAP_SHIFT;
++	struct page *head_page = NULL;
++	bool need_copy;
+ 
+ 	/* Now we don't support partial mapping */
+ 	if (count != (domain->bounce_size >> PAGE_SHIFT))
+@@ -263,17 +293,25 @@ int vduse_domain_add_user_bounce_pages(struct vduse_iova_domain *domain,
+ 		goto out;
+ 
+ 	for (i = 0; i < count; i++) {
+-		map = &domain->bounce_maps[i];
+-		if (map->bounce_page) {
++		need_copy = false;
++		head_map = &domain->bounce_maps[(i * inner_pages)];
++		head_page = head_map->bounce_page;
++		for (j = 0; j < inner_pages; j++) {
++			if ((i * inner_pages + j) >= bounce_pfns)
++				break;
++			map = &domain->bounce_maps[(i * inner_pages + j)];
+ 			/* Copy kernel page to user page if it's in use */
+-			if (map->orig_phys != INVALID_PHYS_ADDR)
+-				memcpy_to_page(pages[i], 0,
+-					       page_address(map->bounce_page),
+-					       PAGE_SIZE);
+-			__free_page(map->bounce_page);
++			if ((head_page) && (map->orig_phys != INVALID_PHYS_ADDR))
++				need_copy = true;
++			map->bounce_page = pages[i];
+ 		}
+-		map->bounce_page = pages[i];
+ 		get_page(pages[i]);
++		if ((head_page) && (need_copy))
++			memcpy_to_page(pages[i], 0,
++				       page_address(head_page),
++				       PAGE_SIZE);
++		if (head_page)
++			__free_page(head_page);
+ 	}
+ 	domain->user_bounce_pages = true;
+ 	ret = 0;
+@@ -285,8 +323,12 @@ out:
+ 
+ void vduse_domain_remove_user_bounce_pages(struct vduse_iova_domain *domain)
+ {
+-	struct vduse_bounce_map *map;
+-	unsigned long i, count;
++	struct vduse_bounce_map *map, *head_map;
++	unsigned long i, j, count;
++	int inner_pages = PAGE_SIZE / BOUNCE_MAP_SIZE;
++	int bounce_pfns = domain->bounce_size >> BOUNCE_MAP_SHIFT;
++	struct page *head_page = NULL;
++	bool need_copy;
+ 
+ 	write_lock(&domain->bounce_lock);
+ 	if (!domain->user_bounce_pages)
+@@ -296,18 +338,34 @@ void vduse_domain_remove_user_bounce_pages(struct vduse_iova_domain *domain)
+ 	for (i = 0; i < count; i++) {
+ 		struct page *page = NULL;
+ 
+-		map = &domain->bounce_maps[i];
+-		if (WARN_ON(!map->bounce_page))
++		need_copy = false;
++		head_map = &domain->bounce_maps[(i * inner_pages)];
++		if (WARN_ON(!head_map->bounce_page))
+ 			continue;
+-
+-		/* Copy user page to kernel page if it's in use */
+-		if (map->orig_phys != INVALID_PHYS_ADDR) {
++		head_page = head_map->bounce_page;
++
++		for (j = 0; j < inner_pages; j++) {
++			if ((i * inner_pages + j) >= bounce_pfns)
++				break;
++			map = &domain->bounce_maps[(i * inner_pages + j)];
++			if (WARN_ON(!map->bounce_page))
++				continue;
++			/* Copy user page to kernel page if it's in use */
++			if (map->orig_phys != INVALID_PHYS_ADDR)
++				need_copy = true;
++		}
++		if (need_copy) {
+ 			page = alloc_page(GFP_ATOMIC | __GFP_NOFAIL);
+ 			memcpy_from_page(page_address(page),
+-					 map->bounce_page, 0, PAGE_SIZE);
++					 head_page, 0, PAGE_SIZE);
++		}
++		for (j = 0; j < inner_pages; j++) {
++			if ((i * inner_pages + j) >= bounce_pfns)
++				break;
++			map = &domain->bounce_maps[(i * inner_pages + j)];
++			map->bounce_page = page;
+ 		}
+-		put_page(map->bounce_page);
+-		map->bounce_page = page;
++		put_page(head_page);
+ 	}
+ 	domain->user_bounce_pages = false;
+ out:
+@@ -421,17 +479,15 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
+ 	vduse_domain_free_iova(iovad, dma_addr, size);
+ }
+ 
+-void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
+-				  size_t size, dma_addr_t *dma_addr,
+-				  gfp_t flag, unsigned long attrs)
++dma_addr_t vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
++				       size_t size, void *orig)
+ {
+ 	struct iova_domain *iovad = &domain->consistent_iovad;
+ 	unsigned long limit = domain->iova_limit;
+ 	dma_addr_t iova = vduse_domain_alloc_iova(iovad, size, limit);
+-	void *orig = alloc_pages_exact(size, flag);
+ 
+-	if (!iova || !orig)
+-		goto err;
++	if (!iova)
++		return DMA_MAPPING_ERROR;
+ 
+ 	spin_lock(&domain->iotlb_lock);
+ 	if (vduse_iotlb_add_range(domain, (u64)iova, (u64)iova + size - 1,
+@@ -442,27 +498,20 @@ void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
+ 	}
+ 	spin_unlock(&domain->iotlb_lock);
+ 
+-	*dma_addr = iova;
++	return iova;
+ 
+-	return orig;
+ err:
+-	*dma_addr = DMA_MAPPING_ERROR;
+-	if (orig)
+-		free_pages_exact(orig, size);
+-	if (iova)
+-		vduse_domain_free_iova(iovad, iova, size);
++	vduse_domain_free_iova(iovad, iova, size);
+ 
+-	return NULL;
++	return DMA_MAPPING_ERROR;
+ }
+ 
+ void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size,
+-				void *vaddr, dma_addr_t dma_addr,
+-				unsigned long attrs)
++				dma_addr_t dma_addr, unsigned long attrs)
+ {
+ 	struct iova_domain *iovad = &domain->consistent_iovad;
+ 	struct vhost_iotlb_map *map;
+ 	struct vdpa_map_file *map_file;
+-	phys_addr_t pa;
+ 
+ 	spin_lock(&domain->iotlb_lock);
+ 	map = vhost_iotlb_itree_first(domain->iotlb, (u64)dma_addr,
+@@ -474,12 +523,10 @@ void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size,
+ 	map_file = (struct vdpa_map_file *)map->opaque;
+ 	fput(map_file->file);
+ 	kfree(map_file);
+-	pa = map->addr;
+ 	vhost_iotlb_map_free(domain->iotlb, map);
+ 	spin_unlock(&domain->iotlb_lock);
+ 
+ 	vduse_domain_free_iova(iovad, dma_addr, size);
+-	free_pages_exact(phys_to_virt(pa), size);
+ }
+ 
+ static vm_fault_t vduse_domain_mmap_fault(struct vm_fault *vmf)
+@@ -557,7 +604,7 @@ vduse_domain_create(unsigned long iova_limit, size_t bounce_size)
+ 	unsigned long pfn, bounce_pfns;
+ 	int ret;
+ 
+-	bounce_pfns = PAGE_ALIGN(bounce_size) >> PAGE_SHIFT;
++	bounce_pfns = PAGE_ALIGN(bounce_size) >> BOUNCE_MAP_SHIFT;
+ 	if (iova_limit <= bounce_size)
+ 		return NULL;
+ 
+@@ -589,7 +636,7 @@ vduse_domain_create(unsigned long iova_limit, size_t bounce_size)
+ 	rwlock_init(&domain->bounce_lock);
+ 	spin_lock_init(&domain->iotlb_lock);
+ 	init_iova_domain(&domain->stream_iovad,
+-			PAGE_SIZE, IOVA_START_PFN);
++			BOUNCE_MAP_SIZE, IOVA_START_PFN);
+ 	ret = iova_domain_init_rcaches(&domain->stream_iovad);
+ 	if (ret)
+ 		goto err_iovad_stream;
+diff --git a/drivers/vdpa/vdpa_user/iova_domain.h b/drivers/vdpa/vdpa_user/iova_domain.h
+index 173e979b84a937..14b4370ce93963 100644
+--- a/drivers/vdpa/vdpa_user/iova_domain.h
++++ b/drivers/vdpa/vdpa_user/iova_domain.h
+@@ -19,6 +19,11 @@
+ 
+ #define INVALID_PHYS_ADDR (~(phys_addr_t)0)
+ 
++#define BOUNCE_MAP_SHIFT	12
++#define BOUNCE_MAP_SIZE	(1 << BOUNCE_MAP_SHIFT)
++#define BOUNCE_MAP_MASK	(~(BOUNCE_MAP_SIZE - 1))
++#define BOUNCE_MAP_ALIGN(addr)	(((addr) + BOUNCE_MAP_SIZE - 1) & ~(BOUNCE_MAP_SIZE - 1))
++
+ struct vduse_bounce_map {
+ 	struct page *bounce_page;
+ 	u64 orig_phys;
+@@ -53,13 +58,11 @@ void vduse_domain_unmap_page(struct vduse_iova_domain *domain,
+ 			     dma_addr_t dma_addr, size_t size,
+ 			     enum dma_data_direction dir, unsigned long attrs);
+ 
+-void *vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
+-				  size_t size, dma_addr_t *dma_addr,
+-				  gfp_t flag, unsigned long attrs);
++dma_addr_t vduse_domain_alloc_coherent(struct vduse_iova_domain *domain,
++				       size_t size, void *orig);
+ 
+ void vduse_domain_free_coherent(struct vduse_iova_domain *domain, size_t size,
+-				void *vaddr, dma_addr_t dma_addr,
+-				unsigned long attrs);
++				dma_addr_t dma_addr, unsigned long attrs);
+ 
+ void vduse_domain_reset_bounce_map(struct vduse_iova_domain *domain);
+ 
+diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c
+index d6a3a58dbda476..85f9bbb563c5ee 100644
+--- a/drivers/vdpa/vdpa_user/vduse_dev.c
++++ b/drivers/vdpa/vdpa_user/vduse_dev.c
+@@ -851,18 +851,23 @@ static void *vduse_dev_alloc_coherent(struct device *dev, size_t size,
+ {
+ 	struct vduse_dev *vdev = dev_to_vduse(dev);
+ 	struct vduse_iova_domain *domain = vdev->domain;
+-	unsigned long iova;
+ 	void *addr;
+ 
+ 	*dma_addr = DMA_MAPPING_ERROR;
+-	addr = vduse_domain_alloc_coherent(domain, size,
+-				(dma_addr_t *)&iova, flag, attrs);
++
++	addr = alloc_pages_exact(size, flag | __GFP_ZERO);
+ 	if (!addr)
+ 		return NULL;
+ 
+-	*dma_addr = (dma_addr_t)iova;
++	*dma_addr = vduse_domain_alloc_coherent(domain, size, addr);
++	if (*dma_addr == DMA_MAPPING_ERROR)
++		goto err;
+ 
+ 	return addr;
++
++err:
++	free_pages_exact(addr, size);
++	return NULL;
+ }
+ 
+ static void vduse_dev_free_coherent(struct device *dev, size_t size,
+@@ -872,7 +877,8 @@ static void vduse_dev_free_coherent(struct device *dev, size_t size,
+ 	struct vduse_dev *vdev = dev_to_vduse(dev);
+ 	struct vduse_iova_domain *domain = vdev->domain;
+ 
+-	vduse_domain_free_coherent(domain, size, vaddr, dma_addr, attrs);
++	vduse_domain_free_coherent(domain, size, dma_addr, attrs);
++	free_pages_exact(vaddr, size);
+ }
+ 
+ static size_t vduse_dev_max_mapping_size(struct device *dev)
+diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
+index 8563264d11fac6..ed853a2aec2fde 100644
+--- a/drivers/video/fbdev/core/bitblit.c
++++ b/drivers/video/fbdev/core/bitblit.c
+@@ -261,10 +261,10 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 		       int fg, int bg)
+ {
+ 	struct fb_cursor cursor;
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ 	int w = DIV_ROUND_UP(vc->vc_font.width, 8), c;
+-	int y = real_y(ops->p, vc->state.y);
++	int y = real_y(par->p, vc->state.y);
+ 	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
+ 	int err = 1;
+ 	char *src;
+@@ -278,10 +278,10 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 	attribute = get_attribute(info, c);
+ 	src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
+ 
+-	if (ops->cursor_state.image.data != src ||
+-	    ops->cursor_reset) {
+-	    ops->cursor_state.image.data = src;
+-	    cursor.set |= FB_CUR_SETIMAGE;
++	if (par->cursor_state.image.data != src ||
++	    par->cursor_reset) {
++		par->cursor_state.image.data = src;
++		cursor.set |= FB_CUR_SETIMAGE;
+ 	}
+ 
+ 	if (attribute) {
+@@ -290,46 +290,46 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 		dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
+ 		if (!dst)
+ 			return;
+-		kfree(ops->cursor_data);
+-		ops->cursor_data = dst;
++		kfree(par->cursor_data);
++		par->cursor_data = dst;
+ 		update_attr(dst, src, attribute, vc);
+ 		src = dst;
+ 	}
+ 
+-	if (ops->cursor_state.image.fg_color != fg ||
+-	    ops->cursor_state.image.bg_color != bg ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.fg_color = fg;
+-		ops->cursor_state.image.bg_color = bg;
++	if (par->cursor_state.image.fg_color != fg ||
++	    par->cursor_state.image.bg_color != bg ||
++	    par->cursor_reset) {
++		par->cursor_state.image.fg_color = fg;
++		par->cursor_state.image.bg_color = bg;
+ 		cursor.set |= FB_CUR_SETCMAP;
+ 	}
+ 
+-	if ((ops->cursor_state.image.dx != (vc->vc_font.width * vc->state.x)) ||
+-	    (ops->cursor_state.image.dy != (vc->vc_font.height * y)) ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.dx = vc->vc_font.width * vc->state.x;
+-		ops->cursor_state.image.dy = vc->vc_font.height * y;
++	if ((par->cursor_state.image.dx != (vc->vc_font.width * vc->state.x)) ||
++	    (par->cursor_state.image.dy != (vc->vc_font.height * y)) ||
++	    par->cursor_reset) {
++		par->cursor_state.image.dx = vc->vc_font.width * vc->state.x;
++		par->cursor_state.image.dy = vc->vc_font.height * y;
+ 		cursor.set |= FB_CUR_SETPOS;
+ 	}
+ 
+-	if (ops->cursor_state.image.height != vc->vc_font.height ||
+-	    ops->cursor_state.image.width != vc->vc_font.width ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.height = vc->vc_font.height;
+-		ops->cursor_state.image.width = vc->vc_font.width;
++	if (par->cursor_state.image.height != vc->vc_font.height ||
++	    par->cursor_state.image.width != vc->vc_font.width ||
++	    par->cursor_reset) {
++		par->cursor_state.image.height = vc->vc_font.height;
++		par->cursor_state.image.width = vc->vc_font.width;
+ 		cursor.set |= FB_CUR_SETSIZE;
+ 	}
+ 
+-	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.hot.x = cursor.hot.y = 0;
++	if (par->cursor_state.hot.x || par->cursor_state.hot.y ||
++	    par->cursor_reset) {
++		par->cursor_state.hot.x = cursor.hot.y = 0;
+ 		cursor.set |= FB_CUR_SETHOT;
+ 	}
+ 
+ 	if (cursor.set & FB_CUR_SETSIZE ||
+-	    vc->vc_cursor_type != ops->p->cursor_shape ||
+-	    ops->cursor_state.mask == NULL ||
+-	    ops->cursor_reset) {
++	    vc->vc_cursor_type != par->p->cursor_shape ||
++	    par->cursor_state.mask == NULL ||
++	    par->cursor_reset) {
+ 		char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
+ 		int cur_height, size, i = 0;
+ 		u8 msk = 0xff;
+@@ -337,13 +337,13 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 		if (!mask)
+ 			return;
+ 
+-		kfree(ops->cursor_state.mask);
+-		ops->cursor_state.mask = mask;
++		kfree(par->cursor_state.mask);
++		par->cursor_state.mask = mask;
+ 
+-		ops->p->cursor_shape = vc->vc_cursor_type;
++		par->p->cursor_shape = vc->vc_cursor_type;
+ 		cursor.set |= FB_CUR_SETSHAPE;
+ 
+-		switch (CUR_SIZE(ops->p->cursor_shape)) {
++		switch (CUR_SIZE(par->p->cursor_shape)) {
+ 		case CUR_NONE:
+ 			cur_height = 0;
+ 			break;
+@@ -374,26 +374,26 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 
+ 	switch (mode) {
+ 	case CM_ERASE:
+-		ops->cursor_state.enable = 0;
++		par->cursor_state.enable = 0;
+ 		break;
+ 	case CM_DRAW:
+ 	case CM_MOVE:
+ 	default:
+-		ops->cursor_state.enable = (use_sw) ? 0 : 1;
++		par->cursor_state.enable = (use_sw) ? 0 : 1;
+ 		break;
+ 	}
+ 
+ 	cursor.image.data = src;
+-	cursor.image.fg_color = ops->cursor_state.image.fg_color;
+-	cursor.image.bg_color = ops->cursor_state.image.bg_color;
+-	cursor.image.dx = ops->cursor_state.image.dx;
+-	cursor.image.dy = ops->cursor_state.image.dy;
+-	cursor.image.height = ops->cursor_state.image.height;
+-	cursor.image.width = ops->cursor_state.image.width;
+-	cursor.hot.x = ops->cursor_state.hot.x;
+-	cursor.hot.y = ops->cursor_state.hot.y;
+-	cursor.mask = ops->cursor_state.mask;
+-	cursor.enable = ops->cursor_state.enable;
++	cursor.image.fg_color = par->cursor_state.image.fg_color;
++	cursor.image.bg_color = par->cursor_state.image.bg_color;
++	cursor.image.dx = par->cursor_state.image.dx;
++	cursor.image.dy = par->cursor_state.image.dy;
++	cursor.image.height = par->cursor_state.image.height;
++	cursor.image.width = par->cursor_state.image.width;
++	cursor.hot.x = par->cursor_state.hot.x;
++	cursor.hot.y = par->cursor_state.hot.y;
++	cursor.mask = par->cursor_state.mask;
++	cursor.enable = par->cursor_state.enable;
+ 	cursor.image.depth = 1;
+ 	cursor.rop = ROP_XOR;
+ 
+@@ -403,31 +403,31 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 	if (err)
+ 		soft_cursor(info, &cursor);
+ 
+-	ops->cursor_reset = 0;
++	par->cursor_reset = 0;
+ }
+ 
+ static int bit_update_start(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	int err;
+ 
+-	err = fb_pan_display(info, &ops->var);
+-	ops->var.xoffset = info->var.xoffset;
+-	ops->var.yoffset = info->var.yoffset;
+-	ops->var.vmode = info->var.vmode;
++	err = fb_pan_display(info, &par->var);
++	par->var.xoffset = info->var.xoffset;
++	par->var.yoffset = info->var.yoffset;
++	par->var.vmode = info->var.vmode;
+ 	return err;
+ }
+ 
+-void fbcon_set_bitops(struct fbcon_ops *ops)
++void fbcon_set_bitops(struct fbcon_par *par)
+ {
+-	ops->bmove = bit_bmove;
+-	ops->clear = bit_clear;
+-	ops->putcs = bit_putcs;
+-	ops->clear_margins = bit_clear_margins;
+-	ops->cursor = bit_cursor;
+-	ops->update_start = bit_update_start;
+-	ops->rotate_font = NULL;
+-
+-	if (ops->rotate)
+-		fbcon_set_rotate(ops);
++	par->bmove = bit_bmove;
++	par->clear = bit_clear;
++	par->putcs = bit_putcs;
++	par->clear_margins = bit_clear_margins;
++	par->cursor = bit_cursor;
++	par->update_start = bit_update_start;
++	par->rotate_font = NULL;
++
++	if (par->rotate)
++		fbcon_set_rotate(par);
+ }
+diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
+index 6ceb3c8d732790..6bb86a415c6cf3 100644
+--- a/drivers/video/fbdev/core/fbcon.c
++++ b/drivers/video/fbdev/core/fbcon.c
+@@ -198,27 +198,27 @@ static struct device *fbcon_device;
+ #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+ static inline void fbcon_set_rotation(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+ 	if (!(info->flags & FBINFO_MISC_TILEBLITTING) &&
+-	    ops->p->con_rotate < 4)
+-		ops->rotate = ops->p->con_rotate;
++	    par->p->con_rotate < 4)
++		par->rotate = par->p->con_rotate;
+ 	else
+-		ops->rotate = 0;
++		par->rotate = 0;
+ }
+ 
+ static void fbcon_rotate(struct fb_info *info, u32 rotate)
+ {
+-	struct fbcon_ops *ops= info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fb_info *fb_info;
+ 
+-	if (!ops || ops->currcon == -1)
++	if (!par || par->currcon == -1)
+ 		return;
+ 
+-	fb_info = fbcon_info_from_console(ops->currcon);
++	fb_info = fbcon_info_from_console(par->currcon);
+ 
+ 	if (info == fb_info) {
+-		struct fbcon_display *p = &fb_display[ops->currcon];
++		struct fbcon_display *p = &fb_display[par->currcon];
+ 
+ 		if (rotate < 4)
+ 			p->con_rotate = rotate;
+@@ -231,12 +231,12 @@ static void fbcon_rotate(struct fb_info *info, u32 rotate)
+ 
+ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct vc_data *vc;
+ 	struct fbcon_display *p;
+ 	int i;
+ 
+-	if (!ops || ops->currcon < 0 || rotate > 3)
++	if (!par || par->currcon < 0 || rotate > 3)
+ 		return;
+ 
+ 	for (i = first_fb_vc; i <= last_fb_vc; i++) {
+@@ -254,9 +254,9 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
+ #else
+ static inline void fbcon_set_rotation(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+-	ops->rotate = FB_ROTATE_UR;
++	par->rotate = FB_ROTATE_UR;
+ }
+ 
+ static void fbcon_rotate(struct fb_info *info, u32 rotate)
+@@ -272,17 +272,17 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
+ 
+ static int fbcon_get_rotate(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+-	return (ops) ? ops->rotate : 0;
++	return (par) ? par->rotate : 0;
+ }
+ 
+ static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+ 	return (info->state != FBINFO_STATE_RUNNING ||
+-		vc->vc_mode != KD_TEXT || ops->graphics);
++		vc->vc_mode != KD_TEXT || par->graphics);
+ }
+ 
+ static int get_color(struct vc_data *vc, struct fb_info *info,
+@@ -354,7 +354,7 @@ static int get_color(struct vc_data *vc, struct fb_info *info,
+ 
+ static void fb_flashcursor(struct work_struct *work)
+ {
+-	struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work);
++	struct fbcon_par *par = container_of(work, struct fbcon_par, cursor_work.work);
+ 	struct fb_info *info;
+ 	struct vc_data *vc = NULL;
+ 	int c;
+@@ -369,10 +369,10 @@ static void fb_flashcursor(struct work_struct *work)
+ 		return;
+ 
+ 	/* protected by console_lock */
+-	info = ops->info;
++	info = par->info;
+ 
+-	if (ops->currcon != -1)
+-		vc = vc_cons[ops->currcon].d;
++	if (par->currcon != -1)
++		vc = vc_cons[par->currcon].d;
+ 
+ 	if (!vc || !con_is_visible(vc) ||
+ 	    fbcon_info_from_console(vc->vc_num) != info ||
+@@ -382,30 +382,30 @@ static void fb_flashcursor(struct work_struct *work)
+ 	}
+ 
+ 	c = scr_readw((u16 *) vc->vc_pos);
+-	mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
++	mode = (!par->cursor_flash || par->cursor_state.enable) ?
+ 		CM_ERASE : CM_DRAW;
+-	ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
++	par->cursor(vc, info, mode, get_color(vc, info, c, 1),
+ 		    get_color(vc, info, c, 0));
+ 	console_unlock();
+ 
+-	queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
+-			   ops->cur_blink_jiffies);
++	queue_delayed_work(system_power_efficient_wq, &par->cursor_work,
++			   par->cur_blink_jiffies);
+ }
+ 
+ static void fbcon_add_cursor_work(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+ 	if (!fbcon_cursor_noblink)
+-		queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
+-				   ops->cur_blink_jiffies);
++		queue_delayed_work(system_power_efficient_wq, &par->cursor_work,
++				   par->cur_blink_jiffies);
+ }
+ 
+ static void fbcon_del_cursor_work(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+-	cancel_delayed_work_sync(&ops->cursor_work);
++	cancel_delayed_work_sync(&par->cursor_work);
+ }
+ 
+ #ifndef MODULE
+@@ -559,7 +559,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
+ 			       int cols, int rows, int new_cols, int new_rows)
+ {
+ 	/* Need to make room for the logo */
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	int cnt, erase = vc->vc_video_erase_char, step;
+ 	unsigned short *save = NULL, *r, *q;
+ 	int logo_height;
+@@ -575,7 +575,7 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
+ 	 */
+ 	if (fb_get_color_depth(&info->var, &info->fix) == 1)
+ 		erase &= ~0x400;
+-	logo_height = fb_prepare_logo(info, ops->rotate);
++	logo_height = fb_prepare_logo(info, par->rotate);
+ 	logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height);
+ 	q = (unsigned short *) (vc->vc_origin +
+ 				vc->vc_size_row * rows);
+@@ -648,15 +648,15 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info,
+ #ifdef CONFIG_FB_TILEBLITTING
+ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+-	ops->p = &fb_display[vc->vc_num];
++	par->p = &fb_display[vc->vc_num];
+ 
+ 	if ((info->flags & FBINFO_MISC_TILEBLITTING))
+ 		fbcon_set_tileops(vc, info);
+ 	else {
+ 		fbcon_set_rotation(info);
+-		fbcon_set_bitops(ops);
++		fbcon_set_bitops(par);
+ 	}
+ }
+ 
+@@ -673,12 +673,12 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
+ #else
+ static void set_blitting_type(struct vc_data *vc, struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+ 	info->flags &= ~FBINFO_MISC_TILEBLITTING;
+-	ops->p = &fb_display[vc->vc_num];
++	par->p = &fb_display[vc->vc_num];
+ 	fbcon_set_rotation(info);
+-	fbcon_set_bitops(ops);
++	fbcon_set_bitops(par);
+ }
+ 
+ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
+@@ -698,13 +698,13 @@ static void fbcon_release(struct fb_info *info)
+ 	module_put(info->fbops->owner);
+ 
+ 	if (info->fbcon_par) {
+-		struct fbcon_ops *ops = info->fbcon_par;
++		struct fbcon_par *par = info->fbcon_par;
+ 
+ 		fbcon_del_cursor_work(info);
+-		kfree(ops->cursor_state.mask);
+-		kfree(ops->cursor_data);
+-		kfree(ops->cursor_src);
+-		kfree(ops->fontbuffer);
++		kfree(par->cursor_state.mask);
++		kfree(par->cursor_data);
++		kfree(par->cursor_src);
++		kfree(par->fontbuffer);
+ 		kfree(info->fbcon_par);
+ 		info->fbcon_par = NULL;
+ 	}
+@@ -712,7 +712,7 @@ static void fbcon_release(struct fb_info *info)
+ 
+ static int fbcon_open(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops;
++	struct fbcon_par *par;
+ 
+ 	if (!try_module_get(info->fbops->owner))
+ 		return -ENODEV;
+@@ -726,16 +726,16 @@ static int fbcon_open(struct fb_info *info)
+ 	}
+ 	unlock_fb_info(info);
+ 
+-	ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
+-	if (!ops) {
++	par = kzalloc(sizeof(*par), GFP_KERNEL);
++	if (!par) {
+ 		fbcon_release(info);
+ 		return -ENOMEM;
+ 	}
+ 
+-	INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
+-	ops->info = info;
+-	info->fbcon_par = ops;
+-	ops->cur_blink_jiffies = HZ / 5;
++	INIT_DELAYED_WORK(&par->cursor_work, fb_flashcursor);
++	par->info = info;
++	info->fbcon_par = par;
++	par->cur_blink_jiffies = HZ / 5;
+ 
+ 	return 0;
+ }
+@@ -782,12 +782,12 @@ static void con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
+ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
+ 				int unit, int show_logo)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	int ret;
+ 
+-	ops->currcon = fg_console;
++	par->currcon = fg_console;
+ 
+-	if (info->fbops->fb_set_par && !ops->initialized) {
++	if (info->fbops->fb_set_par && !par->initialized) {
+ 		ret = info->fbops->fb_set_par(info);
+ 
+ 		if (ret)
+@@ -796,8 +796,8 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
+ 				"error code %d\n", ret);
+ 	}
+ 
+-	ops->initialized = true;
+-	ops->graphics = 0;
++	par->initialized = true;
++	par->graphics = 0;
+ 	fbcon_set_disp(info, &info->var, unit);
+ 
+ 	if (show_logo) {
+@@ -934,7 +934,7 @@ static const char *fbcon_startup(void)
+ 	struct vc_data *vc = vc_cons[fg_console].d;
+ 	const struct font_desc *font = NULL;
+ 	struct fb_info *info = NULL;
+-	struct fbcon_ops *ops;
++	struct fbcon_par *par;
+ 	int rows, cols;
+ 
+ 	/*
+@@ -954,10 +954,10 @@ static const char *fbcon_startup(void)
+ 	if (fbcon_open(info))
+ 		return NULL;
+ 
+-	ops = info->fbcon_par;
+-	ops->currcon = -1;
+-	ops->graphics = 1;
+-	ops->cur_rotate = -1;
++	par = info->fbcon_par;
++	par->currcon = -1;
++	par->graphics = 1;
++	par->cur_rotate = -1;
+ 
+ 	p->con_rotate = initial_rotation;
+ 	if (p->con_rotate == -1)
+@@ -980,8 +980,8 @@ static const char *fbcon_startup(void)
+ 		vc->vc_font.charcount = font->charcount;
+ 	}
+ 
+-	cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+-	rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
++	cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
++	rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
+ 	cols /= vc->vc_font.width;
+ 	rows /= vc->vc_font.height;
+ 	vc_resize(vc, cols, rows);
+@@ -999,7 +999,7 @@ static const char *fbcon_startup(void)
+ static void fbcon_init(struct vc_data *vc, bool init)
+ {
+ 	struct fb_info *info;
+-	struct fbcon_ops *ops;
++	struct fbcon_par *par;
+ 	struct vc_data **default_mode = vc->vc_display_fg;
+ 	struct vc_data *svc = *default_mode;
+ 	struct fbcon_display *t, *p = &fb_display[vc->vc_num];
+@@ -1074,8 +1074,8 @@ static void fbcon_init(struct vc_data *vc, bool init)
+ 	if (!*vc->uni_pagedict_loc)
+ 		con_copy_unimap(vc, svc);
+ 
+-	ops = info->fbcon_par;
+-	ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
++	par = info->fbcon_par;
++	par->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
+ 
+ 	p->con_rotate = initial_rotation;
+ 	if (p->con_rotate == -1)
+@@ -1087,8 +1087,8 @@ static void fbcon_init(struct vc_data *vc, bool init)
+ 
+ 	cols = vc->vc_cols;
+ 	rows = vc->vc_rows;
+-	new_cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+-	new_rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
++	new_cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
++	new_rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
+ 	new_cols /= vc->vc_font.width;
+ 	new_rows /= vc->vc_font.height;
+ 
+@@ -1100,7 +1100,7 @@ static void fbcon_init(struct vc_data *vc, bool init)
+ 	 * We need to do it in fbcon_init() to prevent screen corruption.
+ 	 */
+ 	if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) {
+-		if (info->fbops->fb_set_par && !ops->initialized) {
++		if (info->fbops->fb_set_par && !par->initialized) {
+ 			ret = info->fbops->fb_set_par(info);
+ 
+ 			if (ret)
+@@ -1109,10 +1109,10 @@ static void fbcon_init(struct vc_data *vc, bool init)
+ 					"error code %d\n", ret);
+ 		}
+ 
+-		ops->initialized = true;
++		par->initialized = true;
+ 	}
+ 
+-	ops->graphics = 0;
++	par->graphics = 0;
+ 
+ #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+ 	if ((info->flags & FBINFO_HWACCEL_COPYAREA) &&
+@@ -1136,12 +1136,12 @@ static void fbcon_init(struct vc_data *vc, bool init)
+ 	if (logo)
+ 		fbcon_prepare_logo(vc, info, cols, rows, new_cols, new_rows);
+ 
+-	if (ops->rotate_font && ops->rotate_font(info, vc)) {
+-		ops->rotate = FB_ROTATE_UR;
++	if (par->rotate_font && par->rotate_font(info, vc)) {
++		par->rotate = FB_ROTATE_UR;
+ 		set_blitting_type(vc, info);
+ 	}
+ 
+-	ops->p = &fb_display[fg_console];
++	par->p = &fb_display[fg_console];
+ }
+ 
+ static void fbcon_free_font(struct fbcon_display *p)
+@@ -1179,7 +1179,7 @@ static void fbcon_deinit(struct vc_data *vc)
+ {
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+ 	struct fb_info *info;
+-	struct fbcon_ops *ops;
++	struct fbcon_par *par;
+ 	int idx;
+ 
+ 	fbcon_free_font(p);
+@@ -1194,15 +1194,15 @@ static void fbcon_deinit(struct vc_data *vc)
+ 	if (!info)
+ 		goto finished;
+ 
+-	ops = info->fbcon_par;
++	par = info->fbcon_par;
+ 
+-	if (!ops)
++	if (!par)
+ 		goto finished;
+ 
+ 	if (con_is_visible(vc))
+ 		fbcon_del_cursor_work(info);
+ 
+-	ops->initialized = false;
++	par->initialized = false;
+ finished:
+ 
+ 	fbcon_free_font(p);
+@@ -1249,7 +1249,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+ 			  unsigned int height, unsigned int width)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	int fg, bg;
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+ 	u_int y_break;
+@@ -1264,7 +1264,7 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+ 		vc->vc_top = 0;
+ 		/*
+ 		 * If the font dimensions are not an integral of the display
+-		 * dimensions then the ops->clear below won't end up clearing
++		 * dimensions then the par->clear below won't end up clearing
+ 		 * the margins.  Call clear_margins here in case the logo
+ 		 * bitmap stretched into the margin area.
+ 		 */
+@@ -1278,11 +1278,10 @@ static void __fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+ 	y_break = p->vrows - p->yscroll;
+ 	if (sy < y_break && sy + height - 1 >= y_break) {
+ 		u_int b = y_break - sy;
+-		ops->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg);
+-		ops->clear(vc, info, real_y(p, sy + b), sx, height - b,
+-				 width, fg, bg);
++		par->clear(vc, info, real_y(p, sy), sx, b, width, fg, bg);
++		par->clear(vc, info, real_y(p, sy + b), sx, height - b, width, fg, bg);
+ 	} else
+-		ops->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg);
++		par->clear(vc, info, real_y(p, sy), sx, height, width, fg, bg);
+ }
+ 
+ static void fbcon_clear(struct vc_data *vc, unsigned int sy, unsigned int sx,
+@@ -1296,10 +1295,10 @@ static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+ 	if (!fbcon_is_inactive(vc, info))
+-		ops->putcs(vc, info, s, count, real_y(p, ypos), xpos,
++		par->putcs(vc, info, s, count, real_y(p, ypos), xpos,
+ 			   get_color(vc, info, scr_readw(s), 1),
+ 			   get_color(vc, info, scr_readw(s), 0));
+ }
+@@ -1315,19 +1314,19 @@ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)
+ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+ 	if (!fbcon_is_inactive(vc, info))
+-		ops->clear_margins(vc, info, margin_color, bottom_only);
++		par->clear_margins(vc, info, margin_color, bottom_only);
+ }
+ 
+ static void fbcon_cursor(struct vc_data *vc, int mode)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+  	int c = scr_readw((u16 *) vc->vc_pos);
+ 
+-	ops->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
++	par->cur_blink_jiffies = msecs_to_jiffies(vc->vc_cur_blink_ms);
+ 
+ 	if (fbcon_is_inactive(vc, info) || vc->vc_deccm != 1)
+ 		return;
+@@ -1337,12 +1336,12 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
+ 	else
+ 		fbcon_add_cursor_work(info);
+ 
+-	ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
++	par->cursor_flash = (mode == CM_ERASE) ? 0 : 1;
+ 
+-	if (!ops->cursor)
++	if (!par->cursor)
+ 		return;
+ 
+-	ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
++	par->cursor(vc, info, mode, get_color(vc, info, c, 1),
+ 		    get_color(vc, info, c, 0));
+ }
+ 
+@@ -1356,9 +1355,8 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+ 	struct fbcon_display *p, *t;
+ 	struct vc_data **default_mode, *vc;
+ 	struct vc_data *svc;
+-	struct fbcon_ops *ops = info->fbcon_par;
+-	int rows, cols;
+-	unsigned long ret = 0;
++	struct fbcon_par *par = info->fbcon_par;
++	int rows, cols, ret;
+ 
+ 	p = &fb_display[unit];
+ 
+@@ -1389,7 +1387,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+ 	var->yoffset = info->var.yoffset;
+ 	var->xoffset = info->var.xoffset;
+ 	fb_set_var(info, var);
+-	ops->var = info->var;
++	par->var = info->var;
+ 	vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
+ 	vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
+ 	if (vc->vc_font.charcount == 256) {
+@@ -1405,8 +1403,8 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+ 	if (!*vc->uni_pagedict_loc)
+ 		con_copy_unimap(vc, svc);
+ 
+-	cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+-	rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
++	cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
++	rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
+ 	cols /= vc->vc_font.width;
+ 	rows /= vc->vc_font.height;
+ 	ret = vc_resize(vc, cols, rows);
+@@ -1418,16 +1416,16 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
+ static __inline__ void ywrap_up(struct vc_data *vc, int count)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+ 
+ 	p->yscroll += count;
+ 	if (p->yscroll >= p->vrows)	/* Deal with wrap */
+ 		p->yscroll -= p->vrows;
+-	ops->var.xoffset = 0;
+-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+-	ops->var.vmode |= FB_VMODE_YWRAP;
+-	ops->update_start(info);
++	par->var.xoffset = 0;
++	par->var.yoffset = p->yscroll * vc->vc_font.height;
++	par->var.vmode |= FB_VMODE_YWRAP;
++	par->update_start(info);
+ 	scrollback_max += count;
+ 	if (scrollback_max > scrollback_phys_max)
+ 		scrollback_max = scrollback_phys_max;
+@@ -1437,16 +1435,16 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count)
+ static __inline__ void ywrap_down(struct vc_data *vc, int count)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+ 
+ 	p->yscroll -= count;
+ 	if (p->yscroll < 0)	/* Deal with wrap */
+ 		p->yscroll += p->vrows;
+-	ops->var.xoffset = 0;
+-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+-	ops->var.vmode |= FB_VMODE_YWRAP;
+-	ops->update_start(info);
++	par->var.xoffset = 0;
++	par->var.yoffset = p->yscroll * vc->vc_font.height;
++	par->var.vmode |= FB_VMODE_YWRAP;
++	par->update_start(info);
+ 	scrollback_max -= count;
+ 	if (scrollback_max < 0)
+ 		scrollback_max = 0;
+@@ -1457,19 +1455,19 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+ 	p->yscroll += count;
+ 	if (p->yscroll > p->vrows - vc->vc_rows) {
+-		ops->bmove(vc, info, p->vrows - vc->vc_rows,
++		par->bmove(vc, info, p->vrows - vc->vc_rows,
+ 			    0, 0, 0, vc->vc_rows, vc->vc_cols);
+ 		p->yscroll -= p->vrows - vc->vc_rows;
+ 	}
+ 
+-	ops->var.xoffset = 0;
+-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+-	ops->var.vmode &= ~FB_VMODE_YWRAP;
+-	ops->update_start(info);
++	par->var.xoffset = 0;
++	par->var.yoffset = p->yscroll * vc->vc_font.height;
++	par->var.vmode &= ~FB_VMODE_YWRAP;
++	par->update_start(info);
+ 	fbcon_clear_margins(vc, 1);
+ 	scrollback_max += count;
+ 	if (scrollback_max > scrollback_phys_max)
+@@ -1480,7 +1478,7 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)
+ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+ 
+ 	p->yscroll += count;
+@@ -1490,10 +1488,10 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
+ 		fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
+ 	}
+ 
+-	ops->var.xoffset = 0;
+-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+-	ops->var.vmode &= ~FB_VMODE_YWRAP;
+-	ops->update_start(info);
++	par->var.xoffset = 0;
++	par->var.yoffset = p->yscroll * vc->vc_font.height;
++	par->var.vmode &= ~FB_VMODE_YWRAP;
++	par->update_start(info);
+ 	fbcon_clear_margins(vc, 1);
+ 	scrollback_max += count;
+ 	if (scrollback_max > scrollback_phys_max)
+@@ -1505,19 +1503,19 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+ 	p->yscroll -= count;
+ 	if (p->yscroll < 0) {
+-		ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
++		par->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
+ 			    0, vc->vc_rows, vc->vc_cols);
+ 		p->yscroll += p->vrows - vc->vc_rows;
+ 	}
+ 
+-	ops->var.xoffset = 0;
+-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+-	ops->var.vmode &= ~FB_VMODE_YWRAP;
+-	ops->update_start(info);
++	par->var.xoffset = 0;
++	par->var.yoffset = p->yscroll * vc->vc_font.height;
++	par->var.vmode &= ~FB_VMODE_YWRAP;
++	par->update_start(info);
+ 	fbcon_clear_margins(vc, 1);
+ 	scrollback_max -= count;
+ 	if (scrollback_max < 0)
+@@ -1528,7 +1526,7 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)
+ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+ 
+ 	p->yscroll -= count;
+@@ -1538,10 +1536,10 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
+ 		fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
+ 	}
+ 
+-	ops->var.xoffset = 0;
+-	ops->var.yoffset = p->yscroll * vc->vc_font.height;
+-	ops->var.vmode &= ~FB_VMODE_YWRAP;
+-	ops->update_start(info);
++	par->var.xoffset = 0;
++	par->var.yoffset = p->yscroll * vc->vc_font.height;
++	par->var.vmode &= ~FB_VMODE_YWRAP;
++	par->update_start(info);
+ 	fbcon_clear_margins(vc, 1);
+ 	scrollback_max -= count;
+ 	if (scrollback_max < 0)
+@@ -1590,7 +1588,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
+ 	unsigned short *d = (unsigned short *)
+ 	    (vc->vc_origin + vc->vc_size_row * line);
+ 	unsigned short *s = d + offset;
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+ 	while (count--) {
+ 		unsigned short *start = s;
+@@ -1603,8 +1601,8 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
+ 
+ 			if (c == scr_readw(d)) {
+ 				if (s > start) {
+-					ops->bmove(vc, info, line + ycount, x,
+-						   line, x, 1, s-start);
++					par->bmove(vc, info, line + ycount, x,
++						   line, x, 1, s - start);
+ 					x += s - start + 1;
+ 					start = s + 1;
+ 				} else {
+@@ -1619,8 +1617,7 @@ static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
+ 			d++;
+ 		} while (s < le);
+ 		if (s > start)
+-			ops->bmove(vc, info, line + ycount, x, line, x, 1,
+-				   s-start);
++			par->bmove(vc, info, line + ycount, x, line, x, 1, s - start);
+ 		console_conditional_schedule();
+ 		if (ycount > 0)
+ 			line++;
+@@ -1691,7 +1688,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy,
+ 			    int dy, int dx, int height, int width, u_int y_break)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	u_int b;
+ 
+ 	if (sy < y_break && sy + height > y_break) {
+@@ -1725,8 +1722,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy,
+ 		}
+ 		return;
+ 	}
+-	ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
+-		   height, width);
++	par->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx, height, width);
+ }
+ 
+ static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
+@@ -1953,15 +1949,13 @@ static void updatescrollmode_accel(struct fbcon_display *p,
+ 					struct vc_data *vc)
+ {
+ #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	int cap = info->flags;
+ 	u16 t = 0;
+-	int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
+-				  info->fix.xpanstep);
+-	int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
+-	int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+-	int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
+-				   info->var.xres_virtual);
++	int ypan = FBCON_SWAP(par->rotate, info->fix.ypanstep, info->fix.xpanstep);
++	int ywrap = FBCON_SWAP(par->rotate, info->fix.ywrapstep, t);
++	int yres = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
++	int vyres = FBCON_SWAP(par->rotate, info->var.yres_virtual, info->var.xres_virtual);
+ 	int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
+ 		divides(ypan, vc->vc_font.height) && vyres > yres;
+ 	int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
+@@ -1994,11 +1988,10 @@ static void updatescrollmode(struct fbcon_display *p,
+ 					struct fb_info *info,
+ 					struct vc_data *vc)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	int fh = vc->vc_font.height;
+-	int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
+-	int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
+-				   info->var.xres_virtual);
++	int yres = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
++	int vyres = FBCON_SWAP(par->rotate, info->var.yres_virtual, info->var.xres_virtual);
+ 
+ 	p->vrows = vyres/fh;
+ 	if (yres > (fh * (vc->vc_rows + 1)))
+@@ -2017,7 +2010,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
+ 			unsigned int height, unsigned int user)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+ 	struct fb_var_screeninfo var = info->var;
+ 	int x_diff, y_diff, virt_w, virt_h, virt_fw, virt_fh;
+@@ -2040,12 +2033,10 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
+ 			return -EINVAL;
+ 	}
+ 
+-	virt_w = FBCON_SWAP(ops->rotate, width, height);
+-	virt_h = FBCON_SWAP(ops->rotate, height, width);
+-	virt_fw = FBCON_SWAP(ops->rotate, vc->vc_font.width,
+-				 vc->vc_font.height);
+-	virt_fh = FBCON_SWAP(ops->rotate, vc->vc_font.height,
+-				 vc->vc_font.width);
++	virt_w = FBCON_SWAP(par->rotate, width, height);
++	virt_h = FBCON_SWAP(par->rotate, height, width);
++	virt_fw = FBCON_SWAP(par->rotate, vc->vc_font.width, vc->vc_font.height);
++	virt_fh = FBCON_SWAP(par->rotate, vc->vc_font.height, vc->vc_font.width);
+ 	var.xres = virt_w * virt_fw;
+ 	var.yres = virt_h * virt_fh;
+ 	x_diff = info->var.xres - var.xres;
+@@ -2071,7 +2062,7 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
+ 			fb_set_var(info, &var);
+ 		}
+ 		var_to_display(p, &info->var, info);
+-		ops->var = info->var;
++		par->var = info->var;
+ 	}
+ 	updatescrollmode(p, info, vc);
+ 	return 0;
+@@ -2080,13 +2071,13 @@ static int fbcon_resize(struct vc_data *vc, unsigned int width,
+ static bool fbcon_switch(struct vc_data *vc)
+ {
+ 	struct fb_info *info, *old_info = NULL;
+-	struct fbcon_ops *ops;
++	struct fbcon_par *par;
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+ 	struct fb_var_screeninfo var;
+ 	int i, ret, prev_console;
+ 
+ 	info = fbcon_info_from_console(vc->vc_num);
+-	ops = info->fbcon_par;
++	par = info->fbcon_par;
+ 
+ 	if (logo_shown >= 0) {
+ 		struct vc_data *conp2 = vc_cons[logo_shown].d;
+@@ -2097,7 +2088,7 @@ static bool fbcon_switch(struct vc_data *vc)
+ 		logo_shown = FBCON_LOGO_CANSHOW;
+ 	}
+ 
+-	prev_console = ops->currcon;
++	prev_console = par->currcon;
+ 	if (prev_console != -1)
+ 		old_info = fbcon_info_from_console(prev_console);
+ 	/*
+@@ -2110,9 +2101,9 @@ static bool fbcon_switch(struct vc_data *vc)
+ 	 */
+ 	fbcon_for_each_registered_fb(i) {
+ 		if (fbcon_registered_fb[i]->fbcon_par) {
+-			struct fbcon_ops *o = fbcon_registered_fb[i]->fbcon_par;
++			struct fbcon_par *par = fbcon_registered_fb[i]->fbcon_par;
+ 
+-			o->currcon = vc->vc_num;
++			par->currcon = vc->vc_num;
+ 		}
+ 	}
+ 	memset(&var, 0, sizeof(struct fb_var_screeninfo));
+@@ -2126,7 +2117,7 @@ static bool fbcon_switch(struct vc_data *vc)
+ 	info->var.activate = var.activate;
+ 	var.vmode |= info->var.vmode & ~FB_VMODE_MASK;
+ 	fb_set_var(info, &var);
+-	ops->var = info->var;
++	par->var = info->var;
+ 
+ 	if (old_info != NULL && (old_info != info ||
+ 				 info->flags & FBINFO_MISC_ALWAYS_SETPAR)) {
+@@ -2144,16 +2135,16 @@ static bool fbcon_switch(struct vc_data *vc)
+ 	}
+ 
+ 	if (fbcon_is_inactive(vc, info) ||
+-	    ops->blank_state != FB_BLANK_UNBLANK)
++	    par->blank_state != FB_BLANK_UNBLANK)
+ 		fbcon_del_cursor_work(info);
+ 	else
+ 		fbcon_add_cursor_work(info);
+ 
+ 	set_blitting_type(vc, info);
+-	ops->cursor_reset = 1;
++	par->cursor_reset = 1;
+ 
+-	if (ops->rotate_font && ops->rotate_font(info, vc)) {
+-		ops->rotate = FB_ROTATE_UR;
++	if (par->rotate_font && par->rotate_font(info, vc)) {
++		par->rotate = FB_ROTATE_UR;
+ 		set_blitting_type(vc, info);
+ 	}
+ 
+@@ -2184,8 +2175,8 @@ static bool fbcon_switch(struct vc_data *vc)
+ 	scrollback_current = 0;
+ 
+ 	if (!fbcon_is_inactive(vc, info)) {
+-	    ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+-	    ops->update_start(info);
++	    par->var.xoffset = par->var.yoffset = p->yscroll = 0;
++	    par->update_start(info);
+ 	}
+ 
+ 	fbcon_set_palette(vc, color_table);
+@@ -2194,7 +2185,7 @@ static bool fbcon_switch(struct vc_data *vc)
+ 	if (logo_shown == FBCON_LOGO_DRAW) {
+ 
+ 		logo_shown = fg_console;
+-		fb_show_logo(info, ops->rotate);
++		fb_show_logo(info, par->rotate);
+ 		update_region(vc,
+ 			      vc->vc_origin + vc->vc_size_row * vc->vc_top,
+ 			      vc->vc_size_row * (vc->vc_bottom -
+@@ -2222,27 +2213,27 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
+ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+ 	if (mode_switch) {
+ 		struct fb_var_screeninfo var = info->var;
+ 
+-		ops->graphics = 1;
++		par->graphics = 1;
+ 
+ 		if (!blank) {
+ 			var.activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE |
+ 				FB_ACTIVATE_KD_TEXT;
+ 			fb_set_var(info, &var);
+-			ops->graphics = 0;
+-			ops->var = info->var;
++			par->graphics = 0;
++			par->var = info->var;
+ 		}
+ 	}
+ 
+  	if (!fbcon_is_inactive(vc, info)) {
+-		if (ops->blank_state != blank) {
+-			ops->blank_state = blank;
++		if (par->blank_state != blank) {
++			par->blank_state = blank;
+ 			fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW);
+-			ops->cursor_flash = (!blank);
++			par->cursor_flash = (!blank);
+ 
+ 			if (fb_blank(info, blank))
+ 				fbcon_generic_blank(vc, info, blank);
+@@ -2253,7 +2244,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
+ 	}
+ 
+ 	if (mode_switch || fbcon_is_inactive(vc, info) ||
+-	    ops->blank_state != FB_BLANK_UNBLANK)
++	    par->blank_state != FB_BLANK_UNBLANK)
+ 		fbcon_del_cursor_work(info);
+ 	else
+ 		fbcon_add_cursor_work(info);
+@@ -2264,10 +2255,10 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
+ static int fbcon_debug_enter(struct vc_data *vc)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+-	ops->save_graphics = ops->graphics;
+-	ops->graphics = 0;
++	par->save_graphics = par->graphics;
++	par->graphics = 0;
+ 	if (info->fbops->fb_debug_enter)
+ 		info->fbops->fb_debug_enter(info);
+ 	fbcon_set_palette(vc, color_table);
+@@ -2277,9 +2268,9 @@ static int fbcon_debug_enter(struct vc_data *vc)
+ static int fbcon_debug_leave(struct vc_data *vc)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+-	ops->graphics = ops->save_graphics;
++	par->graphics = par->save_graphics;
+ 	if (info->fbops->fb_debug_leave)
+ 		info->fbops->fb_debug_leave(info);
+ 	return 0;
+@@ -2415,7 +2406,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
+ 			     const u8 * data, int userfont)
+ {
+ 	struct fb_info *info = fbcon_info_from_console(vc->vc_num);
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fbcon_display *p = &fb_display[vc->vc_num];
+ 	int resize, ret, old_userfont, old_width, old_height, old_charcount;
+ 	u8 *old_data = vc->vc_font.data;
+@@ -2442,8 +2433,8 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
+ 	if (resize) {
+ 		int cols, rows;
+ 
+-		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+-		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
++		cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
++		rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
+ 		cols /= w;
+ 		rows /= h;
+ 		ret = vc_resize(vc, cols, rows);
+@@ -2676,11 +2667,11 @@ static void fbcon_invert_region(struct vc_data *vc, u16 * p, int cnt)
+ void fbcon_suspended(struct fb_info *info)
+ {
+ 	struct vc_data *vc = NULL;
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+-	if (!ops || ops->currcon < 0)
++	if (!par || par->currcon < 0)
+ 		return;
+-	vc = vc_cons[ops->currcon].d;
++	vc = vc_cons[par->currcon].d;
+ 
+ 	/* Clear cursor, restore saved data */
+ 	fbcon_cursor(vc, CM_ERASE);
+@@ -2689,27 +2680,27 @@ void fbcon_suspended(struct fb_info *info)
+ void fbcon_resumed(struct fb_info *info)
+ {
+ 	struct vc_data *vc;
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+-	if (!ops || ops->currcon < 0)
++	if (!par || par->currcon < 0)
+ 		return;
+-	vc = vc_cons[ops->currcon].d;
++	vc = vc_cons[par->currcon].d;
+ 
+ 	update_screen(vc);
+ }
+ 
+ static void fbcon_modechanged(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct vc_data *vc;
+ 	struct fbcon_display *p;
+ 	int rows, cols;
+ 
+-	if (!ops || ops->currcon < 0)
++	if (!par || par->currcon < 0)
+ 		return;
+-	vc = vc_cons[ops->currcon].d;
++	vc = vc_cons[par->currcon].d;
+ 	if (vc->vc_mode != KD_TEXT ||
+-	    fbcon_info_from_console(ops->currcon) != info)
++	    fbcon_info_from_console(par->currcon) != info)
+ 		return;
+ 
+ 	p = &fb_display[vc->vc_num];
+@@ -2717,8 +2708,8 @@ static void fbcon_modechanged(struct fb_info *info)
+ 
+ 	if (con_is_visible(vc)) {
+ 		var_to_display(p, &info->var, info);
+-		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+-		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
++		cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
++		rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
+ 		cols /= vc->vc_font.width;
+ 		rows /= vc->vc_font.height;
+ 		vc_resize(vc, cols, rows);
+@@ -2727,8 +2718,8 @@ static void fbcon_modechanged(struct fb_info *info)
+ 		scrollback_current = 0;
+ 
+ 		if (!fbcon_is_inactive(vc, info)) {
+-		    ops->var.xoffset = ops->var.yoffset = p->yscroll = 0;
+-		    ops->update_start(info);
++		    par->var.xoffset = par->var.yoffset = p->yscroll = 0;
++		    par->update_start(info);
+ 		}
+ 
+ 		fbcon_set_palette(vc, color_table);
+@@ -2738,12 +2729,12 @@ static void fbcon_modechanged(struct fb_info *info)
+ 
+ static void fbcon_set_all_vcs(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct vc_data *vc;
+ 	struct fbcon_display *p;
+ 	int i, rows, cols, fg = -1;
+ 
+-	if (!ops || ops->currcon < 0)
++	if (!par || par->currcon < 0)
+ 		return;
+ 
+ 	for (i = first_fb_vc; i <= last_fb_vc; i++) {
+@@ -2760,8 +2751,8 @@ static void fbcon_set_all_vcs(struct fb_info *info)
+ 		p = &fb_display[vc->vc_num];
+ 		set_blitting_type(vc, info);
+ 		var_to_display(p, &info->var, info);
+-		cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+-		rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
++		cols = FBCON_SWAP(par->rotate, info->var.xres, info->var.yres);
++		rows = FBCON_SWAP(par->rotate, info->var.yres, info->var.xres);
+ 		cols /= vc->vc_font.width;
+ 		rows /= vc->vc_font.height;
+ 		vc_resize(vc, cols, rows);
+@@ -2784,13 +2775,13 @@ EXPORT_SYMBOL(fbcon_update_vcs);
+ /* let fbcon check if it supports a new screen resolution */
+ int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct vc_data *vc;
+ 	unsigned int i;
+ 
+ 	WARN_CONSOLE_UNLOCKED();
+ 
+-	if (!ops)
++	if (!par)
+ 		return 0;
+ 
+ 	/* prevent setting a screen size which is smaller than font size */
+@@ -3088,15 +3079,14 @@ int fbcon_fb_registered(struct fb_info *info)
+ 
+ void fbcon_fb_blanked(struct fb_info *info, int blank)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct vc_data *vc;
+ 
+-	if (!ops || ops->currcon < 0)
++	if (!par || par->currcon < 0)
+ 		return;
+ 
+-	vc = vc_cons[ops->currcon].d;
+-	if (vc->vc_mode != KD_TEXT ||
+-			fbcon_info_from_console(ops->currcon) != info)
++	vc = vc_cons[par->currcon].d;
++	if (vc->vc_mode != KD_TEXT || fbcon_info_from_console(par->currcon) != info)
+ 		return;
+ 
+ 	if (con_is_visible(vc)) {
+@@ -3105,7 +3095,7 @@ void fbcon_fb_blanked(struct fb_info *info, int blank)
+ 		else
+ 			do_unblank_screen(0);
+ 	}
+-	ops->blank_state = blank;
++	par->blank_state = blank;
+ }
+ 
+ void fbcon_new_modelist(struct fb_info *info)
+@@ -3296,7 +3286,7 @@ static ssize_t show_cursor_blink(struct device *device,
+ 				 struct device_attribute *attr, char *buf)
+ {
+ 	struct fb_info *info;
+-	struct fbcon_ops *ops;
++	struct fbcon_par *par;
+ 	int idx, blink = -1;
+ 
+ 	console_lock();
+@@ -3306,12 +3296,12 @@ static ssize_t show_cursor_blink(struct device *device,
+ 		goto err;
+ 
+ 	info = fbcon_registered_fb[idx];
+-	ops = info->fbcon_par;
++	par = info->fbcon_par;
+ 
+-	if (!ops)
++	if (!par)
+ 		goto err;
+ 
+-	blink = delayed_work_pending(&ops->cursor_work);
++	blink = delayed_work_pending(&par->cursor_work);
+ err:
+ 	console_unlock();
+ 	return sysfs_emit(buf, "%d\n", blink);
+diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
+index 7945b360862cb3..95d2399fe8fc50 100644
+--- a/drivers/video/fbdev/core/fbcon.h
++++ b/drivers/video/fbdev/core/fbcon.h
+@@ -50,7 +50,7 @@ struct fbcon_display {
+     const struct fb_videomode *mode;
+ };
+ 
+-struct fbcon_ops {
++struct fbcon_par {
+ 	void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
+ 		      int sx, int dy, int dx, int height, int width);
+ 	void (*clear)(struct vc_data *vc, struct fb_info *info, int sy,
+@@ -185,7 +185,7 @@ static inline u_short fb_scrollmode(struct fbcon_display *fb)
+ #ifdef CONFIG_FB_TILEBLITTING
+ extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
+ #endif
+-extern void fbcon_set_bitops(struct fbcon_ops *ops);
++extern void fbcon_set_bitops(struct fbcon_par *par);
+ extern int  soft_cursor(struct fb_info *info, struct fb_cursor *cursor);
+ 
+ #define FBCON_ATTRIBUTE_UNDERLINE 1
+@@ -224,7 +224,7 @@ static inline int get_attribute(struct fb_info *info, u16 c)
+         (i == FB_ROTATE_UR || i == FB_ROTATE_UD) ? _r : _v; })
+ 
+ #ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+-extern void fbcon_set_rotate(struct fbcon_ops *ops);
++extern void fbcon_set_rotate(struct fbcon_par *par);
+ #else
+ #define fbcon_set_rotate(x) do {} while(0)
+ #endif /* CONFIG_FRAMEBUFFER_CONSOLE_ROTATION */
+diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
+index 9f4d65478554ad..c988e8b7e981c0 100644
+--- a/drivers/video/fbdev/core/fbcon_ccw.c
++++ b/drivers/video/fbdev/core/fbcon_ccw.c
+@@ -63,9 +63,9 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
+ static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ 		     int sx, int dy, int dx, int height, int width)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fb_copyarea area;
+-	u32 vyres = GETVYRES(ops->p, info);
++	u32 vyres = GETVYRES(par->p, info);
+ 
+ 	area.sx = sy * vc->vc_font.height;
+ 	area.sy = vyres - ((sx + width) * vc->vc_font.width);
+@@ -80,9 +80,9 @@ static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
+ 		     int sx, int height, int width, int fg, int bg)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fb_fillrect region;
+-	u32 vyres = GETVYRES(ops->p, info);
++	u32 vyres = GETVYRES(par->p, info);
+ 
+ 	region.color = bg;
+ 	region.dx = sy * vc->vc_font.height;
+@@ -99,13 +99,13 @@ static inline void ccw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+ 				    u32 d_pitch, u32 s_pitch, u32 cellsize,
+ 				    struct fb_image *image, u8 *buf, u8 *dst)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ 	u32 idx = (vc->vc_font.height + 7) >> 3;
+ 	u8 *src;
+ 
+ 	while (cnt--) {
+-		src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
++		src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize;
+ 
+ 		if (attr) {
+ 			ccw_update_attr(buf, src, attr, vc);
+@@ -130,7 +130,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
+ 		      int fg, int bg)
+ {
+ 	struct fb_image image;
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	u32 width = (vc->vc_font.height + 7)/8;
+ 	u32 cellsize = width * vc->vc_font.width;
+ 	u32 maxcnt = info->pixmap.size/cellsize;
+@@ -139,9 +139,9 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
+ 	u32 cnt, pitch, size;
+ 	u32 attribute = get_attribute(info, scr_readw(s));
+ 	u8 *dst, *buf = NULL;
+-	u32 vyres = GETVYRES(ops->p, info);
++	u32 vyres = GETVYRES(par->p, info);
+ 
+-	if (!ops->fontbuffer)
++	if (!par->fontbuffer)
+ 		return;
+ 
+ 	image.fg_color = fg;
+@@ -221,28 +221,28 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 		       int fg, int bg)
+ {
+ 	struct fb_cursor cursor;
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ 	int w = (vc->vc_font.height + 7) >> 3, c;
+-	int y = real_y(ops->p, vc->state.y);
++	int y = real_y(par->p, vc->state.y);
+ 	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
+ 	int err = 1, dx, dy;
+ 	char *src;
+-	u32 vyres = GETVYRES(ops->p, info);
++	u32 vyres = GETVYRES(par->p, info);
+ 
+-	if (!ops->fontbuffer)
++	if (!par->fontbuffer)
+ 		return;
+ 
+ 	cursor.set = 0;
+ 
+  	c = scr_readw((u16 *) vc->vc_pos);
+ 	attribute = get_attribute(info, c);
+-	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
++	src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+ 
+-	if (ops->cursor_state.image.data != src ||
+-	    ops->cursor_reset) {
+-	    ops->cursor_state.image.data = src;
+-	    cursor.set |= FB_CUR_SETIMAGE;
++	if (par->cursor_state.image.data != src ||
++	    par->cursor_reset) {
++		par->cursor_state.image.data = src;
++		cursor.set |= FB_CUR_SETIMAGE;
+ 	}
+ 
+ 	if (attribute) {
+@@ -251,49 +251,49 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 		dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC);
+ 		if (!dst)
+ 			return;
+-		kfree(ops->cursor_data);
+-		ops->cursor_data = dst;
++		kfree(par->cursor_data);
++		par->cursor_data = dst;
+ 		ccw_update_attr(dst, src, attribute, vc);
+ 		src = dst;
+ 	}
+ 
+-	if (ops->cursor_state.image.fg_color != fg ||
+-	    ops->cursor_state.image.bg_color != bg ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.fg_color = fg;
+-		ops->cursor_state.image.bg_color = bg;
++	if (par->cursor_state.image.fg_color != fg ||
++	    par->cursor_state.image.bg_color != bg ||
++	    par->cursor_reset) {
++		par->cursor_state.image.fg_color = fg;
++		par->cursor_state.image.bg_color = bg;
+ 		cursor.set |= FB_CUR_SETCMAP;
+ 	}
+ 
+-	if (ops->cursor_state.image.height != vc->vc_font.width ||
+-	    ops->cursor_state.image.width != vc->vc_font.height ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.height = vc->vc_font.width;
+-		ops->cursor_state.image.width = vc->vc_font.height;
++	if (par->cursor_state.image.height != vc->vc_font.width ||
++	    par->cursor_state.image.width != vc->vc_font.height ||
++	    par->cursor_reset) {
++		par->cursor_state.image.height = vc->vc_font.width;
++		par->cursor_state.image.width = vc->vc_font.height;
+ 		cursor.set |= FB_CUR_SETSIZE;
+ 	}
+ 
+ 	dx = y * vc->vc_font.height;
+ 	dy = vyres - ((vc->state.x + 1) * vc->vc_font.width);
+ 
+-	if (ops->cursor_state.image.dx != dx ||
+-	    ops->cursor_state.image.dy != dy ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.dx = dx;
+-		ops->cursor_state.image.dy = dy;
++	if (par->cursor_state.image.dx != dx ||
++	    par->cursor_state.image.dy != dy ||
++	    par->cursor_reset) {
++		par->cursor_state.image.dx = dx;
++		par->cursor_state.image.dy = dy;
+ 		cursor.set |= FB_CUR_SETPOS;
+ 	}
+ 
+-	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.hot.x = cursor.hot.y = 0;
++	if (par->cursor_state.hot.x || par->cursor_state.hot.y ||
++	    par->cursor_reset) {
++		par->cursor_state.hot.x = cursor.hot.y = 0;
+ 		cursor.set |= FB_CUR_SETHOT;
+ 	}
+ 
+ 	if (cursor.set & FB_CUR_SETSIZE ||
+-	    vc->vc_cursor_type != ops->p->cursor_shape ||
+-	    ops->cursor_state.mask == NULL ||
+-	    ops->cursor_reset) {
++	    vc->vc_cursor_type != par->p->cursor_shape ||
++	    par->cursor_state.mask == NULL ||
++	    par->cursor_reset) {
+ 		char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
+ 						 GFP_ATOMIC);
+ 		int cur_height, size, i = 0;
+@@ -309,13 +309,13 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 			return;
+ 		}
+ 
+-		kfree(ops->cursor_state.mask);
+-		ops->cursor_state.mask = mask;
++		kfree(par->cursor_state.mask);
++		par->cursor_state.mask = mask;
+ 
+-		ops->p->cursor_shape = vc->vc_cursor_type;
++		par->p->cursor_shape = vc->vc_cursor_type;
+ 		cursor.set |= FB_CUR_SETSHAPE;
+ 
+-		switch (CUR_SIZE(ops->p->cursor_shape)) {
++		switch (CUR_SIZE(par->p->cursor_shape)) {
+ 		case CUR_NONE:
+ 			cur_height = 0;
+ 			break;
+@@ -350,26 +350,26 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 
+ 	switch (mode) {
+ 	case CM_ERASE:
+-		ops->cursor_state.enable = 0;
++		par->cursor_state.enable = 0;
+ 		break;
+ 	case CM_DRAW:
+ 	case CM_MOVE:
+ 	default:
+-		ops->cursor_state.enable = (use_sw) ? 0 : 1;
++		par->cursor_state.enable = (use_sw) ? 0 : 1;
+ 		break;
+ 	}
+ 
+ 	cursor.image.data = src;
+-	cursor.image.fg_color = ops->cursor_state.image.fg_color;
+-	cursor.image.bg_color = ops->cursor_state.image.bg_color;
+-	cursor.image.dx = ops->cursor_state.image.dx;
+-	cursor.image.dy = ops->cursor_state.image.dy;
+-	cursor.image.height = ops->cursor_state.image.height;
+-	cursor.image.width = ops->cursor_state.image.width;
+-	cursor.hot.x = ops->cursor_state.hot.x;
+-	cursor.hot.y = ops->cursor_state.hot.y;
+-	cursor.mask = ops->cursor_state.mask;
+-	cursor.enable = ops->cursor_state.enable;
++	cursor.image.fg_color = par->cursor_state.image.fg_color;
++	cursor.image.bg_color = par->cursor_state.image.bg_color;
++	cursor.image.dx = par->cursor_state.image.dx;
++	cursor.image.dy = par->cursor_state.image.dy;
++	cursor.image.height = par->cursor_state.image.height;
++	cursor.image.width = par->cursor_state.image.width;
++	cursor.hot.x = par->cursor_state.hot.x;
++	cursor.hot.y = par->cursor_state.hot.y;
++	cursor.mask = par->cursor_state.mask;
++	cursor.enable = par->cursor_state.enable;
+ 	cursor.image.depth = 1;
+ 	cursor.rop = ROP_XOR;
+ 
+@@ -379,32 +379,32 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 	if (err)
+ 		soft_cursor(info, &cursor);
+ 
+-	ops->cursor_reset = 0;
++	par->cursor_reset = 0;
+ }
+ 
+ static int ccw_update_start(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	u32 yoffset;
+-	u32 vyres = GETVYRES(ops->p, info);
++	u32 vyres = GETVYRES(par->p, info);
+ 	int err;
+ 
+-	yoffset = (vyres - info->var.yres) - ops->var.xoffset;
+-	ops->var.xoffset = ops->var.yoffset;
+-	ops->var.yoffset = yoffset;
+-	err = fb_pan_display(info, &ops->var);
+-	ops->var.xoffset = info->var.xoffset;
+-	ops->var.yoffset = info->var.yoffset;
+-	ops->var.vmode = info->var.vmode;
++	yoffset = (vyres - info->var.yres) - par->var.xoffset;
++	par->var.xoffset = par->var.yoffset;
++	par->var.yoffset = yoffset;
++	err = fb_pan_display(info, &par->var);
++	par->var.xoffset = info->var.xoffset;
++	par->var.yoffset = info->var.yoffset;
++	par->var.vmode = info->var.vmode;
+ 	return err;
+ }
+ 
+-void fbcon_rotate_ccw(struct fbcon_ops *ops)
++void fbcon_rotate_ccw(struct fbcon_par *par)
+ {
+-	ops->bmove = ccw_bmove;
+-	ops->clear = ccw_clear;
+-	ops->putcs = ccw_putcs;
+-	ops->clear_margins = ccw_clear_margins;
+-	ops->cursor = ccw_cursor;
+-	ops->update_start = ccw_update_start;
++	par->bmove = ccw_bmove;
++	par->clear = ccw_clear;
++	par->putcs = ccw_putcs;
++	par->clear_margins = ccw_clear_margins;
++	par->cursor = ccw_cursor;
++	par->update_start = ccw_update_start;
+ }
+diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
+index b18e31886da102..81954ccc35efcf 100644
+--- a/drivers/video/fbdev/core/fbcon_cw.c
++++ b/drivers/video/fbdev/core/fbcon_cw.c
+@@ -48,9 +48,9 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
+ static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ 		     int sx, int dy, int dx, int height, int width)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fb_copyarea area;
+-	u32 vxres = GETVXRES(ops->p, info);
++	u32 vxres = GETVXRES(par->p, info);
+ 
+ 	area.sx = vxres - ((sy + height) * vc->vc_font.height);
+ 	area.sy = sx * vc->vc_font.width;
+@@ -65,9 +65,9 @@ static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
+ 		     int sx, int height, int width, int fg, int bg)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fb_fillrect region;
+-	u32 vxres = GETVXRES(ops->p, info);
++	u32 vxres = GETVXRES(par->p, info);
+ 
+ 	region.color = bg;
+ 	region.dx = vxres - ((sy + height) * vc->vc_font.height);
+@@ -84,13 +84,13 @@ static inline void cw_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+ 				    u32 d_pitch, u32 s_pitch, u32 cellsize,
+ 				    struct fb_image *image, u8 *buf, u8 *dst)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ 	u32 idx = (vc->vc_font.height + 7) >> 3;
+ 	u8 *src;
+ 
+ 	while (cnt--) {
+-		src = ops->fontbuffer + (scr_readw(s++) & charmask)*cellsize;
++		src = par->fontbuffer + (scr_readw(s++) & charmask) * cellsize;
+ 
+ 		if (attr) {
+ 			cw_update_attr(buf, src, attr, vc);
+@@ -115,7 +115,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
+ 		      int fg, int bg)
+ {
+ 	struct fb_image image;
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	u32 width = (vc->vc_font.height + 7)/8;
+ 	u32 cellsize = width * vc->vc_font.width;
+ 	u32 maxcnt = info->pixmap.size/cellsize;
+@@ -124,9 +124,9 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
+ 	u32 cnt, pitch, size;
+ 	u32 attribute = get_attribute(info, scr_readw(s));
+ 	u8 *dst, *buf = NULL;
+-	u32 vxres = GETVXRES(ops->p, info);
++	u32 vxres = GETVXRES(par->p, info);
+ 
+-	if (!ops->fontbuffer)
++	if (!par->fontbuffer)
+ 		return;
+ 
+ 	image.fg_color = fg;
+@@ -204,28 +204,28 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 		      int fg, int bg)
+ {
+ 	struct fb_cursor cursor;
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ 	int w = (vc->vc_font.height + 7) >> 3, c;
+-	int y = real_y(ops->p, vc->state.y);
++	int y = real_y(par->p, vc->state.y);
+ 	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
+ 	int err = 1, dx, dy;
+ 	char *src;
+-	u32 vxres = GETVXRES(ops->p, info);
++	u32 vxres = GETVXRES(par->p, info);
+ 
+-	if (!ops->fontbuffer)
++	if (!par->fontbuffer)
+ 		return;
+ 
+ 	cursor.set = 0;
+ 
+  	c = scr_readw((u16 *) vc->vc_pos);
+ 	attribute = get_attribute(info, c);
+-	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
++	src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.width));
+ 
+-	if (ops->cursor_state.image.data != src ||
+-	    ops->cursor_reset) {
+-	    ops->cursor_state.image.data = src;
+-	    cursor.set |= FB_CUR_SETIMAGE;
++	if (par->cursor_state.image.data != src ||
++	    par->cursor_reset) {
++		par->cursor_state.image.data = src;
++		cursor.set |= FB_CUR_SETIMAGE;
+ 	}
+ 
+ 	if (attribute) {
+@@ -234,49 +234,49 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 		dst = kmalloc_array(w, vc->vc_font.width, GFP_ATOMIC);
+ 		if (!dst)
+ 			return;
+-		kfree(ops->cursor_data);
+-		ops->cursor_data = dst;
++		kfree(par->cursor_data);
++		par->cursor_data = dst;
+ 		cw_update_attr(dst, src, attribute, vc);
+ 		src = dst;
+ 	}
+ 
+-	if (ops->cursor_state.image.fg_color != fg ||
+-	    ops->cursor_state.image.bg_color != bg ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.fg_color = fg;
+-		ops->cursor_state.image.bg_color = bg;
++	if (par->cursor_state.image.fg_color != fg ||
++	    par->cursor_state.image.bg_color != bg ||
++	    par->cursor_reset) {
++		par->cursor_state.image.fg_color = fg;
++		par->cursor_state.image.bg_color = bg;
+ 		cursor.set |= FB_CUR_SETCMAP;
+ 	}
+ 
+-	if (ops->cursor_state.image.height != vc->vc_font.width ||
+-	    ops->cursor_state.image.width != vc->vc_font.height ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.height = vc->vc_font.width;
+-		ops->cursor_state.image.width = vc->vc_font.height;
++	if (par->cursor_state.image.height != vc->vc_font.width ||
++	    par->cursor_state.image.width != vc->vc_font.height ||
++	    par->cursor_reset) {
++		par->cursor_state.image.height = vc->vc_font.width;
++		par->cursor_state.image.width = vc->vc_font.height;
+ 		cursor.set |= FB_CUR_SETSIZE;
+ 	}
+ 
+ 	dx = vxres - ((y * vc->vc_font.height) + vc->vc_font.height);
+ 	dy = vc->state.x * vc->vc_font.width;
+ 
+-	if (ops->cursor_state.image.dx != dx ||
+-	    ops->cursor_state.image.dy != dy ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.dx = dx;
+-		ops->cursor_state.image.dy = dy;
++	if (par->cursor_state.image.dx != dx ||
++	    par->cursor_state.image.dy != dy ||
++	    par->cursor_reset) {
++		par->cursor_state.image.dx = dx;
++		par->cursor_state.image.dy = dy;
+ 		cursor.set |= FB_CUR_SETPOS;
+ 	}
+ 
+-	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.hot.x = cursor.hot.y = 0;
++	if (par->cursor_state.hot.x || par->cursor_state.hot.y ||
++	    par->cursor_reset) {
++		par->cursor_state.hot.x = cursor.hot.y = 0;
+ 		cursor.set |= FB_CUR_SETHOT;
+ 	}
+ 
+ 	if (cursor.set & FB_CUR_SETSIZE ||
+-	    vc->vc_cursor_type != ops->p->cursor_shape ||
+-	    ops->cursor_state.mask == NULL ||
+-	    ops->cursor_reset) {
++	    vc->vc_cursor_type != par->p->cursor_shape ||
++	    par->cursor_state.mask == NULL ||
++	    par->cursor_reset) {
+ 		char *tmp, *mask = kmalloc_array(w, vc->vc_font.width,
+ 						 GFP_ATOMIC);
+ 		int cur_height, size, i = 0;
+@@ -292,13 +292,13 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 			return;
+ 		}
+ 
+-		kfree(ops->cursor_state.mask);
+-		ops->cursor_state.mask = mask;
++		kfree(par->cursor_state.mask);
++		par->cursor_state.mask = mask;
+ 
+-		ops->p->cursor_shape = vc->vc_cursor_type;
++		par->p->cursor_shape = vc->vc_cursor_type;
+ 		cursor.set |= FB_CUR_SETSHAPE;
+ 
+-		switch (CUR_SIZE(ops->p->cursor_shape)) {
++		switch (CUR_SIZE(par->p->cursor_shape)) {
+ 		case CUR_NONE:
+ 			cur_height = 0;
+ 			break;
+@@ -333,26 +333,26 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 
+ 	switch (mode) {
+ 	case CM_ERASE:
+-		ops->cursor_state.enable = 0;
++		par->cursor_state.enable = 0;
+ 		break;
+ 	case CM_DRAW:
+ 	case CM_MOVE:
+ 	default:
+-		ops->cursor_state.enable = (use_sw) ? 0 : 1;
++		par->cursor_state.enable = (use_sw) ? 0 : 1;
+ 		break;
+ 	}
+ 
+ 	cursor.image.data = src;
+-	cursor.image.fg_color = ops->cursor_state.image.fg_color;
+-	cursor.image.bg_color = ops->cursor_state.image.bg_color;
+-	cursor.image.dx = ops->cursor_state.image.dx;
+-	cursor.image.dy = ops->cursor_state.image.dy;
+-	cursor.image.height = ops->cursor_state.image.height;
+-	cursor.image.width = ops->cursor_state.image.width;
+-	cursor.hot.x = ops->cursor_state.hot.x;
+-	cursor.hot.y = ops->cursor_state.hot.y;
+-	cursor.mask = ops->cursor_state.mask;
+-	cursor.enable = ops->cursor_state.enable;
++	cursor.image.fg_color = par->cursor_state.image.fg_color;
++	cursor.image.bg_color = par->cursor_state.image.bg_color;
++	cursor.image.dx = par->cursor_state.image.dx;
++	cursor.image.dy = par->cursor_state.image.dy;
++	cursor.image.height = par->cursor_state.image.height;
++	cursor.image.width = par->cursor_state.image.width;
++	cursor.hot.x = par->cursor_state.hot.x;
++	cursor.hot.y = par->cursor_state.hot.y;
++	cursor.mask = par->cursor_state.mask;
++	cursor.enable = par->cursor_state.enable;
+ 	cursor.image.depth = 1;
+ 	cursor.rop = ROP_XOR;
+ 
+@@ -362,32 +362,32 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 	if (err)
+ 		soft_cursor(info, &cursor);
+ 
+-	ops->cursor_reset = 0;
++	par->cursor_reset = 0;
+ }
+ 
+ static int cw_update_start(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
+-	u32 vxres = GETVXRES(ops->p, info);
++	struct fbcon_par *par = info->fbcon_par;
++	u32 vxres = GETVXRES(par->p, info);
+ 	u32 xoffset;
+ 	int err;
+ 
+-	xoffset = vxres - (info->var.xres + ops->var.yoffset);
+-	ops->var.yoffset = ops->var.xoffset;
+-	ops->var.xoffset = xoffset;
+-	err = fb_pan_display(info, &ops->var);
+-	ops->var.xoffset = info->var.xoffset;
+-	ops->var.yoffset = info->var.yoffset;
+-	ops->var.vmode = info->var.vmode;
++	xoffset = vxres - (info->var.xres + par->var.yoffset);
++	par->var.yoffset = par->var.xoffset;
++	par->var.xoffset = xoffset;
++	err = fb_pan_display(info, &par->var);
++	par->var.xoffset = info->var.xoffset;
++	par->var.yoffset = info->var.yoffset;
++	par->var.vmode = info->var.vmode;
+ 	return err;
+ }
+ 
+-void fbcon_rotate_cw(struct fbcon_ops *ops)
++void fbcon_rotate_cw(struct fbcon_par *par)
+ {
+-	ops->bmove = cw_bmove;
+-	ops->clear = cw_clear;
+-	ops->putcs = cw_putcs;
+-	ops->clear_margins = cw_clear_margins;
+-	ops->cursor = cw_cursor;
+-	ops->update_start = cw_update_start;
++	par->bmove = cw_bmove;
++	par->clear = cw_clear;
++	par->putcs = cw_putcs;
++	par->clear_margins = cw_clear_margins;
++	par->cursor = cw_cursor;
++	par->update_start = cw_update_start;
+ }
+diff --git a/drivers/video/fbdev/core/fbcon_rotate.c b/drivers/video/fbdev/core/fbcon_rotate.c
+index 4a06e71ae4434a..a3f507825eed8a 100644
+--- a/drivers/video/fbdev/core/fbcon_rotate.c
++++ b/drivers/video/fbdev/core/fbcon_rotate.c
+@@ -20,35 +20,35 @@
+ 
+ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	int len, err = 0;
+ 	int s_cellsize, d_cellsize, i;
+ 	const u8 *src;
+ 	u8 *dst;
+ 
+-	if (vc->vc_font.data == ops->fontdata &&
+-	    ops->p->con_rotate == ops->cur_rotate)
++	if (vc->vc_font.data == par->fontdata &&
++	    par->p->con_rotate == par->cur_rotate)
+ 		goto finished;
+ 
+-	src = ops->fontdata = vc->vc_font.data;
+-	ops->cur_rotate = ops->p->con_rotate;
++	src = par->fontdata = vc->vc_font.data;
++	par->cur_rotate = par->p->con_rotate;
+ 	len = vc->vc_font.charcount;
+ 	s_cellsize = ((vc->vc_font.width + 7)/8) *
+ 		vc->vc_font.height;
+ 	d_cellsize = s_cellsize;
+ 
+-	if (ops->rotate == FB_ROTATE_CW ||
+-	    ops->rotate == FB_ROTATE_CCW)
++	if (par->rotate == FB_ROTATE_CW ||
++	    par->rotate == FB_ROTATE_CCW)
+ 		d_cellsize = ((vc->vc_font.height + 7)/8) *
+ 			vc->vc_font.width;
+ 
+ 	if (info->fbops->fb_sync)
+ 		info->fbops->fb_sync(info);
+ 
+-	if (ops->fd_size < d_cellsize * len) {
+-		kfree(ops->fontbuffer);
+-		ops->fontbuffer = NULL;
+-		ops->fd_size = 0;
++	if (par->fd_size < d_cellsize * len) {
++		kfree(par->fontbuffer);
++		par->fontbuffer = NULL;
++		par->fd_size = 0;
+ 
+ 		dst = kmalloc_array(len, d_cellsize, GFP_KERNEL);
+ 
+@@ -57,14 +57,14 @@ static int fbcon_rotate_font(struct fb_info *info, struct vc_data *vc)
+ 			goto finished;
+ 		}
+ 
+-		ops->fd_size = d_cellsize * len;
+-		ops->fontbuffer = dst;
++		par->fd_size = d_cellsize * len;
++		par->fontbuffer = dst;
+ 	}
+ 
+-	dst = ops->fontbuffer;
+-	memset(dst, 0, ops->fd_size);
++	dst = par->fontbuffer;
++	memset(dst, 0, par->fd_size);
+ 
+-	switch (ops->rotate) {
++	switch (par->rotate) {
+ 	case FB_ROTATE_UD:
+ 		for (i = len; i--; ) {
+ 			rotate_ud(src, dst, vc->vc_font.width,
+@@ -96,19 +96,19 @@ finished:
+ 	return err;
+ }
+ 
+-void fbcon_set_rotate(struct fbcon_ops *ops)
++void fbcon_set_rotate(struct fbcon_par *par)
+ {
+-	ops->rotate_font = fbcon_rotate_font;
++	par->rotate_font = fbcon_rotate_font;
+ 
+-	switch(ops->rotate) {
++	switch (par->rotate) {
+ 	case FB_ROTATE_CW:
+-		fbcon_rotate_cw(ops);
++		fbcon_rotate_cw(par);
+ 		break;
+ 	case FB_ROTATE_UD:
+-		fbcon_rotate_ud(ops);
++		fbcon_rotate_ud(par);
+ 		break;
+ 	case FB_ROTATE_CCW:
+-		fbcon_rotate_ccw(ops);
++		fbcon_rotate_ccw(par);
+ 		break;
+ 	}
+ }
+diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h
+index 01cbe303b8a295..48305e1a07631f 100644
+--- a/drivers/video/fbdev/core/fbcon_rotate.h
++++ b/drivers/video/fbdev/core/fbcon_rotate.h
+@@ -90,7 +90,7 @@ static inline void rotate_ccw(const char *in, char *out, u32 width, u32 height)
+ 	}
+ }
+ 
+-extern void fbcon_rotate_cw(struct fbcon_ops *ops);
+-extern void fbcon_rotate_ud(struct fbcon_ops *ops);
+-extern void fbcon_rotate_ccw(struct fbcon_ops *ops);
++extern void fbcon_rotate_cw(struct fbcon_par *par);
++extern void fbcon_rotate_ud(struct fbcon_par *par);
++extern void fbcon_rotate_ccw(struct fbcon_par *par);
+ #endif
+diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
+index b6b074cfd9dc08..2ae1701f8f97e8 100644
+--- a/drivers/video/fbdev/core/fbcon_ud.c
++++ b/drivers/video/fbdev/core/fbcon_ud.c
+@@ -48,10 +48,10 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute,
+ static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ 		     int sx, int dy, int dx, int height, int width)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fb_copyarea area;
+-	u32 vyres = GETVYRES(ops->p, info);
+-	u32 vxres = GETVXRES(ops->p, info);
++	u32 vyres = GETVYRES(par->p, info);
++	u32 vxres = GETVXRES(par->p, info);
+ 
+ 	area.sy = vyres - ((sy + height) * vc->vc_font.height);
+ 	area.sx = vxres - ((sx + width) * vc->vc_font.width);
+@@ -66,10 +66,10 @@ static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
+ 		     int sx, int height, int width, int fg, int bg)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	struct fb_fillrect region;
+-	u32 vyres = GETVYRES(ops->p, info);
+-	u32 vxres = GETVXRES(ops->p, info);
++	u32 vyres = GETVYRES(par->p, info);
++	u32 vxres = GETVXRES(par->p, info);
+ 
+ 	region.color = bg;
+ 	region.dy = vyres - ((sy + height) * vc->vc_font.height);
+@@ -86,13 +86,13 @@ static inline void ud_putcs_aligned(struct vc_data *vc, struct fb_info *info,
+ 				    u32 d_pitch, u32 s_pitch, u32 cellsize,
+ 				    struct fb_image *image, u8 *buf, u8 *dst)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ 	u32 idx = vc->vc_font.width >> 3;
+ 	u8 *src;
+ 
+ 	while (cnt--) {
+-		src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
++		src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize;
+ 
+ 		if (attr) {
+ 			ud_update_attr(buf, src, attr, vc);
+@@ -119,7 +119,7 @@ static inline void ud_putcs_unaligned(struct vc_data *vc,
+ 				      struct fb_image *image, u8 *buf,
+ 				      u8 *dst)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	u16 charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ 	u32 shift_low = 0, mod = vc->vc_font.width % 8;
+ 	u32 shift_high = 8;
+@@ -127,7 +127,7 @@ static inline void ud_putcs_unaligned(struct vc_data *vc,
+ 	u8 *src;
+ 
+ 	while (cnt--) {
+-		src = ops->fontbuffer + (scr_readw(s--) & charmask)*cellsize;
++		src = par->fontbuffer + (scr_readw(s--) & charmask) * cellsize;
+ 
+ 		if (attr) {
+ 			ud_update_attr(buf, src, attr, vc);
+@@ -152,7 +152,7 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
+ 		      int fg, int bg)
+ {
+ 	struct fb_image image;
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	u32 width = (vc->vc_font.width + 7)/8;
+ 	u32 cellsize = width * vc->vc_font.height;
+ 	u32 maxcnt = info->pixmap.size/cellsize;
+@@ -161,10 +161,10 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
+ 	u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
+ 	u32 attribute = get_attribute(info, scr_readw(s));
+ 	u8 *dst, *buf = NULL;
+-	u32 vyres = GETVYRES(ops->p, info);
+-	u32 vxres = GETVXRES(ops->p, info);
++	u32 vyres = GETVYRES(par->p, info);
++	u32 vxres = GETVXRES(par->p, info);
+ 
+-	if (!ops->fontbuffer)
++	if (!par->fontbuffer)
+ 		return;
+ 
+ 	image.fg_color = fg;
+@@ -251,29 +251,29 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 		      int fg, int bg)
+ {
+ 	struct fb_cursor cursor;
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	unsigned short charmask = vc->vc_hi_font_mask ? 0x1ff : 0xff;
+ 	int w = (vc->vc_font.width + 7) >> 3, c;
+-	int y = real_y(ops->p, vc->state.y);
++	int y = real_y(par->p, vc->state.y);
+ 	int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
+ 	int err = 1, dx, dy;
+ 	char *src;
+-	u32 vyres = GETVYRES(ops->p, info);
+-	u32 vxres = GETVXRES(ops->p, info);
++	u32 vyres = GETVYRES(par->p, info);
++	u32 vxres = GETVXRES(par->p, info);
+ 
+-	if (!ops->fontbuffer)
++	if (!par->fontbuffer)
+ 		return;
+ 
+ 	cursor.set = 0;
+ 
+  	c = scr_readw((u16 *) vc->vc_pos);
+ 	attribute = get_attribute(info, c);
+-	src = ops->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
++	src = par->fontbuffer + ((c & charmask) * (w * vc->vc_font.height));
+ 
+-	if (ops->cursor_state.image.data != src ||
+-	    ops->cursor_reset) {
+-	    ops->cursor_state.image.data = src;
+-	    cursor.set |= FB_CUR_SETIMAGE;
++	if (par->cursor_state.image.data != src ||
++	    par->cursor_reset) {
++		par->cursor_state.image.data = src;
++		cursor.set |= FB_CUR_SETIMAGE;
+ 	}
+ 
+ 	if (attribute) {
+@@ -282,49 +282,49 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 		dst = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
+ 		if (!dst)
+ 			return;
+-		kfree(ops->cursor_data);
+-		ops->cursor_data = dst;
++		kfree(par->cursor_data);
++		par->cursor_data = dst;
+ 		ud_update_attr(dst, src, attribute, vc);
+ 		src = dst;
+ 	}
+ 
+-	if (ops->cursor_state.image.fg_color != fg ||
+-	    ops->cursor_state.image.bg_color != bg ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.fg_color = fg;
+-		ops->cursor_state.image.bg_color = bg;
++	if (par->cursor_state.image.fg_color != fg ||
++	    par->cursor_state.image.bg_color != bg ||
++	    par->cursor_reset) {
++		par->cursor_state.image.fg_color = fg;
++		par->cursor_state.image.bg_color = bg;
+ 		cursor.set |= FB_CUR_SETCMAP;
+ 	}
+ 
+-	if (ops->cursor_state.image.height != vc->vc_font.height ||
+-	    ops->cursor_state.image.width != vc->vc_font.width ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.height = vc->vc_font.height;
+-		ops->cursor_state.image.width = vc->vc_font.width;
++	if (par->cursor_state.image.height != vc->vc_font.height ||
++	    par->cursor_state.image.width != vc->vc_font.width ||
++	    par->cursor_reset) {
++		par->cursor_state.image.height = vc->vc_font.height;
++		par->cursor_state.image.width = vc->vc_font.width;
+ 		cursor.set |= FB_CUR_SETSIZE;
+ 	}
+ 
+ 	dy = vyres - ((y * vc->vc_font.height) + vc->vc_font.height);
+ 	dx = vxres - ((vc->state.x * vc->vc_font.width) + vc->vc_font.width);
+ 
+-	if (ops->cursor_state.image.dx != dx ||
+-	    ops->cursor_state.image.dy != dy ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.image.dx = dx;
+-		ops->cursor_state.image.dy = dy;
++	if (par->cursor_state.image.dx != dx ||
++	    par->cursor_state.image.dy != dy ||
++	    par->cursor_reset) {
++		par->cursor_state.image.dx = dx;
++		par->cursor_state.image.dy = dy;
+ 		cursor.set |= FB_CUR_SETPOS;
+ 	}
+ 
+-	if (ops->cursor_state.hot.x || ops->cursor_state.hot.y ||
+-	    ops->cursor_reset) {
+-		ops->cursor_state.hot.x = cursor.hot.y = 0;
++	if (par->cursor_state.hot.x || par->cursor_state.hot.y ||
++	    par->cursor_reset) {
++		par->cursor_state.hot.x = cursor.hot.y = 0;
+ 		cursor.set |= FB_CUR_SETHOT;
+ 	}
+ 
+ 	if (cursor.set & FB_CUR_SETSIZE ||
+-	    vc->vc_cursor_type != ops->p->cursor_shape ||
+-	    ops->cursor_state.mask == NULL ||
+-	    ops->cursor_reset) {
++	    vc->vc_cursor_type != par->p->cursor_shape ||
++	    par->cursor_state.mask == NULL ||
++	    par->cursor_reset) {
+ 		char *mask = kmalloc_array(w, vc->vc_font.height, GFP_ATOMIC);
+ 		int cur_height, size, i = 0;
+ 		u8 msk = 0xff;
+@@ -332,13 +332,13 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 		if (!mask)
+ 			return;
+ 
+-		kfree(ops->cursor_state.mask);
+-		ops->cursor_state.mask = mask;
++		kfree(par->cursor_state.mask);
++		par->cursor_state.mask = mask;
+ 
+-		ops->p->cursor_shape = vc->vc_cursor_type;
++		par->p->cursor_shape = vc->vc_cursor_type;
+ 		cursor.set |= FB_CUR_SETSHAPE;
+ 
+-		switch (CUR_SIZE(ops->p->cursor_shape)) {
++		switch (CUR_SIZE(par->p->cursor_shape)) {
+ 		case CUR_NONE:
+ 			cur_height = 0;
+ 			break;
+@@ -373,26 +373,26 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 
+ 	switch (mode) {
+ 	case CM_ERASE:
+-		ops->cursor_state.enable = 0;
++		par->cursor_state.enable = 0;
+ 		break;
+ 	case CM_DRAW:
+ 	case CM_MOVE:
+ 	default:
+-		ops->cursor_state.enable = (use_sw) ? 0 : 1;
++		par->cursor_state.enable = (use_sw) ? 0 : 1;
+ 		break;
+ 	}
+ 
+ 	cursor.image.data = src;
+-	cursor.image.fg_color = ops->cursor_state.image.fg_color;
+-	cursor.image.bg_color = ops->cursor_state.image.bg_color;
+-	cursor.image.dx = ops->cursor_state.image.dx;
+-	cursor.image.dy = ops->cursor_state.image.dy;
+-	cursor.image.height = ops->cursor_state.image.height;
+-	cursor.image.width = ops->cursor_state.image.width;
+-	cursor.hot.x = ops->cursor_state.hot.x;
+-	cursor.hot.y = ops->cursor_state.hot.y;
+-	cursor.mask = ops->cursor_state.mask;
+-	cursor.enable = ops->cursor_state.enable;
++	cursor.image.fg_color = par->cursor_state.image.fg_color;
++	cursor.image.bg_color = par->cursor_state.image.bg_color;
++	cursor.image.dx = par->cursor_state.image.dx;
++	cursor.image.dy = par->cursor_state.image.dy;
++	cursor.image.height = par->cursor_state.image.height;
++	cursor.image.width = par->cursor_state.image.width;
++	cursor.hot.x = par->cursor_state.hot.x;
++	cursor.hot.y = par->cursor_state.hot.y;
++	cursor.mask = par->cursor_state.mask;
++	cursor.enable = par->cursor_state.enable;
+ 	cursor.image.depth = 1;
+ 	cursor.rop = ROP_XOR;
+ 
+@@ -402,36 +402,36 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 	if (err)
+ 		soft_cursor(info, &cursor);
+ 
+-	ops->cursor_reset = 0;
++	par->cursor_reset = 0;
+ }
+ 
+ static int ud_update_start(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	int xoffset, yoffset;
+-	u32 vyres = GETVYRES(ops->p, info);
+-	u32 vxres = GETVXRES(ops->p, info);
++	u32 vyres = GETVYRES(par->p, info);
++	u32 vxres = GETVXRES(par->p, info);
+ 	int err;
+ 
+-	xoffset = vxres - info->var.xres - ops->var.xoffset;
+-	yoffset = vyres - info->var.yres - ops->var.yoffset;
++	xoffset = vxres - info->var.xres - par->var.xoffset;
++	yoffset = vyres - info->var.yres - par->var.yoffset;
+ 	if (yoffset < 0)
+ 		yoffset += vyres;
+-	ops->var.xoffset = xoffset;
+-	ops->var.yoffset = yoffset;
+-	err = fb_pan_display(info, &ops->var);
+-	ops->var.xoffset = info->var.xoffset;
+-	ops->var.yoffset = info->var.yoffset;
+-	ops->var.vmode = info->var.vmode;
++	par->var.xoffset = xoffset;
++	par->var.yoffset = yoffset;
++	err = fb_pan_display(info, &par->var);
++	par->var.xoffset = info->var.xoffset;
++	par->var.yoffset = info->var.yoffset;
++	par->var.vmode = info->var.vmode;
+ 	return err;
+ }
+ 
+-void fbcon_rotate_ud(struct fbcon_ops *ops)
++void fbcon_rotate_ud(struct fbcon_par *par)
+ {
+-	ops->bmove = ud_bmove;
+-	ops->clear = ud_clear;
+-	ops->putcs = ud_putcs;
+-	ops->clear_margins = ud_clear_margins;
+-	ops->cursor = ud_cursor;
+-	ops->update_start = ud_update_start;
++	par->bmove = ud_bmove;
++	par->clear = ud_clear;
++	par->putcs = ud_putcs;
++	par->clear_margins = ud_clear_margins;
++	par->cursor = ud_cursor;
++	par->update_start = ud_update_start;
+ }
+diff --git a/drivers/video/fbdev/core/softcursor.c b/drivers/video/fbdev/core/softcursor.c
+index 29e5b21cf373e5..900788c059153f 100644
+--- a/drivers/video/fbdev/core/softcursor.c
++++ b/drivers/video/fbdev/core/softcursor.c
+@@ -21,7 +21,7 @@
+ 
+ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	unsigned int scan_align = info->pixmap.scan_align - 1;
+ 	unsigned int buf_align = info->pixmap.buf_align - 1;
+ 	unsigned int i, size, dsize, s_pitch, d_pitch;
+@@ -34,19 +34,19 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
+ 	s_pitch = (cursor->image.width + 7) >> 3;
+ 	dsize = s_pitch * cursor->image.height;
+ 
+-	if (dsize + sizeof(struct fb_image) != ops->cursor_size) {
+-		kfree(ops->cursor_src);
+-		ops->cursor_size = dsize + sizeof(struct fb_image);
++	if (dsize + sizeof(struct fb_image) != par->cursor_size) {
++		kfree(par->cursor_src);
++		par->cursor_size = dsize + sizeof(struct fb_image);
+ 
+-		ops->cursor_src = kmalloc(ops->cursor_size, GFP_ATOMIC);
+-		if (!ops->cursor_src) {
+-			ops->cursor_size = 0;
++		par->cursor_src = kmalloc(par->cursor_size, GFP_ATOMIC);
++		if (!par->cursor_src) {
++			par->cursor_size = 0;
+ 			return -ENOMEM;
+ 		}
+ 	}
+ 
+-	src = ops->cursor_src + sizeof(struct fb_image);
+-	image = (struct fb_image *)ops->cursor_src;
++	src = par->cursor_src + sizeof(struct fb_image);
++	image = (struct fb_image *)par->cursor_src;
+ 	*image = cursor->image;
+ 	d_pitch = (s_pitch + scan_align) & ~scan_align;
+ 
+diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c
+index b3aa0c6620c7d1..f2712256d7a07a 100644
+--- a/drivers/video/fbdev/core/tileblit.c
++++ b/drivers/video/fbdev/core/tileblit.c
+@@ -151,34 +151,34 @@ static void tile_cursor(struct vc_data *vc, struct fb_info *info, int mode,
+ 
+ static int tile_update_start(struct fb_info *info)
+ {
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 	int err;
+ 
+-	err = fb_pan_display(info, &ops->var);
+-	ops->var.xoffset = info->var.xoffset;
+-	ops->var.yoffset = info->var.yoffset;
+-	ops->var.vmode = info->var.vmode;
++	err = fb_pan_display(info, &par->var);
++	par->var.xoffset = info->var.xoffset;
++	par->var.yoffset = info->var.yoffset;
++	par->var.vmode = info->var.vmode;
+ 	return err;
+ }
+ 
+ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info)
+ {
+ 	struct fb_tilemap map;
+-	struct fbcon_ops *ops = info->fbcon_par;
++	struct fbcon_par *par = info->fbcon_par;
+ 
+-	ops->bmove = tile_bmove;
+-	ops->clear = tile_clear;
+-	ops->putcs = tile_putcs;
+-	ops->clear_margins = tile_clear_margins;
+-	ops->cursor = tile_cursor;
+-	ops->update_start = tile_update_start;
++	par->bmove = tile_bmove;
++	par->clear = tile_clear;
++	par->putcs = tile_putcs;
++	par->clear_margins = tile_clear_margins;
++	par->cursor = tile_cursor;
++	par->update_start = tile_update_start;
+ 
+-	if (ops->p) {
++	if (par->p) {
+ 		map.width = vc->vc_font.width;
+ 		map.height = vc->vc_font.height;
+ 		map.depth = 1;
+ 		map.length = vc->vc_font.charcount;
+-		map.data = ops->p->fontdata;
++		map.data = par->p->fontdata;
+ 		info->tileops->fb_settile(info, &map);
+ 	}
+ }
+diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
+index 88ac24202a1ff4..945af6db125537 100644
+--- a/drivers/video/fbdev/efifb.c
++++ b/drivers/video/fbdev/efifb.c
+@@ -108,7 +108,7 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
+  */
+ #if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \
+     defined CONFIG_ACPI_BGRT
+-static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si)
++static void efifb_copy_bmp(u8 *src, u32 *dst, int width, const struct screen_info *si)
+ {
+ 	u8 r, g, b;
+ 
+@@ -130,7 +130,7 @@ static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si)
+  * resolution still fits, it will be displayed very close to the right edge of
+  * the display looking quite bad. This function checks for this.
+  */
+-static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
++static bool efifb_bgrt_sanity_check(const struct screen_info *si, u32 bmp_width)
+ {
+ 	/*
+ 	 * All x86 firmwares horizontally center the image (the yoffset
+@@ -141,16 +141,15 @@ static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
+ 	return bgrt_tab.image_offset_x == expected_xoffset;
+ }
+ #else
+-static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width)
++static bool efifb_bgrt_sanity_check(const struct screen_info *si, u32 bmp_width)
+ {
+ 	return true;
+ }
+ #endif
+ 
+-static void efifb_show_boot_graphics(struct fb_info *info)
++static void efifb_show_boot_graphics(struct fb_info *info, const struct screen_info *si)
+ {
+ 	u32 bmp_width, bmp_height, bmp_pitch, dst_x, y, src_y;
+-	struct screen_info *si = &screen_info;
+ 	struct bmp_file_header *file_header;
+ 	struct bmp_dib_header *dib_header;
+ 	void *bgrt_image = NULL;
+@@ -247,7 +246,8 @@ error:
+ 	pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n");
+ }
+ #else
+-static inline void efifb_show_boot_graphics(struct fb_info *info) {}
++static inline void efifb_show_boot_graphics(struct fb_info *info, const struct screen_info *si)
++{ }
+ #endif
+ 
+ /*
+@@ -282,7 +282,7 @@ static const struct fb_ops efifb_ops = {
+ 	.fb_setcolreg	= efifb_setcolreg,
+ };
+ 
+-static int efifb_setup(char *options)
++static int efifb_setup(struct screen_info *si, char *options)
+ {
+ 	char *this_opt;
+ 
+@@ -290,16 +290,16 @@ static int efifb_setup(char *options)
+ 		while ((this_opt = strsep(&options, ",")) != NULL) {
+ 			if (!*this_opt) continue;
+ 
+-			efifb_setup_from_dmi(&screen_info, this_opt);
++			efifb_setup_from_dmi(si, this_opt);
+ 
+ 			if (!strncmp(this_opt, "base:", 5))
+-				screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
++				si->lfb_base = simple_strtoul(this_opt+5, NULL, 0);
+ 			else if (!strncmp(this_opt, "stride:", 7))
+-				screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
++				si->lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
+ 			else if (!strncmp(this_opt, "height:", 7))
+-				screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
++				si->lfb_height = simple_strtoul(this_opt+7, NULL, 0);
+ 			else if (!strncmp(this_opt, "width:", 6))
+-				screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
++				si->lfb_width = simple_strtoul(this_opt+6, NULL, 0);
+ 			else if (!strcmp(this_opt, "nowc"))
+ 				mem_flags &= ~EFI_MEMORY_WC;
+ 			else if (!strcmp(this_opt, "nobgrt"))
+@@ -310,15 +310,15 @@ static int efifb_setup(char *options)
+ 	return 0;
+ }
+ 
+-static inline bool fb_base_is_valid(void)
++static inline bool fb_base_is_valid(struct screen_info *si)
+ {
+-	if (screen_info.lfb_base)
++	if (si->lfb_base)
+ 		return true;
+ 
+-	if (!(screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE))
++	if (!(si->capabilities & VIDEO_CAPABILITY_64BIT_BASE))
+ 		return false;
+ 
+-	if (screen_info.ext_lfb_base)
++	if (si->ext_lfb_base)
+ 		return true;
+ 
+ 	return false;
+@@ -329,7 +329,10 @@ static ssize_t name##_show(struct device *dev,				\
+ 			   struct device_attribute *attr,		\
+ 			   char *buf)					\
+ {									\
+-	return sprintf(buf, fmt "\n", (screen_info.lfb_##name));	\
++	struct screen_info *si = dev_get_platdata(dev);			\
++	if (!si)							\
++		return -ENODEV;						\
++	return sprintf(buf, fmt "\n", (si->lfb_##name));		\
+ }									\
+ static DEVICE_ATTR_RO(name)
+ 
+@@ -356,6 +359,7 @@ static u64 bar_offset;
+ 
+ static int efifb_probe(struct platform_device *dev)
+ {
++	struct screen_info *si = &screen_info;
+ 	struct fb_info *info;
+ 	struct efifb_par *par;
+ 	int err, orientation;
+@@ -365,48 +369,49 @@ static int efifb_probe(struct platform_device *dev)
+ 	char *option = NULL;
+ 	efi_memory_desc_t md;
+ 
+-	if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
++	if (si->orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
+ 		return -ENODEV;
+ 
+ 	if (fb_get_options("efifb", &option))
+ 		return -ENODEV;
+-	efifb_setup(option);
++	efifb_setup(si, option);
++	kfree(option);
+ 
+ 	/* We don't get linelength from UGA Draw Protocol, only from
+ 	 * EFI Graphics Protocol.  So if it's not in DMI, and it's not
+ 	 * passed in from the user, we really can't use the framebuffer.
+ 	 */
+-	if (!screen_info.lfb_linelength)
++	if (!si->lfb_linelength)
+ 		return -ENODEV;
+ 
+-	if (!screen_info.lfb_depth)
+-		screen_info.lfb_depth = 32;
+-	if (!screen_info.pages)
+-		screen_info.pages = 1;
+-	if (!fb_base_is_valid()) {
++	if (!si->lfb_depth)
++		si->lfb_depth = 32;
++	if (!si->pages)
++		si->pages = 1;
++	if (!fb_base_is_valid(si)) {
+ 		printk(KERN_DEBUG "efifb: invalid framebuffer address\n");
+ 		return -ENODEV;
+ 	}
+ 	printk(KERN_INFO "efifb: probing for efifb\n");
+ 
+ 	/* just assume they're all unset if any are */
+-	if (!screen_info.blue_size) {
+-		screen_info.blue_size = 8;
+-		screen_info.blue_pos = 0;
+-		screen_info.green_size = 8;
+-		screen_info.green_pos = 8;
+-		screen_info.red_size = 8;
+-		screen_info.red_pos = 16;
+-		screen_info.rsvd_size = 8;
+-		screen_info.rsvd_pos = 24;
++	if (!si->blue_size) {
++		si->blue_size = 8;
++		si->blue_pos = 0;
++		si->green_size = 8;
++		si->green_pos = 8;
++		si->red_size = 8;
++		si->red_pos = 16;
++		si->rsvd_size = 8;
++		si->rsvd_pos = 24;
+ 	}
+ 
+-	efifb_fix.smem_start = screen_info.lfb_base;
++	efifb_fix.smem_start = si->lfb_base;
+ 
+-	if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
++	if (si->capabilities & VIDEO_CAPABILITY_64BIT_BASE) {
+ 		u64 ext_lfb_base;
+ 
+-		ext_lfb_base = (u64)(unsigned long)screen_info.ext_lfb_base << 32;
++		ext_lfb_base = (u64)(unsigned long)si->ext_lfb_base << 32;
+ 		efifb_fix.smem_start |= ext_lfb_base;
+ 	}
+ 
+@@ -417,10 +422,10 @@ static int efifb_probe(struct platform_device *dev)
+ 		efifb_fix.smem_start = bar_resource->start + bar_offset;
+ 	}
+ 
+-	efifb_defined.bits_per_pixel = screen_info.lfb_depth;
+-	efifb_defined.xres = screen_info.lfb_width;
+-	efifb_defined.yres = screen_info.lfb_height;
+-	efifb_fix.line_length = screen_info.lfb_linelength;
++	efifb_defined.bits_per_pixel = si->lfb_depth;
++	efifb_defined.xres = si->lfb_width;
++	efifb_defined.yres = si->lfb_height;
++	efifb_fix.line_length = si->lfb_linelength;
+ 
+ 	/*   size_vmode -- that is the amount of memory needed for the
+ 	 *                 used video mode, i.e. the minimum amount of
+@@ -430,7 +435,7 @@ static int efifb_probe(struct platform_device *dev)
+ 	/*   size_total -- all video memory we have. Used for
+ 	 *                 entries, ressource allocation and bounds
+ 	 *                 checking. */
+-	size_total = screen_info.lfb_size;
++	size_total = si->lfb_size;
+ 	if (size_total < size_vmode)
+ 		size_total = size_vmode;
+ 
+@@ -505,14 +510,14 @@ static int efifb_probe(struct platform_device *dev)
+ 		goto err_release_fb;
+ 	}
+ 
+-	efifb_show_boot_graphics(info);
++	efifb_show_boot_graphics(info, si);
+ 
+ 	pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n",
+ 	       efifb_fix.smem_start, size_remap/1024, size_total/1024);
+ 	pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+ 	       efifb_defined.xres, efifb_defined.yres,
+ 	       efifb_defined.bits_per_pixel, efifb_fix.line_length,
+-	       screen_info.pages);
++	       si->pages);
+ 
+ 	efifb_defined.xres_virtual = efifb_defined.xres;
+ 	efifb_defined.yres_virtual = efifb_fix.smem_len /
+@@ -526,26 +531,26 @@ static int efifb_probe(struct platform_device *dev)
+ 	efifb_defined.left_margin  = (efifb_defined.xres / 8) & 0xf8;
+ 	efifb_defined.hsync_len    = (efifb_defined.xres / 8) & 0xf8;
+ 
+-	efifb_defined.red.offset    = screen_info.red_pos;
+-	efifb_defined.red.length    = screen_info.red_size;
+-	efifb_defined.green.offset  = screen_info.green_pos;
+-	efifb_defined.green.length  = screen_info.green_size;
+-	efifb_defined.blue.offset   = screen_info.blue_pos;
+-	efifb_defined.blue.length   = screen_info.blue_size;
+-	efifb_defined.transp.offset = screen_info.rsvd_pos;
+-	efifb_defined.transp.length = screen_info.rsvd_size;
++	efifb_defined.red.offset    = si->red_pos;
++	efifb_defined.red.length    = si->red_size;
++	efifb_defined.green.offset  = si->green_pos;
++	efifb_defined.green.length  = si->green_size;
++	efifb_defined.blue.offset   = si->blue_pos;
++	efifb_defined.blue.length   = si->blue_size;
++	efifb_defined.transp.offset = si->rsvd_pos;
++	efifb_defined.transp.length = si->rsvd_size;
+ 
+ 	pr_info("efifb: %s: "
+ 	       "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+ 	       "Truecolor",
+-	       screen_info.rsvd_size,
+-	       screen_info.red_size,
+-	       screen_info.green_size,
+-	       screen_info.blue_size,
+-	       screen_info.rsvd_pos,
+-	       screen_info.red_pos,
+-	       screen_info.green_pos,
+-	       screen_info.blue_pos);
++	       si->rsvd_size,
++	       si->red_size,
++	       si->green_size,
++	       si->blue_size,
++	       si->rsvd_pos,
++	       si->red_pos,
++	       si->green_pos,
++	       si->blue_pos);
+ 
+ 	efifb_fix.ypanstep  = 0;
+ 	efifb_fix.ywrapstep = 0;
+diff --git a/drivers/watchdog/watchdog_pretimeout.c b/drivers/watchdog/watchdog_pretimeout.c
+index e5295c990fa1b8..787b6227b8ccc3 100644
+--- a/drivers/watchdog/watchdog_pretimeout.c
++++ b/drivers/watchdog/watchdog_pretimeout.c
+@@ -165,6 +165,8 @@ void watchdog_unregister_governor(struct watchdog_governor *gov)
+ 	}
+ 
+ 	spin_lock_irq(&pretimeout_lock);
++	if (default_gov == gov)
++		default_gov = NULL;
+ 	list_for_each_entry(p, &pretimeout_list, entry)
+ 		if (p->wdd->gov == gov)
+ 			p->wdd->gov = default_gov;
+diff --git a/fs/afs/addr_list.c b/fs/afs/addr_list.c
+index de1ae0bead3baf..ac05a59e9d4649 100644
+--- a/fs/afs/addr_list.c
++++ b/fs/afs/addr_list.c
+@@ -45,7 +45,7 @@ struct afs_addr_list *afs_alloc_addrlist(unsigned int nr,
+ 	alist->max_addrs = nr;
+ 
+ 	for (i = 0; i < nr; i++) {
+-		struct sockaddr_rxrpc *srx = &alist->addrs[i];
++		struct sockaddr_rxrpc *srx = &alist->addrs[i].srx;
+ 		srx->srx_family			= AF_RXRPC;
+ 		srx->srx_service		= service;
+ 		srx->transport_type		= SOCK_DGRAM;
+@@ -281,7 +281,7 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port)
+ 		return;
+ 
+ 	for (i = 0; i < alist->nr_ipv4; i++) {
+-		struct sockaddr_in *a = &alist->addrs[i].transport.sin;
++		struct sockaddr_in *a = &alist->addrs[i].srx.transport.sin;
+ 		u32 a_addr = ntohl(a->sin_addr.s_addr);
+ 		u16 a_port = ntohs(a->sin_port);
+ 
+@@ -298,7 +298,7 @@ void afs_merge_fs_addr4(struct afs_addr_list *alist, __be32 xdr, u16 port)
+ 			alist->addrs + i,
+ 			sizeof(alist->addrs[0]) * (alist->nr_addrs - i));
+ 
+-	srx = &alist->addrs[i];
++	srx = &alist->addrs[i].srx;
+ 	srx->srx_family = AF_RXRPC;
+ 	srx->transport_type = SOCK_DGRAM;
+ 	srx->transport_len = sizeof(srx->transport.sin);
+@@ -321,7 +321,7 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port)
+ 		return;
+ 
+ 	for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) {
+-		struct sockaddr_in6 *a = &alist->addrs[i].transport.sin6;
++		struct sockaddr_in6 *a = &alist->addrs[i].srx.transport.sin6;
+ 		u16 a_port = ntohs(a->sin6_port);
+ 
+ 		diff = memcmp(xdr, &a->sin6_addr, 16);
+@@ -338,7 +338,7 @@ void afs_merge_fs_addr6(struct afs_addr_list *alist, __be32 *xdr, u16 port)
+ 			alist->addrs + i,
+ 			sizeof(alist->addrs[0]) * (alist->nr_addrs - i));
+ 
+-	srx = &alist->addrs[i];
++	srx = &alist->addrs[i].srx;
+ 	srx->srx_family = AF_RXRPC;
+ 	srx->transport_type = SOCK_DGRAM;
+ 	srx->transport_len = sizeof(srx->transport.sin6);
+diff --git a/fs/afs/fs_probe.c b/fs/afs/fs_probe.c
+index daaf3810cc9256..3dd24842f277ba 100644
+--- a/fs/afs/fs_probe.c
++++ b/fs/afs/fs_probe.c
+@@ -153,12 +153,12 @@ responded:
+ 	if (call->service_id == YFS_FS_SERVICE) {
+ 		server->probe.is_yfs = true;
+ 		set_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
+-		alist->addrs[index].srx_service = call->service_id;
++		alist->addrs[index].srx.srx_service = call->service_id;
+ 	} else {
+ 		server->probe.not_yfs = true;
+ 		if (!server->probe.is_yfs) {
+ 			clear_bit(AFS_SERVER_FL_IS_YFS, &server->flags);
+-			alist->addrs[index].srx_service = call->service_id;
++			alist->addrs[index].srx.srx_service = call->service_id;
+ 		}
+ 		cap0 = ntohl(call->tmp);
+ 		if (cap0 & AFS3_VICED_CAPABILITY_64BITFILES)
+@@ -182,7 +182,7 @@ out:
+ 	spin_unlock(&server->probe_lock);
+ 
+ 	_debug("probe %pU [%u] %pISpc rtt=%u ret=%d",
+-	       &server->uuid, index, &alist->addrs[index].transport,
++	       &server->uuid, index, &alist->addrs[index].srx.transport,
+ 	       rtt_us, ret);
+ 
+ 	return afs_done_one_fs_probe(call->net, server);
+diff --git a/fs/afs/internal.h b/fs/afs/internal.h
+index 0973cd0a396959..d1287cc3d9381b 100644
+--- a/fs/afs/internal.h
++++ b/fs/afs/internal.h
+@@ -87,7 +87,9 @@ struct afs_addr_list {
+ 	enum dns_lookup_status	status:8;
+ 	unsigned long		failed;		/* Mask of addrs that failed locally/ICMP */
+ 	unsigned long		responded;	/* Mask of addrs that responded */
+-	struct sockaddr_rxrpc	addrs[];
++	struct {
++		struct sockaddr_rxrpc	srx;
++	} addrs[] __counted_by(max_addrs);
+ #define AFS_MAX_ADDRESSES ((unsigned int)(sizeof(unsigned long) * 8))
+ };
+ 
+@@ -972,6 +974,8 @@ extern void afs_put_addrlist(struct afs_addr_list *);
+ extern struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *,
+ 						      const char *, size_t, char,
+ 						      unsigned short, unsigned short);
++bool afs_addr_list_same(const struct afs_addr_list *a,
++			const struct afs_addr_list *b);
+ extern struct afs_vlserver_list *afs_dns_query(struct afs_cell *, time64_t *);
+ extern bool afs_iterate_addresses(struct afs_addr_cursor *);
+ extern int afs_end_cursor(struct afs_addr_cursor *);
+diff --git a/fs/afs/proc.c b/fs/afs/proc.c
+index 2a0c83d7156598..ab9cd986cfd9e1 100644
+--- a/fs/afs/proc.c
++++ b/fs/afs/proc.c
+@@ -307,7 +307,7 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v)
+ 		for (i = 0; i < alist->nr_addrs; i++)
+ 			seq_printf(m, " %c %pISpc\n",
+ 				   alist->preferred == i ? '>' : '-',
+-				   &alist->addrs[i].transport);
++				   &alist->addrs[i].srx.transport);
+ 	}
+ 	seq_printf(m, " info: fl=%lx rtt=%d\n", vlserver->flags, vlserver->rtt);
+ 	seq_printf(m, " probe: fl=%x e=%d ac=%d out=%d\n",
+@@ -399,7 +399,7 @@ static int afs_proc_servers_show(struct seq_file *m, void *v)
+ 		   alist->version, alist->responded, alist->failed);
+ 	for (i = 0; i < alist->nr_addrs; i++)
+ 		seq_printf(m, "    [%x] %pISpc%s\n",
+-			   i, &alist->addrs[i].transport,
++			   i, &alist->addrs[i].srx.transport,
+ 			   alist->preferred == i ? "*" : "");
+ 	return 0;
+ }
+diff --git a/fs/afs/rotate.c b/fs/afs/rotate.c
+index a840c3588ebbbc..abe020f1a63a06 100644
+--- a/fs/afs/rotate.c
++++ b/fs/afs/rotate.c
+@@ -409,7 +409,7 @@ iterate_address:
+ 
+ 	_debug("address [%u] %u/%u %pISp",
+ 	       op->index, op->ac.index, op->ac.alist->nr_addrs,
+-	       &op->ac.alist->addrs[op->ac.index].transport);
++	       &op->ac.alist->addrs[op->ac.index].srx.transport);
+ 
+ 	_leave(" = t");
+ 	return true;
+diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
+index 3493d82a10ff8d..3aa0d268642062 100644
+--- a/fs/afs/rxrpc.c
++++ b/fs/afs/rxrpc.c
+@@ -23,8 +23,15 @@ static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned
+ static void afs_process_async_call(struct work_struct *);
+ static void afs_rx_new_call(struct sock *, struct rxrpc_call *, unsigned long);
+ static void afs_rx_discard_new_call(struct rxrpc_call *, unsigned long);
++static void afs_rx_attach(struct rxrpc_call *rxcall, unsigned long user_call_ID);
+ static int afs_deliver_cm_op_id(struct afs_call *);
+ 
++static const struct rxrpc_kernel_ops afs_rxrpc_callback_ops = {
++	.notify_new_call	= afs_rx_new_call,
++	.discard_new_call	= afs_rx_discard_new_call,
++	.user_attach_call	= afs_rx_attach,
++};
++
+ /* asynchronous incoming call initial processing */
+ static const struct afs_call_type afs_RXCMxxxx = {
+ 	.name		= "CB.xxxx",
+@@ -83,8 +90,7 @@ int afs_open_socket(struct afs_net *net)
+ 	 * it sends back to us.
+ 	 */
+ 
+-	rxrpc_kernel_new_call_notification(socket, afs_rx_new_call,
+-					   afs_rx_discard_new_call);
++	rxrpc_kernel_set_notifications(socket, &afs_rxrpc_callback_ops);
+ 
+ 	ret = kernel_listen(socket, INT_MAX);
+ 	if (ret < 0)
+@@ -302,7 +308,7 @@ static void afs_notify_end_request_tx(struct sock *sock,
+  */
+ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
+ {
+-	struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index];
++	struct sockaddr_rxrpc *srx = &ac->alist->addrs[ac->index].srx;
+ 	struct rxrpc_call *rxcall;
+ 	struct msghdr msg;
+ 	struct kvec iov[1];
+@@ -474,7 +480,7 @@ static void afs_log_error(struct afs_call *call, s32 remote_abort)
+ 		max = m + 1;
+ 		pr_notice("kAFS: Peer reported %s failure on %s [%pISp]\n",
+ 			  msg, call->type->name,
+-			  &call->alist->addrs[call->addr_ix].transport);
++			  &call->alist->addrs[call->addr_ix].srx.transport);
+ 	}
+ }
+ 
+@@ -748,7 +754,6 @@ void afs_charge_preallocation(struct work_struct *work)
+ 
+ 		if (rxrpc_kernel_charge_accept(net->socket,
+ 					       afs_wake_up_async_call,
+-					       afs_rx_attach,
+ 					       (unsigned long)call,
+ 					       GFP_KERNEL,
+ 					       call->debug_id) < 0)
+diff --git a/fs/afs/server.c b/fs/afs/server.c
+index f92ce4b7d73a19..b068711301ebb3 100644
+--- a/fs/afs/server.c
++++ b/fs/afs/server.c
+@@ -43,7 +43,7 @@ struct afs_server *afs_find_server(struct afs_net *net,
+ 			hlist_for_each_entry_rcu(server, &net->fs_addresses6, addr6_link) {
+ 				alist = rcu_dereference(server->addresses);
+ 				for (i = alist->nr_ipv4; i < alist->nr_addrs; i++) {
+-					b = &alist->addrs[i].transport.sin6;
++					b = &alist->addrs[i].srx.transport.sin6;
+ 					diff = ((u16 __force)a->sin6_port -
+ 						(u16 __force)b->sin6_port);
+ 					if (diff == 0)
+@@ -59,7 +59,7 @@ struct afs_server *afs_find_server(struct afs_net *net,
+ 			hlist_for_each_entry_rcu(server, &net->fs_addresses4, addr4_link) {
+ 				alist = rcu_dereference(server->addresses);
+ 				for (i = 0; i < alist->nr_ipv4; i++) {
+-					b = &alist->addrs[i].transport.sin;
++					b = &alist->addrs[i].srx.transport.sin;
+ 					diff = ((u16 __force)a->sin_port -
+ 						(u16 __force)b->sin_port);
+ 					if (diff == 0)
+diff --git a/fs/afs/vl_alias.c b/fs/afs/vl_alias.c
+index b2cc10df95308c..9580b03d849389 100644
+--- a/fs/afs/vl_alias.c
++++ b/fs/afs/vl_alias.c
+@@ -94,8 +94,8 @@ static int afs_compare_fs_alists(const struct afs_server *server_a,
+ 	lb = rcu_dereference(server_b->addresses);
+ 
+ 	while (a < la->nr_addrs && b < lb->nr_addrs) {
+-		const struct sockaddr_rxrpc *srx_a = &la->addrs[a];
+-		const struct sockaddr_rxrpc *srx_b = &lb->addrs[b];
++		const struct sockaddr_rxrpc *srx_a = &la->addrs[a].srx;
++		const struct sockaddr_rxrpc *srx_b = &lb->addrs[b].srx;
+ 		int diff = afs_compare_addrs(srx_a, srx_b);
+ 
+ 		if (diff < 0) {
+diff --git a/fs/afs/vl_probe.c b/fs/afs/vl_probe.c
+index 58452b86e67270..bdd9372e3fb2a5 100644
+--- a/fs/afs/vl_probe.c
++++ b/fs/afs/vl_probe.c
+@@ -106,12 +106,12 @@ responded:
+ 	if (call->service_id == YFS_VL_SERVICE) {
+ 		server->probe.flags |= AFS_VLSERVER_PROBE_IS_YFS;
+ 		set_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags);
+-		alist->addrs[index].srx_service = call->service_id;
++		alist->addrs[index].srx.srx_service = call->service_id;
+ 	} else {
+ 		server->probe.flags |= AFS_VLSERVER_PROBE_NOT_YFS;
+ 		if (!(server->probe.flags & AFS_VLSERVER_PROBE_IS_YFS)) {
+ 			clear_bit(AFS_VLSERVER_FL_IS_YFS, &server->flags);
+-			alist->addrs[index].srx_service = call->service_id;
++			alist->addrs[index].srx.srx_service = call->service_id;
+ 		}
+ 	}
+ 
+@@ -131,7 +131,7 @@ out:
+ 	spin_unlock(&server->probe_lock);
+ 
+ 	_debug("probe [%u][%u] %pISpc rtt=%u ret=%d",
+-	       server_index, index, &alist->addrs[index].transport, rtt_us, ret);
++	       server_index, index, &alist->addrs[index].srx.transport, rtt_us, ret);
+ 
+ 	afs_done_one_vl_probe(server, have_result);
+ }
+diff --git a/fs/afs/vl_rotate.c b/fs/afs/vl_rotate.c
+index eb415ce563600e..e52b9d4c8a0ab9 100644
+--- a/fs/afs/vl_rotate.c
++++ b/fs/afs/vl_rotate.c
+@@ -249,7 +249,7 @@ iterate_address:
+ 
+ 	_debug("VL address %d/%d", vc->ac.index, vc->ac.alist->nr_addrs);
+ 
+-	_leave(" = t %pISpc", &vc->ac.alist->addrs[vc->ac.index].transport);
++	_leave(" = t %pISpc", &vc->ac.alist->addrs[vc->ac.index].srx.transport);
+ 	return true;
+ 
+ next_server:
+diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
+index 96a8b13b57d969..d872ccb5f4b2d9 100644
+--- a/fs/binfmt_elf_fdpic.c
++++ b/fs/binfmt_elf_fdpic.c
+@@ -231,6 +231,10 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm)
+ 	for (i = 0; i < exec_params.hdr.e_phnum; i++, phdr++) {
+ 		switch (phdr->p_type) {
+ 		case PT_INTERP:
++			/* elf ABI allows only one interpreter */
++			if (interpreter_name)
++				continue;
++
+ 			retval = -ENOMEM;
+ 			if (phdr->p_filesz > PATH_MAX)
+ 				goto error;
+diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
+index a45b5ba12a9cb8..e4dfcf11b5f7e5 100644
+--- a/fs/binfmt_misc.c
++++ b/fs/binfmt_misc.c
+@@ -199,9 +199,6 @@ static int load_misc_binary(struct linux_binprm *bprm)
+ 			goto ret;
+ 	}
+ 
+-	if (fmt->flags & MISC_FMT_OPEN_BINARY)
+-		bprm->have_execfd = 1;
+-
+ 	/* make argv[1] be the path to the binary */
+ 	retval = copy_string_kernel(bprm->interp, bprm);
+ 	if (retval < 0)
+@@ -231,6 +228,8 @@ static int load_misc_binary(struct linux_binprm *bprm)
+ 		goto ret;
+ 
+ 	bprm->interpreter = interp_file;
++	if (fmt->flags & MISC_FMT_OPEN_BINARY)
++		bprm->have_execfd = 1;
+ 	if (fmt->flags & MISC_FMT_CREDENTIALS)
+ 		bprm->execfd_creds = 1;
+ 
+diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
+index c6e3b9a2921ab1..8be5614ae9b620 100644
+--- a/fs/btrfs/free-space-cache.c
++++ b/fs/btrfs/free-space-cache.c
+@@ -559,6 +559,9 @@ static int io_ctl_check_crc(struct btrfs_io_ctl *io_ctl, int index)
+ 	u32 crc = ~(u32)0;
+ 	unsigned offset = 0;
+ 
++	if (index >= io_ctl->num_pages)
++		return -EIO;
++
+ 	if (index == 0)
+ 		offset = sizeof(u32) * io_ctl->num_pages;
+ 
+diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
+index 0f05eb97925fdd..0b7a4b90053692 100644
+--- a/fs/btrfs/relocation.c
++++ b/fs/btrfs/relocation.c
+@@ -586,6 +586,7 @@ static int __must_check __add_reloc_root(struct btrfs_root *root)
+ 		btrfs_err(fs_info,
+ 			    "Duplicate root found for start=%llu while inserting into relocation tree",
+ 			    node->bytenr);
++		kfree(node);
+ 		return -EEXIST;
+ 	}
+ 
+@@ -1991,6 +1992,7 @@ again:
+ 				 * corruption, e.g. bad reloc tree key offset.
+ 				 */
+ 				ret = -EINVAL;
++				btrfs_put_root(root);
+ 				goto out;
+ 			}
+ 			ret = merge_reloc_root(rc, root);
+diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
+index 00045b8eadd142..67e6cb0eba3a58 100644
+--- a/fs/ceph/caps.c
++++ b/fs/ceph/caps.c
+@@ -4267,6 +4267,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
+ 
+ 	snaptrace = h + 1;
+ 	snaptrace_len = le32_to_cpu(h->snap_trace_len);
++	ceph_decode_need(&snaptrace, end, snaptrace_len, bad);
+ 	p = snaptrace + snaptrace_len;
+ 
+ 	if (msg_version >= 2) {
+diff --git a/fs/coredump.c b/fs/coredump.c
+index d3a4f5dc2e362a..2f1f66f42fab40 100644
+--- a/fs/coredump.c
++++ b/fs/coredump.c
+@@ -560,6 +560,7 @@ static int umh_coredump_setup(struct subprocess_info *info, struct cred *new)
+ 		if (err < 0)
+ 			goto out_fail;
+ 
++		fput(pidfs_file);
+ 		pidfs_file = NULL;
+ 	}
+ 
+diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
+index 8bfb3ce864766e..47645c5539bc84 100644
+--- a/fs/crypto/inline_crypt.c
++++ b/fs/crypto/inline_crypt.c
+@@ -21,22 +21,14 @@
+ 
+ #include "fscrypt_private.h"
+ 
+-static struct block_device **fscrypt_get_devices(struct super_block *sb,
+-						 unsigned int *num_devs)
++static unsigned int
++fscrypt_get_devices(struct super_block *sb,
++		    struct block_device *devs[FSCRYPT_MAX_DEVICES])
+ {
+-	struct block_device **devs;
+-
+-	if (sb->s_cop->get_devices) {
+-		devs = sb->s_cop->get_devices(sb, num_devs);
+-		if (devs)
+-			return devs;
+-	}
+-	devs = kmalloc(sizeof(*devs), GFP_KERNEL);
+-	if (!devs)
+-		return ERR_PTR(-ENOMEM);
++	if (sb->s_cop->get_devices)
++		return sb->s_cop->get_devices(sb, devs);
+ 	devs[0] = sb->s_bdev;
+-	*num_devs = 1;
+-	return devs;
++	return 1;
+ }
+ 
+ static unsigned int fscrypt_get_dun_bytes(const struct fscrypt_info *ci)
+@@ -95,7 +87,7 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci)
+ 	const struct inode *inode = ci->ci_inode;
+ 	struct super_block *sb = inode->i_sb;
+ 	struct blk_crypto_config crypto_cfg;
+-	struct block_device **devs;
++	struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ 	unsigned int num_devs;
+ 	unsigned int i;
+ 
+@@ -132,20 +124,15 @@ int fscrypt_select_encryption_impl(struct fscrypt_info *ci)
+ 	crypto_cfg.data_unit_size = sb->s_blocksize;
+ 	crypto_cfg.dun_bytes = fscrypt_get_dun_bytes(ci);
+ 
+-	devs = fscrypt_get_devices(sb, &num_devs);
+-	if (IS_ERR(devs))
+-		return PTR_ERR(devs);
+-
++	num_devs = fscrypt_get_devices(sb, devs);
+ 	for (i = 0; i < num_devs; i++) {
+ 		if (!blk_crypto_config_supported(devs[i], &crypto_cfg))
+-			goto out_free_devs;
++			return 0;
+ 	}
+ 
+ 	fscrypt_log_blk_crypto_impl(ci->ci_mode, devs, num_devs, &crypto_cfg);
+ 
+ 	ci->ci_inlinecrypt = true;
+-out_free_devs:
+-	kfree(devs);
+ 
+ 	return 0;
+ }
+@@ -158,7 +145,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+ 	struct super_block *sb = inode->i_sb;
+ 	enum blk_crypto_mode_num crypto_mode = ci->ci_mode->blk_crypto_mode;
+ 	struct blk_crypto_key *blk_key;
+-	struct block_device **devs;
++	struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ 	unsigned int num_devs;
+ 	unsigned int i;
+ 	int err;
+@@ -175,17 +162,12 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+ 	}
+ 
+ 	/* Start using blk-crypto on all the filesystem's block devices. */
+-	devs = fscrypt_get_devices(sb, &num_devs);
+-	if (IS_ERR(devs)) {
+-		err = PTR_ERR(devs);
+-		goto fail;
+-	}
++	num_devs = fscrypt_get_devices(sb, devs);
+ 	for (i = 0; i < num_devs; i++) {
+ 		err = blk_crypto_start_using_key(devs[i], blk_key);
+ 		if (err)
+ 			break;
+ 	}
+-	kfree(devs);
+ 	if (err) {
+ 		fscrypt_err(inode, "error %d starting to use blk-crypto", err);
+ 		goto fail;
+@@ -209,20 +191,21 @@ void fscrypt_destroy_inline_crypt_key(struct super_block *sb,
+ 				      struct fscrypt_prepared_key *prep_key)
+ {
+ 	struct blk_crypto_key *blk_key = prep_key->blk_key;
+-	struct block_device **devs;
++	struct block_device *devs[FSCRYPT_MAX_DEVICES];
+ 	unsigned int num_devs;
+ 	unsigned int i;
+ 
+ 	if (!blk_key)
+ 		return;
+ 
+-	/* Evict the key from all the filesystem's block devices. */
+-	devs = fscrypt_get_devices(sb, &num_devs);
+-	if (!IS_ERR(devs)) {
+-		for (i = 0; i < num_devs; i++)
+-			blk_crypto_evict_key(devs[i], blk_key);
+-		kfree(devs);
+-	}
++	/*
++	 * Evict the key from all the filesystem's block devices.
++	 * This *must* be done before the key is freed.
++	 */
++	num_devs = fscrypt_get_devices(sb, devs);
++	for (i = 0; i < num_devs; i++)
++		blk_crypto_evict_key(devs[i], blk_key);
++
+ 	kfree_sensitive(blk_key);
+ }
+ 
+diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c
+index 159dd0288349a0..7e0bb9a75c5906 100644
+--- a/fs/crypto/keysetup_v1.c
++++ b/fs/crypto/keysetup_v1.c
+@@ -199,13 +199,19 @@ find_or_insert_direct_key(struct fscrypt_direct_key *to_insert,
+ 		if (memcmp(ci->ci_policy.v1.master_key_descriptor,
+ 			   dk->dk_descriptor, FSCRYPT_KEY_DESCRIPTOR_SIZE) != 0)
+ 			continue;
++		/* The sb is used at eviction time, so it must be the same. */
++		if (ci->ci_inode->i_sb != dk->dk_sb)
++			continue;
+ 		if (ci->ci_mode != dk->dk_mode)
+ 			continue;
+ 		if (!fscrypt_is_key_prepared(&dk->dk_key, ci))
+ 			continue;
+ 		if (crypto_memneq(raw_key, dk->dk_raw, ci->ci_mode->keysize))
+ 			continue;
+-		/* using existing tfm with same (descriptor, mode, raw_key) */
++		/*
++		 * Use an existing prepared key with the same (descriptor, sb,
++		 * mode, inlinecrypt, raw_key) combination.
++		 */
+ 		refcount_inc(&dk->dk_refcount);
+ 		spin_unlock(&fscrypt_direct_keys_lock);
+ 		free_direct_key(to_insert);
+diff --git a/fs/exec.c b/fs/exec.c
+index a7dfac338a22c8..9d3e2eda9d55e9 100644
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -882,7 +882,7 @@ int transfer_args_to_stack(struct linux_binprm *bprm,
+ 	stop = bprm->p >> PAGE_SHIFT;
+ 	sp = *sp_location;
+ 
+-	for (index = MAX_ARG_PAGES - 1; index >= stop; index--) {
++	for (index = MAX_ARG_PAGES; index-- > stop; ) {
+ 		unsigned int offset = index == stop ? bprm->p & ~PAGE_MASK : 0;
+ 		char *src = kmap_local_page(bprm->page[index]) + offset;
+ 		sp -= PAGE_SIZE - offset;
+diff --git a/fs/exfat/balloc.c b/fs/exfat/balloc.c
+index 32209acd51be4f..2d4fe3d754bbc5 100644
+--- a/fs/exfat/balloc.c
++++ b/fs/exfat/balloc.c
+@@ -45,12 +45,37 @@ static const unsigned char used_bit[] = {
+ /*
+  *  Allocation Bitmap Management Functions
+  */
++static bool exfat_test_bitmap_range(struct super_block *sb, unsigned int clu,
++		unsigned int count)
++{
++	struct exfat_sb_info *sbi = EXFAT_SB(sb);
++	unsigned int start = clu;
++	unsigned int end = clu + count;
++	unsigned int ent_idx, i, b;
++
++	if (!is_valid_cluster(sbi, start) || !is_valid_cluster(sbi, end - 1))
++		return false;
++
++	while (start < end) {
++		ent_idx = CLUSTER_TO_BITMAP_ENT(start);
++		i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
++		b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
++
++		if (!test_bit_le(b, sbi->vol_amap[i]->b_data))
++			return false;
++
++		start++;
++	}
++
++	return true;
++}
++
+ static int exfat_allocate_bitmap(struct super_block *sb,
+ 		struct exfat_dentry *ep)
+ {
+ 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
+ 	long long map_size;
+-	unsigned int i, need_map_size;
++	unsigned int i, j, need_map_size;
+ 	sector_t sector;
+ 
+ 	sbi->map_clu = le32_to_cpu(ep->dentry.bitmap.start_clu);
+@@ -77,20 +102,25 @@ static int exfat_allocate_bitmap(struct super_block *sb,
+ 	sector = exfat_cluster_to_sector(sbi, sbi->map_clu);
+ 	for (i = 0; i < sbi->map_sectors; i++) {
+ 		sbi->vol_amap[i] = sb_bread(sb, sector + i);
+-		if (!sbi->vol_amap[i]) {
+-			/* release all buffers and free vol_amap */
+-			int j = 0;
+-
+-			while (j < i)
+-				brelse(sbi->vol_amap[j++]);
+-
+-			kvfree(sbi->vol_amap);
+-			sbi->vol_amap = NULL;
+-			return -EIO;
+-		}
++		if (!sbi->vol_amap[i])
++			goto err_out;
+ 	}
+ 
++	if (exfat_test_bitmap_range(sb, sbi->map_clu,
++		EXFAT_B_TO_CLU_ROUND_UP(map_size, sbi)) == false)
++		goto err_out;
++
+ 	return 0;
++
++err_out:
++	j = 0;
++	/* release all buffers and free vol_amap */
++	while (j < i)
++		brelse(sbi->vol_amap[j++]);
++
++	kvfree(sbi->vol_amap);
++	sbi->vol_amap = NULL;
++	return -EIO;
+ }
+ 
+ int exfat_load_bitmap(struct super_block *sb)
+diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
+index c018d548e16348..95adc2c4c3c087 100644
+--- a/fs/f2fs/super.c
++++ b/fs/f2fs/super.c
+@@ -3248,24 +3248,27 @@ static void f2fs_get_ino_and_lblk_bits(struct super_block *sb,
+ 	*lblk_bits_ret = 8 * sizeof(block_t);
+ }
+ 
+-static struct block_device **f2fs_get_devices(struct super_block *sb,
+-					      unsigned int *num_devs)
++static unsigned int
++f2fs_get_devices(struct super_block *sb,
++		 struct block_device *devs[FSCRYPT_MAX_DEVICES])
+ {
+ 	struct f2fs_sb_info *sbi = F2FS_SB(sb);
+-	struct block_device **devs;
++	int ndevs;
+ 	int i;
+ 
+-	if (!f2fs_is_multi_device(sbi))
+-		return NULL;
++	static_assert(MAX_DEVICES <= FSCRYPT_MAX_DEVICES);
+ 
+-	devs = kmalloc_array(sbi->s_ndevs, sizeof(*devs), GFP_KERNEL);
+-	if (!devs)
+-		return ERR_PTR(-ENOMEM);
++	if (!f2fs_is_multi_device(sbi)) {
++		devs[0] = sb->s_bdev;
++		return 1;
++	}
++	ndevs = sbi->s_ndevs;
++	if (WARN_ON_ONCE(ndevs > FSCRYPT_MAX_DEVICES))
++		ndevs = FSCRYPT_MAX_DEVICES;
+ 
+-	for (i = 0; i < sbi->s_ndevs; i++)
++	for (i = 0; i < ndevs; i++)
+ 		devs[i] = FDEV(i).bdev;
+-	*num_devs = sbi->s_ndevs;
+-	return devs;
++	return ndevs;
+ }
+ 
+ static const struct fscrypt_operations f2fs_cryptops = {
+diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
+index 4bc57934aa52df..bc7d176c4cf139 100644
+--- a/fs/iomap/buffered-io.c
++++ b/fs/iomap/buffered-io.c
+@@ -98,13 +98,17 @@ static void ifs_clear_range_dirty(struct folio *folio,
+ {
+ 	struct inode *inode = folio->mapping->host;
+ 	unsigned int blks_per_folio = i_blocks_per_folio(inode, folio);
+-	unsigned int first_blk = (off >> inode->i_blkbits);
+-	unsigned int last_blk = (off + len - 1) >> inode->i_blkbits;
+-	unsigned int nr_blks = last_blk - first_blk + 1;
++	unsigned int first_blk = round_up(off, i_blocksize(inode)) >>
++				 inode->i_blkbits;
++	unsigned int last_blk = (off + len) >> inode->i_blkbits;
+ 	unsigned long flags;
+ 
++	if (first_blk >= last_blk)
++		return;
++
+ 	spin_lock_irqsave(&ifs->state_lock, flags);
+-	bitmap_clear(ifs->state, first_blk + blks_per_folio, nr_blks);
++	bitmap_clear(ifs->state, first_blk + blks_per_folio,
++		     last_blk - first_blk);
+ 	spin_unlock_irqrestore(&ifs->state_lock, flags);
+ }
+ 
+diff --git a/fs/namei.c b/fs/namei.c
+index 861390e523b2a0..72918875d62a68 100644
+--- a/fs/namei.c
++++ b/fs/namei.c
+@@ -2603,6 +2603,49 @@ static struct dentry *__kern_path_locked(struct filename *name, struct path *pat
+ 	return d;
+ }
+ 
++/**
++ * kern_path_parent: lookup path returning parent and target
++ * @name: path name
++ * @path: path to store parent in
++ *
++ * The path @name should end with a normal component, not "." or ".." or "/".
++ * A lookup is performed and if successful the parent information
++ * is store in @parent and the dentry is returned.
++ *
++ * The dentry maybe negative, the parent will be positive.
++ *
++ * Returns:  dentry or error.
++ */
++struct dentry *kern_path_parent(const char *name, struct path *path)
++{
++	struct filename *filename = getname_kernel(name);
++	struct path parent_path;
++	struct dentry *d;
++	struct qstr last;
++	int type, error;
++
++	error = filename_parentat(AT_FDCWD, filename, 0, &parent_path, &last, &type);
++	if (error) {
++		d = ERR_PTR(error);
++		goto out;
++	}
++	if (unlikely(type != LAST_NORM)) {
++		path_put(&parent_path);
++		d = ERR_PTR(-EINVAL);
++		goto out;
++	}
++
++	d = lookup_one_len_unlocked(last.name, parent_path.dentry, last.len);
++	if (IS_ERR(d)) {
++		path_put(&parent_path);
++		goto out;
++	}
++	*path = parent_path;
++out:
++	putname(filename);
++	return d;
++}
++
+ struct dentry *kern_path_locked(const char *name, struct path *path)
+ {
+ 	struct filename *filename = getname_kernel(name);
+diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
+index 3d5ae22ed3a816..1ab81d639d5c3a 100644
+--- a/fs/nfs/internal.h
++++ b/fs/nfs/internal.h
+@@ -784,17 +784,19 @@ void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize)
+ }
+ 
+ /*
+- * Record the page as unstable (an extra writeback period) and mark its
+- * inode as dirty.
++ * Record the request's range as unstable (an extra writeback period) and
++ * mark its inode as dirty.
+  */
+-static inline void nfs_folio_mark_unstable(struct folio *folio,
++static inline void nfs_folio_mark_unstable(struct nfs_page *req,
+ 					   struct nfs_commit_info *cinfo)
+ {
++	struct folio *folio = nfs_page_to_folio(req);
++
+ 	if (folio && !cinfo->dreq) {
+-		struct inode *inode = folio_file_mapping(folio)->host;
+-		long nr = folio_nr_pages(folio);
++		struct inode *inode = folio->mapping->host;
++		long nr = DIV_ROUND_UP(req->wb_bytes, PAGE_SIZE);
+ 
+-		/* This page is really still in write-back - just that the
++		/* This range is really still in write-back - just that the
+ 		 * writeback is happening on the server now.
+ 		 */
+ 		node_stat_mod_folio(folio, NR_WRITEBACK, nr);
+diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c
+index 698d4d64c6b641..4f343dd1e65bb0 100644
+--- a/fs/nfs/pnfs_nfs.c
++++ b/fs/nfs/pnfs_nfs.c
+@@ -1226,7 +1226,7 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
+ 
+ 	nfs_request_add_commit_list_locked(req, list, cinfo);
+ 	mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
+-	nfs_folio_mark_unstable(nfs_page_to_folio(req), cinfo);
++	nfs_folio_mark_unstable(req, cinfo);
+ 	return;
+ out_resched:
+ 	mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
+diff --git a/fs/nfs/write.c b/fs/nfs/write.c
+index dc57e67cefcd18..85426764017cef 100644
+--- a/fs/nfs/write.c
++++ b/fs/nfs/write.c
+@@ -933,7 +933,7 @@ nfs_request_add_commit_list(struct nfs_page *req, struct nfs_commit_info *cinfo)
+ 	mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
+ 	nfs_request_add_commit_list_locked(req, &cinfo->mds->list, cinfo);
+ 	mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
+-	nfs_folio_mark_unstable(nfs_page_to_folio(req), cinfo);
++	nfs_folio_mark_unstable(req, cinfo);
+ }
+ EXPORT_SYMBOL_GPL(nfs_request_add_commit_list);
+ 
+@@ -992,10 +992,12 @@ nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg,
+ 	nfs_request_add_commit_list(req, cinfo);
+ }
+ 
+-static void nfs_folio_clear_commit(struct folio *folio)
++static void nfs_folio_clear_commit(struct nfs_page *req)
+ {
++	struct folio *folio = nfs_page_to_folio(req);
++
+ 	if (folio) {
+-		long nr = folio_nr_pages(folio);
++		long nr = DIV_ROUND_UP(req->wb_bytes, PAGE_SIZE);
+ 
+ 		node_stat_mod_folio(folio, NR_WRITEBACK, -nr);
+ 		wb_stat_mod(&inode_to_bdi(folio_file_mapping(folio)->host)->wb,
+@@ -1016,7 +1018,7 @@ static void nfs_clear_request_commit(struct nfs_commit_info *cinfo,
+ 			nfs_request_remove_commit_list(req, cinfo);
+ 		}
+ 		mutex_unlock(&NFS_I(inode)->commit_mutex);
+-		nfs_folio_clear_commit(nfs_page_to_folio(req));
++		nfs_folio_clear_commit(req);
+ 	}
+ }
+ 
+@@ -1834,7 +1836,7 @@ void nfs_retry_commit(struct list_head *page_list,
+ 		req = nfs_list_entry(page_list->next);
+ 		nfs_list_remove_request(req);
+ 		nfs_mark_request_commit(req, lseg, cinfo, ds_commit_idx);
+-		nfs_folio_clear_commit(nfs_page_to_folio(req));
++		nfs_folio_clear_commit(req);
+ 		nfs_unlock_and_release_request(req);
+ 	}
+ }
+@@ -1902,7 +1904,7 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
+ 		req = nfs_list_entry(data->pages.next);
+ 		nfs_list_remove_request(req);
+ 		folio = nfs_page_to_folio(req);
+-		nfs_folio_clear_commit(folio);
++		nfs_folio_clear_commit(req);
+ 
+ 		dprintk("NFS:       commit (%s/%llu %d@%lld)",
+ 			nfs_req_openctx(req)->dentry->d_sb->s_id,
+diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
+index e3b128cc24138a..52fe95d02fc47a 100644
+--- a/fs/nfsd/nfs4xdr.c
++++ b/fs/nfsd/nfs4xdr.c
+@@ -4096,7 +4096,7 @@ out_err:
+ 
+ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
+ 				 struct nfsd4_read *read,
+-				 struct file *file, unsigned long maxcount)
++				 unsigned long maxcount)
+ {
+ 	struct xdr_stream *xdr = resp->xdr;
+ 	unsigned int base = xdr->buf->page_len & ~PAGE_MASK;
+@@ -4107,7 +4107,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
+ 	if (xdr_reserve_space_vec(xdr, maxcount) < 0)
+ 		return nfserr_resource;
+ 
+-	nfserr = nfsd_iter_read(resp->rqstp, read->rd_fhp, file,
++	nfserr = nfsd_iter_read(resp->rqstp, read->rd_fhp, read->rd_nf,
+ 				read->rd_offset, &maxcount, base,
+ 				&read->rd_eof);
+ 	read->rd_length = maxcount;
+@@ -4155,7 +4155,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
+ 	if (file->f_op->splice_read && splice_ok)
+ 		nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
+ 	else
+-		nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
++		nfserr = nfsd4_encode_readv(resp, read, maxcount);
+ 	if (nfserr) {
+ 		xdr_truncate_encode(xdr, starting_len);
+ 		return nfserr;
+@@ -4906,7 +4906,7 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
+ 	if (file->f_op->splice_read && splice_ok)
+ 		nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount);
+ 	else
+-		nfserr = nfsd4_encode_readv(resp, read, file, maxcount);
++		nfserr = nfsd4_encode_readv(resp, read, maxcount);
+ 	if (nfserr)
+ 		return nfserr;
+ 
+diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
+index 5b773fa1c55778..5dc798e89e97be 100644
+--- a/fs/nfsd/vfs.c
++++ b/fs/nfsd/vfs.c
+@@ -1061,7 +1061,7 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+  * nfsd_iter_read - Perform a VFS read using an iterator
+  * @rqstp: RPC transaction context
+  * @fhp: file handle of file to be read
+- * @file: opened struct file of file to be read
++ * @nf: opened struct nfsd_file of file to be read
+  * @offset: starting byte offset
+  * @count: IN: requested number of bytes; OUT: number of bytes read
+  * @base: offset in first page of read buffer
+@@ -1074,9 +1074,10 @@ __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+  * returned.
+  */
+ __be32 nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+-		      struct file *file, loff_t offset, unsigned long *count,
++		      struct nfsd_file *nf, loff_t offset, unsigned long *count,
+ 		      unsigned int base, u32 *eof)
+ {
++	struct file *file = nf->nf_file;
+ 	unsigned long v, total;
+ 	struct iov_iter iter;
+ 	loff_t ppos = offset;
+@@ -1258,7 +1259,7 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 	if (file->f_op->splice_read && test_bit(RQ_SPLICE_OK, &rqstp->rq_flags))
+ 		err = nfsd_splice_read(rqstp, fhp, file, offset, count, eof);
+ 	else
+-		err = nfsd_iter_read(rqstp, fhp, file, offset, count, 0, eof);
++		err = nfsd_iter_read(rqstp, fhp, nf, offset, count, 0, eof);
+ 
+ 	nfsd_file_put(nf);
+ 	trace_nfsd_read_done(rqstp, fhp, offset, *count);
+diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
+index 6f059c5ac22b78..bf695d5cc04e45 100644
+--- a/fs/nfsd/vfs.h
++++ b/fs/nfsd/vfs.h
+@@ -120,7 +120,7 @@ __be32		nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ 				unsigned long *count,
+ 				u32 *eof);
+ __be32		nfsd_iter_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+-				struct file *file, loff_t offset,
++				struct nfsd_file *nf, loff_t offset,
+ 				unsigned long *count, unsigned int base,
+ 				u32 *eof);
+ __be32		nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
+diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
+index dbf7b3cd70ca5e..7f4fdf3f2b09ec 100644
+--- a/fs/overlayfs/copy_up.c
++++ b/fs/overlayfs/copy_up.c
+@@ -793,7 +793,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
+ {
+ 	struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
+ 	struct inode *udir = d_inode(c->destdir);
+-	struct dentry *temp, *upper;
++	struct dentry *temp, *upper, *newdentry = NULL;
+ 	struct file *tmpfile;
+ 	struct ovl_cu_creds cc;
+ 	int err;
+@@ -826,6 +826,14 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
+ 	err = PTR_ERR(upper);
+ 	if (!IS_ERR(upper)) {
+ 		err = ovl_do_link(ofs, temp, udir, upper);
++		if (!err) {
++			/*
++			 * Record the linked dentry -- not the disconnected
++			 * O_TMPFILE dentry -- so that ->d_revalidate() on
++			 * the upper fs sees the real parent/name.
++			 */
++			newdentry = dget(upper);
++		}
+ 		dput(upper);
+ 	}
+ 	inode_unlock(udir);
+@@ -841,7 +849,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
+ 
+ 	if (!c->metacopy)
+ 		ovl_set_upperdata(d_inode(c->dentry));
+-	ovl_inode_update(d_inode(c->dentry), dget(temp));
++	ovl_inode_update(d_inode(c->dentry), newdentry);
+ 
+ out_fput:
+ 	fput(tmpfile);
+diff --git a/fs/posix_acl.c b/fs/posix_acl.c
+index a05fe94970ce78..a6cfa830177f48 100644
+--- a/fs/posix_acl.c
++++ b/fs/posix_acl.c
+@@ -94,6 +94,13 @@ static void __forget_cached_acl(struct posix_acl **p)
+ {
+ 	struct posix_acl *old;
+ 
++	/*
++	 * ACL_DONT_CACHE is expected to be a "const" value and xchg it with
++	 * ACL_NOT_CACHED would enable acl caching for the inode -
++	 * clearly not what the caller has intended.
++	 */
++	if (READ_ONCE(*p) == ACL_DONT_CACHE)
++		return;
+ 	old = xchg(p, ACL_NOT_CACHED);
+ 	if (!is_uncached_acl(old))
+ 		posix_acl_release(old);
+diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
+index 2a3fc96ca62230..203d3363e3d5a2 100644
+--- a/fs/proc/namespaces.c
++++ b/fs/proc/namespaces.c
+@@ -46,7 +46,7 @@ static const char *proc_ns_get_link(struct dentry *dentry,
+ 	const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
+ 	struct task_struct *task;
+ 	struct path ns_path;
+-	int error = -EACCES;
++	int error;
+ 
+ 	if (!dentry)
+ 		return ERR_PTR(-ECHILD);
+@@ -59,6 +59,7 @@ static const char *proc_ns_get_link(struct dentry *dentry,
+ 	if (error)
+ 		goto out_put_task;
+ 
++	error = -EACCES;
+ 	if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
+ 		goto out;
+ 
+@@ -90,6 +91,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl
+ 	if (res)
+ 		goto out_put_task;
+ 
++	res = -EACCES;
+ 	if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
+ 		res = ns_get_name(name, sizeof(name), task, ns_ops);
+ 		if (res >= 0)
+diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
+index 46ca8f326c9813..29a390a497aefe 100644
+--- a/fs/smb/client/misc.c
++++ b/fs/smb/client/misc.c
+@@ -964,6 +964,8 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
+ 	int i, rc = 0;
+ 	char *data_end;
+ 	struct dfs_referral_level_3 *ref;
++	unsigned int path_consumed;
++	size_t search_name_len;
+ 
+ 	if (rsp_size < sizeof(*rsp)) {
+ 		cifs_dbg(VFS | ONCE,
+@@ -1011,6 +1013,7 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
+ 		rc = -ENOMEM;
+ 		goto parse_DFS_referrals_exit;
+ 	}
++	search_name_len = strlen(searchName);
+ 
+ 	/* collect necessary data from referrals */
+ 	for (i = 0; i < *num_of_nodes; i++) {
+@@ -1019,21 +1022,34 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
+ 		struct dfs_info3_param *node = (*target_nodes)+i;
+ 
+ 		node->flags = le32_to_cpu(rsp->DFSFlags);
++		path_consumed = le16_to_cpu(rsp->PathConsumed);
+ 		if (is_unicode) {
+-			__le16 *tmp = kmalloc(strlen(searchName)*2 + 2,
+-						GFP_KERNEL);
+-			if (tmp == NULL) {
++			size_t search_name_utf16_len = search_name_len * 2 + 2;
++			__le16 *tmp;
++
++			if (path_consumed > search_name_utf16_len) {
++				rc = -EINVAL;
++				goto parse_DFS_referrals_exit;
++			}
++
++			tmp = kmalloc(search_name_utf16_len, GFP_KERNEL);
++			if (!tmp) {
+ 				rc = -ENOMEM;
+ 				goto parse_DFS_referrals_exit;
+ 			}
+-			cifsConvertToUTF16((__le16 *) tmp, searchName,
++			cifsConvertToUTF16((__le16 *)tmp, searchName,
+ 					   PATH_MAX, nls_codepage, remap);
+-			node->path_consumed = cifs_utf16_bytes(tmp,
+-					le16_to_cpu(rsp->PathConsumed),
+-					nls_codepage);
++			node->path_consumed = cifs_utf16_bytes(tmp, path_consumed,
++							       nls_codepage);
+ 			kfree(tmp);
+-		} else
+-			node->path_consumed = le16_to_cpu(rsp->PathConsumed);
++		} else {
++			if (path_consumed > search_name_len) {
++				rc = -EINVAL;
++				goto parse_DFS_referrals_exit;
++			}
++
++			node->path_consumed = path_consumed;
++		}
+ 
+ 		node->server_type = le16_to_cpu(ref->ServerType);
+ 		node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags);
+diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
+index c66b02f67d3391..8a15694c1bbb56 100644
+--- a/fs/smb/client/smb2ops.c
++++ b/fs/smb/client/smb2ops.c
+@@ -3417,6 +3417,7 @@ static int smb3_simple_fallocate_range(unsigned int xid,
+ 	struct file_allocated_range_buffer in_data, *out_data = NULL, *tmp_data;
+ 	u32 out_data_len;
+ 	char *buf = NULL;
++	u64 range_start, range_len, range_end;
+ 	loff_t l;
+ 	int rc;
+ 
+@@ -3453,13 +3454,21 @@ static int smb3_simple_fallocate_range(unsigned int xid,
+ 			goto out;
+ 		}
+ 
+-		if (off < le64_to_cpu(tmp_data->file_offset)) {
++		range_start = le64_to_cpu(tmp_data->file_offset);
++		range_len = le64_to_cpu(tmp_data->length);
++		if (check_add_overflow(range_start, range_len, &range_end) ||
++		    range_end > S64_MAX) {
++			rc = -EINVAL;
++			goto out;
++		}
++
++		if (off < range_start) {
+ 			/*
+ 			 * We are at a hole. Write until the end of the region
+ 			 * or until the next allocated data,
+ 			 * whichever comes next.
+ 			 */
+-			l = le64_to_cpu(tmp_data->file_offset) - off;
++			l = range_start - off;
+ 			if (len < l)
+ 				l = len;
+ 			rc = smb3_simple_fallocate_write_range(xid, tcon,
+@@ -3476,11 +3485,13 @@ static int smb3_simple_fallocate_range(unsigned int xid,
+ 		 * until the end of the data or the end of the region
+ 		 * we are supposed to fallocate, whichever comes first.
+ 		 */
+-		l = le64_to_cpu(tmp_data->length);
+-		if (len < l)
+-			l = len;
+-		off += l;
+-		len -= l;
++		if (off < range_end) {
++			l = range_end - off;
++			if (len < l)
++				l = len;
++			off += l;
++			len -= l;
++		}
+ 
+ 		tmp_data = &tmp_data[1];
+ 		out_data_len -= sizeof(struct file_allocated_range_buffer);
+diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
+index 82a7709b3e9ac8..109bb71d06adff 100644
+--- a/fs/smb/server/oplock.c
++++ b/fs/smb/server/oplock.c
+@@ -705,6 +705,7 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
+ out:
+ 	ksmbd_free_work_struct(work);
+ 	ksmbd_conn_r_count_dec(conn);
++	ksmbd_conn_put(conn);
+ }
+ 
+ /**
+@@ -740,7 +741,7 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
+ 	br_info->open_trunc = opinfo->open_trunc;
+ 
+ 	work->request_buf = (char *)br_info;
+-	work->conn = conn;
++	work->conn = ksmbd_conn_get(conn);
+ 	work->sess = opinfo->sess;
+ 
+ 	ksmbd_conn_r_count_inc(conn);
+@@ -814,6 +815,7 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
+ out:
+ 	ksmbd_free_work_struct(work);
+ 	ksmbd_conn_r_count_dec(conn);
++	ksmbd_conn_put(conn);
+ }
+ 
+ /**
+@@ -853,7 +855,7 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
+ 	memcpy(br_info->lease_key, lease->lease_key, SMB2_LEASE_KEY_SIZE);
+ 
+ 	work->request_buf = (char *)br_info;
+-	work->conn = conn;
++	work->conn = ksmbd_conn_get(conn);
+ 	work->sess = opinfo->sess;
+ 
+ 	ksmbd_conn_r_count_inc(conn);
+diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c
+index 727cb49926ee52..ffbddf00d24e95 100644
+--- a/fs/smb/server/smb2misc.c
++++ b/fs/smb/server/smb2misc.c
+@@ -400,6 +400,11 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
+ 		return 1;
+ 	}
+ 
++	if (len < __SMB2_HEADER_STRUCTURE_SIZE + sizeof(__le16)) {
++		ksmbd_debug(SMB, "Message is too small for StructureSize2\n");
++		return 1;
++	}
++
+ 	if (smb2_req_struct_sizes[command] != pdu->StructureSize2) {
+ 		if (!(command == SMB2_OPLOCK_BREAK_HE &&
+ 		    (le16_to_cpu(pdu->StructureSize2) == OP_BREAK_STRUCT_SIZE_20 ||
+diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
+index 3ddff0d9b8ba3d..41bc4b06fad08a 100644
+--- a/fs/smb/server/smb2pdu.c
++++ b/fs/smb/server/smb2pdu.c
+@@ -1483,11 +1483,6 @@ static int ntlm_authenticate(struct ksmbd_work *work,
+ 		return -EPERM;
+ 	}
+ 
+-	/* Check for previous session */
+-	prev_id = le64_to_cpu(req->PreviousSessionId);
+-	if (prev_id && prev_id != sess->id)
+-		destroy_previous_session(conn, user, prev_id);
+-
+ 	if (sess->state == SMB2_SESSION_VALID) {
+ 		/*
+ 		 * Reuse session if anonymous try to connect
+@@ -1525,6 +1520,10 @@ static int ntlm_authenticate(struct ksmbd_work *work,
+ 		}
+ 	}
+ 
++	prev_id = le64_to_cpu(req->PreviousSessionId);
++	if (prev_id && prev_id != sess->id)
++		destroy_previous_session(conn, sess->user, prev_id);
++
+ 	/*
+ 	 * If session state is SMB2_SESSION_VALID, We can assume
+ 	 * that it is reauthentication. And the user/password
+diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
+index 420d4e0733e5f1..06936ae521cf00 100644
+--- a/fs/smb/server/smbacl.c
++++ b/fs/smb/server/smbacl.c
+@@ -595,7 +595,8 @@ static void parse_dacl(struct mnt_idmap *idmap,
+ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ 				       struct smb_ace *pndace,
+ 				       struct smb_fattr *fattr, u16 *num_aces,
+-				       u16 *size, u32 nt_aces_num)
++				       u16 *size, u16 existing_nt_aces,
++				       bool had_nt_aces)
+ {
+ 	struct posix_acl_entry *pace;
+ 	struct smb_sid *sid;
+@@ -627,14 +628,14 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ 
+ 			gid = posix_acl_gid_translate(idmap, pace);
+ 			id_to_sid(gid, SIDUNIX_GROUP, sid);
+-		} else if (pace->e_tag == ACL_OTHER && !nt_aces_num) {
++		} else if (pace->e_tag == ACL_OTHER && !had_nt_aces) {
+ 			smb_copy_sid(sid, &sid_everyone);
+ 		} else {
+ 			kfree(sid);
+ 			continue;
+ 		}
+ 		ntace = pndace;
+-		for (j = 0; j < nt_aces_num; j++) {
++		for (j = 0; j < existing_nt_aces; j++) {
+ 			if (ntace->sid.sub_auth[ntace->sid.num_subauth - 1] ==
+ 					sid->sub_auth[sid->num_subauth - 1])
+ 				goto pass_same_sid;
+@@ -649,6 +650,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ 		ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, flags,
+ 				pace->e_perm, 0777);
+ 		if (check_add_overflow(*size, ace_sz, size)) {
++			*size -= ace_sz;
+ 			kfree(sid);
+ 			break;
+ 		}
+@@ -663,6 +665,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,
+ 			ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED,
+ 					0x03, pace->e_perm, 0777);
+ 			if (check_add_overflow(*size, ace_sz, size)) {
++				*size -= ace_sz;
+ 				kfree(sid);
+ 				break;
+ 			}
+@@ -676,7 +679,7 @@ pass_same_sid:
+ 		kfree(sid);
+ 	}
+ 
+-	if (nt_aces_num)
++	if (had_nt_aces)
+ 		return;
+ 
+ posix_default_acl:
+@@ -708,6 +711,7 @@ posix_default_acl:
+ 		ace_sz = fill_ace_for_sid(ntace, sid, ACCESS_ALLOWED, 0x0b,
+ 				pace->e_perm, 0777);
+ 		if (check_add_overflow(*size, ace_sz, size)) {
++			*size -= ace_sz;
+ 			kfree(sid);
+ 			break;
+ 		}
+@@ -729,6 +733,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ {
+ 	struct smb_ace *ntace, *pndace;
+ 	u16 nt_num_aces = le16_to_cpu(nt_dacl->num_aces), num_aces = 0;
++	u16 copied_nt_aces;
+ 	unsigned short size = 0;
+ 	int i;
+ 
+@@ -738,24 +743,41 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,
+ 		for (i = 0; i < nt_num_aces; i++) {
+ 			unsigned short nt_ace_size;
+ 
+-			if (offsetof(struct smb_ace, access_req) > aces_size)
++			if (aces_size < offsetof(struct smb_ace, sid) +
++					CIFS_SID_BASE_SIZE)
+ 				break;
+ 
+ 			nt_ace_size = le16_to_cpu(ntace->size);
+-			if (nt_ace_size > aces_size)
++			if (nt_ace_size > aces_size ||
++			    nt_ace_size < offsetof(struct smb_ace, sid) +
++					  CIFS_SID_BASE_SIZE)
+ 				break;
+ 
++			if (ntace->sid.num_subauth == 0 ||
++			    ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES ||
++			    nt_ace_size < offsetof(struct smb_ace, sid) +
++					  CIFS_SID_BASE_SIZE +
++					  sizeof(__le32) *
++					  ntace->sid.num_subauth)
++				goto next_ace;
++
+ 			memcpy((char *)pndace + size, ntace, nt_ace_size);
+-			if (check_add_overflow(size, nt_ace_size, &size))
++			if (check_add_overflow(size, nt_ace_size, &size)) {
++				size -= nt_ace_size;
+ 				break;
++			}
++			num_aces++;
++
++next_ace:
+ 			aces_size -= nt_ace_size;
+ 			ntace = (struct smb_ace *)((char *)ntace + nt_ace_size);
+-			num_aces++;
+ 		}
+ 	}
+ 
++	copied_nt_aces = num_aces;
+ 	set_posix_acl_entries_dacl(idmap, pndace, fattr,
+-				   &num_aces, &size, nt_num_aces);
++				   &num_aces, &size, copied_nt_aces,
++				   nt_num_aces != 0);
+ 	pndacl->num_aces = cpu_to_le16(num_aces);
+ 	pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
+ }
+@@ -773,7 +795,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,
+ 
+ 	if (fattr->cf_acls) {
+ 		set_posix_acl_entries_dacl(idmap, pndace, fattr,
+-					   &num_aces, &size, num_aces);
++					   &num_aces, &size, num_aces, false);
+ 		goto out;
+ 	}
+ 
+diff --git a/include/linux/audit.h b/include/linux/audit.h
+index 625210306813b5..2da263b4834234 100644
+--- a/include/linux/audit.h
++++ b/include/linux/audit.h
+@@ -16,7 +16,7 @@
+ #include <uapi/linux/netfilter/nf_tables.h>
+ #include <uapi/linux/fanotify.h>
+ 
+-#define AUDIT_INO_UNSET ((unsigned long)-1)
++#define AUDIT_INO_UNSET ((u64)-1)
+ #define AUDIT_DEV_UNSET ((dev_t)-1)
+ 
+ struct audit_sig_info {
+@@ -122,8 +122,8 @@ enum audit_nfcfgop {
+ 	AUDIT_NFT_OP_INVALID,
+ };
+ 
+-extern int __init audit_register_class(int class, unsigned *list);
+-extern int audit_classify_syscall(int abi, unsigned syscall);
++extern int __init audit_register_class(int class, unsigned int *list);
++extern int audit_classify_syscall(int abi, unsigned int syscall);
+ extern int audit_classify_arch(int arch);
+ 
+ /* audit_names->type values */
+diff --git a/include/linux/audit_arch.h b/include/linux/audit_arch.h
+index 2b8153791e6a5d..a35069a6c15de2 100644
+--- a/include/linux/audit_arch.h
++++ b/include/linux/audit_arch.h
+@@ -21,13 +21,13 @@ enum auditsc_class_t {
+ 	AUDITSC_NVALS /* count */
+ };
+ 
+-extern int audit_classify_compat_syscall(int abi, unsigned syscall);
++extern int audit_classify_compat_syscall(int abi, unsigned int syscall);
+ 
+ /* only for compat system calls */
+-extern unsigned compat_write_class[];
+-extern unsigned compat_read_class[];
+-extern unsigned compat_dir_class[];
+-extern unsigned compat_chattr_class[];
+-extern unsigned compat_signal_class[];
++extern unsigned int compat_write_class[];
++extern unsigned int compat_read_class[];
++extern unsigned int compat_dir_class[];
++extern unsigned int compat_chattr_class[];
++extern unsigned int compat_signal_class[];
+ 
+ #endif
+diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h
+index 4195444ec45d15..eb091218a285cb 100644
+--- a/include/linux/bootconfig.h
++++ b/include/linux/bootconfig.h
+@@ -264,6 +264,9 @@ static inline struct xbc_node * __init xbc_node_get_subkey(struct xbc_node *node
+ int __init xbc_node_compose_key_after(struct xbc_node *root,
+ 			struct xbc_node *node, char *buf, size_t size);
+ 
++/* Render key/value pairs under @root as a flat cmdline string */
++int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root);
++
+ /**
+  * xbc_node_compose_key() - Compose full key string of the XBC node
+  * @node: An XBC node.
+diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h
+index 1de7ece5d36d43..4f962dccc6c500 100644
+--- a/include/linux/bpf_lsm.h
++++ b/include/linux/bpf_lsm.h
+@@ -13,6 +13,8 @@
+ 
+ #ifdef CONFIG_BPF_LSM
+ 
++extern bool bpf_lsm_initialized __ro_after_init;
++
+ #define LSM_HOOK(RET, DEFAULT, NAME, ...) \
+ 	RET bpf_lsm_##NAME(__VA_ARGS__);
+ #include <linux/lsm_hook_defs.h>
+@@ -47,6 +49,8 @@ void bpf_lsm_find_cgroup_shim(const struct bpf_prog *prog, bpf_func_t *bpf_func)
+ 
+ #else /* !CONFIG_BPF_LSM */
+ 
++#define bpf_lsm_initialized false
++
+ static inline bool bpf_lsm_is_sleepable_hook(u32 btf_id)
+ {
+ 	return false;
+diff --git a/include/linux/firmware.h b/include/linux/firmware.h
+index de7fea3bca51e5..2035a0d9cc86fa 100644
+--- a/include/linux/firmware.h
++++ b/include/linux/firmware.h
+@@ -4,6 +4,7 @@
+ 
+ #include <linux/types.h>
+ #include <linux/compiler.h>
++#include <linux/cleanup.h>
+ #include <linux/gfp.h>
+ 
+ #define FW_ACTION_NOUEVENT 0
+@@ -196,4 +197,6 @@ static inline void firmware_upload_unregister(struct fw_upload *fw_upload)
+ 
+ int firmware_request_cache(struct device *device, const char *name);
+ 
++DEFINE_FREE(firmware, struct firmware *, release_firmware(_T))
++
+ #endif
+diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
+index c895b12737a193..e55ba9f1e38398 100644
+--- a/include/linux/fscrypt.h
++++ b/include/linux/fscrypt.h
+@@ -57,6 +57,9 @@ struct fscrypt_name {
+ /* Maximum value for the third parameter of fscrypt_operations.set_context(). */
+ #define FSCRYPT_SET_CONTEXT_MAX_SIZE	40
+ 
++/* Maximum supported number of block devices per filesystem */
++#define FSCRYPT_MAX_DEVICES	8
++
+ #ifdef CONFIG_FS_ENCRYPTION
+ 
+ /*
+@@ -161,21 +164,20 @@ struct fscrypt_operations {
+ 				      int *ino_bits_ret, int *lblk_bits_ret);
+ 
+ 	/*
+-	 * Return an array of pointers to the block devices to which the
+-	 * filesystem may write encrypted file contents, NULL if the filesystem
+-	 * only has a single such block device, or an ERR_PTR() on error.
++	 * Retrieve the list of block devices to which the filesystem may write
++	 * encrypted file contents.
+ 	 *
+-	 * On successful non-NULL return, *num_devs is set to the number of
+-	 * devices in the returned array.  The caller must free the returned
+-	 * array using kfree().
++	 * This writes the block_device pointers to @devs and returns the count
++	 * (between 1 and FSCRYPT_MAX_DEVICES inclusively).
+ 	 *
+ 	 * If the filesystem can use multiple block devices (other than block
+ 	 * devices that aren't used for encrypted file contents, such as
+ 	 * external journal devices), and wants to support inline encryption,
+ 	 * then it must implement this function.  Otherwise it's not needed.
+ 	 */
+-	struct block_device **(*get_devices)(struct super_block *sb,
+-					     unsigned int *num_devs);
++	unsigned int (*get_devices)(
++		struct super_block *sb,
++		struct block_device *devs[FSCRYPT_MAX_DEVICES]);
+ };
+ 
+ static inline struct fscrypt_info *fscrypt_get_info(const struct inode *inode)
+diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
+index 57c7b4009f5758..17ff73f1b684b5 100644
+--- a/include/linux/kvm_host.h
++++ b/include/linux/kvm_host.h
+@@ -378,6 +378,7 @@ struct kvm_vcpu {
+ 		bool dy_eligible;
+ 	} spin_loop;
+ #endif
++	bool wants_to_run;
+ 	bool preempted;
+ 	bool ready;
+ 	struct kvm_vcpu_arch arch;
+diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
+index 3b56b60195ceb9..2365b4d6185733 100644
+--- a/include/linux/lsm_hooks.h
++++ b/include/linux/lsm_hooks.h
+@@ -61,6 +61,7 @@ struct lsm_blob_sizes {
+ 	int	lbs_file;
+ 	int lbs_backing_file;
+ 	int	lbs_inode;
++	int	lbs_sock;
+ 	int	lbs_superblock;
+ 	int	lbs_ipc;
+ 	int	lbs_msg_msg;
+diff --git a/include/linux/namei.h b/include/linux/namei.h
+index 1463cbda488867..c1ff032607dd6e 100644
+--- a/include/linux/namei.h
++++ b/include/linux/namei.h
+@@ -61,6 +61,7 @@ struct dentry *lookup_one_qstr_excl(const struct qstr *name,
+ 				    struct dentry *base,
+ 				    unsigned int flags);
+ extern int kern_path(const char *, unsigned, struct path *);
++struct dentry *kern_path_parent(const char *name, struct path *parent);
+ 
+ extern struct dentry *kern_path_create(int, const char *, struct path *, unsigned int);
+ extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
+diff --git a/include/linux/pinctrl/consumer.h b/include/linux/pinctrl/consumer.h
+index 4729d54e899535..89b6718e8f26b4 100644
+--- a/include/linux/pinctrl/consumer.h
++++ b/include/linux/pinctrl/consumer.h
+@@ -17,6 +17,7 @@
+ #include <linux/pinctrl/pinctrl-state.h>
+ 
+ struct device;
++struct gpio_chip;
+ 
+ /* This struct is private to the core and should be regarded as a cookie */
+ struct pinctrl;
+@@ -28,8 +29,10 @@ struct pinctrl_state;
+ extern bool pinctrl_gpio_can_use_line(unsigned gpio);
+ extern int pinctrl_gpio_request(unsigned gpio);
+ extern void pinctrl_gpio_free(unsigned gpio);
+-extern int pinctrl_gpio_direction_input(unsigned gpio);
+-extern int pinctrl_gpio_direction_output(unsigned gpio);
++extern int pinctrl_gpio_direction_input(struct gpio_chip *gc,
++					unsigned int offset);
++extern int pinctrl_gpio_direction_output(struct gpio_chip *gc,
++					 unsigned int offset);
+ extern int pinctrl_gpio_set_config(unsigned gpio, unsigned long config);
+ 
+ extern struct pinctrl * __must_check pinctrl_get(struct device *dev);
+@@ -77,12 +80,14 @@ static inline void pinctrl_gpio_free(unsigned gpio)
+ {
+ }
+ 
+-static inline int pinctrl_gpio_direction_input(unsigned gpio)
++static inline int
++pinctrl_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+ {
+ 	return 0;
+ }
+ 
+-static inline int pinctrl_gpio_direction_output(unsigned gpio)
++static inline int
++pinctrl_gpio_direction_output(struct gpio_chip *gc, unsigned int offset)
+ {
+ 	return 0;
+ }
+diff --git a/include/linux/ppp_channel.h b/include/linux/ppp_channel.h
+index 45e6e427ceb8a0..f73fbea0dbc239 100644
+--- a/include/linux/ppp_channel.h
++++ b/include/linux/ppp_channel.h
+@@ -42,8 +42,7 @@ struct ppp_channel {
+ 	int		hdrlen;		/* amount of headroom channel needs */
+ 	void		*ppp;		/* opaque to channel */
+ 	int		speed;		/* transfer rate (bytes/second) */
+-	/* the following is not used at present */
+-	int		latency;	/* overhead time in milliseconds */
++	bool		direct_xmit;	/* no qdisc, xmit directly */
+ };
+ 
+ #ifdef __KERNEL__
+diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
+index 995f29dd545516..c5f5a988798418 100644
+--- a/include/linux/seqlock.h
++++ b/include/linux/seqlock.h
+@@ -1281,7 +1281,7 @@ struct ss_tmp {
+ 	spinlock_t	*lock_irqsave;
+ };
+ 
+-static inline void __scoped_seqlock_cleanup(struct ss_tmp *sst)
++static __always_inline void __scoped_seqlock_cleanup(struct ss_tmp *sst)
+ {
+ 	if (sst->lock)
+ 		spin_unlock(sst->lock);
+@@ -1291,11 +1291,15 @@ static inline void __scoped_seqlock_cleanup(struct ss_tmp *sst)
+ 
+ extern void __scoped_seqlock_invalid_target(void);
+ 
+-#if defined(CONFIG_CC_IS_GCC) && CONFIG_GCC_VERSION < 90000
++#if (defined(CONFIG_CC_IS_GCC) && CONFIG_GCC_VERSION < 90000) || \
++	defined(CONFIG_KASAN) || defined(CONFIG_UBSAN_ALIGNMENT)
+ /*
+  * For some reason some GCC-8 architectures (nios2, alpha) have trouble
+  * determining that the ss_done state is impossible in __scoped_seqlock_next()
+  * below.
++ *
++ * Similarly KASAN and UBSAN_ALIGNMENT are known to confuse compilers enough
++ * to break this. But we don't care about code quality for such builds anyway.
+  */
+ static inline void __scoped_seqlock_bug(void) { }
+ #else
+@@ -1306,7 +1310,7 @@ static inline void __scoped_seqlock_bug(void) { }
+ extern void __scoped_seqlock_bug(void);
+ #endif
+ 
+-static inline void
++static __always_inline void
+ __scoped_seqlock_next(struct ss_tmp *sst, seqlock_t *lock, enum ss_state target)
+ {
+ 	switch (sst->state) {
+diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
+index 7c78ec6356b928..9e6ecc3526e774 100644
+--- a/include/linux/sunrpc/svcsock.h
++++ b/include/linux/sunrpc/svcsock.h
+@@ -26,6 +26,9 @@ struct svc_sock {
+ 	void			(*sk_odata)(struct sock *);
+ 	void			(*sk_owspace)(struct sock *);
+ 
++	/* For sends (protected by xpt_mutex) */
++	struct bio_vec		*sk_bvec;
++
+ 	/* private TCP part */
+ 	/* On-the-wire fragment header: */
+ 	__be32			sk_marker;
+diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
+index 2f8dc47f1eb075..a180482dc209b0 100644
+--- a/include/linux/sunrpc/xdr.h
++++ b/include/linux/sunrpc/xdr.h
+@@ -139,8 +139,23 @@ void	xdr_terminate_string(const struct xdr_buf *, const u32);
+ size_t	xdr_buf_pagecount(const struct xdr_buf *buf);
+ int	xdr_alloc_bvec(struct xdr_buf *buf, gfp_t gfp);
+ void	xdr_free_bvec(struct xdr_buf *buf);
+-unsigned int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
+-			     const struct xdr_buf *xdr);
++int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
++		    const struct xdr_buf *xdr);
++int xdr_buf_to_sg(const struct xdr_buf *buf, unsigned int offset,
++		  unsigned int len, struct scatterlist *sg, unsigned int nsg);
++int xdr_buf_to_sg_alloc(const struct xdr_buf *buf, unsigned int offset,
++			unsigned int len, struct scatterlist *sg_head,
++			unsigned int sg_head_nents,
++			struct scatterlist **sg_overflow, gfp_t gfp);
++
++/*
++ * Inline scatterlist entries for xdr_buf_to_sg_alloc().  Sized to cover the
++ * head kvec, tail kvec, and a few page fragments without any heap allocation.
++ */
++enum {
++	XDR_BUF_TO_SG_NENTS	= 8,
++};
++
+ 
+ static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len)
+ {
+diff --git a/include/linux/vtime.h b/include/linux/vtime.h
+index 3684487d01e1c6..7cee518fde3a24 100644
+--- a/include/linux/vtime.h
++++ b/include/linux/vtime.h
+@@ -37,11 +37,17 @@ extern void vtime_account_irq(struct task_struct *tsk, unsigned int offset);
+ extern void vtime_account_softirq(struct task_struct *tsk);
+ extern void vtime_account_hardirq(struct task_struct *tsk);
+ extern void vtime_flush(struct task_struct *tsk);
++extern void vtime_reset(void);
++extern void vtime_dyntick_start(void);
++extern void vtime_dyntick_stop(void);
+ #else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
+ static inline void vtime_account_irq(struct task_struct *tsk, unsigned int offset) { }
+ static inline void vtime_account_softirq(struct task_struct *tsk) { }
+ static inline void vtime_account_hardirq(struct task_struct *tsk) { }
+ static inline void vtime_flush(struct task_struct *tsk) { }
++static inline void vtime_reset(void) { }
++static inline void vtime_dyntick_start(void) { }
++static inline void vtime_dyntick_stop(void) { }
+ #endif
+ 
+ /*
+diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
+index 52c6dd6d80ac09..c4df93bee09c7f 100644
+--- a/include/linux/workqueue.h
++++ b/include/linux/workqueue.h
+@@ -410,7 +410,7 @@ enum {
+ /*
+  * System-wide workqueues which are always present.
+  *
+- * system_wq is the one used by schedule[_delayed]_work[_on]().
++ * system_percpu_wq is the one used by schedule[_delayed]_work[_on]().
+  * Multi-CPU multi-threaded.  There are users which expect relatively
+  * short queue flush time.  Don't queue works which can run for too
+  * long.
+@@ -421,7 +421,7 @@ enum {
+  * system_long_wq is similar to system_wq but may host long running
+  * works.  Queue flushing might take relatively long.
+  *
+- * system_unbound_wq is unbound workqueue.  Workers are not bound to
++ * system_dfl_wq is unbound workqueue.  Workers are not bound to
+  * any specific CPU, not concurrency managed, and all queued works are
+  * executed immediately as long as max_active limit is not reached and
+  * resources are available.
+@@ -435,10 +435,12 @@ enum {
+  * system_power_efficient_wq is identical to system_wq if
+  * 'wq_power_efficient' is disabled.  See WQ_POWER_EFFICIENT for more info.
+  */
+-extern struct workqueue_struct *system_wq;
++extern struct workqueue_struct *system_wq; /* use system_percpu_wq, this will be removed */
++extern struct workqueue_struct *system_percpu_wq;
+ extern struct workqueue_struct *system_highpri_wq;
+ extern struct workqueue_struct *system_long_wq;
+ extern struct workqueue_struct *system_unbound_wq;
++extern struct workqueue_struct *system_dfl_wq;
+ extern struct workqueue_struct *system_freezable_wq;
+ extern struct workqueue_struct *system_power_efficient_wq;
+ extern struct workqueue_struct *system_freezable_power_efficient_wq;
+diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
+index 4b6a9d2ea37277..bbdef1f63eab92 100644
+--- a/include/media/videobuf2-core.h
++++ b/include/media/videobuf2-core.h
+@@ -1064,8 +1064,8 @@ __poll_t vb2_core_poll(struct vb2_queue *q, struct file *file,
+  * @ppos:	file handle position tracking pointer
+  * @nonblock:	mode selector (1 means blocking calls, 0 means nonblocking)
+  */
+-size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+-		loff_t *ppos, int nonblock);
++ssize_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
++		 loff_t *ppos, int nonblock);
+ /**
+  * vb2_write() - implements write() syscall logic.
+  * @q:		pointer to &struct vb2_queue with videobuf2 queue.
+@@ -1074,8 +1074,8 @@ size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+  * @ppos:	file handle position tracking pointer
+  * @nonblock:	mode selector (1 means blocking calls, 0 means nonblocking)
+  */
+-size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
+-		loff_t *ppos, int nonblock);
++ssize_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
++		  loff_t *ppos, int nonblock);
+ 
+ /**
+  * typedef vb2_thread_fnc - callback function for use with vb2_thread.
+diff --git a/include/net/af_rxrpc.h b/include/net/af_rxrpc.h
+index 5531dd08061e51..051429e8987c82 100644
+--- a/include/net/af_rxrpc.h
++++ b/include/net/af_rxrpc.h
+@@ -28,18 +28,23 @@ enum rxrpc_interruptibility {
+  */
+ extern atomic_t rxrpc_debug_id;
+ 
++/*
++ * Operations table for rxrpc to call out to a kernel application (e.g. kAFS).
++ */
++struct rxrpc_kernel_ops {
++	void (*notify_new_call)(struct sock *sk, struct rxrpc_call *call,
++				unsigned long user_call_ID);
++	void (*discard_new_call)(struct rxrpc_call *call, unsigned long user_call_ID);
++	void (*user_attach_call)(struct rxrpc_call *call, unsigned long user_call_ID);
++};
++
+ typedef void (*rxrpc_notify_rx_t)(struct sock *, struct rxrpc_call *,
+ 				  unsigned long);
+ typedef void (*rxrpc_notify_end_tx_t)(struct sock *, struct rxrpc_call *,
+ 				      unsigned long);
+-typedef void (*rxrpc_notify_new_call_t)(struct sock *, struct rxrpc_call *,
+-					unsigned long);
+-typedef void (*rxrpc_discard_new_call_t)(struct rxrpc_call *, unsigned long);
+-typedef void (*rxrpc_user_attach_call_t)(struct rxrpc_call *, unsigned long);
+ 
+-void rxrpc_kernel_new_call_notification(struct socket *,
+-					rxrpc_notify_new_call_t,
+-					rxrpc_discard_new_call_t);
++void rxrpc_kernel_set_notifications(struct socket *sock,
++				    const struct rxrpc_kernel_ops *app_ops);
+ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
+ 					   struct sockaddr_rxrpc *srx,
+ 					   struct key *key,
+@@ -63,9 +68,9 @@ void rxrpc_kernel_put_call(struct socket *sock, struct rxrpc_call *call);
+ void rxrpc_kernel_get_peer(struct socket *, struct rxrpc_call *,
+ 			   struct sockaddr_rxrpc *);
+ bool rxrpc_kernel_get_srtt(struct socket *, struct rxrpc_call *, u32 *);
+-int rxrpc_kernel_charge_accept(struct socket *, rxrpc_notify_rx_t,
+-			       rxrpc_user_attach_call_t, unsigned long, gfp_t,
+-			       unsigned int);
++int rxrpc_kernel_charge_accept(struct socket *sock, rxrpc_notify_rx_t notify_rx,
++			       unsigned long user_call_ID, gfp_t gfp,
++			       unsigned int debug_id);
+ void rxrpc_kernel_set_tx_length(struct socket *, struct rxrpc_call *, s64);
+ bool rxrpc_kernel_check_life(const struct socket *, const struct rxrpc_call *);
+ u32 rxrpc_kernel_get_epoch(struct socket *, struct rxrpc_call *);
+diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
+index 99d26879b02a53..ba8d3702853d25 100644
+--- a/include/net/bluetooth/rfcomm.h
++++ b/include/net/bluetooth/rfcomm.h
+@@ -229,6 +229,9 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
+ 			u8 bit_rate, u8 data_bits, u8 stop_bits,
+ 			u8 parity, u8 flow_ctrl_settings,
+ 			u8 xon_char, u8 xoff_char, u16 param_mask);
++int rfcomm_dlc_send_rpn(struct rfcomm_dlc *d, u8 bit_rate, u8 data_bits,
++			u8 stop_bits, u8 parity, u8 flow_ctrl_settings,
++			u8 xon_char, u8 xoff_char, u16 param_mask);
+ 
+ /* ---- RFCOMM DLCs (channels) ---- */
+ struct rfcomm_dlc *rfcomm_dlc_alloc(gfp_t prio);
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index a1f828efc9e3de..aac4e1c5430088 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -123,17 +123,6 @@ struct nft_regs {
+ 	};
+ };
+ 
+-struct nft_regs_track {
+-	struct {
+-		const struct nft_expr		*selector;
+-		const struct nft_expr		*bitwise;
+-		u8				num_reg;
+-	} regs[NFT_REG32_NUM];
+-
+-	const struct nft_expr			*cur;
+-	const struct nft_expr			*last;
+-};
+-
+ /* Store/load an u8, u16 or u64 integer to/from the u32 data register.
+  *
+  * Note, when using concatenations, register allocation happens at 32-bit
+@@ -420,8 +409,6 @@ int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src, gfp_t gfp);
+ void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr);
+ int nft_expr_dump(struct sk_buff *skb, unsigned int attr,
+ 		  const struct nft_expr *expr, bool reset);
+-bool nft_expr_reduce_bitwise(struct nft_regs_track *track,
+-			     const struct nft_expr *expr);
+ 
+ struct nft_set_ext;
+ 
+@@ -933,7 +920,6 @@ struct nft_offload_ctx;
+  *	@destroy_clone: destruction clone function
+  *	@dump: function to dump parameters
+  *	@validate: validate expression, called during loop detection
+- *	@reduce: reduce expression
+  *	@gc: garbage collection expression
+  *	@offload: hardware offload expression
+  *	@offload_action: function to report true/false to allocate one slot or not in the flow
+@@ -967,8 +953,6 @@ struct nft_expr_ops {
+ 						bool reset);
+ 	int				(*validate)(const struct nft_ctx *ctx,
+ 						    const struct nft_expr *expr);
+-	bool				(*reduce)(struct nft_regs_track *track,
+-						  const struct nft_expr *expr);
+ 	bool				(*gc)(struct net *net,
+ 					      const struct nft_expr *expr);
+ 	int				(*offload)(struct nft_offload_ctx *ctx,
+@@ -1848,25 +1832,4 @@ static inline u64 nft_net_tstamp(const struct net *net)
+ 	return nft_pernet(net)->tstamp;
+ }
+ 
+-#define __NFT_REDUCE_READONLY	1UL
+-#define NFT_REDUCE_READONLY	(void *)__NFT_REDUCE_READONLY
+-
+-static inline bool nft_reduce_is_readonly(const struct nft_expr *expr)
+-{
+-	return expr->ops->reduce == NFT_REDUCE_READONLY;
+-}
+-
+-void nft_reg_track_update(struct nft_regs_track *track,
+-			  const struct nft_expr *expr, u8 dreg, u8 len);
+-void nft_reg_track_cancel(struct nft_regs_track *track, u8 dreg, u8 len);
+-void __nft_reg_track_cancel(struct nft_regs_track *track, u8 dreg);
+-
+-static inline bool nft_reg_track_cmp(struct nft_regs_track *track,
+-				     const struct nft_expr *expr, u8 dreg)
+-{
+-	return track->regs[dreg].selector &&
+-	       track->regs[dreg].selector->ops == expr->ops &&
+-	       track->regs[dreg].num_reg == 0;
+-}
+-
+ #endif /* _NET_NF_TABLES_H */
+diff --git a/include/net/netfilter/nft_fib.h b/include/net/netfilter/nft_fib.h
+index 38cae7113de462..6147d37c88895b 100644
+--- a/include/net/netfilter/nft_fib.h
++++ b/include/net/netfilter/nft_fib.h
+@@ -36,6 +36,4 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
+ void nft_fib_store_result(void *reg, const struct nft_fib *priv,
+ 			  const struct net_device *dev);
+ 
+-bool nft_fib_reduce(struct nft_regs_track *track,
+-		    const struct nft_expr *expr);
+ #endif
+diff --git a/include/net/netfilter/nft_meta.h b/include/net/netfilter/nft_meta.h
+index d602263590fed5..f74e63290603d9 100644
+--- a/include/net/netfilter/nft_meta.h
++++ b/include/net/netfilter/nft_meta.h
+@@ -43,9 +43,6 @@ void nft_meta_set_destroy(const struct nft_ctx *ctx,
+ int nft_meta_set_validate(const struct nft_ctx *ctx,
+ 			  const struct nft_expr *expr);
+ 
+-bool nft_meta_get_reduce(struct nft_regs_track *track,
+-			 const struct nft_expr *expr);
+-
+ struct nft_inner_tun_ctx;
+ void nft_meta_inner_eval(const struct nft_expr *expr,
+ 			 struct nft_regs *regs, const struct nft_pktinfo *pkt,
+diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
+index d943bb454b1769..5baf98eac3db9d 100644
+--- a/include/net/sctp/structs.h
++++ b/include/net/sctp/structs.h
+@@ -322,7 +322,8 @@ struct sctp_cookie {
+ 
+ 	__u8 auth_random[sizeof(struct sctp_paramhdr) +
+ 			 SCTP_AUTH_RANDOM_LENGTH];
+-	__u8 auth_hmacs[SCTP_AUTH_NUM_HMACS * sizeof(__u16) + 2];
++	__u8 auth_hmacs[sizeof(struct sctp_paramhdr) +
++			SCTP_AUTH_NUM_HMACS * sizeof(__u16)];
+ 	__u8 auth_chunks[sizeof(struct sctp_paramhdr) + SCTP_AUTH_MAX_CHUNKS];
+ 
+ 	/* This is a shim for my peer's INIT packet, followed by
+diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h
+index eac3c05278c153..4c5329b504d0cb 100644
+--- a/include/rdma/ib_umem.h
++++ b/include/rdma/ib_umem.h
+@@ -36,8 +36,10 @@ struct ib_umem_dmabuf {
+ 	struct scatterlist *last_sg;
+ 	unsigned long first_sg_offset;
+ 	unsigned long last_sg_trim;
++	void (*pinned_revoke)(void *priv);
+ 	void *private;
+ 	u8 pinned : 1;
++	u8 revoked : 1;
+ };
+ 
+ static inline struct ib_umem_dmabuf *to_ib_umem_dmabuf(struct ib_umem *umem)
+@@ -122,9 +124,23 @@ struct ib_umem_dmabuf *ib_umem_dmabuf_get_pinned(struct ib_device *device,
+ 						 unsigned long offset,
+ 						 size_t size, int fd,
+ 						 int access);
++struct ib_umem_dmabuf *
++ib_umem_dmabuf_get_pinned_revocable_and_lock(struct ib_device *device,
++					     unsigned long offset, size_t size,
++					     int fd, int access);
++void ib_umem_dmabuf_set_revoke_locked(struct ib_umem_dmabuf *umem_dmabuf,
++				      void (*revoke)(void *priv), void *priv);
++struct ib_umem_dmabuf *
++ib_umem_dmabuf_get_pinned_with_dma_device(struct ib_device *device,
++					  struct device *dma_device,
++					  unsigned long offset, size_t size,
++					  int fd, int access);
+ int ib_umem_dmabuf_map_pages(struct ib_umem_dmabuf *umem_dmabuf);
+ void ib_umem_dmabuf_unmap_pages(struct ib_umem_dmabuf *umem_dmabuf);
+ void ib_umem_dmabuf_release(struct ib_umem_dmabuf *umem_dmabuf);
++void ib_umem_dmabuf_revoke_lock(struct ib_umem_dmabuf *umem_dmabuf);
++void ib_umem_dmabuf_revoke_unlock(struct ib_umem_dmabuf *umem_dmabuf);
++void ib_umem_dmabuf_revoke(struct ib_umem_dmabuf *umem_dmabuf);
+ 
+ int ib_umem_check_rereg(struct ib_umem *umem, int flags, int new_access_flags);
+ 
+@@ -170,12 +186,37 @@ ib_umem_dmabuf_get_pinned(struct ib_device *device, unsigned long offset,
+ {
+ 	return ERR_PTR(-EOPNOTSUPP);
+ }
++
++static inline struct ib_umem_dmabuf *
++ib_umem_dmabuf_get_pinned_revocable_and_lock(struct ib_device *device,
++					     unsigned long offset, size_t size,
++					     int fd, int access)
++{
++	return ERR_PTR(-EOPNOTSUPP);
++}
++
++static inline void
++ib_umem_dmabuf_set_revoke_locked(struct ib_umem_dmabuf *umem_dmabuf,
++				 void (*revoke)(void *priv), void *priv) {}
++
++static inline struct ib_umem_dmabuf *
++ib_umem_dmabuf_get_pinned_with_dma_device(struct ib_device *device,
++					  struct device *dma_device,
++					  unsigned long offset, size_t size,
++					  int fd, int access)
++{
++	return ERR_PTR(-EOPNOTSUPP);
++}
++
+ static inline int ib_umem_dmabuf_map_pages(struct ib_umem_dmabuf *umem_dmabuf)
+ {
+ 	return -EOPNOTSUPP;
+ }
+ static inline void ib_umem_dmabuf_unmap_pages(struct ib_umem_dmabuf *umem_dmabuf) { }
+ static inline void ib_umem_dmabuf_release(struct ib_umem_dmabuf *umem_dmabuf) { }
++static inline void ib_umem_dmabuf_revoke_lock(struct ib_umem_dmabuf *umem_dmabuf) {}
++static inline void ib_umem_dmabuf_revoke_unlock(struct ib_umem_dmabuf *umem_dmabuf) {}
++static inline void ib_umem_dmabuf_revoke(struct ib_umem_dmabuf *umem_dmabuf) {}
+ 
+ static inline int ib_umem_check_rereg(struct ib_umem *umem, int flags,
+ 				      int new_access_flags)
+diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
+index f0560087637ede..8cbec303cb5057 100644
+--- a/include/trace/events/rxrpc.h
++++ b/include/trace/events/rxrpc.h
+@@ -271,10 +271,10 @@
+ 	EM(rxrpc_call_put_poke,			"PUT poke    ") \
+ 	EM(rxrpc_call_put_recvmsg,		"PUT recvmsg ") \
+ 	EM(rxrpc_call_put_recvmsg_peek_nowait,	"PUT peek-nwt") \
++	EM(rxrpc_call_put_release_recvmsg_q,	"PUT rls-rcmq") \
+ 	EM(rxrpc_call_put_release_sock,		"PUT rls-sock") \
+ 	EM(rxrpc_call_put_release_sock_tba,	"PUT rls-sk-a") \
+ 	EM(rxrpc_call_put_sendmsg,		"PUT sendmsg ") \
+-	EM(rxrpc_call_put_unnotify,		"PUT unnotify") \
+ 	EM(rxrpc_call_put_userid_exists,	"PUT u-exists") \
+ 	EM(rxrpc_call_put_userid,		"PUT user-id ") \
+ 	EM(rxrpc_call_see_accept,		"SEE accept  ") \
+@@ -287,6 +287,7 @@
+ 	EM(rxrpc_call_see_disconnected,		"SEE disconn ") \
+ 	EM(rxrpc_call_see_distribute_error,	"SEE dist-err") \
+ 	EM(rxrpc_call_see_input,		"SEE input   ") \
++	EM(rxrpc_call_see_notify_released,	"SEE nfy-rlsd") \
+ 	EM(rxrpc_call_see_recvmsg,		"SEE recvmsg ") \
+ 	EM(rxrpc_call_see_recvmsg_requeue,	"SEE recv-rqu") \
+ 	EM(rxrpc_call_see_recvmsg_requeue_first, "SEE recv-rqF") \
+diff --git a/include/uapi/linux/btrfs.h b/include/uapi/linux/btrfs.h
+index 7b499b90bb779e..9c921ae7c9187b 100644
+--- a/include/uapi/linux/btrfs.h
++++ b/include/uapi/linux/btrfs.h
+@@ -595,7 +595,7 @@ struct btrfs_ioctl_search_args_v2 {
+ 	__u64 buf_size;		   /* in - size of buffer
+ 					    * out - on EOVERFLOW: needed size
+ 					    *       to store item */
+-	__u64 buf[];                       /* out - found items */
++	__u8 buf[];                        /* out - found items */
+ };
+ 
+ /* With a @src_length of zero, the range from @src_offset->EOF is cloned! */
+diff --git a/init/main.c b/init/main.c
+index eac47a2beb7e4b..62d8f7610e846f 100644
+--- a/init/main.c
++++ b/init/main.c
+@@ -316,45 +316,6 @@ static void * __init get_boot_config_from_initrd(size_t *_size)
+ 
+ #ifdef CONFIG_BOOT_CONFIG
+ 
+-static char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
+-
+-#define rest(dst, end) ((end) > (dst) ? (end) - (dst) : 0)
+-
+-static int __init xbc_snprint_cmdline(char *buf, size_t size,
+-				      struct xbc_node *root)
+-{
+-	struct xbc_node *knode, *vnode;
+-	char *end = buf + size;
+-	const char *val;
+-	int ret;
+-
+-	xbc_node_for_each_key_value(root, knode, val) {
+-		ret = xbc_node_compose_key_after(root, knode,
+-					xbc_namebuf, XBC_KEYLEN_MAX);
+-		if (ret < 0)
+-			return ret;
+-
+-		vnode = xbc_node_get_child(knode);
+-		if (!vnode) {
+-			ret = snprintf(buf, rest(buf, end), "%s ", xbc_namebuf);
+-			if (ret < 0)
+-				return ret;
+-			buf += ret;
+-			continue;
+-		}
+-		xbc_array_for_each_value(vnode, val) {
+-			ret = snprintf(buf, rest(buf, end), "%s=\"%s\" ",
+-				       xbc_namebuf, val);
+-			if (ret < 0)
+-				return ret;
+-			buf += ret;
+-		}
+-	}
+-
+-	return buf - (end - size);
+-}
+-#undef rest
+-
+ /* Make an extra command line under given key word */
+ static char * __init xbc_make_cmdline(const char *key)
+ {
+diff --git a/io_uring/rw.c b/io_uring/rw.c
+index 4ff3442ac2eeea..f2ab967b95072a 100644
+--- a/io_uring/rw.c
++++ b/io_uring/rw.c
+@@ -140,27 +140,37 @@ void io_readv_writev_cleanup(struct io_kiocb *req)
+ 	kfree(io->free_iovec);
+ }
+ 
+-static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
++static inline ssize_t io_fixup_restart_res(ssize_t ret)
+ {
+ 	switch (ret) {
+-	case -EIOCBQUEUED:
+-		break;
+ 	case -ERESTARTSYS:
+ 	case -ERESTARTNOINTR:
+ 	case -ERESTARTNOHAND:
+ 	case -ERESTART_RESTARTBLOCK:
+ 		/*
+ 		 * We can't just restart the syscall, since previously
+-		 * submitted sqes may already be in progress. Just fail this
+-		 * IO with EINTR.
++		 * submitted sqes may already be in progress. Just fail
++		 * this IO with EINTR.
+ 		 */
+-		ret = -EINTR;
+-		fallthrough;
++		return -EINTR;
+ 	default:
+-		kiocb->ki_complete(kiocb, ret);
++		return ret;
+ 	}
+ }
+ 
++static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret)
++{
++	/* IO was queued async, completion will happen later */
++	if (ret == -EIOCBQUEUED)
++		return;
++
++	/* transform internal restart error codes */
++	if (unlikely(ret < 0))
++		ret = io_fixup_restart_res(ret);
++
++	kiocb->ki_complete(kiocb, ret);
++}
++
+ static inline loff_t *io_kiocb_update_pos(struct io_kiocb *req)
+ {
+ 	struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
+@@ -885,7 +895,7 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags)
+ 	if (ret >= 0)
+ 		return kiocb_done(req, ret, issue_flags);
+ 
+-	return ret;
++	return io_fixup_restart_res(ret);
+ }
+ 
+ static bool io_kiocb_start_write(struct io_kiocb *req, struct kiocb *kiocb)
+diff --git a/kernel/audit.c b/kernel/audit.c
+index 20b71a5b476026..aa450ea116f1c9 100644
+--- a/kernel/audit.c
++++ b/kernel/audit.c
+@@ -1989,7 +1989,7 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
+ 		 * here and AUDIT_BUFSIZ is at least 1024, then we can
+ 		 * log everything that printk could have logged. */
+ 		avail = audit_expand(ab,
+-			max_t(unsigned, AUDIT_BUFSIZ, 1+len-avail));
++			max_t(unsigned int, AUDIT_BUFSIZ, 1+len-avail));
+ 		if (!avail)
+ 			goto out_va_end;
+ 		len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args2);
+diff --git a/kernel/audit.h b/kernel/audit.h
+index 5156ecd3545733..9cda69f2bd2989 100644
+--- a/kernel/audit.h
++++ b/kernel/audit.h
+@@ -75,7 +75,7 @@ struct audit_names {
+ 	int			name_len;	/* number of chars to log */
+ 	bool			hidden;		/* don't log this record */
+ 
+-	unsigned long		ino;
++	u64			ino;
+ 	dev_t			dev;
+ 	umode_t			mode;
+ 	kuid_t			uid;
+@@ -219,15 +219,15 @@ extern int auditd_test_task(struct task_struct *task);
+ #define AUDIT_INODE_BUCKETS	32
+ extern struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS];
+ 
+-static inline int audit_hash_ino(u32 ino)
++static inline int audit_hash_ino(u64 ino)
+ {
+-	return (ino & (AUDIT_INODE_BUCKETS-1));
++	return ((u32)ino & (AUDIT_INODE_BUCKETS-1));
+ }
+ 
+ /* Indicates that audit should log the full pathname. */
+ #define AUDIT_NAME_FULL -1
+ 
+-extern int audit_match_class(int class, unsigned syscall);
++extern int audit_match_class(int class, unsigned int syscall);
+ extern int audit_comparator(const u32 left, const u32 op, const u32 right);
+ extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right);
+ extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right);
+@@ -250,8 +250,13 @@ extern int audit_del_rule(struct audit_entry *entry);
+ extern void audit_free_rule_rcu(struct rcu_head *head);
+ extern struct list_head audit_filter_list[];
+ 
+-extern struct audit_entry *audit_dupe_rule(struct audit_krule *old);
++struct audit_watch_ctx {
++	struct inode *dir;
++	struct inode *child;
++};
+ 
++extern struct audit_entry *audit_dupe_rule(struct audit_krule *old,
++					   struct audit_watch_ctx *ctx);
+ extern void audit_log_d_path_exe(struct audit_buffer *ab,
+ 				 struct mm_struct *mm);
+ 
+@@ -271,17 +276,18 @@ extern int audit_to_watch(struct audit_krule *krule, char *path, int len,
+ extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);
+ extern void audit_remove_watch_rule(struct audit_krule *krule);
+ extern char *audit_watch_path(struct audit_watch *watch);
+-extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino,
+-			       dev_t dev);
++extern int audit_watch_compare(struct audit_watch *watch, u64 ino, dev_t dev);
+ 
+ extern struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule,
+-						    char *pathname, int len);
++						    char *pathname, int len,
++						    struct audit_watch_ctx *ctx);
+ extern char *audit_mark_path(struct audit_fsnotify_mark *mark);
+ extern void audit_remove_mark(struct audit_fsnotify_mark *audit_mark);
+ extern void audit_remove_mark_rule(struct audit_krule *krule);
+-extern int audit_mark_compare(struct audit_fsnotify_mark *mark,
+-			      unsigned long ino, dev_t dev);
+-extern int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old);
++extern int audit_mark_compare(struct audit_fsnotify_mark *mark, u64 ino,
++			      dev_t dev);
++extern int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old,
++			  struct audit_watch_ctx *ctx);
+ extern int audit_exe_compare(struct task_struct *tsk,
+ 			     struct audit_fsnotify_mark *mark);
+ 
+@@ -312,13 +318,13 @@ extern struct list_head *audit_killed_trees(void);
+ #define audit_watch_path(w) ""
+ #define audit_watch_compare(w, i, d) 0
+ 
+-#define audit_alloc_mark(k, p, l) (ERR_PTR(-EINVAL))
++#define audit_alloc_mark(k, p, l, c) (ERR_PTR(-EINVAL))
+ #define audit_mark_path(m) ""
+ #define audit_remove_mark(m) do { } while (0)
+ #define audit_remove_mark_rule(k) do { } while (0)
+ #define audit_mark_compare(m, i, d) 0
+ #define audit_exe_compare(t, m) (-EINVAL)
+-#define audit_dupe_exe(n, o) (-EINVAL)
++#define audit_dupe_exe(n, o, c) (-EINVAL)
+ 
+ #define audit_remove_tree_rule(rule) BUG()
+ #define audit_add_tree_rule(rule) -EINVAL
+diff --git a/kernel/audit_fsnotify.c b/kernel/audit_fsnotify.c
+index c565fbf66ac876..e62066bf0b0afa 100644
+--- a/kernel/audit_fsnotify.c
++++ b/kernel/audit_fsnotify.c
+@@ -25,7 +25,7 @@
+  */
+ struct audit_fsnotify_mark {
+ 	dev_t dev;		/* associated superblock device */
+-	unsigned long ino;	/* associated inode number */
++	u64 ino;		/* associated inode number */
+ 	char *path;		/* insertion path */
+ 	struct fsnotify_mark mark; /* fsnotify mark on the inode */
+ 	struct audit_krule *rule;
+@@ -57,7 +57,7 @@ char *audit_mark_path(struct audit_fsnotify_mark *mark)
+ 	return mark->path;
+ }
+ 
+-int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev)
++int audit_mark_compare(struct audit_fsnotify_mark *mark, u64 ino, dev_t dev)
+ {
+ 	if (mark->ino == AUDIT_INO_UNSET)
+ 		return 0;
+@@ -71,22 +71,30 @@ static void audit_update_mark(struct audit_fsnotify_mark *audit_mark,
+ 	audit_mark->ino = inode ? inode->i_ino : AUDIT_INO_UNSET;
+ }
+ 
+-struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pathname, int len)
++struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pathname,
++					     int len, struct audit_watch_ctx *ctx)
+ {
+ 	struct audit_fsnotify_mark *audit_mark;
+ 	struct path path;
+ 	struct dentry *dentry;
+-	struct inode *inode;
+-	int ret;
++	struct inode *dir, *child;
++	int ret, allow_dups;
+ 
+ 	if (pathname[0] != '/' || pathname[len-1] == '/')
+ 		return ERR_PTR(-EINVAL);
+ 
+-	dentry = kern_path_locked(pathname, &path);
+-	if (IS_ERR(dentry))
+-		return ERR_CAST(dentry); /* returning an error */
+-	inode = path.dentry->d_inode;
+-	inode_unlock(inode);
++	if (!ctx) {
++		dentry = kern_path_parent(pathname, &path);
++		if (IS_ERR(dentry))
++			return ERR_CAST(dentry); /* returning an error */
++		dir = d_inode(path.dentry);
++		child = d_inode(dentry);
++		allow_dups = 0;
++	} else {
++		dir = ctx->dir;
++		child = ctx->child;
++		allow_dups = 1;
++	}
+ 
+ 	audit_mark = kzalloc(sizeof(*audit_mark), GFP_KERNEL);
+ 	if (unlikely(!audit_mark)) {
+@@ -97,18 +105,21 @@ struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pa
+ 	fsnotify_init_mark(&audit_mark->mark, audit_fsnotify_group);
+ 	audit_mark->mark.mask = AUDIT_FS_EVENTS;
+ 	audit_mark->path = pathname;
+-	audit_update_mark(audit_mark, dentry->d_inode);
+ 	audit_mark->rule = krule;
+ 
+-	ret = fsnotify_add_inode_mark(&audit_mark->mark, inode, 0);
++	audit_update_mark(audit_mark, child);
++	ret = fsnotify_add_inode_mark(&audit_mark->mark, dir, allow_dups);
++
+ 	if (ret < 0) {
+ 		audit_mark->path = NULL;
+ 		fsnotify_put_mark(&audit_mark->mark);
+ 		audit_mark = ERR_PTR(ret);
+ 	}
+ out:
+-	dput(dentry);
+-	path_put(&path);
++	if (!ctx) {
++		dput(dentry);
++		path_put(&path);
++	}
+ 	return audit_mark;
+ }
+ 
+diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
+index e867c17d3f84df..17125ac3a5737b 100644
+--- a/kernel/audit_tree.c
++++ b/kernel/audit_tree.c
+@@ -33,7 +33,7 @@ struct audit_chunk {
+ 	struct audit_node {
+ 		struct list_head list;
+ 		struct audit_tree *owner;
+-		unsigned index;		/* index; upper bit indicates 'will prune' */
++		unsigned int index;	/* index; upper bit indicates 'will prune' */
+ 	} owners[];
+ };
+ 
+diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
+index 7a98cd176a127d..4a7cbb8919419a 100644
+--- a/kernel/audit_watch.c
++++ b/kernel/audit_watch.c
+@@ -37,7 +37,7 @@ struct audit_watch {
+ 	refcount_t		count;	/* reference count */
+ 	dev_t			dev;	/* associated superblock device */
+ 	char			*path;	/* insertion path */
+-	unsigned long		ino;	/* associated inode number */
++	u64			ino;	/* associated inode number */
+ 	struct audit_parent	*parent; /* associated parent */
+ 	struct list_head	wlist;	/* entry in parent->watches list */
+ 	struct list_head	rules;	/* anchor for krule->rlist */
+@@ -125,7 +125,7 @@ char *audit_watch_path(struct audit_watch *watch)
+ 	return watch->path;
+ }
+ 
+-int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
++int audit_watch_compare(struct audit_watch *watch, u64 ino, dev_t dev)
+ {
+ 	return (watch->ino != AUDIT_INO_UNSET) &&
+ 		(watch->ino == ino) &&
+@@ -244,7 +244,8 @@ static void audit_watch_log_rule_change(struct audit_krule *r, struct audit_watc
+ /* Update inode info in audit rules based on filesystem event. */
+ static void audit_update_watch(struct audit_parent *parent,
+ 			       const struct qstr *dname, dev_t dev,
+-			       unsigned long ino, unsigned invalidating)
++			       u64 ino, unsigned int invalidating,
++			       struct audit_watch_ctx *ctx)
+ {
+ 	struct audit_watch *owatch, *nwatch, *nextw;
+ 	struct audit_krule *r, *nextr;
+@@ -280,12 +281,12 @@ static void audit_update_watch(struct audit_parent *parent,
+ 			list_del(&oentry->rule.rlist);
+ 			list_del_rcu(&oentry->list);
+ 
+-			nentry = audit_dupe_rule(&oentry->rule);
++			nentry = audit_dupe_rule(&oentry->rule, ctx);
+ 			if (IS_ERR(nentry)) {
+ 				list_del(&oentry->rule.list);
+ 				audit_panic("error updating watch, removing");
+ 			} else {
+-				int h = audit_hash_ino((u32)ino);
++				int h = audit_hash_ino(ino);
+ 
+ 				/*
+ 				 * nentry->rule.watch == oentry->rule.watch so
+@@ -347,15 +348,18 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
+ /* Get path information necessary for adding watches. */
+ static int audit_get_nd(struct audit_watch *watch, struct path *parent)
+ {
+-	struct dentry *d = kern_path_locked(watch->path, parent);
++	struct dentry *d;
++
++	d = kern_path_parent(watch->path, parent);
+ 	if (IS_ERR(d))
+ 		return PTR_ERR(d);
++
+ 	if (d_is_positive(d)) {
+ 		/* update watch filter fields */
+ 		watch->dev = d->d_sb->s_dev;
+ 		watch->ino = d_backing_inode(d)->i_ino;
+ 	}
+-	inode_unlock(d_backing_inode(parent->dentry));
++
+ 	dput(d);
+ 	return 0;
+ }
+@@ -436,7 +440,7 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
+ 
+ 	audit_add_to_parent(krule, parent);
+ 
+-	h = audit_hash_ino((u32)watch->ino);
++	h = audit_hash_ino(watch->ino);
+ 	*list = &audit_inode_hash[h];
+ error:
+ 	path_put(&parent_path);
+@@ -476,10 +480,17 @@ static int audit_watch_handle_event(struct fsnotify_mark *inode_mark, u32 mask,
+ 	if (WARN_ON_ONCE(inode_mark->group != audit_watch_group))
+ 		return 0;
+ 
+-	if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
+-		audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
+-	else if (mask & (FS_DELETE|FS_MOVED_FROM))
+-		audit_update_watch(parent, dname, AUDIT_DEV_UNSET, AUDIT_INO_UNSET, 1);
++	if (mask & (FS_CREATE|FS_MOVED_TO) && inode) {
++		struct audit_watch_ctx ctx = { .dir = dir, .child = inode };
++
++		audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0,
++				   &ctx);
++	} else if (mask & (FS_DELETE|FS_MOVED_FROM)) {
++		struct audit_watch_ctx ctx = { .dir = dir, .child = NULL };
++
++		audit_update_watch(parent, dname, AUDIT_DEV_UNSET, AUDIT_INO_UNSET, 1,
++				   &ctx);
++	}
+ 	else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
+ 		audit_remove_parent_watches(parent);
+ 
+@@ -502,7 +513,8 @@ static int __init audit_watch_init(void)
+ }
+ device_initcall(audit_watch_init);
+ 
+-int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old)
++int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old,
++		   struct audit_watch_ctx *ctx)
+ {
+ 	struct audit_fsnotify_mark *audit_mark;
+ 	char *pathname;
+@@ -511,7 +523,7 @@ int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old)
+ 	if (!pathname)
+ 		return -ENOMEM;
+ 
+-	audit_mark = audit_alloc_mark(new, pathname, strlen(pathname));
++	audit_mark = audit_alloc_mark(new, pathname, strlen(pathname), ctx);
+ 	if (IS_ERR(audit_mark)) {
+ 		kfree(pathname);
+ 		return PTR_ERR(audit_mark);
+@@ -524,7 +536,7 @@ int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old)
+ int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark)
+ {
+ 	struct file *exe_file;
+-	unsigned long ino;
++	u64 ino;
+ 	dev_t dev;
+ 
+ 	/* only do exe filtering if we are recording @current events/records */
+diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
+index 685bccb20b6f05..3c4fd93254b51a 100644
+--- a/kernel/auditfilter.c
++++ b/kernel/auditfilter.c
+@@ -165,13 +165,13 @@ static inline int audit_to_inode(struct audit_krule *krule,
+ 
+ static __u32 *classes[AUDIT_SYSCALL_CLASSES];
+ 
+-int __init audit_register_class(int class, unsigned *list)
++int __init audit_register_class(int class, unsigned int *list)
+ {
+ 	__u32 *p = kcalloc(AUDIT_BITMASK_SIZE, sizeof(__u32), GFP_KERNEL);
+ 	if (!p)
+ 		return -ENOMEM;
+ 	while (*list != ~0U) {
+-		unsigned n = *list++;
++		unsigned int n = *list++;
+ 		if (n >= AUDIT_BITMASK_SIZE * 32 - AUDIT_SYSCALL_CLASSES) {
+ 			kfree(p);
+ 			return -EINVAL;
+@@ -186,7 +186,7 @@ int __init audit_register_class(int class, unsigned *list)
+ 	return 0;
+ }
+ 
+-int audit_match_class(int class, unsigned syscall)
++int audit_match_class(int class, unsigned int syscall)
+ {
+ 	if (unlikely(syscall >= AUDIT_BITMASK_SIZE * 32))
+ 		return 0;
+@@ -237,7 +237,7 @@ static int audit_match_signal(struct audit_entry *entry)
+ /* Common user-space to kernel rule translation. */
+ static inline struct audit_entry *audit_to_entry_common(struct audit_rule_data *rule)
+ {
+-	unsigned listnr;
++	unsigned int listnr;
+ 	struct audit_entry *entry;
+ 	int i, err;
+ 
+@@ -590,7 +590,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
+ 				err = PTR_ERR(str);
+ 				goto exit_free;
+ 			}
+-			audit_mark = audit_alloc_mark(&entry->rule, str, f_val);
++			audit_mark = audit_alloc_mark(&entry->rule, str, f_val, NULL);
+ 			if (IS_ERR(audit_mark)) {
+ 				kfree(str);
+ 				err = PTR_ERR(audit_mark);
+@@ -818,7 +818,8 @@ static inline int audit_dupe_lsm_field(struct audit_field *df,
+  * rule with the new rule in the filterlist, then free the old rule.
+  * The rlist element is undefined; list manipulations are handled apart from
+  * the initial copy. */
+-struct audit_entry *audit_dupe_rule(struct audit_krule *old)
++struct audit_entry *audit_dupe_rule(struct audit_krule *old,
++				    struct audit_watch_ctx *ctx)
+ {
+ 	u32 fcount = old->field_count;
+ 	struct audit_entry *entry;
+@@ -877,7 +878,7 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
+ 				new->filterkey = fk;
+ 			break;
+ 		case AUDIT_EXE:
+-			err = audit_dupe_exe(new, old);
++			err = audit_dupe_exe(new, old, ctx);
+ 			break;
+ 		}
+ 		if (err) {
+@@ -1408,7 +1409,7 @@ static int update_lsm_rule(struct audit_krule *r)
+ 	if (!security_audit_rule_known(r))
+ 		return 0;
+ 
+-	nentry = audit_dupe_rule(r);
++	nentry = audit_dupe_rule(r, NULL);
+ 	if (entry->rule.exe)
+ 		audit_remove_mark(entry->rule.exe);
+ 	if (IS_ERR(nentry)) {
+diff --git a/kernel/auditsc.c b/kernel/auditsc.c
+index bb3cea8c71488f..1727af77245de7 100644
+--- a/kernel/auditsc.c
++++ b/kernel/auditsc.c
+@@ -150,7 +150,7 @@ static const struct audit_nfcfgop_tab audit_nfcfgs[] = {
+ 
+ static int audit_match_perm(struct audit_context *ctx, int mask)
+ {
+-	unsigned n;
++	unsigned int n;
+ 
+ 	if (unlikely(!ctx))
+ 		return 0;
+@@ -884,7 +884,7 @@ static int audit_filter_inode_name(struct task_struct *tsk,
+ 				   struct audit_names *n,
+ 				   struct audit_context *ctx)
+ {
+-	int h = audit_hash_ino((u32)n->ino);
++	int h = audit_hash_ino(n->ino);
+ 	struct list_head *list = &audit_inode_hash[h];
+ 
+ 	return __audit_filter_op(tsk, ctx, list, n, ctx->major);
+@@ -1549,7 +1549,7 @@ static void audit_log_name(struct audit_context *context, struct audit_names *n,
+ 		audit_log_format(ab, " name=(null)");
+ 
+ 	if (n->ino != AUDIT_INO_UNSET)
+-		audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#ho ouid=%u ogid=%u rdev=%02x:%02x",
++		audit_log_format(ab, " inode=%llu dev=%02x:%02x mode=%#ho ouid=%u ogid=%u rdev=%02x:%02x",
+ 				 n->ino,
+ 				 MAJOR(n->dev),
+ 				 MINOR(n->dev),
+diff --git a/kernel/bpf/bpf_inode_storage.c b/kernel/bpf/bpf_inode_storage.c
+index b0ef45db207c89..288d776f2d4872 100644
+--- a/kernel/bpf/bpf_inode_storage.c
++++ b/kernel/bpf/bpf_inode_storage.c
+@@ -191,6 +191,15 @@ static int notsupp_get_next_key(struct bpf_map *map, void *key,
+ 
+ static struct bpf_map *inode_storage_map_alloc(union bpf_attr *attr)
+ {
++	/*
++	 * Do not allow allocation of BPF_MAP_TYPE_INODE_STORAGE if the BPF LSM
++	 * was not initialized by the LSM framework at boot. Without proper
++	 * initialization, the BPF inode security blob offset remains unprepared,
++	 * causing bpf_inode() to calculate an invalid memory offset and corrupt
++	 * inode->i_security.
++	 */
++	if (!bpf_lsm_initialized)
++		return ERR_PTR(-EOPNOTSUPP);
+ 	return bpf_local_storage_map_alloc(attr, &inode_cache, false);
+ }
+ 
+diff --git a/kernel/bpf/bpf_lsm.c b/kernel/bpf/bpf_lsm.c
+index 147c3a8ad4e8e0..984e944a0221d9 100644
+--- a/kernel/bpf/bpf_lsm.c
++++ b/kernel/bpf/bpf_lsm.c
+@@ -42,7 +42,6 @@ BTF_ID(func, bpf_lsm_inode_need_killpriv)
+ BTF_ID(func, bpf_lsm_inode_getsecurity)
+ BTF_ID(func, bpf_lsm_inode_listsecurity)
+ BTF_ID(func, bpf_lsm_inode_copy_up_xattr)
+-BTF_ID(func, bpf_lsm_getselfattr)
+ BTF_ID(func, bpf_lsm_getprocattr)
+ BTF_ID(func, bpf_lsm_setprocattr)
+ #ifdef CONFIG_KEYS
+diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
+index 1da0092122c1db..5e094c12fc94c5 100644
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -15120,6 +15120,23 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
+ 	mark_reg_unknown(env, regs, BPF_REG_0);
+ 	/* ld_abs load up to 32-bit skb data. */
+ 	regs[BPF_REG_0].subreg_def = env->insn_idx + 1;
++	/*
++	 * See bpf_gen_ld_abs() which emits a hidden BPF_EXIT with r0=0
++	 * which must be explored by the verifier when in a subprog.
++	 */
++	if (env->cur_state->curframe) {
++		struct bpf_verifier_state *branch;
++
++		mark_reg_scratched(env, BPF_REG_0);
++		branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false);
++		if (!branch)
++			return -EFAULT;
++		mark_reg_known_zero(env, regs, BPF_REG_0);
++		err = prepare_func_exit(env, &env->insn_idx);
++		if (err)
++			return err;
++		env->insn_idx--;
++	}
+ 	return 0;
+ }
+ 
+diff --git a/kernel/locking/spinlock_rt.c b/kernel/locking/spinlock_rt.c
+index 48a19ed8486d8e..2c0fd2c7a3c13f 100644
+--- a/kernel/locking/spinlock_rt.c
++++ b/kernel/locking/spinlock_rt.c
+@@ -77,10 +77,27 @@ void __sched rt_spin_unlock(spinlock_t *lock)
+ {
+ 	spin_release(&lock->dep_map, _RET_IP_);
+ 	migrate_enable();
+-	rcu_read_unlock();
+ 
+ 	if (unlikely(!rt_mutex_cmpxchg_release(&lock->lock, current, NULL)))
+ 		rt_mutex_slowunlock(&lock->lock);
++
++	/*
++	 * This must be last to prevent the following UAF:
++	 *
++	 * T1					T2
++	 * spin_lock(&p->lock);			rcu_read_lock();
++	 * invalidate(p);			p = rcu_dereference(ptr);
++	 * rcu_assign_pointer(ptr, NULL);	if (!p) return;
++	 * spin_unlock(&p->lock);		spin_lock(&p->lock);
++	 * kfree_rcu(p);			rcu_read_unlock();
++	 *					....
++	 *					spin_unlock(&p->lock)
++	 *					  rcu_read_unlock(); // Ends grace period
++	 * rcu_do_batch()
++	 *   kfree(p);
++	 *			    UAF ->	  rt_mutex_cmpxchg_release(&p->lock.lock...)
++	 */
++	rcu_read_unlock();
+ }
+ EXPORT_SYMBOL(rt_spin_unlock);
+ 
+@@ -255,17 +272,21 @@ void __sched rt_read_unlock(rwlock_t *rwlock)
+ {
+ 	rwlock_release(&rwlock->dep_map, _RET_IP_);
+ 	migrate_enable();
+-	rcu_read_unlock();
+ 	rwbase_read_unlock(&rwlock->rwbase, TASK_RTLOCK_WAIT);
++
++	/* This must be last. See comment in rt_spin_unlock() */
++	rcu_read_unlock();
+ }
+ EXPORT_SYMBOL(rt_read_unlock);
+ 
+ void __sched rt_write_unlock(rwlock_t *rwlock)
+ {
+ 	rwlock_release(&rwlock->dep_map, _RET_IP_);
+-	rcu_read_unlock();
+ 	migrate_enable();
+ 	rwbase_write_unlock(&rwlock->rwbase);
++
++	/* This must be last. See comment in rt_spin_unlock() */
++	rcu_read_unlock();
+ }
+ EXPORT_SYMBOL(rt_write_unlock);
+ 
+diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
+index b453f8a6a7c764..4feef0d4e4494d 100644
+--- a/kernel/sched/cputime.c
++++ b/kernel/sched/cputime.c
+@@ -424,19 +424,6 @@ static inline void irqtime_account_process_tick(struct task_struct *p, int user_
+  */
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
+ 
+-# ifndef __ARCH_HAS_VTIME_TASK_SWITCH
+-void vtime_task_switch(struct task_struct *prev)
+-{
+-	if (is_idle_task(prev))
+-		vtime_account_idle(prev);
+-	else
+-		vtime_account_kernel(prev);
+-
+-	vtime_flush(prev);
+-	arch_vtime_task_switch(prev);
+-}
+-# endif
+-
+ void vtime_account_irq(struct task_struct *tsk, unsigned int offset)
+ {
+ 	unsigned int pc = irq_count() - offset;
+diff --git a/kernel/taskstats.c b/kernel/taskstats.c
+index a16392b1bdc145..e47e13a5a579bd 100644
+--- a/kernel/taskstats.c
++++ b/kernel/taskstats.c
+@@ -210,13 +210,39 @@ static int fill_stats_for_pid(pid_t pid, struct taskstats *stats)
+ 	return 0;
+ }
+ 
++static void tgid_stats_add_task(struct taskstats *stats,
++				struct task_struct *tsk, u64 now_ns)
++{
++	u64 delta, utime, stime;
++
++	/*
++	 * Each accounting subsystem calls its functions here to
++	 * accumulate its per-task stats for tsk, into the per-tgid structure
++	 *
++	 *	per-task-foo(stats, tsk);
++	 */
++	delayacct_add_tsk(stats, tsk);
++
++	/* calculate task elapsed time in nsec */
++	delta = now_ns - tsk->start_time;
++	/* Convert to micro seconds */
++	do_div(delta, NSEC_PER_USEC);
++	stats->ac_etime += delta;
++
++	task_cputime(tsk, &utime, &stime);
++	stats->ac_utime += div_u64(utime, NSEC_PER_USEC);
++	stats->ac_stime += div_u64(stime, NSEC_PER_USEC);
++
++	stats->nvcsw += tsk->nvcsw;
++	stats->nivcsw += tsk->nivcsw;
++}
++
+ static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)
+ {
+ 	struct task_struct *tsk, *first;
+ 	unsigned long flags;
+ 	int rc = -ESRCH;
+-	u64 delta, utime, stime;
+-	u64 start_time;
++	u64 now_ns;
+ 
+ 	/*
+ 	 * Add additional stats from live tasks except zombie thread group
+@@ -233,32 +259,13 @@ static int fill_stats_for_tgid(pid_t tgid, struct taskstats *stats)
+ 	else
+ 		memset(stats, 0, sizeof(*stats));
+ 
+-	tsk = first;
+-	start_time = ktime_get_ns();
+-	do {
++	now_ns = ktime_get_ns();
++	for_each_thread(first, tsk) {
+ 		if (tsk->exit_state)
+ 			continue;
+-		/*
+-		 * Accounting subsystem can call its functions here to
+-		 * fill in relevant parts of struct taskstsats as follows
+-		 *
+-		 *	per-task-foo(stats, tsk);
+-		 */
+-		delayacct_add_tsk(stats, tsk);
+-
+-		/* calculate task elapsed time in nsec */
+-		delta = start_time - tsk->start_time;
+-		/* Convert to micro seconds */
+-		do_div(delta, NSEC_PER_USEC);
+-		stats->ac_etime += delta;
+ 
+-		task_cputime(tsk, &utime, &stime);
+-		stats->ac_utime += div_u64(utime, NSEC_PER_USEC);
+-		stats->ac_stime += div_u64(stime, NSEC_PER_USEC);
+-
+-		stats->nvcsw += tsk->nvcsw;
+-		stats->nivcsw += tsk->nivcsw;
+-	} while_each_thread(first, tsk);
++		tgid_stats_add_task(stats, tsk, now_ns);
++	}
+ 
+ 	unlock_task_sighand(first, &flags);
+ 	rc = 0;
+@@ -276,18 +283,14 @@ out:
+ static void fill_tgid_exit(struct task_struct *tsk)
+ {
+ 	unsigned long flags;
++	u64 now_ns;
+ 
+ 	spin_lock_irqsave(&tsk->sighand->siglock, flags);
+ 	if (!tsk->signal->stats)
+ 		goto ret;
+ 
+-	/*
+-	 * Each accounting subsystem calls its functions here to
+-	 * accumalate its per-task stats for tsk, into the per-tgid structure
+-	 *
+-	 *	per-task-foo(tsk->signal->stats, tsk);
+-	 */
+-	delayacct_add_tsk(tsk->signal->stats, tsk);
++	now_ns = ktime_get_ns();
++	tgid_stats_add_task(tsk->signal->stats, tsk, now_ns);
+ ret:
+ 	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+ 	return;
+diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
+index 07a4cbb7ffc09a..dbdd147f16e9d8 100644
+--- a/kernel/trace/ftrace.c
++++ b/kernel/trace/ftrace.c
+@@ -1067,6 +1067,12 @@ struct ftrace_ops global_ops = {
+ 					  FTRACE_OPS_FL_PID,
+ };
+ 
++/*
++ * parser_lock - Protects trace_parser state against concurrent operations.
++ * Held across trace_get_user() and subsequent buffer parsing to prevent races.
++ */
++static DEFINE_MUTEX(parser_lock);
++
+ /*
+  * Used by the stack unwinder to know about dynamic ftrace trampolines.
+  */
+@@ -5205,6 +5211,8 @@ ftrace_regex_write(struct file *file, const char __user *ubuf,
+ 	/* iter->hash is a local copy, so we don't need regex_lock */
+ 
+ 	parser = &iter->parser;
++
++	guard(mutex)(&parser_lock);
+ 	read = trace_get_user(parser, ubuf, cnt, ppos);
+ 
+ 	if (read >= 0 && trace_parser_loaded(parser) &&
+@@ -5930,12 +5938,14 @@ int ftrace_regex_release(struct inode *inode, struct file *file)
+ 		iter = file->private_data;
+ 
+ 	parser = &iter->parser;
++	mutex_lock(&parser_lock);
+ 	if (trace_parser_loaded(parser)) {
+ 		int enable = !(iter->flags & FTRACE_ITER_NOTRACE);
+ 
+ 		ftrace_process_regex(iter, parser->buffer,
+ 				     parser->idx, enable);
+ 	}
++	mutex_unlock(&parser_lock);
+ 
+ 	trace_parser_put(parser);
+ 
+@@ -6267,10 +6277,12 @@ ftrace_graph_release(struct inode *inode, struct file *file)
+ 
+ 		parser = &fgd->parser;
+ 
++		mutex_lock(&parser_lock);
+ 		if (trace_parser_loaded((parser))) {
+ 			ret = ftrace_graph_set_hash(fgd->new_hash,
+ 						    parser->buffer);
+ 		}
++		mutex_unlock(&parser_lock);
+ 
+ 		trace_parser_put(parser);
+ 
+@@ -6390,6 +6402,7 @@ ftrace_graph_write(struct file *file, const char __user *ubuf,
+ 
+ 	parser = &fgd->parser;
+ 
++	guard(mutex)(&parser_lock);
+ 	read = trace_get_user(parser, ubuf, cnt, ppos);
+ 
+ 	if (read >= 0 && trace_parser_loaded(parser) &&
+diff --git a/kernel/trace/trace_eprobe.c b/kernel/trace/trace_eprobe.c
+index 6330d25ac6536e..a9be1ed07ae387 100644
+--- a/kernel/trace/trace_eprobe.c
++++ b/kernel/trace/trace_eprobe.c
+@@ -168,7 +168,8 @@ static bool eprobe_dyn_event_match(const char *system, const char *event,
+ 	if (!slash)
+ 		return false;
+ 
+-	if (strncmp(ep->event_system, argv[0], slash - argv[0]))
++	if (strncmp(ep->event_system, argv[0], slash - argv[0]) ||
++	    ep->event_system[slash - argv[0]] != '\0')
+ 		return false;
+ 	if (strcmp(ep->event_name, slash + 1))
+ 		return false;
+diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
+index 2461786b1e4d22..9dabeb86acd175 100644
+--- a/kernel/trace/trace_events_user.c
++++ b/kernel/trace/trace_events_user.c
+@@ -104,6 +104,9 @@ struct user_event_enabler {
+ 
+ 	/* Track enable bit, flags, etc. Aligned for bitops. */
+ 	unsigned long		values;
++
++	/* Defer the event put and enabler free past an RCU grace period. */
++	struct rcu_work		put_rwork;
+ };
+ 
+ /* Bits 0-5 are for the bit to update upon enable/disable (0-63 allowed) */
+@@ -378,17 +381,39 @@ error:
+ 	return NULL;
+ };
+ 
+-static void user_event_enabler_destroy(struct user_event_enabler *enabler,
+-				       bool locked)
++static void delayed_user_event_enabler_put(struct work_struct *work)
+ {
+-	list_del_rcu(&enabler->mm_enablers_link);
++	struct user_event_enabler *enabler = container_of(to_rcu_work(work),
++			struct user_event_enabler, put_rwork);
+ 
+ 	/* No longer tracking the event via the enabler */
+-	user_event_put(enabler->event, locked);
++	user_event_put(enabler->event, false);
+ 
++	/* Run from queue_rcu_work(), the RCU grace period has elapsed */
+ 	kfree(enabler);
+ }
+ 
++static void user_event_enabler_destroy(struct user_event_enabler *enabler)
++{
++	list_del_rcu(&enabler->mm_enablers_link);
++
++	/*
++	 * The enabler is removed from an RCU-traversed list
++	 * (user_event_mm_dup() walks mm->enablers under rcu_read_lock() only),
++	 * and readers there dereference enabler->event and take a new ref on
++	 * it. Both the put of that event reference and the free of the enabler
++	 * therefore have to wait for a grace period so no reader can be looking
++	 * at the enabler or racing the last put of its event.
++	 *
++	 * The put itself must not run in RCU context: when it drops the last
++	 * reference user_event_put() takes event_mutex, which cannot be taken
++	 * from a softirq/RCU callback. Defer both to a work item scheduled
++	 * after a grace period via queue_rcu_work().
++	 */
++	INIT_RCU_WORK(&enabler->put_rwork, delayed_user_event_enabler_put);
++	queue_rcu_work(system_percpu_wq, &enabler->put_rwork);
++}
++
+ static int user_event_mm_fault_in(struct user_event_mm *mm, unsigned long uaddr,
+ 				  int attempt)
+ {
+@@ -446,7 +471,7 @@ static void user_event_enabler_fault_fixup(struct work_struct *work)
+ 
+ 	/* User asked for enabler to be removed during fault */
+ 	if (test_bit(ENABLE_VAL_FREEING_BIT, ENABLE_BITOPS(enabler))) {
+-		user_event_enabler_destroy(enabler, true);
++		user_event_enabler_destroy(enabler);
+ 		goto out;
+ 	}
+ 
+@@ -746,7 +771,7 @@ static void user_event_mm_destroy(struct user_event_mm *mm)
+ 	struct user_event_enabler *enabler, *next;
+ 
+ 	list_for_each_entry_safe(enabler, next, &mm->enablers, mm_enablers_link)
+-		user_event_enabler_destroy(enabler, false);
++		user_event_enabler_destroy(enabler);
+ 
+ 	mmdrop(mm->mm);
+ 	kfree(mm);
+@@ -2579,7 +2604,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
+ 			flags |= enabler->values & ENABLE_VAL_COMPAT_MASK;
+ 
+ 			if (!test_bit(ENABLE_VAL_FAULTING_BIT, ENABLE_BITOPS(enabler)))
+-				user_event_enabler_destroy(enabler, true);
++				user_event_enabler_destroy(enabler);
+ 
+ 			/* Removed at least one */
+ 			ret = 0;
+diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c
+index 64e77b51369748..4d9e5c830dbe11 100644
+--- a/kernel/trace/trace_mmiotrace.c
++++ b/kernel/trace/trace_mmiotrace.c
+@@ -109,7 +109,6 @@ static void mmio_pipe_open(struct trace_iterator *iter)
+ 	iter->private = hiter;
+ }
+ 
+-/* XXX: This is not called when the pipe is closed! */
+ static void mmio_close(struct trace_iterator *iter)
+ {
+ 	struct header_iter *hiter = iter->private;
+@@ -146,7 +145,7 @@ static ssize_t mmio_read(struct trace_iterator *iter, struct file *filp,
+ 		goto print_out;
+ 	}
+ 
+-	if (!hiter)
++	if (!hiter || !hiter->dev)
+ 		return 0;
+ 
+ 	mmio_print_pcidev(s, hiter->dev);
+@@ -279,6 +278,7 @@ static struct tracer mmio_tracer __read_mostly =
+ 	.start		= mmio_trace_start,
+ 	.pipe_open	= mmio_pipe_open,
+ 	.close		= mmio_close,
++	.pipe_close	= mmio_close,
+ 	.read		= mmio_read,
+ 	.print_line	= mmio_print_line,
+ 	.noboot		= true,
+diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
+index c0f9ec31a91cef..f72a9926c6351a 100644
+--- a/kernel/trace/trace_probe.c
++++ b/kernel/trace/trace_probe.c
+@@ -186,7 +186,7 @@ void __trace_probe_log_err(int offset, int err_type)
+ 
+ 	lockdep_assert_held(&dyn_event_ops_mutex);
+ 
+-	if (!trace_probe_log.argv)
++	if (!trace_probe_log.argv || !trace_probe_log.argc)
+ 		return;
+ 
+ 	/* Recalculate the length and allocate buffer */
+@@ -1779,7 +1779,7 @@ int traceprobe_update_arg(struct probe_arg *arg)
+ }
+ 
+ /* When len=0, we just calculate the needed length */
+-#define LEN_OR_ZERO (len ? len - pos : 0)
++#define LEN_OR_ZERO (len > pos ? len - pos : 0)
+ static int __set_print_fmt(struct trace_probe *tp, char *buf, int len,
+ 			   enum probe_print_type ptype)
+ {
+@@ -2105,16 +2105,17 @@ int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b)
+ bool trace_probe_match_command_args(struct trace_probe *tp,
+ 				    int argc, const char **argv)
+ {
+-	char buf[MAX_ARGSTR_LEN + 1];
+ 	int i;
+ 
+ 	if (tp->nr_args < argc)
+ 		return false;
+ 
+ 	for (i = 0; i < argc; i++) {
+-		snprintf(buf, sizeof(buf), "%s=%s",
+-			 tp->args[i].name, tp->args[i].comm);
+-		if (strcmp(buf, argv[i]))
++		int len = strlen(tp->args[i].name);
++
++		if (strncmp(argv[i], tp->args[i].name, len) ||
++		    argv[i][len] != '=' ||
++		    strcmp(argv[i] + len + 1, tp->args[i].comm))
+ 			return false;
+ 	}
+ 	return true;
+diff --git a/kernel/workqueue.c b/kernel/workqueue.c
+index b59cc9f86d1595..fd215673ddf8a3 100644
+--- a/kernel/workqueue.c
++++ b/kernel/workqueue.c
+@@ -425,12 +425,16 @@ static struct kthread_worker *pwq_release_worker;
+ 
+ struct workqueue_struct *system_wq __read_mostly;
+ EXPORT_SYMBOL(system_wq);
++struct workqueue_struct *system_percpu_wq __read_mostly;
++EXPORT_SYMBOL(system_percpu_wq);
+ struct workqueue_struct *system_highpri_wq __read_mostly;
+ EXPORT_SYMBOL_GPL(system_highpri_wq);
+ struct workqueue_struct *system_long_wq __read_mostly;
+ EXPORT_SYMBOL_GPL(system_long_wq);
+ struct workqueue_struct *system_unbound_wq __read_mostly;
+ EXPORT_SYMBOL_GPL(system_unbound_wq);
++struct workqueue_struct *system_dfl_wq __read_mostly;
++EXPORT_SYMBOL_GPL(system_dfl_wq);
+ struct workqueue_struct *system_freezable_wq __read_mostly;
+ EXPORT_SYMBOL_GPL(system_freezable_wq);
+ struct workqueue_struct *system_power_efficient_wq __read_mostly;
+@@ -6609,6 +6613,22 @@ static void __init restrict_unbound_cpumask(const char *name, const struct cpuma
+ 	cpumask_and(wq_unbound_cpumask, wq_unbound_cpumask, mask);
+ }
+ 
++static void __init init_cpu_worker_pool(struct worker_pool *pool, int cpu, int nice)
++{
++	BUG_ON(init_worker_pool(pool));
++	pool->cpu = cpu;
++	cpumask_copy(pool->attrs->cpumask, cpumask_of(cpu));
++	cpumask_copy(pool->attrs->__pod_cpumask, cpumask_of(cpu));
++	pool->attrs->nice = nice;
++	pool->attrs->affn_strict = true;
++	pool->node = cpu_to_node(cpu);
++
++	/* alloc pool ID */
++	mutex_lock(&wq_pool_mutex);
++	BUG_ON(worker_pool_assign_id(pool));
++	mutex_unlock(&wq_pool_mutex);
++}
++
+ /**
+  * workqueue_init_early - early init for workqueue subsystem
+  *
+@@ -6657,20 +6677,8 @@ void __init workqueue_init_early(void)
+ 		struct worker_pool *pool;
+ 
+ 		i = 0;
+-		for_each_cpu_worker_pool(pool, cpu) {
+-			BUG_ON(init_worker_pool(pool));
+-			pool->cpu = cpu;
+-			cpumask_copy(pool->attrs->cpumask, cpumask_of(cpu));
+-			cpumask_copy(pool->attrs->__pod_cpumask, cpumask_of(cpu));
+-			pool->attrs->nice = std_nice[i++];
+-			pool->attrs->affn_strict = true;
+-			pool->node = cpu_to_node(cpu);
+-
+-			/* alloc pool ID */
+-			mutex_lock(&wq_pool_mutex);
+-			BUG_ON(worker_pool_assign_id(pool));
+-			mutex_unlock(&wq_pool_mutex);
+-		}
++		for_each_cpu_worker_pool(pool, cpu)
++			init_cpu_worker_pool(pool, cpu, std_nice[i++]);
+ 	}
+ 
+ 	/* create default unbound and ordered wq attrs */
+@@ -6692,10 +6700,11 @@ void __init workqueue_init_early(void)
+ 	}
+ 
+ 	system_wq = alloc_workqueue("events", 0, 0);
++	system_percpu_wq = alloc_workqueue("events", 0, 0);
+ 	system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI, 0);
+ 	system_long_wq = alloc_workqueue("events_long", 0, 0);
+-	system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND,
+-					    WQ_MAX_ACTIVE);
++	system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, WQ_MAX_ACTIVE);
++	system_dfl_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, WQ_MAX_ACTIVE);
+ 	system_freezable_wq = alloc_workqueue("events_freezable",
+ 					      WQ_FREEZABLE, 0);
+ 	system_power_efficient_wq = alloc_workqueue("events_power_efficient",
+@@ -6703,8 +6712,9 @@ void __init workqueue_init_early(void)
+ 	system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_power_efficient",
+ 					      WQ_FREEZABLE | WQ_POWER_EFFICIENT,
+ 					      0);
+-	BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq ||
+-	       !system_unbound_wq || !system_freezable_wq ||
++	BUG_ON(!system_wq || !system_percpu_wq || !system_highpri_wq ||
++	       !system_long_wq || !system_unbound_wq || !system_dfl_wq ||
++	       !system_freezable_wq ||
+ 	       !system_power_efficient_wq ||
+ 	       !system_freezable_power_efficient_wq);
+ }
+diff --git a/lib/bootconfig.c b/lib/bootconfig.c
+index 675f34cf32f0d0..95ce04eb6bf122 100644
+--- a/lib/bootconfig.c
++++ b/lib/bootconfig.c
+@@ -407,6 +407,71 @@ const char * __init xbc_node_find_next_key_value(struct xbc_node *root,
+ 		return "";	/* No value key */
+ }
+ 
++static char xbc_namebuf[XBC_KEYLEN_MAX] __initdata;
++
++#define rest(dst, end) ((end) > (dst) ? (end) - (dst) : 0)
++
++/**
++ * xbc_snprint_cmdline() - Render bootconfig keys under @root as a cmdline string
++ * @buf: Destination buffer (may be NULL when @size is 0 to query the length)
++ * @size: Size of @buf in bytes
++ * @root: Subtree root whose key=value pairs should be rendered
++ *
++ * Walk all key/value pairs under @root and emit them as a space-separated
++ * cmdline string into @buf. Values containing whitespace are quoted with
++ * double quotes. Returns the number of bytes that would be written if @buf
++ * were large enough (matching snprintf semantics), or a negative errno on
++ * failure.
++ */
++int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root)
++{
++	struct xbc_node *knode, *vnode;
++	const char *val, *q;
++	size_t len = 0;
++	int ret;
++
++	/*
++	 * Track the running written length rather than advancing @buf, so we
++	 * never form "buf + size" or "buf += ret" while @buf is NULL (the
++	 * size-probe call passes buf=NULL, size=0). NULL pointer arithmetic
++	 * is undefined behavior and trips host UBSan / FORTIFY_SOURCE when
++	 * this renderer runs at kernel build time. snprintf(NULL, 0, ...)
++	 * itself is well defined and returns the would-be length.
++	 */
++	xbc_node_for_each_key_value(root, knode, val) {
++		ret = xbc_node_compose_key_after(root, knode,
++					xbc_namebuf, XBC_KEYLEN_MAX);
++		if (ret < 0)
++			return ret;
++
++		vnode = xbc_node_get_child(knode);
++		if (!vnode) {
++			ret = snprintf(buf ? buf + len : NULL, rest(len, size),
++				       "%s ", xbc_namebuf);
++			if (ret < 0)
++				return ret;
++			len += ret;
++			continue;
++		}
++		xbc_array_for_each_value(vnode, val) {
++			/*
++			 * For prettier and more readable /proc/cmdline, only
++			 * quote the value when necessary, i.e. when it contains
++			 * whitespace.
++			 */
++			q = strpbrk(val, " \t\r\n") ? "\"" : "";
++			ret = snprintf(buf ? buf + len : NULL, rest(len, size),
++				       "%s=%s%s%s ", xbc_namebuf, q, val, q);
++			if (ret < 0)
++				return ret;
++			len += ret;
++		}
++	}
++
++	return len;
++}
++#undef rest
++
+ /* XBC parse and tree build */
+ 
+ static int __init xbc_init_node(struct xbc_node *node, char *data, uint32_t flag)
+diff --git a/lib/compat_audit.c b/lib/compat_audit.c
+index 3d6b8996f027df..fee1dfccd116b0 100644
+--- a/lib/compat_audit.c
++++ b/lib/compat_audit.c
+@@ -4,32 +4,32 @@
+ #include <linux/audit_arch.h>
+ #include <asm/unistd32.h>
+ 
+-unsigned compat_dir_class[] = {
++unsigned int compat_dir_class[] = {
+ #include <asm-generic/audit_dir_write.h>
+ ~0U
+ };
+ 
+-unsigned compat_read_class[] = {
++unsigned int compat_read_class[] = {
+ #include <asm-generic/audit_read.h>
+ ~0U
+ };
+ 
+-unsigned compat_write_class[] = {
++unsigned int compat_write_class[] = {
+ #include <asm-generic/audit_write.h>
+ ~0U
+ };
+ 
+-unsigned compat_chattr_class[] = {
++unsigned int compat_chattr_class[] = {
+ #include <asm-generic/audit_change_attr.h>
+ ~0U
+ };
+ 
+-unsigned compat_signal_class[] = {
++unsigned int compat_signal_class[] = {
+ #include <asm-generic/audit_signal.h>
+ ~0U
+ };
+ 
+-int audit_classify_compat_syscall(int abi, unsigned syscall)
++int audit_classify_compat_syscall(int abi, unsigned int syscall)
+ {
+ 	switch (syscall) {
+ #ifdef __NR_open
+diff --git a/mm/damon/core.c b/mm/damon/core.c
+index 46600265d7ffce..734ab958ec5769 100644
+--- a/mm/damon/core.c
++++ b/mm/damon/core.c
+@@ -210,8 +210,21 @@ int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges,
+ {
+ 	struct damon_region *r, *next;
+ 	unsigned int i;
++	unsigned long last_end;
+ 	int err;
+ 
++	for (i = 0; i < nr_ranges; i++) {
++		unsigned long start, end;
++
++		start = ALIGN_DOWN(ranges[i].start, DAMON_MIN_REGION);
++		end = ALIGN(ranges[i].end, DAMON_MIN_REGION);
++		if (start >= end)
++			return -EINVAL;
++		if (i > 0 && last_end > start)
++			return -EINVAL;
++		last_end = end;
++	}
++
+ 	/* Remove regions which are not in the new ranges */
+ 	damon_for_each_region_safe(r, next, t) {
+ 		for (i = 0; i < nr_ranges; i++) {
+diff --git a/mm/mm_init.c b/mm/mm_init.c
+index f9f87e2299b8f1..a71fbb3cec3870 100644
+--- a/mm/mm_init.c
++++ b/mm/mm_init.c
+@@ -649,6 +649,20 @@ static inline void fixup_hashdist(void)
+ static inline void fixup_hashdist(void) {}
+ #endif /* CONFIG_NUMA */
+ 
++#ifdef CONFIG_ZONE_DEVICE
++static __meminit void pageblock_migratetype_init_range(unsigned long pfn,
++		unsigned long nr_pages, int migratetype)
++{
++	const unsigned long end = pfn + nr_pages;
++
++	for (pfn = pageblock_align(pfn); pfn < end; pfn += pageblock_nr_pages) {
++		set_pageblock_migratetype(pfn_to_page(pfn), migratetype);
++		if (IS_ALIGNED(pfn, PAGES_PER_SECTION))
++			cond_resched();
++	}
++}
++#endif
++
+ #ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
+ static inline void pgdat_set_deferred_range(pg_data_t *pgdat)
+ {
+@@ -992,21 +1006,6 @@ static void __ref __init_zone_device_page(struct page *page, unsigned long pfn,
+ 	page->pgmap = pgmap;
+ 	page->zone_device_data = NULL;
+ 
+-	/*
+-	 * Mark the block movable so that blocks are reserved for
+-	 * movable at startup. This will force kernel allocations
+-	 * to reserve their blocks rather than leaking throughout
+-	 * the address space during boot when many long-lived
+-	 * kernel allocations are made.
+-	 *
+-	 * Please note that MEMINIT_HOTPLUG path doesn't clear memmap
+-	 * because this is done early in section_activate()
+-	 */
+-	if (pageblock_aligned(pfn)) {
+-		set_pageblock_migratetype(page, MIGRATE_MOVABLE);
+-		cond_resched();
+-	}
+-
+ 	/*
+ 	 * ZONE_DEVICE pages are released directly to the driver page allocator
+ 	 * which will set the page count to 1 when allocating the page.
+@@ -1098,6 +1097,9 @@ void __ref memmap_init_zone_device(struct zone *zone,
+ 
+ 		__init_zone_device_page(page, pfn, zone_idx, nid, pgmap);
+ 
++		if (IS_ALIGNED(pfn, PAGES_PER_SECTION))
++			cond_resched();
++
+ 		if (pfns_per_compound == 1)
+ 			continue;
+ 
+@@ -1105,6 +1107,8 @@ void __ref memmap_init_zone_device(struct zone *zone,
+ 				     compound_nr_pages(pfn, altmap, pgmap));
+ 	}
+ 
++	pageblock_migratetype_init_range(start_pfn, nr_pages, MIGRATE_MOVABLE);
++
+ 	pr_debug("%s initialised %lu pages in %ums\n", __func__,
+ 		nr_pages, jiffies_to_msecs(jiffies - start));
+ }
+diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c
+index 7c4f89fee157da..4b1fcea37941f0 100644
+--- a/net/bluetooth/hci_sync.c
++++ b/net/bluetooth/hci_sync.c
+@@ -953,12 +953,16 @@ int hci_update_eir_sync(struct hci_dev *hdev)
+ 
+ 	memset(&cp, 0, sizeof(cp));
+ 
++	hci_dev_lock(hdev);
+ 	eir_create(hdev, cp.data);
+ 
+-	if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
++	if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) {
++		hci_dev_unlock(hdev);
+ 		return 0;
++	}
+ 
+ 	memcpy(hdev->eir, cp.data, sizeof(cp.data));
++	hci_dev_unlock(hdev);
+ 
+ 	return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp,
+ 				     HCI_CMD_TIMEOUT);
+@@ -990,6 +994,7 @@ int hci_update_class_sync(struct hci_dev *hdev)
+ 	if (hci_dev_test_flag(hdev, HCI_SERVICE_CACHE))
+ 		return 0;
+ 
++	hci_dev_lock(hdev);
+ 	cod[0] = hdev->minor_class;
+ 	cod[1] = hdev->major_class;
+ 	cod[2] = get_service_classes(hdev);
+@@ -997,8 +1002,12 @@ int hci_update_class_sync(struct hci_dev *hdev)
+ 	if (hci_dev_test_flag(hdev, HCI_LIMITED_DISCOVERABLE))
+ 		cod[1] |= 0x20;
+ 
+-	if (memcmp(cod, hdev->dev_class, 3) == 0)
++	if (memcmp(cod, hdev->dev_class, 3) == 0) {
++		hci_dev_unlock(hdev);
+ 		return 0;
++	}
++
++	hci_dev_unlock(hdev);
+ 
+ 	return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_CLASS_OF_DEV,
+ 				     sizeof(cod), cod, HCI_CMD_TIMEOUT);
+diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
+index 20fe7f011b75c2..979caeb85a42c7 100644
+--- a/net/bluetooth/mgmt.c
++++ b/net/bluetooth/mgmt.c
+@@ -3005,6 +3005,8 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data)
+ 	struct mgmt_cp_unpair_device *cp = cmd->param;
+ 	struct hci_conn *conn;
+ 
++	hci_dev_lock(hdev);
++
+ 	if (cp->addr.type == BDADDR_BREDR)
+ 		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+ 					       &cp->addr.bdaddr);
+@@ -3012,6 +3014,11 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data)
+ 		conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
+ 					       le_addr_type(cp->addr.type));
+ 
++	if (conn)
++		hci_conn_get(conn);
++
++	hci_dev_unlock(hdev);
++
+ 	if (!conn)
+ 		return 0;
+ 
+@@ -3019,6 +3026,7 @@ static int unpair_device_sync(struct hci_dev *hdev, void *data)
+ 	 * will clean up the connection no matter the error.
+ 	 */
+ 	hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
++	hci_conn_put(conn);
+ 
+ 	return 0;
+ }
+@@ -3166,6 +3174,8 @@ static int disconnect_sync(struct hci_dev *hdev, void *data)
+ 	struct mgmt_cp_disconnect *cp = cmd->param;
+ 	struct hci_conn *conn;
+ 
++	hci_dev_lock(hdev);
++
+ 	if (cp->addr.type == BDADDR_BREDR)
+ 		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+ 					       &cp->addr.bdaddr);
+@@ -3173,6 +3183,11 @@ static int disconnect_sync(struct hci_dev *hdev, void *data)
+ 		conn = hci_conn_hash_lookup_le(hdev, &cp->addr.bdaddr,
+ 					       le_addr_type(cp->addr.type));
+ 
++	if (conn)
++		hci_conn_get(conn);
++
++	hci_dev_unlock(hdev);
++
+ 	if (!conn)
+ 		return -ENOTCONN;
+ 
+@@ -3180,6 +3195,7 @@ static int disconnect_sync(struct hci_dev *hdev, void *data)
+ 	 * will clean up the connection no matter the error.
+ 	 */
+ 	hci_abort_conn(conn, HCI_ERROR_REMOTE_USER_TERM);
++	hci_conn_put(conn);
+ 
+ 	return 0;
+ }
+@@ -7401,6 +7417,9 @@ static void get_conn_info_complete(struct hci_dev *hdev, void *data, int err)
+ 		rp.max_tx_power = HCI_TX_POWER_INVALID;
+ 	}
+ 
++	if (conn)
++		hci_conn_put(conn);
++
+ 	mgmt_cmd_complete(cmd->sk, cmd->hdev->id, MGMT_OP_GET_CONN_INFO, status,
+ 			  &rp, sizeof(rp));
+ 
+@@ -7415,6 +7434,8 @@ static int get_conn_info_sync(struct hci_dev *hdev, void *data)
+ 	int err;
+ 	__le16   handle;
+ 
++	hci_dev_lock(hdev);
++
+ 	/* Make sure we are still connected */
+ 	if (cp->addr.type == BDADDR_BREDR)
+ 		conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
+@@ -7422,12 +7443,16 @@ static int get_conn_info_sync(struct hci_dev *hdev, void *data)
+ 	else
+ 		conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
+ 
+-	if (!conn || conn->state != BT_CONNECTED)
++	if (!conn || conn->state != BT_CONNECTED) {
++		hci_dev_unlock(hdev);
+ 		return MGMT_STATUS_NOT_CONNECTED;
++	}
+ 
+-	cmd->user_data = conn;
++	cmd->user_data = hci_conn_get(conn);
+ 	handle = cpu_to_le16(conn->handle);
+ 
++	hci_dev_unlock(hdev);
++
+ 	/* Refresh RSSI each time */
+ 	err = hci_read_rssi_sync(hdev, handle);
+ 
+@@ -7561,6 +7586,9 @@ static void get_clock_info_complete(struct hci_dev *hdev, void *data, int err)
+ 	}
+ 
+ complete:
++	if (conn)
++		hci_conn_put(conn);
++
+ 	mgmt_cmd_complete(cmd->sk, cmd->hdev->id, cmd->opcode, status, &rp,
+ 			  sizeof(rp));
+ 
+@@ -7577,15 +7605,21 @@ static int get_clock_info_sync(struct hci_dev *hdev, void *data)
+ 	memset(&hci_cp, 0, sizeof(hci_cp));
+ 	hci_read_clock_sync(hdev, &hci_cp);
+ 
++	hci_dev_lock(hdev);
++
+ 	/* Make sure connection still exists */
+ 	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
+-	if (!conn || conn->state != BT_CONNECTED)
++	if (!conn || conn->state != BT_CONNECTED) {
++		hci_dev_unlock(hdev);
+ 		return MGMT_STATUS_NOT_CONNECTED;
++	}
+ 
+-	cmd->user_data = conn;
++	cmd->user_data = hci_conn_get(conn);
+ 	hci_cp.handle = cpu_to_le16(conn->handle);
+ 	hci_cp.which = 0x01; /* Piconet clock */
+ 
++	hci_dev_unlock(hdev);
++
+ 	return hci_read_clock_sync(hdev, &hci_cp);
+ }
+ 
+diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
+index 07971e918e5b60..41a6eda1a1498e 100644
+--- a/net/bluetooth/rfcomm/core.c
++++ b/net/bluetooth/rfcomm/core.c
+@@ -1031,6 +1031,23 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
+ 	return rfcomm_send_frame(s, buf, ptr - buf);
+ }
+ 
++int rfcomm_dlc_send_rpn(struct rfcomm_dlc *d, u8 bit_rate, u8 data_bits,
++			u8 stop_bits, u8 parity, u8 flow_ctrl_settings,
++			u8 xon_char, u8 xoff_char, u16 param_mask)
++{
++	int err = -ENOTCONN;
++
++	rfcomm_lock();
++	if (d->session)
++		err = rfcomm_send_rpn(d->session, 1, d->dlci, bit_rate,
++				      data_bits, stop_bits, parity,
++				      flow_ctrl_settings, xon_char, xoff_char,
++				      param_mask);
++	rfcomm_unlock();
++
++	return err;
++}
++
+ static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
+ {
+ 	struct rfcomm_hdr *hdr;
+diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
+index 389d7b47ad6132..3f732b5fdeec2e 100644
+--- a/net/bluetooth/rfcomm/tty.c
++++ b/net/bluetooth/rfcomm/tty.c
+@@ -864,7 +864,7 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty,
+ 
+ 	BT_DBG("tty %p termios %p", tty, old);
+ 
+-	if (!dev || !dev->dlc || !dev->dlc->session)
++	if (!dev || !dev->dlc)
+ 		return;
+ 
+ 	/* Handle turning off CRTSCTS */
+@@ -985,9 +985,8 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty,
+ 	}
+ 
+ 	if (changes)
+-		rfcomm_send_rpn(dev->dlc->session, 1, dev->dlc->dlci, baud,
+-				data_bits, stop_bits, parity,
+-				RFCOMM_RPN_FLOW_NONE, x_on, x_off, changes);
++		rfcomm_dlc_send_rpn(dev->dlc, baud, data_bits, stop_bits, parity,
++				    RFCOMM_RPN_FLOW_NONE, x_on, x_off, changes);
+ }
+ 
+ static void rfcomm_tty_throttle(struct tty_struct *tty)
+diff --git a/net/bridge/br_netlink_tunnel.c b/net/bridge/br_netlink_tunnel.c
+index 17abf092f7cac1..b006d1127c5495 100644
+--- a/net/bridge/br_netlink_tunnel.c
++++ b/net/bridge/br_netlink_tunnel.c
+@@ -271,7 +271,8 @@ static void __vlan_tunnel_handle_range(const struct net_bridge_port *p,
+ 	if (!*v_start)
+ 		goto out_init;
+ 
+-	if (v && curr_change && br_vlan_can_enter_range(v, *v_end)) {
++	if (v && curr_change &&
++	    br_vlan_can_enter_range(v, *v_end, br_get_pvid(vg))) {
+ 		*v_end = v;
+ 		return;
+ 	}
+diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
+index f0d8edc378a0eb..4867464bde32b6 100644
+--- a/net/bridge/br_private.h
++++ b/net/bridge/br_private.h
+@@ -1563,7 +1563,8 @@ void br_vlan_notify(const struct net_bridge *br,
+ 		    u16 vid, u16 vid_range,
+ 		    int cmd);
+ bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
+-			     const struct net_bridge_vlan *range_end);
++			     const struct net_bridge_vlan *range_end,
++			     u16 pvid);
+ 
+ void br_vlan_fill_forward_path_pvid(struct net_bridge *br,
+ 				    struct net_device_path_ctx *ctx,
+@@ -1804,7 +1805,8 @@ static inline void br_vlan_notify(const struct net_bridge *br,
+ }
+ 
+ static inline bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
+-					   const struct net_bridge_vlan *range_end)
++					   const struct net_bridge_vlan *range_end,
++					   u16 pvid)
+ {
+ 	return true;
+ }
+diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
+index cc54b8267bcc7b..171d1dddb26a81 100644
+--- a/net/bridge/br_vlan.c
++++ b/net/bridge/br_vlan.c
+@@ -1943,9 +1943,11 @@ out_kfree:
+ 
+ /* check if v_curr can enter a range ending in range_end */
+ bool br_vlan_can_enter_range(const struct net_bridge_vlan *v_curr,
+-			     const struct net_bridge_vlan *range_end)
++			     const struct net_bridge_vlan *range_end,
++			     u16 pvid)
+ {
+-	return v_curr->vid - range_end->vid == 1 &&
++	return v_curr->vid != pvid && range_end->vid != pvid &&
++	       v_curr->vid - range_end->vid == 1 &&
+ 	       range_end->flags == v_curr->flags &&
+ 	       br_vlan_opts_eq_range(v_curr, range_end);
+ }
+@@ -2027,8 +2029,8 @@ static int br_vlan_dump_dev(const struct net_device *dev,
+ 			idx += range_end->vid - range_start->vid + 1;
+ 
+ 			range_start = v;
+-		} else if (dump_stats || v->vid == pvid ||
+-			   !br_vlan_can_enter_range(v, range_end)) {
++		} else if (dump_stats ||
++			   !br_vlan_can_enter_range(v, range_end, pvid)) {
+ 			u16 vlan_flags = br_vlan_flags(range_start, pvid);
+ 
+ 			if (!br_vlan_fill_vids(skb, range_start->vid,
+diff --git a/net/bridge/br_vlan_options.c b/net/bridge/br_vlan_options.c
+index 8fa89b04ee942d..4a736e005bad7e 100644
+--- a/net/bridge/br_vlan_options.c
++++ b/net/bridge/br_vlan_options.c
+@@ -310,8 +310,7 @@ int br_vlan_process_options(const struct net_bridge *br,
+ 				continue;
+ 			}
+ 
+-			if (v->vid == pvid ||
+-			    !br_vlan_can_enter_range(v, curr_end)) {
++			if (!br_vlan_can_enter_range(v, curr_end, pvid)) {
+ 				br_vlan_notify(br, p, curr_start->vid,
+ 					       curr_end->vid, RTM_NEWVLAN);
+ 				curr_start = v;
+diff --git a/net/bridge/netfilter/nft_meta_bridge.c b/net/bridge/netfilter/nft_meta_bridge.c
+index 475d7d1709b9fb..8426b5c6b624e8 100644
+--- a/net/bridge/netfilter/nft_meta_bridge.c
++++ b/net/bridge/netfilter/nft_meta_bridge.c
+@@ -104,7 +104,6 @@ static const struct nft_expr_ops nft_meta_bridge_get_ops = {
+ 	.eval		= nft_meta_bridge_get_eval,
+ 	.init		= nft_meta_bridge_get_init,
+ 	.dump		= nft_meta_get_dump,
+-	.reduce		= nft_meta_get_reduce,
+ };
+ 
+ static void nft_meta_bridge_set_eval(const struct nft_expr *expr,
+@@ -151,24 +150,6 @@ static int nft_meta_bridge_set_init(const struct nft_ctx *ctx,
+ 	return 0;
+ }
+ 
+-static bool nft_meta_bridge_set_reduce(struct nft_regs_track *track,
+-				       const struct nft_expr *expr)
+-{
+-	int i;
+-
+-	for (i = 0; i < NFT_REG32_NUM; i++) {
+-		if (!track->regs[i].selector)
+-			continue;
+-
+-		if (track->regs[i].selector->ops != &nft_meta_bridge_get_ops)
+-			continue;
+-
+-		__nft_reg_track_cancel(track, i);
+-	}
+-
+-	return false;
+-}
+-
+ static int nft_meta_bridge_set_validate(const struct nft_ctx *ctx,
+ 					const struct nft_expr *expr)
+ {
+@@ -193,7 +174,6 @@ static const struct nft_expr_ops nft_meta_bridge_set_ops = {
+ 	.init		= nft_meta_bridge_set_init,
+ 	.destroy	= nft_meta_set_destroy,
+ 	.dump		= nft_meta_set_dump,
+-	.reduce		= nft_meta_bridge_set_reduce,
+ 	.validate	= nft_meta_bridge_set_validate,
+ };
+ 
+diff --git a/net/bridge/netfilter/nft_reject_bridge.c b/net/bridge/netfilter/nft_reject_bridge.c
+index 1cb5c16e97b7fa..cd2b04236a99ca 100644
+--- a/net/bridge/netfilter/nft_reject_bridge.c
++++ b/net/bridge/netfilter/nft_reject_bridge.c
+@@ -184,7 +184,6 @@ static const struct nft_expr_ops nft_reject_bridge_ops = {
+ 	.init		= nft_reject_init,
+ 	.dump		= nft_reject_dump,
+ 	.validate	= nft_reject_bridge_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_reject_bridge_type __read_mostly = {
+diff --git a/net/can/bcm.c b/net/can/bcm.c
+index 04653df3a173e2..fcd923c223f4ba 100644
+--- a/net/can/bcm.c
++++ b/net/can/bcm.c
+@@ -109,11 +109,12 @@ struct bcm_op {
+ 	int ifindex;
+ 	canid_t can_id;
+ 	u32 flags;
+-	unsigned long frames_abs, frames_filtered;
++	atomic_long_t frames_abs, frames_filtered;
+ 	struct bcm_timeval ival1, ival2;
+ 	struct hrtimer timer, thrtimer;
+ 	ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg;
+ 	int rx_ifindex;
++	int if_detected; /* first received ifindex in ANYDEV rx_op mode */
+ 	int cfsiz;
+ 	u32 count;
+ 	u32 nframes;
+@@ -125,7 +126,8 @@ struct bcm_op {
+ 	struct canfd_frame last_sframe;
+ 	struct sock *sk;
+ 	struct net_device *rx_reg_dev;
+-	spinlock_t bcm_tx_lock; /* protect currframe/count in runtime updates */
++	spinlock_t bcm_tx_lock; /* protect tx data and timer updates */
++	spinlock_t bcm_rx_update_lock; /* protect filter/timer data updates */
+ };
+ 
+ struct bcm_sock {
+@@ -215,10 +217,13 @@ static int bcm_proc_show(struct seq_file *m, void *v)
+ 
+ 	list_for_each_entry_rcu(op, &bo->rx_ops, list) {
+ 
+-		unsigned long reduction;
++		long reduction, frames_filtered, frames_abs;
++
++		frames_filtered = atomic_long_read(&op->frames_filtered);
++		frames_abs = atomic_long_read(&op->frames_abs);
+ 
+ 		/* print only active entries & prevent division by zero */
+-		if (!op->frames_abs)
++		if (!frames_abs)
+ 			continue;
+ 
+ 		seq_printf(m, "rx_op: %03X %-5s ", op->can_id,
+@@ -240,9 +245,9 @@ static int bcm_proc_show(struct seq_file *m, void *v)
+ 				   (long long)ktime_to_us(op->kt_ival2));
+ 
+ 		seq_printf(m, "# recv %ld (%ld) => reduction: ",
+-			   op->frames_filtered, op->frames_abs);
++			   frames_filtered, frames_abs);
+ 
+-		reduction = 100 - (op->frames_filtered * 100) / op->frames_abs;
++		reduction = 100 - (frames_filtered * 100) / frames_abs;
+ 
+ 		seq_printf(m, "%s%ld%%\n",
+ 			   (reduction == 100) ? "near " : "", reduction);
+@@ -266,7 +271,8 @@ static int bcm_proc_show(struct seq_file *m, void *v)
+ 			seq_printf(m, "t2=%lld ",
+ 				   (long long)ktime_to_us(op->kt_ival2));
+ 
+-		seq_printf(m, "# sent %ld\n", op->frames_abs);
++		seq_printf(m, "# sent %ld\n",
++			   atomic_long_read(&op->frames_abs));
+ 	}
+ 	seq_putc(m, '\n');
+ 
+@@ -276,25 +282,49 @@ static int bcm_proc_show(struct seq_file *m, void *v)
+ }
+ #endif /* CONFIG_PROC_FS */
+ 
++static void bcm_update_rx_stats(struct bcm_op *op)
++{
++	/* prevent overflow of the reduction% calculation in bcm_proc_show() */
++	if (atomic_long_inc_return(&op->frames_abs) > LONG_MAX / 100) {
++		atomic_long_set(&op->frames_filtered, 0);
++		atomic_long_set(&op->frames_abs, 0);
++	}
++}
++
++static void bcm_update_tx_stats(struct bcm_op *op)
++{
++	/* tx_op has no reduction% calculation - use the full range and
++	 * just keep the displayed counter non-negative on overflow
++	 */
++	if (atomic_long_inc_return(&op->frames_abs) == LONG_MAX)
++		atomic_long_set(&op->frames_abs, 0);
++}
++
+ /*
+  * bcm_can_tx - send the (next) CAN frame to the appropriate CAN interface
+  *              of the given bcm tx op
+  */
+-static void bcm_can_tx(struct bcm_op *op)
++static void bcm_can_tx(struct bcm_op *op, struct canfd_frame *cf)
+ {
+ 	struct sk_buff *skb;
+ 	struct net_device *dev;
+-	struct canfd_frame *cf;
++	struct canfd_frame cframe;
++	bool cyclic = !cf;
++	unsigned int idx = 0;
+ 	int err;
+ 
+ 	/* no target device? => exit */
+ 	if (!op->ifindex)
+ 		return;
+ 
+-	/* read currframe under lock protection */
+-	spin_lock_bh(&op->bcm_tx_lock);
+-	cf = op->frames + op->cfsiz * op->currframe;
+-	spin_unlock_bh(&op->bcm_tx_lock);
++	if (cyclic) {
++		/* read currframe under lock protection */
++		spin_lock_bh(&op->bcm_tx_lock);
++		idx = op->currframe;
++		memcpy(&cframe, op->frames + op->cfsiz * idx, op->cfsiz);
++		cf = &cframe;
++		spin_unlock_bh(&op->bcm_tx_lock);
++	}
+ 
+ 	dev = dev_get_by_index(sock_net(op->sk), op->ifindex);
+ 	if (!dev) {
+@@ -321,16 +351,22 @@ static void bcm_can_tx(struct bcm_op *op)
+ 	spin_lock_bh(&op->bcm_tx_lock);
+ 
+ 	if (!err)
+-		op->frames_abs++;
++		bcm_update_tx_stats(op);
+ 
+-	op->currframe++;
++	/* only advance the cyclic sequence if nothing reset currframe while
++	 * we were sending - a concurrent TX_RESET_MULTI_IDX means this
++	 * frame's bookkeeping belongs to a sequence that no longer exists
++	 */
++	if (!cyclic || op->currframe == idx) {
++		op->currframe++;
+ 
+-	/* reached last frame? */
+-	if (op->currframe >= op->nframes)
+-		op->currframe = 0;
++		/* reached last frame? */
++		if (op->currframe >= op->nframes)
++			op->currframe = 0;
+ 
+-	if (op->count > 0)
+-		op->count--;
++		if (op->count > 0)
++			op->count--;
++	}
+ 
+ 	spin_unlock_bh(&op->bcm_tx_lock);
+ out:
+@@ -405,12 +441,18 @@ static bool bcm_tx_set_expiry(struct bcm_op *op, struct hrtimer *hrt)
+ {
+ 	ktime_t ival;
+ 
++	spin_lock_bh(&op->bcm_tx_lock);
++
+ 	if (op->kt_ival1 && op->count)
+ 		ival = op->kt_ival1;
+-	else if (op->kt_ival2)
++	else if (op->kt_ival2) {
+ 		ival = op->kt_ival2;
+-	else
++	} else {
++		spin_unlock_bh(&op->bcm_tx_lock);
+ 		return false;
++	}
++
++	spin_unlock_bh(&op->bcm_tx_lock);
+ 
+ 	hrtimer_set_expires(hrt, ktime_add(ktime_get(), ival));
+ 	return true;
+@@ -427,26 +469,48 @@ static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer)
+ {
+ 	struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
+ 	struct bcm_msg_head msg_head;
++	bool tx_ival1, tx_ival2;
++
++	/* snapshot kt_ival1/kt_ival2/count under lock to avoid torn
++	 * ktime_t reads racing with concurrent bcm_tx_setup() updates
++	 */
++	spin_lock_bh(&op->bcm_tx_lock);
++	tx_ival1 = op->kt_ival1 && (op->count > 0);
++	tx_ival2 = !!op->kt_ival2;
++	spin_unlock_bh(&op->bcm_tx_lock);
++
++	if (tx_ival1) {
++		u32 flags, count;
++		struct bcm_timeval ival1, ival2;
+ 
+-	if (op->kt_ival1 && (op->count > 0)) {
+-		bcm_can_tx(op);
+-		if (!op->count && (op->flags & TX_COUNTEVT)) {
++		bcm_can_tx(op, NULL);
+ 
++		/* snapshot variables under lock to avoid torn reads racing
++		 * with concurrent bcm_tx_setup() updates
++		 */
++		spin_lock_bh(&op->bcm_tx_lock);
++		flags = op->flags;
++		count = op->count;
++		ival1 = op->ival1;
++		ival2 = op->ival2;
++		spin_unlock_bh(&op->bcm_tx_lock);
++
++		if (!count && (flags & TX_COUNTEVT)) {
+ 			/* create notification to user */
+ 			memset(&msg_head, 0, sizeof(msg_head));
+ 			msg_head.opcode  = TX_EXPIRED;
+-			msg_head.flags   = op->flags;
+-			msg_head.count   = op->count;
+-			msg_head.ival1   = op->ival1;
+-			msg_head.ival2   = op->ival2;
++			msg_head.flags   = flags;
++			msg_head.count   = count;
++			msg_head.ival1   = ival1;
++			msg_head.ival2   = ival2;
+ 			msg_head.can_id  = op->can_id;
+ 			msg_head.nframes = 0;
+ 
+ 			bcm_send_to_user(op, &msg_head, NULL, 0);
+ 		}
+ 
+-	} else if (op->kt_ival2) {
+-		bcm_can_tx(op);
++	} else if (tx_ival2) {
++		bcm_can_tx(op, NULL);
+ 	}
+ 
+ 	return bcm_tx_set_expiry(op, &op->timer) ?
+@@ -460,12 +524,9 @@ static void bcm_rx_changed(struct bcm_op *op, struct canfd_frame *data)
+ {
+ 	struct bcm_msg_head head;
+ 
+-	/* update statistics */
+-	op->frames_filtered++;
+-
+-	/* prevent statistics overflow */
+-	if (op->frames_filtered > ULONG_MAX/100)
+-		op->frames_filtered = op->frames_abs = 0;
++	/* update statistics (frames_filtered <= frames_abs) */
++	if (atomic_long_read(&op->frames_abs))
++		atomic_long_inc(&op->frames_filtered);
+ 
+ 	/* this element is not throttled anymore */
+ 	data->flags &= (BCM_CAN_FLAGS_MASK|RX_RECV);
+@@ -585,6 +646,8 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
+ 	struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer);
+ 	struct bcm_msg_head msg_head;
+ 
++	spin_lock_bh(&op->bcm_rx_update_lock);
++
+ 	/* if user wants to be informed, when cyclic CAN-Messages come back */
+ 	if ((op->flags & RX_ANNOUNCE_RESUME) && op->last_frames) {
+ 		/* clear received CAN frames to indicate 'nothing received' */
+@@ -601,6 +664,8 @@ static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer)
+ 	msg_head.can_id  = op->can_id;
+ 	msg_head.nframes = 0;
+ 
++	spin_unlock_bh(&op->bcm_rx_update_lock);
++
+ 	bcm_send_to_user(op, &msg_head, NULL, 0);
+ 
+ 	return HRTIMER_NORESTART;
+@@ -649,15 +714,26 @@ static int bcm_rx_thr_flush(struct bcm_op *op)
+ static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer)
+ {
+ 	struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer);
++	enum hrtimer_restart ret;
++
++	spin_lock_bh(&op->bcm_rx_update_lock);
+ 
+-	if (bcm_rx_thr_flush(op)) {
++	/* kt_ival2 may have been concurrently cleared by bcm_rx_setup()
++	 * before it cancels this timer - never forward with a zero
++	 * interval in that case.
++	 */
++	if (bcm_rx_thr_flush(op) && op->kt_ival2) {
+ 		hrtimer_forward_now(hrtimer, op->kt_ival2);
+-		return HRTIMER_RESTART;
++		ret = HRTIMER_RESTART;
+ 	} else {
+ 		/* rearm throttle handling */
+ 		op->kt_lastmsg = 0;
+-		return HRTIMER_NORESTART;
++		ret = HRTIMER_NORESTART;
+ 	}
++
++	spin_unlock_bh(&op->bcm_rx_update_lock);
++
++	return ret;
+ }
+ 
+ /*
+@@ -667,7 +743,9 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
+ {
+ 	struct bcm_op *op = (struct bcm_op *)data;
+ 	const struct canfd_frame *rxframe = (struct canfd_frame *)skb->data;
++	struct canfd_frame rtrframe;
+ 	unsigned int i;
++	bool rtr_frame;
+ 
+ 	if (op->can_id != rxframe->can_id)
+ 		return;
+@@ -681,22 +759,66 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
+ 			return;
+ 	}
+ 
++	/* An ANYDEV op with an active RX timeout and/or throttle timer
++	 * tracks a single source interface: claim the first interface that
++	 * delivers a matching frame and reject frames from any other one,
++	 * before hrtimer_cancel() below can touch op->timer - this avoids
++	 * racing bcm_rx_timeout_handler() across concurrent interfaces.
++	 * RX_RTR_FRAME ops are excluded, as kt_ival1/kt_ival2 may briefly
++	 * hold a stale value from an earlier non-RTR configuration.
++	 */
++	if (!op->ifindex) {
++		spin_lock_bh(&op->bcm_rx_update_lock);
++
++		if (!(op->flags & RX_RTR_FRAME) &&
++		    (op->kt_ival1 || op->kt_ival2)) {
++			/* don't claim to vanishing interface */
++			if (!op->if_detected &&
++			    skb->dev->reg_state == NETREG_REGISTERED)
++				op->if_detected = skb->dev->ifindex;
++
++			if (op->if_detected != skb->dev->ifindex) {
++				spin_unlock_bh(&op->bcm_rx_update_lock);
++				return;
++			}
++		}
++
++		spin_unlock_bh(&op->bcm_rx_update_lock);
++	}
++
+ 	/* disable timeout */
+ 	hrtimer_cancel(&op->timer);
+ 
+-	/* save rx timestamp */
+-	op->rx_stamp = skb->tstamp;
+-	/* save originator for recvfrom() */
+-	op->rx_ifindex = skb->dev->ifindex;
+-	/* update statistics */
+-	op->frames_abs++;
++	/* op->flags/op->frames may be updated concurrently by bcm_rx_setup() */
++	spin_lock_bh(&op->bcm_rx_update_lock);
++
++	rtr_frame = op->flags & RX_RTR_FRAME;
++	if (rtr_frame) {
++		bcm_update_rx_stats(op);
++		/* snapshot RTR content under lock */
++		memcpy(&rtrframe, op->frames, op->cfsiz);
++		spin_unlock_bh(&op->bcm_rx_update_lock);
+ 
+-	if (op->flags & RX_RTR_FRAME) {
+ 		/* send reply for RTR-request (placed in op->frames[0]) */
+-		bcm_can_tx(op);
++		bcm_can_tx(op, &rtrframe);
+ 		return;
+ 	}
+ 
++	/* update statistics in the same critical section as bcm_rx_changed()
++	 * below: frames_filtered must never be checked/incremented against a
++	 * frames_abs snapshot from a concurrent bcm_rx_handler() call on
++	 * another CPU for the same (wildcard) op, or frames_filtered can end
++	 * up larger than frames_abs.
++	 */
++	bcm_update_rx_stats(op);
++
++	/* save rx timestamp and originator for recvfrom() under lock: an
++	 * ANYDEV op without an active timer can still run concurrently on
++	 * different CPUs, so content and meta data must be bundled here.
++	 */
++	op->rx_stamp = skb->tstamp;
++	op->rx_ifindex = skb->dev->ifindex;
++
+ 	if (op->flags & RX_FILTER_ID) {
+ 		/* the easiest case */
+ 		bcm_rx_update_and_send(op, op->last_frames, rxframe);
+@@ -730,6 +852,8 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data)
+ 
+ rx_starttimer:
+ 	bcm_rx_starttimer(op);
++
++	spin_unlock_bh(&op->bcm_rx_update_lock);
+ }
+ 
+ /*
+@@ -795,6 +919,7 @@ static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
+ 
+ 		/* mark as removed subscription */
+ 		op->rx_reg_dev = NULL;
++		dev_put(dev);
+ 	} else
+ 		printk(KERN_ERR "can-bcm: bcm_rx_unreg: registered device "
+ 		       "mismatch %p %p\n", op->rx_reg_dev, dev);
+@@ -825,17 +950,14 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
+ 				 * Only remove subscriptions that had not
+ 				 * been removed due to NETDEV_UNREGISTER
+ 				 * in bcm_notifier()
++				 *
++				 * op->rx_reg_dev is a tracked reference taken
++				 * when the subscription was registered, so it
++				 * stays valid here even if a concurrent
++				 * NETDEV_UNREGISTER already unlisted the dev.
+ 				 */
+-				if (op->rx_reg_dev) {
+-					struct net_device *dev;
+-
+-					dev = dev_get_by_index(sock_net(op->sk),
+-							       op->ifindex);
+-					if (dev) {
+-						bcm_rx_unreg(dev, op);
+-						dev_put(dev);
+-					}
+-				}
++				if (op->rx_reg_dev)
++					bcm_rx_unreg(op->rx_reg_dev, op);
+ 			} else
+ 				can_rx_unregister(sock_net(op->sk), NULL,
+ 						  op->can_id,
+@@ -922,6 +1044,8 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 	/* check the given can_id */
+ 	op = bcm_find_op(&bo->tx_ops, msg_head, ifindex);
+ 	if (op) {
++		void *new_frames;
++
+ 		/* update existing BCM operation */
+ 
+ 		/*
+@@ -932,11 +1056,23 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 		if (msg_head->nframes > op->nframes)
+ 			return -E2BIG;
+ 
+-		/* update CAN frames content */
++		/* get new CAN frames content into a staging buffer before
++		 * locking: validate and normalize the frames there so that
++		 * bcm_can_tx() / bcm_tx_timeout_handler() never observe a
++		 * partially updated or unvalidated frame in op->frames
++		 */
++		new_frames = kmalloc(msg_head->nframes * op->cfsiz, GFP_KERNEL);
++		if (!new_frames)
++			return -ENOMEM;
++
+ 		for (i = 0; i < msg_head->nframes; i++) {
+ 
+-			cf = op->frames + op->cfsiz * i;
++			cf = new_frames + op->cfsiz * i;
+ 			err = memcpy_from_msg((u8 *)cf, msg, op->cfsiz);
++			if (err < 0) {
++				kfree(new_frames);
++				return err;
++			}
+ 
+ 			if (op->flags & CAN_FD_FRAME) {
+ 				if (cf->len > 64)
+@@ -946,36 +1082,38 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 					err = -EINVAL;
+ 			}
+ 
+-			if (err < 0)
++			if (err < 0) {
++				kfree(new_frames);
+ 				return err;
++			}
+ 
+ 			if (msg_head->flags & TX_CP_CAN_ID) {
+ 				/* copy can_id into frame */
+ 				cf->can_id = msg_head->can_id;
+ 			}
+ 		}
++
++		spin_lock_bh(&op->bcm_tx_lock);
++
++		/* update CAN frames content */
++		memcpy(op->frames, new_frames, msg_head->nframes * op->cfsiz);
++
+ 		op->flags = msg_head->flags;
+ 
+-		/* only lock for unlikely count/nframes/currframe changes */
+ 		if (op->nframes != msg_head->nframes ||
+-		    op->flags & TX_RESET_MULTI_IDX ||
+-		    op->flags & SETTIMER) {
+-
+-			spin_lock_bh(&op->bcm_tx_lock);
++		    op->flags & TX_RESET_MULTI_IDX) {
++			/* potentially update changed nframes */
++			op->nframes = msg_head->nframes;
++			/* restart multiple frame transmission */
++			op->currframe = 0;
++		}
+ 
+-			if (op->nframes != msg_head->nframes ||
+-			    op->flags & TX_RESET_MULTI_IDX) {
+-				/* potentially update changed nframes */
+-				op->nframes = msg_head->nframes;
+-				/* restart multiple frame transmission */
+-				op->currframe = 0;
+-			}
++		if (op->flags & SETTIMER)
++			op->count = msg_head->count;
+ 
+-			if (op->flags & SETTIMER)
+-				op->count = msg_head->count;
++		spin_unlock_bh(&op->bcm_tx_lock);
+ 
+-			spin_unlock_bh(&op->bcm_tx_lock);
+-		}
++		kfree(new_frames);
+ 
+ 	} else {
+ 		/* insert new BCM operation for the given can_id */
+@@ -1052,10 +1190,12 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 
+ 	if (op->flags & SETTIMER) {
+ 		/* set timer values */
++		spin_lock_bh(&op->bcm_tx_lock);
+ 		op->ival1 = msg_head->ival1;
+ 		op->ival2 = msg_head->ival2;
+ 		op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
+ 		op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
++		spin_unlock_bh(&op->bcm_tx_lock);
+ 
+ 		/* disable an active timer due to zero values? */
+ 		if (!op->kt_ival1 && !op->kt_ival2)
+@@ -1073,7 +1213,7 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 		list_add_rcu(&op->list, &bo->tx_ops);
+ 
+ 	if (op->flags & TX_ANNOUNCE)
+-		bcm_can_tx(op);
++		bcm_can_tx(op, NULL);
+ 
+ 	if (op->flags & STARTTIMER)
+ 		bcm_tx_start_timer(op);
+@@ -1087,6 +1227,39 @@ free_op:
+ 	return err;
+ }
+ 
++static int bcm_rx_setup_rtr_check(struct bcm_msg_head *msg_head,
++				  struct bcm_op *op, void *new_frames)
++{
++	struct canfd_frame *frame0 = new_frames;
++
++	if (!(msg_head->flags & RX_RTR_FRAME))
++		return 0;
++
++	/* this frame is sent out as-is by bcm_can_tx() whenever a matching
++	 * remote request is received, so validate its length the same way
++	 * bcm_tx_setup() validates TX_SETUP frames before installing it
++	 */
++	if (msg_head->flags & CAN_FD_FRAME) {
++		if (frame0->len > 64)
++			return -EINVAL;
++	} else {
++		if (frame0->len > 8)
++			return -EINVAL;
++	}
++
++	/* funny feature in RX(!)_SETUP only for RTR-mode:
++	 * copy can_id into frame BUT without RTR-flag to
++	 * prevent a full-load-loopback-test ... ;-]
++	 * normalize this on the staged buffer, before it is
++	 * ever installed into op->frames.
++	 */
++	if ((msg_head->flags & TX_CP_CAN_ID) ||
++	    frame0->can_id == op->can_id)
++		frame0->can_id = op->can_id & ~CAN_RTR_FLAG;
++
++	return 0;
++}
++
+ /*
+  * bcm_rx_setup - create or update a bcm rx op (for bcm_sendmsg)
+  */
+@@ -1096,6 +1269,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 	struct bcm_sock *bo = bcm_sk(sk);
+ 	struct bcm_op *op;
+ 	int do_rx_register;
++	int new_op = 0;
+ 	int err = 0;
+ 
+ 	if ((msg_head->flags & RX_FILTER_ID) || (!(msg_head->nframes))) {
+@@ -1121,6 +1295,8 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 	/* check the given can_id */
+ 	op = bcm_find_op(&bo->rx_ops, msg_head, ifindex);
+ 	if (op) {
++		void *new_frames = NULL;
++
+ 		/* update existing BCM operation */
+ 
+ 		/*
+@@ -1132,21 +1308,62 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 			return -E2BIG;
+ 
+ 		if (msg_head->nframes) {
+-			/* update CAN frames content */
+-			err = memcpy_from_msg(op->frames, msg,
++			/* get new CAN frames content before locking */
++			new_frames = kmalloc(msg_head->nframes * op->cfsiz,
++					     GFP_KERNEL);
++			if (!new_frames)
++				return -ENOMEM;
++
++			err = memcpy_from_msg(new_frames, msg,
+ 					      msg_head->nframes * op->cfsiz);
+-			if (err < 0)
++			if (err < 0) {
++				kfree(new_frames);
+ 				return err;
++			}
+ 
+-			/* clear last_frames to indicate 'nothing received' */
+-			memset(op->last_frames, 0, msg_head->nframes * op->cfsiz);
++			err = bcm_rx_setup_rtr_check(msg_head, op, new_frames);
++			if (err < 0) {
++				kfree(new_frames);
++				return err;
++			}
+ 		}
+ 
++		spin_lock_bh(&op->bcm_rx_update_lock);
+ 		op->nframes = msg_head->nframes;
+ 		op->flags = msg_head->flags;
+ 
+-		/* Only an update -> do not call can_rx_register() */
+-		do_rx_register = 0;
++		if (msg_head->nframes) {
++			/* update CAN frames content */
++			memcpy(op->frames, new_frames,
++			       msg_head->nframes * op->cfsiz);
++
++			/* clear last_frames to indicate 'nothing received' */
++			memset(op->last_frames, 0,
++			       msg_head->nframes * op->cfsiz);
++		}
++
++		if (msg_head->flags & SETTIMER) {
++			op->ival1 = msg_head->ival1;
++			op->ival2 = msg_head->ival2;
++			op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
++			op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
++			op->kt_lastmsg = 0;
++			op->if_detected = 0; /* reclaim ifindex in ANYDEV mode */
++		}
++		spin_unlock_bh(&op->bcm_rx_update_lock);
++
++		/* free temporary frames / kfree(NULL) is safe */
++		kfree(new_frames);
++
++		/* Don't register a new CAN filter for the rx_op update unless
++		 * a concurrent NETDEV_UNREGISTER notifier already tore down
++		 * the previous registration. In this case the receiver needs
++		 * to be re-registered here so that this update doesn't
++		 * silently stop delivering frames for the given ifindex.
++		 * Ops with ifindex = 0 (all CAN interfaces) never carry a
++		 * tracked rx_reg_dev and stay registered as-is.
++		 */
++		do_rx_register = (ifindex && !op->rx_reg_dev) ? 1 : 0;
+ 
+ 	} else {
+ 		/* insert new BCM operation for the given can_id */
+@@ -1155,6 +1372,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 			return -ENOMEM;
+ 
+ 		spin_lock_init(&op->bcm_tx_lock);
++		spin_lock_init(&op->bcm_rx_update_lock);
+ 		op->can_id = msg_head->can_id;
+ 		op->nframes = msg_head->nframes;
+ 		op->cfsiz = CFSIZ(msg_head->flags);
+@@ -1188,14 +1406,12 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 		if (msg_head->nframes) {
+ 			err = memcpy_from_msg(op->frames, msg,
+ 					      msg_head->nframes * op->cfsiz);
+-			if (err < 0) {
+-				if (op->frames != &op->sframe)
+-					kfree(op->frames);
+-				if (op->last_frames != &op->last_sframe)
+-					kfree(op->last_frames);
+-				kfree(op);
+-				return err;
+-			}
++			if (err < 0)
++				goto free_op;
++
++			err = bcm_rx_setup_rtr_check(msg_head, op, op->frames);
++			if (err < 0)
++				goto free_op;
+ 		}
+ 
+ 		/* bcm_can_tx / bcm_tx_timeout_handler needs this */
+@@ -1217,35 +1433,29 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 
+ 		/* call can_rx_register() */
+ 		do_rx_register = 1;
++		new_op = 1;
+ 
+ 	} /* if ((op = bcm_find_op(&bo->rx_ops, msg_head->can_id, ifindex))) */
+ 
+ 	/* check flags */
+ 
+ 	if (op->flags & RX_RTR_FRAME) {
+-		struct canfd_frame *frame0 = op->frames;
+-
+ 		/* no timers in RTR-mode */
+ 		hrtimer_cancel(&op->thrtimer);
+ 		hrtimer_cancel(&op->timer);
+-
+-		/*
+-		 * funny feature in RX(!)_SETUP only for RTR-mode:
+-		 * copy can_id into frame BUT without RTR-flag to
+-		 * prevent a full-load-loopback-test ... ;-]
+-		 */
+-		if ((op->flags & TX_CP_CAN_ID) ||
+-		    (frame0->can_id == op->can_id))
+-			frame0->can_id = op->can_id & ~CAN_RTR_FLAG;
+-
+ 	} else {
+ 		if (op->flags & SETTIMER) {
+ 
+-			/* set timer value */
+-			op->ival1 = msg_head->ival1;
+-			op->ival2 = msg_head->ival2;
+-			op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
+-			op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
++			/* set timers (locked) for newly created op */
++			if (new_op) {
++				spin_lock_bh(&op->bcm_rx_update_lock);
++				op->ival1 = msg_head->ival1;
++				op->ival2 = msg_head->ival2;
++				op->kt_ival1 = bcm_timeval_to_ktime(msg_head->ival1);
++				op->kt_ival2 = bcm_timeval_to_ktime(msg_head->ival2);
++				op->kt_lastmsg = 0;
++				spin_unlock_bh(&op->bcm_rx_update_lock);
++			}
+ 
+ 			/* disable an active timer due to zero value? */
+ 			if (!op->kt_ival1)
+@@ -1255,9 +1465,11 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 			 * In any case cancel the throttle timer, flush
+ 			 * potentially blocked msgs and reset throttle handling
+ 			 */
+-			op->kt_lastmsg = 0;
+ 			hrtimer_cancel(&op->thrtimer);
++
++			spin_lock_bh(&op->bcm_rx_update_lock);
+ 			bcm_rx_thr_flush(op);
++			spin_unlock_bh(&op->bcm_rx_update_lock);
+ 		}
+ 
+ 		if ((op->flags & STARTTIMER) && op->kt_ival1)
+@@ -1265,7 +1477,10 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 				      HRTIMER_MODE_REL_SOFT);
+ 	}
+ 
+-	/* now we can register for can_ids, if we added a new bcm_op */
++	/* now we can register for can_ids, if we added a new bcm_op
++	 * or need to re-register after a NETDEV_UNREGISTER tore down
++	 * the previous registration of an existing op
++	 */
+ 	if (do_rx_register) {
+ 		if (ifindex) {
+ 			struct net_device *dev;
+@@ -1278,7 +1493,15 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 						      bcm_rx_handler, op,
+ 						      "bcm", sk);
+ 
+-				op->rx_reg_dev = dev;
++				/* keep a reference so that a later
++				 * unregister can safely reach the device even
++				 * if a concurrent NETDEV_UNREGISTER has
++				 * already unlisted it by ifindex
++				 */
++				if (!err) {
++					op->rx_reg_dev = dev;
++					dev_hold(dev);
++				}
+ 				dev_put(dev);
+ 			} else {
+ 				/* the requested device is gone - do not
+@@ -1287,21 +1510,43 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
+ 				err = -ENODEV;
+ 			}
+ 
+-		} else
++		} else {
+ 			err = can_rx_register(sock_net(sk), NULL, op->can_id,
+ 					      REGMASK(op->can_id),
+ 					      bcm_rx_handler, op, "bcm", sk);
++		}
++
+ 		if (err) {
+-			/* this bcm rx op is broken -> remove it */
+-			bcm_remove_op(op);
++			/* newly created bcm rx op is broken -> remove it */
++			if (new_op) {
++				bcm_remove_op(op);
++				return err;
++			}
++
++			/* an existing op just stays unregistered.
++			 * Cancel op->timer and (defensively) op->thrtimer.
++			 * Other settings can't be reached until the next
++			 * successful RX_SETUP.
++			 */
++			hrtimer_cancel(&op->timer);
++			hrtimer_cancel(&op->thrtimer);
+ 			return err;
+ 		}
+ 
+-		/* add this bcm_op to the list of the rx_ops */
+-		list_add_rcu(&op->list, &bo->rx_ops);
++		/* add a new bcm_op to the list of the rx_ops */
++		if (new_op)
++			list_add_rcu(&op->list, &bo->rx_ops);
+ 	}
+ 
+ 	return msg_head->nframes * op->cfsiz + MHSIZ;
++
++free_op:
++	if (op->frames != &op->sframe)
++		kfree(op->frames);
++	if (op->last_frames != &op->last_sframe)
++		kfree(op->last_frames);
++	kfree(op);
++	return err;
+ }
+ 
+ /*
+@@ -1506,11 +1751,30 @@ static void bcm_notify(struct bcm_sock *bo, unsigned long msg,
+ 	case NETDEV_UNREGISTER:
+ 		lock_sock(sk);
+ 
+-		/* remove device specific receive entries */
+-		list_for_each_entry(op, &bo->rx_ops, list)
++		/* rx_ops: remove device specific receive entries */
++		list_for_each_entry(op, &bo->rx_ops, list) {
+ 			if (op->rx_reg_dev == dev)
+ 				bcm_rx_unreg(dev, op);
+ 
++			/* release an ANYDEV op's claim (see bcm_rx_handler())
++			 * on this now confirmed-gone interface.
++			 */
++			if (!op->ifindex) {
++				spin_lock_bh(&op->bcm_rx_update_lock);
++				if (op->if_detected == dev->ifindex)
++					op->if_detected = 0;
++				spin_unlock_bh(&op->bcm_rx_update_lock);
++			}
++		}
++
++		/* tx_ops: stop device specific cyclic transmissions on the
++		 * vanishing ifindex. Cancelling the timer is enough to stop
++		 * cyclic bcm_can_tx() calls as there is no re-arming.
++		 */
++		list_for_each_entry(op, &bo->tx_ops, list)
++			if (op->ifindex == dev->ifindex)
++				hrtimer_cancel(&op->timer);
++
+ 		/* remove device reference, if this is our bound device */
+ 		if (bo->bound && bo->ifindex == dev->ifindex) {
+ #if IS_ENABLED(CONFIG_PROC_FS)
+@@ -1643,16 +1907,14 @@ static int bcm_release(struct socket *sock)
+ 			 * Only remove subscriptions that had not
+ 			 * been removed due to NETDEV_UNREGISTER
+ 			 * in bcm_notifier()
++			 *
++			 * op->rx_reg_dev is a tracked reference taken
++			 * when the subscription was registered, so it
++			 * stays valid here even if a concurrent
++			 * NETDEV_UNREGISTER already unlisted the device.
+ 			 */
+-			if (op->rx_reg_dev) {
+-				struct net_device *dev;
+-
+-				dev = dev_get_by_index(net, op->ifindex);
+-				if (dev) {
+-					bcm_rx_unreg(dev, op);
+-					dev_put(dev);
+-				}
+-			}
++			if (op->rx_reg_dev)
++				bcm_rx_unreg(op->rx_reg_dev, op);
+ 		} else
+ 			can_rx_unregister(net, NULL, op->can_id,
+ 					  REGMASK(op->can_id),
+diff --git a/net/can/isotp.c b/net/can/isotp.c
+index 80adf7366e63a8..efc5eeac7c8861 100644
+--- a/net/can/isotp.c
++++ b/net/can/isotp.c
+@@ -150,11 +150,12 @@ struct isotp_sock {
+ 	struct sock sk;
+ 	int bound;
+ 	int ifindex;
++	struct net_device *dev;
+ 	canid_t txid;
+ 	canid_t rxid;
+ 	ktime_t tx_gap;
+ 	ktime_t lastrxcf_tstamp;
+-	struct hrtimer rxtimer, txtimer, txfrtimer;
++	struct hrtimer rxtimer, txtimer, txfrtimer, echotimer;
+ 	struct can_isotp_options opt;
+ 	struct can_isotp_fc_options rxfc, txfc;
+ 	struct can_isotp_ll_options ll;
+@@ -162,6 +163,7 @@ struct isotp_sock {
+ 	u32 force_tx_stmin;
+ 	u32 force_rx_stmin;
+ 	u32 cfecho; /* consecutive frame echo tag */
++	u32 tx_gen; /* generation, bumped per new tx transfer */
+ 	struct tpcon rx, tx;
+ 	struct list_head notifier;
+ 	wait_queue_head_t wait;
+@@ -368,6 +370,15 @@ static int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae)
+ 
+ 	hrtimer_cancel(&so->txtimer);
+ 
++	/* isotp_tx_timeout() may have given up on this job while
++	 * hrtimer_cancel() above waited for it to finish; so->rx_lock
++	 * (held by our caller isotp_rcv()) rules out a concurrent claim,
++	 * so a plain recheck is enough here.
++	 */
++	if (so->tx.state != ISOTP_WAIT_FC &&
++	    so->tx.state != ISOTP_WAIT_FIRST_FC)
++		return 1;
++
+ 	if ((cf->len < ae + FC_CONTENT_SZ) ||
+ 	    ((so->opt.flags & ISOTP_CHECK_PADDING) &&
+ 	     check_pad(so, cf, ae + FC_CONTENT_SZ, so->opt.rxpad_content))) {
+@@ -413,7 +424,7 @@ static int isotp_rcv_fc(struct isotp_sock *so, struct canfd_frame *cf, int ae)
+ 		so->tx.bs = 0;
+ 		so->tx.state = ISOTP_SENDING;
+ 		/* send CF frame and enable echo timeout handling */
+-		hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
++		hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
+ 			      HRTIMER_MODE_REL_SOFT);
+ 		isotp_send_cframe(so);
+ 		break;
+@@ -566,6 +577,14 @@ static int isotp_rcv_cf(struct sock *sk, struct canfd_frame *cf, int ae,
+ 
+ 	hrtimer_cancel(&so->rxtimer);
+ 
++	/* isotp_rx_timer_handler() may have raced us for so->rx.state
++	 * while hrtimer_cancel() above waited for it to finish, already
++	 * reporting ETIMEDOUT and resetting the reception; don't process
++	 * this CF into a reassembly that has already been given up on.
++	 */
++	if (so->rx.state != ISOTP_WAIT_DATA)
++		return 1;
++
+ 	/* CFs are never longer than the FF */
+ 	if (cf->len > so->rx.ll_dl)
+ 		return 1;
+@@ -855,20 +874,36 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
+ 	struct canfd_frame *cf = (struct canfd_frame *)skb->data;
+ 
+ 	/* only handle my own local echo CF/SF skb's (no FF!) */
+-	if (skb->sk != sk || so->cfecho != *(u32 *)cf->data)
++	if (skb->sk != sk)
+ 		return;
+ 
++	/* unlike isotp_rcv_fc()/isotp_rcv_cf(), not already under so->rx_lock
++	 * (no isotp_rcv() caller here), so take it ourselves
++	 */
++	spin_lock(&so->rx_lock);
++
++	/* so->cfecho may since belong to a new transfer; recheck under lock */
++	if (so->cfecho != *(u32 *)cf->data)
++		goto out_unlock;
++
+ 	/* cancel local echo timeout */
+-	hrtimer_cancel(&so->txtimer);
++	hrtimer_cancel(&so->echotimer);
+ 
+ 	/* local echo skb with consecutive frame has been consumed */
+ 	so->cfecho = 0;
+ 
++	/* claiming a transfer also takes so->rx_lock, so a plain recheck
++	 * is enough: so->tx.state can't have flipped to ISOTP_SENDING for
++	 * a new claim while we're still in here
++	 */
++	if (so->tx.state != ISOTP_SENDING)
++		goto out_unlock;
++
+ 	if (so->tx.idx >= so->tx.len) {
+ 		/* we are done */
+ 		so->tx.state = ISOTP_IDLE;
+ 		wake_up_interruptible(&so->wait);
+-		return;
++		goto out_unlock;
+ 	}
+ 
+ 	if (so->txfc.bs && so->tx.bs >= so->txfc.bs) {
+@@ -876,53 +911,83 @@ static void isotp_rcv_echo(struct sk_buff *skb, void *data)
+ 		so->tx.state = ISOTP_WAIT_FC;
+ 		hrtimer_start(&so->txtimer, ktime_set(ISOTP_FC_TIMEOUT, 0),
+ 			      HRTIMER_MODE_REL_SOFT);
+-		return;
++		goto out_unlock;
+ 	}
+ 
+ 	/* no gap between data frames needed => use burst mode */
+ 	if (!so->tx_gap) {
+ 		/* enable echo timeout handling */
+-		hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
++		hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
+ 			      HRTIMER_MODE_REL_SOFT);
+ 		isotp_send_cframe(so);
+-		return;
++		goto out_unlock;
+ 	}
+ 
+ 	/* start timer to send next consecutive frame with correct delay */
+ 	hrtimer_start(&so->txfrtimer, so->tx_gap, HRTIMER_MODE_REL_SOFT);
++
++out_unlock:
++	spin_unlock(&so->rx_lock);
+ }
+ 
+-static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
++/* shared by so->txtimer's and so->echotimer's callbacks. Both timers get
++ * cancelled under so->rx_lock elsewhere, so this must stay lock-free to
++ * avoid deadlocking with that; uses so->tx_gen instead to avoid tainting
++ * a new transfer with an error from the one that just timed out.
++ */
++static enum hrtimer_restart isotp_tx_timeout(struct isotp_sock *so)
+ {
+-	struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
+-					     txtimer);
+ 	struct sock *sk = &so->sk;
++	u32 gen = READ_ONCE(so->tx_gen);
++	u32 old_state = READ_ONCE(so->tx.state);
+ 
+ 	/* don't handle timeouts in IDLE or SHUTDOWN state */
+-	if (so->tx.state == ISOTP_IDLE || so->tx.state == ISOTP_SHUTDOWN)
++	if (old_state == ISOTP_IDLE || old_state == ISOTP_SHUTDOWN)
++		return HRTIMER_NORESTART;
++
++	/* only claim the timeout if the state is still unchanged */
++	if (cmpxchg(&so->tx.state, old_state, ISOTP_IDLE) != old_state)
+ 		return HRTIMER_NORESTART;
+ 
+ 	/* we did not get any flow control or echo frame in time */
+ 
+-	/* report 'communication error on send' */
+-	sk->sk_err = ECOMM;
+-	if (!sock_flag(sk, SOCK_DEAD))
+-		sk_error_report(sk);
++	if (READ_ONCE(so->tx_gen) == gen) {
++		/* report 'communication error on send' */
++		sk->sk_err = ECOMM;
++		if (!sock_flag(sk, SOCK_DEAD))
++			sk_error_report(sk);
++	}
+ 
+-	/* reset tx state */
+-	so->tx.state = ISOTP_IDLE;
+ 	wake_up_interruptible(&so->wait);
+ 
+ 	return HRTIMER_NORESTART;
+ }
+ 
++/* so->txtimer: fires when a Flow Control frame does not arrive in time */
++static enum hrtimer_restart isotp_tx_timer_handler(struct hrtimer *hrtimer)
++{
++	struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
++					     txtimer);
++
++	return isotp_tx_timeout(so);
++}
++
++/* so->echotimer: fires when a sent CF/SF's local echo does not arrive */
++static enum hrtimer_restart isotp_echo_timer_handler(struct hrtimer *hrtimer)
++{
++	struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
++					     echotimer);
++
++	return isotp_tx_timeout(so);
++}
++
+ static enum hrtimer_restart isotp_txfr_timer_handler(struct hrtimer *hrtimer)
+ {
+ 	struct isotp_sock *so = container_of(hrtimer, struct isotp_sock,
+ 					     txfrtimer);
+ 
+ 	/* start echo timeout handling and cover below protocol error */
+-	hrtimer_start(&so->txtimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
++	hrtimer_start(&so->echotimer, ktime_set(ISOTP_ECHO_TIMEOUT, 0),
+ 		      HRTIMER_MODE_REL_SOFT);
+ 
+ 	/* cfecho should be consumed by isotp_rcv_echo() here */
+@@ -942,13 +1007,24 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
+ 	int ae = (so->opt.flags & CAN_ISOTP_EXTEND_ADDR) ? 1 : 0;
+ 	int wait_tx_done = (so->opt.flags & CAN_ISOTP_WAIT_TX_DONE) ? 1 : 0;
+ 	s64 hrtimer_sec = ISOTP_ECHO_TIMEOUT;
++	struct hrtimer *tx_hrt = &so->echotimer;
++	u32 new_state = ISOTP_SENDING;
+ 	int off;
+ 	int err;
+ 
+ 	if (!so->bound || so->tx.state == ISOTP_SHUTDOWN)
+ 		return -EADDRNOTAVAIL;
+ 
+-	while (cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SENDING) != ISOTP_IDLE) {
++	/* claim the socket under so->rx_lock: this serializes the claim
++	 * with the RX path and with sendmsg()'s own error paths below, so
++	 * none of them can ever see a transfer mid-claim
++	 */
++	for (;;) {
++		spin_lock_bh(&so->rx_lock);
++		if (READ_ONCE(so->tx.state) == ISOTP_IDLE)
++			break;
++		spin_unlock_bh(&so->rx_lock);
++
+ 		/* we do not support multiple buffers - for now */
+ 		if (msg->msg_flags & MSG_DONTWAIT)
+ 			return -EAGAIN;
+@@ -957,9 +1033,29 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
+ 			return -EADDRNOTAVAIL;
+ 
+ 		/* wait for complete transmission of current pdu */
+-		err = wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE);
++		err = wait_event_interruptible(so->wait,
++					       so->tx.state == ISOTP_IDLE);
+ 		if (err)
+-			goto err_event_drop;
++			return err;
++	}
++
++	/* new transfer: bump so->tx_gen and drain the old one's timers,
++	 * still under the so->rx_lock we just claimed the socket with
++	 */
++	WRITE_ONCE(so->tx.state, ISOTP_SENDING);
++	WRITE_ONCE(so->tx_gen, READ_ONCE(so->tx_gen) + 1);
++	hrtimer_cancel(&so->txtimer);
++	hrtimer_cancel(&so->echotimer);
++	hrtimer_cancel(&so->txfrtimer);
++	so->cfecho = 0;
++	spin_unlock_bh(&so->rx_lock);
++
++	/* so->bound is only checked once above - a wakeup may have
++	 * unbound/rebound the socket meanwhile, so re-validate it
++	 */
++	if (!so->bound) {
++		err = -EADDRNOTAVAIL;
++		goto err_out_drop;
+ 	}
+ 
+ 	/* PDU size > default => try max_pdu_size */
+@@ -1064,18 +1160,33 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
+ 			so->cfecho = *(u32 *)cf->data;
+ 		} else {
+ 			/* standard flow control check */
+-			so->tx.state = ISOTP_WAIT_FIRST_FC;
++			new_state = ISOTP_WAIT_FIRST_FC;
+ 
+ 			/* start timeout for FC */
+ 			hrtimer_sec = ISOTP_FC_TIMEOUT;
++			tx_hrt = &so->txtimer;
+ 
+ 			/* no CF echo tag for isotp_rcv_echo() (FF-mode) */
+ 			so->cfecho = 0;
+ 		}
+ 	}
+ 
+-	hrtimer_start(&so->txtimer, ktime_set(hrtimer_sec, 0),
++	spin_lock_bh(&so->rx_lock);
++	if (so->tx.state == ISOTP_SHUTDOWN) {
++		/* isotp_release() has since taken over and already drained
++		 * our timers - don't send into a socket that's going away
++		 */
++		spin_unlock_bh(&so->rx_lock);
++		kfree_skb(skb);
++		dev_put(dev);
++		wake_up_interruptible(&so->wait);
++		return -EADDRNOTAVAIL;
++	}
++	/* WAIT_FIRST_FC for standard FF, else stays ISOTP_SENDING */
++	so->tx.state = new_state;
++	hrtimer_start(tx_hrt, ktime_set(hrtimer_sec, 0),
+ 		      HRTIMER_MODE_REL_SOFT);
++	spin_unlock_bh(&so->rx_lock);
+ 
+ 	/* send the first or only CAN frame */
+ 	cf->flags = so->ll.tx_flags;
+@@ -1088,13 +1199,10 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
+ 		pr_notice_once("can-isotp: %s: can_send_ret %pe\n",
+ 			       __func__, ERR_PTR(err));
+ 
++		spin_lock_bh(&so->rx_lock);
+ 		/* no transmission -> no timeout monitoring */
+-		hrtimer_cancel(&so->txtimer);
+-
+-		/* reset consecutive frame echo tag */
+-		so->cfecho = 0;
+-
+-		goto err_out_drop;
++		hrtimer_cancel(tx_hrt);
++		goto err_out_drop_locked;
+ 	}
+ 
+ 	if (wait_tx_done) {
+@@ -1110,14 +1218,21 @@ static int isotp_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
+ 
+ 	return size;
+ 
++err_out_drop:
++	/* claimed but nothing sent yet - no timer to cancel */
++	spin_lock_bh(&so->rx_lock);
++	goto err_out_drop_locked;
+ err_event_drop:
+-	/* got signal: force tx state machine to be idle */
+-	so->tx.state = ISOTP_IDLE;
++	/* interrupted waiting on our own transfer - drain its timers */
++	spin_lock_bh(&so->rx_lock);
+ 	hrtimer_cancel(&so->txfrtimer);
+ 	hrtimer_cancel(&so->txtimer);
+-err_out_drop:
+-	/* drop this PDU and unlock a potential wait queue */
++	hrtimer_cancel(&so->echotimer);
++err_out_drop_locked:
++	/* release the claim; so->rx_lock still held from above */
++	so->cfecho = 0;
+ 	so->tx.state = ISOTP_IDLE;
++	spin_unlock_bh(&so->rx_lock);
+ 	wake_up_interruptible(&so->wait);
+ 
+ 	return err;
+@@ -1179,13 +1294,20 @@ static int isotp_release(struct socket *sock)
+ 	so = isotp_sk(sk);
+ 	net = sock_net(sk);
+ 
+-	/* wait for complete transmission of current pdu */
+-	while (wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0 &&
+-	       cmpxchg(&so->tx.state, ISOTP_IDLE, ISOTP_SHUTDOWN) != ISOTP_IDLE)
++	/* best-effort: wait for a running pdu to finish, but don't block on
++	 * it forever - give up after the first signal
++	 */
++	while (so->tx.state != ISOTP_IDLE &&
++	       wait_event_interruptible(so->wait, so->tx.state == ISOTP_IDLE) == 0)
+ 		;
+ 
+-	/* force state machines to be idle also when a signal occurred */
++	/* claim the socket under so->rx_lock like sendmsg() does, so its
++	 * claim can't race the forced ISOTP_SHUTDOWN below; force it
++	 * unconditionally, even when a signal cut the wait above short
++	 */
++	spin_lock_bh(&so->rx_lock);
+ 	so->tx.state = ISOTP_SHUTDOWN;
++	spin_unlock_bh(&so->rx_lock);
+ 	so->rx.state = ISOTP_IDLE;
+ 
+ 	spin_lock(&isotp_notifier_lock);
+@@ -1197,28 +1319,30 @@ static int isotp_release(struct socket *sock)
+ 	list_del(&so->notifier);
+ 	spin_unlock(&isotp_notifier_lock);
+ 
++	rtnl_lock();
+ 	lock_sock(sk);
+ 
+-	/* remove current filters & unregister */
+-	if (so->bound) {
+-		if (so->ifindex) {
+-			struct net_device *dev;
+-
+-			dev = dev_get_by_index(net, so->ifindex);
+-			if (dev) {
+-				if (isotp_register_rxid(so))
+-					can_rx_unregister(net, dev, so->rxid,
+-							  SINGLE_MASK(so->rxid),
+-							  isotp_rcv, sk);
+-
+-				can_rx_unregister(net, dev, so->txid,
+-						  SINGLE_MASK(so->txid),
+-						  isotp_rcv_echo, sk);
+-				dev_put(dev);
+-			}
+-		}
++	/* remove current filters & unregister
++	 * tracked reference so->dev is taken at bind() time with rtnl_lock
++	 */
++	if (so->bound && so->dev) {
++		if (isotp_register_rxid(so))
++			can_rx_unregister(net, so->dev, so->rxid,
++					  SINGLE_MASK(so->rxid),
++					  isotp_rcv, sk);
++
++		can_rx_unregister(net, so->dev, so->txid,
++				  SINGLE_MASK(so->txid),
++				  isotp_rcv_echo, sk);
++		dev_put(so->dev);
+ 	}
+ 
++	so->ifindex = 0;
++	so->bound = 0;
++	so->dev = NULL;
++
++	rtnl_unlock();
++
+ 	/* Always wait for a grace period before touching the timers below.
+ 	 * A concurrent NETDEV_UNREGISTER may have already unregistered our
+ 	 * filters and cleared so->bound in isotp_notify() without waiting
+@@ -1229,11 +1353,9 @@ static int isotp_release(struct socket *sock)
+ 
+ 	hrtimer_cancel(&so->txfrtimer);
+ 	hrtimer_cancel(&so->txtimer);
++	hrtimer_cancel(&so->echotimer);
+ 	hrtimer_cancel(&so->rxtimer);
+ 
+-	so->ifindex = 0;
+-	so->bound = 0;
+-
+ 	sock_orphan(sk);
+ 	sock->sk = NULL;
+ 
+@@ -1287,6 +1409,7 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
+ 	if (!addr->can_ifindex)
+ 		return -ENODEV;
+ 
++	rtnl_lock();
+ 	lock_sock(sk);
+ 
+ 	if (so->bound) {
+@@ -1294,6 +1417,17 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
+ 		goto out;
+ 	}
+ 
++	/* A transmission or reception that outlived a previous binding
++	 * (unbound by NETDEV_UNREGISTER) may still be draining; the FC/echo
++	 * and RX watchdog timers bound how long this takes. Checked together
++	 * with so->bound in the same lock_sock() section above, so there is
++	 * no window in which a concurrent isotp_notify() could be missed.
++	 */
++	if (so->tx.state != ISOTP_IDLE || so->rx.state != ISOTP_IDLE) {
++		err = -EAGAIN;
++		goto out;
++	}
++
+ 	/* ensure different CAN IDs when the rx_id is to be registered */
+ 	if (isotp_register_rxid(so) && rx_id == tx_id) {
+ 		err = -EADDRNOTAVAIL;
+@@ -1306,14 +1440,12 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
+ 		goto out;
+ 	}
+ 	if (dev->type != ARPHRD_CAN) {
+-		dev_put(dev);
+ 		err = -ENODEV;
+-		goto out;
++		goto out_put_dev;
+ 	}
+-	if (dev->mtu < so->ll.mtu) {
+-		dev_put(dev);
++	if (READ_ONCE(dev->mtu) < so->ll.mtu) {
+ 		err = -EINVAL;
+-		goto out;
++		goto out_put_dev;
+ 	}
+ 	if (!(dev->flags & IFF_UP))
+ 		notify_enetdown = 1;
+@@ -1331,16 +1463,25 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
+ 	can_rx_register(net, dev, tx_id, SINGLE_MASK(tx_id),
+ 			isotp_rcv_echo, sk, "isotpe", sk);
+ 
+-	dev_put(dev);
+-
+ 	/* switch to new settings */
+ 	so->ifindex = ifindex;
+ 	so->rxid = rx_id;
+ 	so->txid = tx_id;
+ 	so->bound = 1;
+ 
++	/* bind() ok -> hold a reference for so->dev so that isotp_release()
++	 * can safely reach the device later, even if a concurrent
++	 * NETDEV_UNREGISTER has already unlisted it by ifindex.
++	 */
++	so->dev = dev;
++	dev_hold(so->dev);
++
++out_put_dev:
++	/* remove potential reference from dev_get_by_index() */
++	dev_put(dev);
+ out:
+ 	release_sock(sk);
++	rtnl_unlock();
+ 
+ 	if (notify_enetdown) {
+ 		sk->sk_err = ENETDOWN;
+@@ -1543,7 +1684,7 @@ static void isotp_notify(struct isotp_sock *so, unsigned long msg,
+ 	if (!net_eq(dev_net(dev), sock_net(sk)))
+ 		return;
+ 
+-	if (so->ifindex != dev->ifindex)
++	if (so->dev != dev)
+ 		return;
+ 
+ 	switch (msg) {
+@@ -1559,10 +1700,12 @@ static void isotp_notify(struct isotp_sock *so, unsigned long msg,
+ 			can_rx_unregister(dev_net(dev), dev, so->txid,
+ 					  SINGLE_MASK(so->txid),
+ 					  isotp_rcv_echo, sk);
++			dev_put(so->dev);
+ 		}
+ 
+ 		so->ifindex = 0;
+ 		so->bound  = 0;
++		so->dev = NULL;
+ 		release_sock(sk);
+ 
+ 		sk->sk_err = ENODEV;
+@@ -1622,6 +1765,7 @@ static int isotp_init(struct sock *sk)
+ 
+ 	so->ifindex = 0;
+ 	so->bound = 0;
++	so->dev = NULL;
+ 
+ 	so->opt.flags = CAN_ISOTP_DEFAULT_FLAGS;
+ 	so->opt.ext_address = CAN_ISOTP_DEFAULT_EXT_ADDRESS;
+@@ -1652,6 +1796,8 @@ static int isotp_init(struct sock *sk)
+ 	so->rxtimer.function = isotp_rx_timer_handler;
+ 	hrtimer_init(&so->txtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+ 	so->txtimer.function = isotp_tx_timer_handler;
++	hrtimer_init(&so->echotimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
++	so->echotimer.function = isotp_echo_timer_handler;
+ 	hrtimer_init(&so->txfrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
+ 	so->txfrtimer.function = isotp_txfr_timer_handler;
+ 
+diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c
+index 6c37562a50f72e..d8dada03b3cd12 100644
+--- a/net/can/j1939/transport.c
++++ b/net/can/j1939/transport.c
+@@ -350,6 +350,18 @@ static void j1939_session_skb_drop_old(struct j1939_session *session)
+ 	}
+ }
+ 
++static bool j1939_address_is_local(struct j1939_priv *priv, u8 addr)
++{
++	bool local = false;
++
++	read_lock_bh(&priv->lock);
++	if (j1939_address_is_unicast(addr) && priv->ents[addr].nusers)
++		local = true;
++	read_unlock_bh(&priv->lock);
++
++	return local;
++}
++
+ void j1939_session_skb_queue(struct j1939_session *session,
+ 			     struct sk_buff *skb)
+ {
+@@ -358,8 +370,7 @@ void j1939_session_skb_queue(struct j1939_session *session,
+ 
+ 	j1939_ac_fixup(priv, skb);
+ 
+-	if (j1939_address_is_unicast(skcb->addr.da) &&
+-	    priv->ents[skcb->addr.da].nusers)
++	if (j1939_address_is_local(priv, skcb->addr.da))
+ 		skcb->flags |= J1939_ECU_LOCAL_DST;
+ 
+ 	skcb->flags |= J1939_ECU_LOCAL_SRC;
+@@ -2021,8 +2032,7 @@ struct j1939_session *j1939_tp_send(struct j1939_priv *priv,
+ 		return ERR_PTR(ret);
+ 
+ 	/* fix DST flags, it may be used there soon */
+-	if (j1939_address_is_unicast(skcb->addr.da) &&
+-	    priv->ents[skcb->addr.da].nusers)
++	if (j1939_address_is_local(priv, skcb->addr.da))
+ 		skcb->flags |= J1939_ECU_LOCAL_DST;
+ 
+ 	/* src is always local, I'm sending ... */
+diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
+index a21c157daf7dd3..c83559f015e465 100644
+--- a/net/ceph/auth_x.c
++++ b/net/ceph/auth_x.c
+@@ -781,9 +781,16 @@ static int ceph_x_update_authorizer(
+ 
+ 	au = (struct ceph_x_authorizer *)auth->authorizer;
+ 	if (au->secret_id < th->secret_id) {
++		int ret;
++
+ 		dout("ceph_x_update_authorizer service %u secret %llu < %llu\n",
+ 		     au->service, au->secret_id, th->secret_id);
+-		return ceph_x_build_authorizer(ac, th, au);
++		ret = ceph_x_build_authorizer(ac, th, au);
++		if (ret)
++			return ret;
++
++		auth->authorizer_buf = au->buf->vec.iov_base;
++		auth->authorizer_buf_len = au->buf->vec.iov_len;
+ 	}
+ 	return 0;
+ }
+diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
+index 285e981730e5cb..15bba470960d8b 100644
+--- a/net/ceph/ceph_common.c
++++ b/net/ceph/ceph_common.c
+@@ -763,13 +763,13 @@ void ceph_destroy_client(struct ceph_client *client)
+ 
+ 	atomic_set(&client->msgr.stopping, 1);
+ 
++	ceph_debugfs_client_cleanup(client);
++
+ 	/* unmount */
+ 	ceph_osdc_stop(&client->osdc);
+ 	ceph_monc_stop(&client->monc);
+ 	ceph_messenger_fini(&client->msgr);
+ 
+-	ceph_debugfs_client_cleanup(client);
+-
+ 	ceph_destroy_options(client->options);
+ 
+ 	kfree(client);
+diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c
+index 9608072863dc49..326a1f0eaa7264 100644
+--- a/net/ceph/mon_client.c
++++ b/net/ceph/mon_client.c
+@@ -114,7 +114,7 @@ static struct ceph_monmap *ceph_monmap_decode(void **p, void *end, bool msgr2)
+ 
+ 	dout("%s fsid %pU epoch %u num_mon %u\n", __func__, &fsid, epoch,
+ 	     num_mon);
+-	if (num_mon > CEPH_MAX_MON)
++	if (num_mon == 0 || num_mon > CEPH_MAX_MON)
+ 		goto e_inval;
+ 
+ 	monmap = kmalloc(struct_size(monmap, mon_inst, num_mon), GFP_NOIO);
+@@ -821,7 +821,7 @@ static void handle_get_version_reply(struct ceph_mon_client *monc,
+ 	struct ceph_mon_generic_request *req;
+ 	u64 tid = le64_to_cpu(msg->hdr.tid);
+ 	void *p = msg->front.iov_base;
+-	void *end = p + msg->front_alloc_len;
++	void *const end = p + msg->front.iov_len;
+ 	u64 handle;
+ 
+ 	dout("%s msg %p tid %llu\n", __func__, msg, tid);
+diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
+index c34a5bf86831b3..30d75970be4496 100644
+--- a/net/ceph/osdmap.c
++++ b/net/ceph/osdmap.c
+@@ -520,6 +520,8 @@ static struct crush_map *crush_decode(void *pbyval, void *end)
+ 		ceph_decode_need(p, end, 4*sizeof(u32), bad);
+ 		b->id = ceph_decode_32(p);
+ 		b->type = ceph_decode_16(p);
++		if (b->type == 0)
++			goto bad;
+ 		b->alg = ceph_decode_8(p);
+ 		if (b->alg != alg) {
+ 			b->alg = 0;
+@@ -1844,6 +1846,8 @@ static int decode_new_up_state_weight(void **p, void *end, u8 struct_v,
+ 	void *new_up_client;
+ 	void *new_state;
+ 	void *new_weight_end;
++	const u32 new_state_item_size =
++	    sizeof(u32) + (struct_v >= 5 ? sizeof(u32) : sizeof(u8));
+ 	u32 len;
+ 	int ret;
+ 	int i;
+@@ -1864,7 +1868,8 @@ static int decode_new_up_state_weight(void **p, void *end, u8 struct_v,
+ 
+ 	new_state = *p;
+ 	ceph_decode_32_safe(p, end, len, e_inval);
+-	len *= sizeof(u32) + (struct_v >= 5 ? sizeof(u32) : sizeof(u8));
++	if (check_mul_overflow(len, new_state_item_size, &len))
++		goto e_inval;
+ 	ceph_decode_need(p, end, len, e_inval);
+ 	*p += len;
+ 
+@@ -3057,8 +3062,11 @@ static int get_immediate_parent(struct crush_map *c, int id,
+ 			if (b->items[j] != id)
+ 				continue;
+ 
+-			*parent_type_id = b->type;
+ 			type_cn = lookup_crush_name(&c->type_names, b->type);
++			if (WARN_ON_ONCE(!type_cn))
++				continue;
++
++			*parent_type_id = b->type;
+ 			parent_loc->cl_type_name = type_cn->cn_name;
+ 			parent_loc->cl_name = cn->cn_name;
+ 			return b->id;
+diff --git a/net/core/sock_map.c b/net/core/sock_map.c
+index 3a53b6a0e76e2b..052057303cff11 100644
+--- a/net/core/sock_map.c
++++ b/net/core/sock_map.c
+@@ -539,6 +539,8 @@ static bool sock_map_sk_state_allowed(const struct sock *sk)
+ {
+ 	if (sk_is_tcp(sk))
+ 		return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN);
++	if (sk_is_udp(sk))
++		return sk_hashed(sk);
+ 	if (sk_is_stream_unix(sk))
+ 		return (1 << sk->sk_state) & TCPF_ESTABLISHED;
+ 	if (sk_is_vsock(sk) &&
+diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
+index b8230faa567f77..58e757dc555461 100644
+--- a/net/hsr/hsr_slave.c
++++ b/net/hsr/hsr_slave.c
+@@ -228,6 +228,8 @@ void hsr_del_port(struct hsr_port *port)
+ 		netdev_rx_handler_unregister(port->dev);
+ 		if (!port->hsr->fwd_offloaded)
+ 			dev_set_promiscuity(port->dev, -1);
++		if (port->type == HSR_PT_SLAVE_A || port->type == HSR_PT_SLAVE_B)
++			vlan_vids_del_by_dev(port->dev, master->dev);
+ 		netdev_upper_dev_unlink(port->dev, master->dev);
+ 	}
+ 
+diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
+index c9e1526e749b2b..53e7664eeb0a2a 100644
+--- a/net/ipv4/fib_trie.c
++++ b/net/ipv4/fib_trie.c
+@@ -1390,7 +1390,7 @@ succeeded:
+ out_remove_new_fa:
+ 	fib_remove_alias(t, tp, l, new_fa);
+ out_free_new_fa:
+-	kmem_cache_free(fn_alias_kmem, new_fa);
++	alias_free_mem_rcu(new_fa);
+ out:
+ 	fib_release_info(fi);
+ err:
+diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
+index 3fcf11f83d87bd..7c4c7b7fe38468 100644
+--- a/net/ipv4/icmp.c
++++ b/net/ipv4/icmp.c
+@@ -536,11 +536,23 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4,
+ 		if (IS_ERR(rt2))
+ 			err = PTR_ERR(rt2);
+ 	} else {
+-		struct flowi4 fl4_2 = {};
++		struct flowi4 fl4_2 = fl4_dec;
+ 		unsigned long orefdst;
+ 
+-		fl4_2.daddr = fl4_dec.saddr;
+-		rt2 = ip_route_output_key(net, &fl4_2);
++		swap(fl4_2.daddr, fl4_2.saddr);
++		switch (fl4_2.flowi4_proto) {
++		case IPPROTO_TCP:
++		case IPPROTO_UDP:
++		case IPPROTO_SCTP:
++		case IPPROTO_DCCP:
++			swap(fl4_2.fl4_sport, fl4_2.fl4_dport);
++			break;
++		}
++
++		fl4_2.flowi4_oif = l3mdev_master_ifindex(route_lookup_dev);
++		fl4_2.flowi4_flags |= FLOWI_FLAG_ANYSRC;
++
++		rt2 = __ip_route_output_key(net, &fl4_2);
+ 		if (IS_ERR(rt2)) {
+ 			err = PTR_ERR(rt2);
+ 			goto relookup_failed;
+diff --git a/net/ipv4/netfilter/nft_dup_ipv4.c b/net/ipv4/netfilter/nft_dup_ipv4.c
+index ef5dd88107ddbb..d53a65ddbd7b73 100644
+--- a/net/ipv4/netfilter/nft_dup_ipv4.c
++++ b/net/ipv4/netfilter/nft_dup_ipv4.c
+@@ -76,7 +76,6 @@ static const struct nft_expr_ops nft_dup_ipv4_ops = {
+ 	.eval		= nft_dup_ipv4_eval,
+ 	.init		= nft_dup_ipv4_init,
+ 	.dump		= nft_dup_ipv4_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static const struct nla_policy nft_dup_ipv4_policy[NFTA_DUP_MAX + 1] = {
+diff --git a/net/ipv4/netfilter/nft_fib_ipv4.c b/net/ipv4/netfilter/nft_fib_ipv4.c
+index 94931d52048f11..73f0446020faf2 100644
+--- a/net/ipv4/netfilter/nft_fib_ipv4.c
++++ b/net/ipv4/netfilter/nft_fib_ipv4.c
+@@ -157,7 +157,6 @@ static const struct nft_expr_ops nft_fib4_type_ops = {
+ 	.init		= nft_fib_init,
+ 	.dump		= nft_fib_dump,
+ 	.validate	= nft_fib_validate,
+-	.reduce		= nft_fib_reduce,
+ };
+ 
+ static const struct nft_expr_ops nft_fib4_ops = {
+@@ -167,7 +166,6 @@ static const struct nft_expr_ops nft_fib4_ops = {
+ 	.init		= nft_fib_init,
+ 	.dump		= nft_fib_dump,
+ 	.validate	= nft_fib_validate,
+-	.reduce		= nft_fib_reduce,
+ };
+ 
+ static const struct nft_expr_ops *
+diff --git a/net/ipv4/netfilter/nft_reject_ipv4.c b/net/ipv4/netfilter/nft_reject_ipv4.c
+index 6cb213bb7256a8..55fc23a8f7a706 100644
+--- a/net/ipv4/netfilter/nft_reject_ipv4.c
++++ b/net/ipv4/netfilter/nft_reject_ipv4.c
+@@ -45,7 +45,6 @@ static const struct nft_expr_ops nft_reject_ipv4_ops = {
+ 	.init		= nft_reject_init,
+ 	.dump		= nft_reject_dump,
+ 	.validate	= nft_reject_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_reject_ipv4_type __read_mostly = {
+diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
+index 4f30ddd2016b68..e751464f4fad9e 100644
+--- a/net/ipv4/nexthop.c
++++ b/net/ipv4/nexthop.c
+@@ -1527,8 +1527,8 @@ static bool nh_res_bucket_migrate(struct nh_res_table *res_table,
+ 				  bool notify_nl, bool force)
+ {
+ 	struct nh_res_bucket *bucket = &res_table->nh_buckets[bucket_index];
++	struct netlink_ext_ack extack = {};
+ 	struct nh_grp_entry *new_nhge;
+-	struct netlink_ext_ack extack;
+ 	int err;
+ 
+ 	new_nhge = list_first_entry_or_null(&res_table->uw_nh_entries,
+diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
+index da5e14ec8ed6da..337f6edd4757e3 100644
+--- a/net/ipv4/tcp_bpf.c
++++ b/net/ipv4/tcp_bpf.c
+@@ -590,7 +590,7 @@ wait_for_sndbuf:
+ wait_for_memory:
+ 		err = sk_stream_wait_memory(sk, &timeo);
+ 		if (err) {
+-			if (msg_tx && msg_tx != psock->cork)
++			if (msg_tx == &tmp)
+ 				sk_msg_free(sk, msg_tx);
+ 			goto out_err;
+ 		}
+diff --git a/net/ipv6/ila/ila_common.c b/net/ipv6/ila/ila_common.c
+index b8d43ed4689db9..ca54a227fc2f63 100644
+--- a/net/ipv6/ila/ila_common.c
++++ b/net/ipv6/ila/ila_common.c
+@@ -84,6 +84,7 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
+ 			struct tcphdr *th = (struct tcphdr *)
+ 					(skb_network_header(skb) + nhoff);
+ 
++			ip6h = ipv6_hdr(skb);
+ 			diff = get_csum_diff(ip6h, p);
+ 			inet_proto_csum_replace_by_diff(&th->check, skb,
+ 							diff, true, true);
+@@ -95,6 +96,7 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
+ 					(skb_network_header(skb) + nhoff);
+ 
+ 			if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
++				ip6h = ipv6_hdr(skb);
+ 				diff = get_csum_diff(ip6h, p);
+ 				inet_proto_csum_replace_by_diff(&uh->check, skb,
+ 								diff, true, true);
+@@ -109,6 +111,7 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
+ 			struct icmp6hdr *ih = (struct icmp6hdr *)
+ 					(skb_network_header(skb) + nhoff);
+ 
++			ip6h = ipv6_hdr(skb);
+ 			diff = get_csum_diff(ip6h, p);
+ 			inet_proto_csum_replace_by_diff(&ih->icmp6_cksum, skb,
+ 							diff, true, true);
+@@ -126,6 +129,15 @@ void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p,
+ 	switch (p->csum_mode) {
+ 	case ILA_CSUM_ADJUST_TRANSPORT:
+ 		ila_csum_adjust_transport(skb, p);
++		/*
++		 * ila_csum_adjust_transport() calls pskb_may_pull(), which can
++		 * reallocate the skb head and leave ip6h (and the iaddr derived
++		 * from it) dangling; reload both before the write below.  The
++		 * other csum modes do not pull, so their cached pointers stay
++		 * valid.
++		 */
++		ip6h = ipv6_hdr(skb);
++		iaddr = ila_a2i(&ip6h->daddr);
+ 		break;
+ 	case ILA_CSUM_NEUTRAL_MAP:
+ 		if (sir2ila) {
+diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
+index 5a2583a82f974f..825d40b505cde7 100644
+--- a/net/ipv6/ip6_tunnel.c
++++ b/net/ipv6/ip6_tunnel.c
+@@ -2055,6 +2055,9 @@ static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
+ 	struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
+ 	struct ip_tunnel_encap ipencap;
+ 
++	if (!rtnl_dev_link_net_capable(dev, net))
++		return -EPERM;
++
+ 	if (dev == ip6n->fb_tnl_dev)
+ 		return -EINVAL;
+ 
+diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
+index ee34831f5621a8..342e7066f765f5 100644
+--- a/net/ipv6/ndisc.c
++++ b/net/ipv6/ndisc.c
+@@ -973,10 +973,8 @@ out:
+ 	return reason;
+ }
+ 
+-static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
++static int accept_untracked_na(struct inet6_dev *idev, struct in6_addr *saddr)
+ {
+-	struct inet6_dev *idev = __in6_dev_get(dev);
+-
+ 	switch (READ_ONCE(idev->cnf.accept_untracked_na)) {
+ 	case 0: /* Don't accept untracked na (absent in neighbor cache) */
+ 		return 0;
+@@ -986,7 +984,7 @@ static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr)
+ 		 * same subnet as an address configured on the interface that
+ 		 * received the na
+ 		 */
+-		return !!ipv6_chk_prefix(saddr, dev);
++		return !!ipv6_chk_prefix(saddr, idev->dev);
+ 	default:
+ 		return 0;
+ 	}
+@@ -1085,7 +1083,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb)
+ 	 */
+ 	new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE;
+ 	if (!neigh && lladdr && idev && idev->cnf.forwarding) {
+-		if (accept_untracked_na(dev, saddr)) {
++		if (accept_untracked_na(idev, saddr)) {
+ 			neigh = neigh_create(&nd_tbl, &msg->target, dev);
+ 			new_state = NUD_STALE;
+ 		}
+diff --git a/net/ipv6/netfilter/nft_dup_ipv6.c b/net/ipv6/netfilter/nft_dup_ipv6.c
+index 492a811828a71b..95ec27b3971c11 100644
+--- a/net/ipv6/netfilter/nft_dup_ipv6.c
++++ b/net/ipv6/netfilter/nft_dup_ipv6.c
+@@ -74,7 +74,6 @@ static const struct nft_expr_ops nft_dup_ipv6_ops = {
+ 	.eval		= nft_dup_ipv6_eval,
+ 	.init		= nft_dup_ipv6_init,
+ 	.dump		= nft_dup_ipv6_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static const struct nla_policy nft_dup_ipv6_policy[NFTA_DUP_MAX + 1] = {
+diff --git a/net/ipv6/netfilter/nft_fib_ipv6.c b/net/ipv6/netfilter/nft_fib_ipv6.c
+index da4a35c20f1017..d600fd2d45a469 100644
+--- a/net/ipv6/netfilter/nft_fib_ipv6.c
++++ b/net/ipv6/netfilter/nft_fib_ipv6.c
+@@ -226,7 +226,6 @@ static const struct nft_expr_ops nft_fib6_type_ops = {
+ 	.init		= nft_fib_init,
+ 	.dump		= nft_fib_dump,
+ 	.validate	= nft_fib_validate,
+-	.reduce		= nft_fib_reduce,
+ };
+ 
+ static const struct nft_expr_ops nft_fib6_ops = {
+@@ -236,7 +235,6 @@ static const struct nft_expr_ops nft_fib6_ops = {
+ 	.init		= nft_fib_init,
+ 	.dump		= nft_fib_dump,
+ 	.validate	= nft_fib_validate,
+-	.reduce		= nft_fib_reduce,
+ };
+ 
+ static const struct nft_expr_ops *
+diff --git a/net/ipv6/netfilter/nft_reject_ipv6.c b/net/ipv6/netfilter/nft_reject_ipv6.c
+index 5c61294f410ee1..ed69c768797ec6 100644
+--- a/net/ipv6/netfilter/nft_reject_ipv6.c
++++ b/net/ipv6/netfilter/nft_reject_ipv6.c
+@@ -46,7 +46,6 @@ static const struct nft_expr_ops nft_reject_ipv6_ops = {
+ 	.init		= nft_reject_init,
+ 	.dump		= nft_reject_dump,
+ 	.validate	= nft_reject_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_reject_ipv6_type __read_mostly = {
+diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
+index 7d72633ea01982..95d7dd7a4d0483 100644
+--- a/net/ipv6/raw.c
++++ b/net/ipv6/raw.c
+@@ -341,7 +341,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr,
+ 		const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data;
+ 
+ 		if (!raw_v6_match(net, sk, nexthdr, &ip6h->saddr, &ip6h->daddr,
+-				  inet6_iif(skb), inet6_iif(skb)))
++				  inet6_iif(skb), inet6_sdif(skb)))
+ 			continue;
+ 		rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
+ 	}
+diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
+index e5d76e782b9613..6bf22fd9cd3802 100644
+--- a/net/ipv6/xfrm6_policy.c
++++ b/net/ipv6/xfrm6_policy.c
+@@ -88,6 +88,7 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
+ 	xdst->u.rt6.rt6i_idev = in6_dev_get(dev);
+ 	if (!xdst->u.rt6.rt6i_idev) {
+ 		netdev_put(dev, &xdst->u.dst.dev_tracker);
++		xdst->u.dst.dev = NULL;
+ 		return -ENODEV;
+ 	}
+ 
+diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
+index e9a9bb0dee065a..965167bf3abddc 100644
+--- a/net/iucv/af_iucv.c
++++ b/net/iucv/af_iucv.c
+@@ -334,6 +334,7 @@ static void iucv_sever_path(struct sock *sk, int with_user_data)
+ 	unsigned char user_data[16];
+ 	struct iucv_sock *iucv = iucv_sk(sk);
+ 	struct iucv_path *path = iucv->path;
++	struct sock_msg_q *p, *n;
+ 
+ 	/* Whoever resets the path pointer, must sever and free it. */
+ 	if (xchg(&iucv->path, NULL)) {
+@@ -345,6 +346,19 @@ static void iucv_sever_path(struct sock *sk, int with_user_data)
+ 		} else
+ 			pr_iucv->path_sever(path, NULL);
+ 		iucv_path_free(path);
++
++		/*
++		 * Message notifications queued on message_q still reference
++		 * the now freed path; drop them, otherwise a later recvmsg()
++		 * would pass the freed iucv_path to message_receive() via
++		 * iucv_process_message_q().
++		 */
++		spin_lock_bh(&iucv->message_q.lock);
++		list_for_each_entry_safe(p, n, &iucv->message_q.list, list) {
++			list_del(&p->list);
++			kfree(p);
++		}
++		spin_unlock_bh(&iucv->message_q.lock);
+ 	}
+ }
+ 
+@@ -1873,7 +1887,8 @@ static int afiucv_hs_callback_syn(struct sock *sk, struct sk_buff *skb)
+ 		afiucv_swap_src_dest(skb);
+ 		trans_hdr->flags = AF_IUCV_FLAG_SYN | AF_IUCV_FLAG_FIN;
+ 		err = dev_queue_xmit(skb);
+-		iucv_sock_kill(nsk);
++		if (nsk)
++			iucv_sock_kill(nsk);
+ 		bh_unlock_sock(sk);
+ 		goto out;
+ 	}
+@@ -2090,6 +2105,8 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
+ 			}
+ 		}
+ 	}
++	if (sk)
++		sock_hold(sk);
+ 	read_unlock(&iucv_sk_list.lock);
+ 	if (!iucv)
+ 		sk = NULL;
+@@ -2139,6 +2156,8 @@ static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
+ 		kfree_skb(skb);
+ 	}
+ 
++	if (sk)
++		sock_put(sk);
+ 	return err;
+ }
+ 
+diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
+index 34d8582c0c072e..2e856a83a7506b 100644
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -810,6 +810,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
+ 	po->chan.private = sk;
+ 	po->chan.ops	 = &pppol2tp_chan_ops;
+ 	po->chan.mtu	 = pppol2tp_tunnel_mtu(tunnel);
++	po->chan.direct_xmit	= true;
+ 
+ 	error = ppp_register_net_channel(sock_net(sk), &po->chan);
+ 	if (error) {
+diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
+index c8c53f4d1bdbfa..d4a554d6d5de5a 100644
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -591,6 +591,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
+ 		WARN_ON(!list_empty(&sdata->u.ap.vlans));
+ 	} else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+ 		/* remove all packets in parent bc_buf pointing to this dev */
++		__skb_queue_head_init(&freeq);
+ 		ps = &sdata->bss->ps;
+ 
+ 		spin_lock_irqsave(&ps->bc_buf.lock, flags);
+@@ -598,10 +599,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
+ 			if (skb->dev == sdata->dev) {
+ 				__skb_unlink(skb, &ps->bc_buf);
+ 				local->total_ps_buffered--;
+-				ieee80211_free_txskb(&local->hw, skb);
++				__skb_queue_tail(&freeq, skb);
+ 			}
+ 		}
+ 		spin_unlock_irqrestore(&ps->bc_buf.lock, flags);
++
++		skb_queue_walk_safe(&freeq, skb, tmp) {
++			__skb_unlink(skb, &freeq);
++			ieee80211_free_txskb(&local->hw, skb);
++		}
+ 	}
+ 
+ 	if (going_down)
+diff --git a/net/mac80211/link.c b/net/mac80211/link.c
+index 2b44f1fe2031a9..f3980ee8173967 100644
+--- a/net/mac80211/link.c
++++ b/net/mac80211/link.c
+@@ -281,6 +281,10 @@ static int ieee80211_vif_update_links(struct ieee80211_sub_if_data *sdata,
+ 		memcpy(sdata->link, old_data, sizeof(old_data));
+ 		memcpy(sdata->vif.link_conf, old, sizeof(old));
+ 		ieee80211_set_vif_links_bitmaps(sdata, old_links, dormant_links);
++		for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
++			ieee80211_link_debugfs_remove(&links[link_id]->data);
++			ieee80211_link_stop(&links[link_id]->data);
++		}
+ 		/* and free (only) the newly allocated links */
+ 		memset(to_free, 0, sizeof(links));
+ 		goto free;
+diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
+index a716a055bff9a4..b0f975dbdde0da 100644
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1568,6 +1568,8 @@ static void sta_ps_start(struct sta_info *sta)
+ 		else
+ 			clear_bit(tid, &sta->txq_buffered_tids);
+ 	}
++
++	sta_info_recalc_tim(sta);
+ }
+ 
+ static void sta_ps_end(struct sta_info *sta)
+diff --git a/net/mac802154/llsec.c b/net/mac802154/llsec.c
+index 09a47104b57727..a55fa5017e9301 100644
+--- a/net/mac802154/llsec.c
++++ b/net/mac802154/llsec.c
+@@ -891,6 +891,11 @@ llsec_do_decrypt_auth(struct sk_buff *skb, const struct mac802154_llsec *sec,
+ 	data = skb_mac_header(skb) + skb->mac_len;
+ 	datalen = skb_tail_pointer(skb) - data;
+ 
++	if (datalen < authlen) {
++		kfree_sensitive(req);
++		return -EBADMSG;
++	}
++
+ 	sg_init_one(&sg, skb_mac_header(skb), assoclen + datalen);
+ 
+ 	if (!(hdr->sec.level & IEEE802154_SCF_SECLEVEL_ENC)) {
+diff --git a/net/mac802154/scan.c b/net/mac802154/scan.c
+index c9f72f271c4ea1..087e32582dbbf9 100644
+--- a/net/mac802154/scan.c
++++ b/net/mac802154/scan.c
+@@ -179,6 +179,7 @@ void mac802154_scan_worker(struct work_struct *work)
+ 	enum nl802154_scan_types scan_req_type;
+ 	struct ieee802154_sub_if_data *sdata;
+ 	unsigned int scan_duration = 0;
++	netdevice_tracker dev_tracker;
+ 	struct wpan_phy *wpan_phy;
+ 	u8 scan_req_duration;
+ 	u8 page, channel;
+@@ -209,6 +210,14 @@ void mac802154_scan_worker(struct work_struct *work)
+ 		return;
+ 	}
+ 
++	/*
++	 * sdata->dev is dereferenced below after rcu_read_unlock() and outside
++	 * the rtnl, and a concurrent DEL_INTERFACE / PHY teardown can free it
++	 * asynchronously from netdev_run_todo(). Pin it with a reference taken
++	 * while the RCU read lock is still held, and drop it at every exit.
++	 */
++	netdev_hold(sdata->dev, &dev_tracker, GFP_ATOMIC);
++
+ 	wpan_phy = scan_req->wpan_phy;
+ 	scan_req_type = scan_req->type;
+ 	scan_req_duration = scan_req->duration;
+@@ -262,12 +271,14 @@ void mac802154_scan_worker(struct work_struct *work)
+ 		"Scan page %u channel %u for %ums\n",
+ 		page, channel, jiffies_to_msecs(scan_duration));
+ 	queue_delayed_work(local->mac_wq, &local->scan_work, scan_duration);
++	netdev_put(sdata->dev, &dev_tracker);
+ 	return;
+ 
+ end_scan:
+ 	rtnl_lock();
+ 	mac802154_scan_cleanup_locked(local, sdata, false);
+ 	rtnl_unlock();
++	netdev_put(sdata->dev, &dev_tracker);
+ }
+ 
+ int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
+diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
+index 0561a530ecf0d9..2099ce095edc8e 100644
+--- a/net/mpls/af_mpls.c
++++ b/net/mpls/af_mpls.c
+@@ -2125,6 +2125,9 @@ static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
+ 		int ifindex;
+ 
+ 		if (i == RTA_OIF) {
++			if (!tb[i])
++				continue;
++
+ 			ifindex = nla_get_u32(tb[i]);
+ 			filter->dev = __dev_get_by_index(net, ifindex);
+ 			if (!filter->dev)
+diff --git a/net/mptcp/options.c b/net/mptcp/options.c
+index bc30ceffd8db96..2d45d8dd592687 100644
+--- a/net/mptcp/options.c
++++ b/net/mptcp/options.c
+@@ -157,17 +157,11 @@ static void mptcp_parse_option(const struct sk_buff *skb,
+ 		ptr++;
+ 
+ 		flags = (*ptr++) & MPTCP_DSS_FLAG_MASK;
+-		mp_opt->data_fin = (flags & MPTCP_DSS_DATA_FIN) != 0;
+ 		mp_opt->dsn64 = (flags & MPTCP_DSS_DSN64) != 0;
+ 		mp_opt->use_map = (flags & MPTCP_DSS_HAS_MAP) != 0;
+ 		mp_opt->ack64 = (flags & MPTCP_DSS_ACK64) != 0;
+ 		mp_opt->use_ack = (flags & MPTCP_DSS_HAS_ACK);
+ 
+-		pr_debug("data_fin=%d dsn64=%d use_map=%d ack64=%d use_ack=%d\n",
+-			 mp_opt->data_fin, mp_opt->dsn64,
+-			 mp_opt->use_map, mp_opt->ack64,
+-			 mp_opt->use_ack);
+-
+ 		expected_opsize = TCPOLEN_MPTCP_DSS_BASE;
+ 
+ 		if (mp_opt->use_ack) {
+@@ -178,12 +172,18 @@ static void mptcp_parse_option(const struct sk_buff *skb,
+ 		}
+ 
+ 		if (mp_opt->use_map) {
++			mp_opt->data_fin = (flags & MPTCP_DSS_DATA_FIN) != 0;
+ 			if (mp_opt->dsn64)
+ 				expected_opsize += TCPOLEN_MPTCP_DSS_MAP64;
+ 			else
+ 				expected_opsize += TCPOLEN_MPTCP_DSS_MAP32;
+ 		}
+ 
++		pr_debug("data_fin=%d dsn64=%d use_map=%d ack64=%d use_ack=%d\n",
++			 mp_opt->data_fin, mp_opt->dsn64,
++			 mp_opt->use_map, mp_opt->ack64,
++			 mp_opt->use_ack);
++
+ 		/* Always parse any csum presence combination, we will enforce
+ 		 * RFC 8684 Section 3.3.0 checks later in subflow_data_ready
+ 		 */
+diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
+index 550a3c03961570..ef7479937ee566 100644
+--- a/net/mptcp/protocol.c
++++ b/net/mptcp/protocol.c
+@@ -3786,6 +3786,7 @@ bool mptcp_finish_join(struct sock *ssk)
+ 	mptcp_data_unlock(parent);
+ 
+ 	if (!ret) {
++		mptcp_pm_close_subflow(msk);
+ err_prohibited:
+ 		subflow->reset_reason = MPTCP_RST_EPROHIBIT;
+ 		return false;
+diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
+index ec31611b7a290b..bd91b8b47f4b75 100644
+--- a/net/netfilter/nf_conntrack_sip.c
++++ b/net/netfilter/nf_conntrack_sip.c
+@@ -947,10 +947,8 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
+ 			return NF_ACCEPT;
+ 		saddr = &ct->tuplehash[!dir].tuple.src.u3;
+ 	} else if (sip_external_media) {
+-		struct net_device *dev = skb_dst(skb)->dev;
+-		struct net *net = dev_net(dev);
+-		struct flowi fl;
+ 		struct dst_entry *dst = NULL;
++		struct flowi fl;
+ 
+ 		memset(&fl, 0, sizeof(fl));
+ 
+@@ -970,7 +968,11 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
+ 		 * through the same interface as the signalling peer.
+ 		 */
+ 		if (dst) {
+-			bool external_media = (dst->dev == dev);
++			const struct dst_entry *this_dst = skb_dst(skb);
++			bool external_media = false;
++
++			if (this_dst && dst->dev == this_dst->dev)
++				external_media = true;
+ 
+ 			dst_release(dst);
+ 			if (external_media)
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index c39fd25a9c9755..fb469623f9cf6c 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -754,58 +754,6 @@ static int nft_delflowtable(struct nft_ctx *ctx,
+ 	return 0;
+ }
+ 
+-static void __nft_reg_track_clobber(struct nft_regs_track *track, u8 dreg)
+-{
+-	int i;
+-
+-	for (i = track->regs[dreg].num_reg; i > 0; i--)
+-		__nft_reg_track_cancel(track, dreg - i);
+-}
+-
+-static void __nft_reg_track_update(struct nft_regs_track *track,
+-				   const struct nft_expr *expr,
+-				   u8 dreg, u8 num_reg)
+-{
+-	track->regs[dreg].selector = expr;
+-	track->regs[dreg].bitwise = NULL;
+-	track->regs[dreg].num_reg = num_reg;
+-}
+-
+-void nft_reg_track_update(struct nft_regs_track *track,
+-			  const struct nft_expr *expr, u8 dreg, u8 len)
+-{
+-	unsigned int regcount;
+-	int i;
+-
+-	__nft_reg_track_clobber(track, dreg);
+-
+-	regcount = DIV_ROUND_UP(len, NFT_REG32_SIZE);
+-	for (i = 0; i < regcount; i++, dreg++)
+-		__nft_reg_track_update(track, expr, dreg, i);
+-}
+-EXPORT_SYMBOL_GPL(nft_reg_track_update);
+-
+-void nft_reg_track_cancel(struct nft_regs_track *track, u8 dreg, u8 len)
+-{
+-	unsigned int regcount;
+-	int i;
+-
+-	__nft_reg_track_clobber(track, dreg);
+-
+-	regcount = DIV_ROUND_UP(len, NFT_REG32_SIZE);
+-	for (i = 0; i < regcount; i++, dreg++)
+-		__nft_reg_track_cancel(track, dreg);
+-}
+-EXPORT_SYMBOL_GPL(nft_reg_track_cancel);
+-
+-void __nft_reg_track_cancel(struct nft_regs_track *track, u8 dreg)
+-{
+-	track->regs[dreg].selector = NULL;
+-	track->regs[dreg].bitwise = NULL;
+-	track->regs[dreg].num_reg = 0;
+-}
+-EXPORT_SYMBOL_GPL(__nft_reg_track_cancel);
+-
+ /*
+  * Tables
+  */
+@@ -9638,16 +9586,9 @@ void nf_tables_trans_destroy_flush_work(void)
+ }
+ EXPORT_SYMBOL_GPL(nf_tables_trans_destroy_flush_work);
+ 
+-static bool nft_expr_reduce(struct nft_regs_track *track,
+-			    const struct nft_expr *expr)
+-{
+-	return false;
+-}
+-
+ static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *chain)
+ {
+ 	const struct nft_expr *expr, *last;
+-	struct nft_regs_track track = {};
+ 	unsigned int size, data_size;
+ 	void *data, *data_boundary;
+ 	struct nft_rule_dp *prule;
+@@ -9684,15 +9625,7 @@ static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *cha
+ 			return -ENOMEM;
+ 
+ 		size = 0;
+-		track.last = nft_expr_last(rule);
+ 		nft_rule_for_each_expr(expr, last, rule) {
+-			track.cur = expr;
+-
+-			if (nft_expr_reduce(&track, expr)) {
+-				expr = track.cur;
+-				continue;
+-			}
+-
+ 			if (WARN_ON_ONCE(data + size + expr->ops->size > data_boundary))
+ 				return -ENOMEM;
+ 
+diff --git a/net/netfilter/nft_bitwise.c b/net/netfilter/nft_bitwise.c
+index 1afb36fb5994db..e0a6703dc0e4a6 100644
+--- a/net/netfilter/nft_bitwise.c
++++ b/net/netfilter/nft_bitwise.c
+@@ -402,61 +402,12 @@ static int nft_bitwise_offload(struct nft_offload_ctx *ctx,
+ 	return 0;
+ }
+ 
+-static bool nft_bitwise_reduce(struct nft_regs_track *track,
+-			       const struct nft_expr *expr)
+-{
+-	const struct nft_bitwise *priv = nft_expr_priv(expr);
+-	const struct nft_bitwise *bitwise;
+-	unsigned int regcount;
+-	u8 dreg;
+-	int i;
+-
+-	if (!track->regs[priv->sreg].selector)
+-		return false;
+-
+-	bitwise = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (track->regs[priv->sreg].selector == track->regs[priv->dreg].selector &&
+-	    track->regs[priv->sreg].num_reg == 0 &&
+-	    track->regs[priv->dreg].bitwise &&
+-	    track->regs[priv->dreg].bitwise->ops == expr->ops &&
+-	    priv->sreg == bitwise->sreg &&
+-	    priv->sreg2 == bitwise->sreg2 &&
+-	    priv->dreg == bitwise->dreg &&
+-	    priv->op == bitwise->op &&
+-	    priv->len == bitwise->len &&
+-	    !memcmp(&priv->mask, &bitwise->mask, sizeof(priv->mask)) &&
+-	    !memcmp(&priv->xor, &bitwise->xor, sizeof(priv->xor)) &&
+-	    !memcmp(&priv->data, &bitwise->data, sizeof(priv->data))) {
+-		track->cur = expr;
+-		return true;
+-	}
+-
+-	if (track->regs[priv->sreg].bitwise ||
+-	    track->regs[priv->sreg].num_reg != 0) {
+-		nft_reg_track_cancel(track, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	if (priv->sreg != priv->dreg) {
+-		nft_reg_track_update(track, track->regs[priv->sreg].selector,
+-				     priv->dreg, priv->len);
+-	}
+-
+-	dreg = priv->dreg;
+-	regcount = DIV_ROUND_UP(priv->len, NFT_REG32_SIZE);
+-	for (i = 0; i < regcount; i++, dreg++)
+-		track->regs[dreg].bitwise = expr;
+-
+-	return false;
+-}
+-
+ static const struct nft_expr_ops nft_bitwise_ops = {
+ 	.type		= &nft_bitwise_type,
+ 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_bitwise)),
+ 	.eval		= nft_bitwise_eval,
+ 	.init		= nft_bitwise_init,
+ 	.dump		= nft_bitwise_dump,
+-	.reduce		= nft_bitwise_reduce,
+ 	.offload	= nft_bitwise_offload,
+ };
+ 
+@@ -559,48 +510,12 @@ static int nft_bitwise_fast_offload(struct nft_offload_ctx *ctx,
+ 	return 0;
+ }
+ 
+-static bool nft_bitwise_fast_reduce(struct nft_regs_track *track,
+-				    const struct nft_expr *expr)
+-{
+-	const struct nft_bitwise_fast_expr *priv = nft_expr_priv(expr);
+-	const struct nft_bitwise_fast_expr *bitwise;
+-
+-	if (!track->regs[priv->sreg].selector)
+-		return false;
+-
+-	bitwise = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (track->regs[priv->sreg].selector == track->regs[priv->dreg].selector &&
+-	    track->regs[priv->dreg].bitwise &&
+-	    track->regs[priv->dreg].bitwise->ops == expr->ops &&
+-	    priv->sreg == bitwise->sreg &&
+-	    priv->dreg == bitwise->dreg &&
+-	    priv->mask == bitwise->mask &&
+-	    priv->xor == bitwise->xor) {
+-		track->cur = expr;
+-		return true;
+-	}
+-
+-	if (track->regs[priv->sreg].bitwise) {
+-		nft_reg_track_cancel(track, priv->dreg, NFT_REG32_SIZE);
+-		return false;
+-	}
+-
+-	if (priv->sreg != priv->dreg) {
+-		track->regs[priv->dreg].selector =
+-			track->regs[priv->sreg].selector;
+-	}
+-	track->regs[priv->dreg].bitwise = expr;
+-
+-	return false;
+-}
+-
+ const struct nft_expr_ops nft_bitwise_fast_ops = {
+ 	.type		= &nft_bitwise_type,
+ 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_bitwise_fast_expr)),
+ 	.eval		= NULL, /* inlined */
+ 	.init		= nft_bitwise_fast_init,
+ 	.dump		= nft_bitwise_fast_dump,
+-	.reduce		= nft_bitwise_fast_reduce,
+ 	.offload	= nft_bitwise_fast_offload,
+ };
+ 
+@@ -637,22 +552,3 @@ struct nft_expr_type nft_bitwise_type __read_mostly = {
+ 	.maxattr	= NFTA_BITWISE_MAX,
+ 	.owner		= THIS_MODULE,
+ };
+-
+-bool nft_expr_reduce_bitwise(struct nft_regs_track *track,
+-			     const struct nft_expr *expr)
+-{
+-	const struct nft_expr *last = track->last;
+-	const struct nft_expr *next;
+-
+-	if (expr == last)
+-		return false;
+-
+-	next = nft_expr_next(expr);
+-	if (next->ops == &nft_bitwise_ops)
+-		return nft_bitwise_reduce(track, next);
+-	else if (next->ops == &nft_bitwise_fast_ops)
+-		return nft_bitwise_fast_reduce(track, next);
+-
+-	return false;
+-}
+-EXPORT_SYMBOL_GPL(nft_expr_reduce_bitwise);
+diff --git a/net/netfilter/nft_byteorder.c b/net/netfilter/nft_byteorder.c
+index 51f5de5c4ca363..baf677643008ed 100644
+--- a/net/netfilter/nft_byteorder.c
++++ b/net/netfilter/nft_byteorder.c
+@@ -177,23 +177,12 @@ nla_put_failure:
+ 	return -1;
+ }
+ 
+-static bool nft_byteorder_reduce(struct nft_regs_track *track,
+-				 const struct nft_expr *expr)
+-{
+-	struct nft_byteorder *priv = nft_expr_priv(expr);
+-
+-	nft_reg_track_cancel(track, priv->dreg, priv->len);
+-
+-	return false;
+-}
+-
+ static const struct nft_expr_ops nft_byteorder_ops = {
+ 	.type		= &nft_byteorder_type,
+ 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_byteorder)),
+ 	.eval		= nft_byteorder_eval,
+ 	.init		= nft_byteorder_init,
+ 	.dump		= nft_byteorder_dump,
+-	.reduce		= nft_byteorder_reduce,
+ };
+ 
+ struct nft_expr_type nft_byteorder_type __read_mostly = {
+diff --git a/net/netfilter/nft_cmp.c b/net/netfilter/nft_cmp.c
+index 2605f43737bc96..b61dc9c3383ee1 100644
+--- a/net/netfilter/nft_cmp.c
++++ b/net/netfilter/nft_cmp.c
+@@ -190,7 +190,6 @@ static const struct nft_expr_ops nft_cmp_ops = {
+ 	.eval		= nft_cmp_eval,
+ 	.init		= nft_cmp_init,
+ 	.dump		= nft_cmp_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ 	.offload	= nft_cmp_offload,
+ };
+ 
+@@ -282,7 +281,6 @@ const struct nft_expr_ops nft_cmp_fast_ops = {
+ 	.eval		= NULL,	/* inlined */
+ 	.init		= nft_cmp_fast_init,
+ 	.dump		= nft_cmp_fast_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ 	.offload	= nft_cmp_fast_offload,
+ };
+ 
+@@ -376,7 +374,6 @@ const struct nft_expr_ops nft_cmp16_fast_ops = {
+ 	.eval		= NULL,	/* inlined */
+ 	.init		= nft_cmp16_fast_init,
+ 	.dump		= nft_cmp16_fast_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ 	.offload	= nft_cmp16_fast_offload,
+ };
+ 
+diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c
+index 67a138b9be3a6b..0dd3379aef1649 100644
+--- a/net/netfilter/nft_compat.c
++++ b/net/netfilter/nft_compat.c
+@@ -794,14 +794,6 @@ static const struct nfnetlink_subsystem nfnl_compat_subsys = {
+ 
+ static struct nft_expr_type nft_match_type;
+ 
+-static bool nft_match_reduce(struct nft_regs_track *track,
+-			     const struct nft_expr *expr)
+-{
+-	const struct xt_match *match = expr->ops->data;
+-
+-	return strcmp(match->name, "comment") == 0;
+-}
+-
+ static const struct nft_expr_ops *
+ nft_match_select_ops(const struct nft_ctx *ctx,
+ 		     const struct nlattr * const tb[])
+@@ -844,7 +836,6 @@ nft_match_select_ops(const struct nft_ctx *ctx,
+ 	ops->dump = nft_match_dump;
+ 	ops->validate = nft_match_validate;
+ 	ops->data = match;
+-	ops->reduce = nft_match_reduce;
+ 
+ 	matchsize = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize));
+ 	if (matchsize > NFT_MATCH_LARGE_THRESH) {
+@@ -933,7 +924,6 @@ nft_target_select_ops(const struct nft_ctx *ctx,
+ 	ops->destroy = nft_target_destroy;
+ 	ops->dump = nft_target_dump;
+ 	ops->data = target;
+-	ops->reduce = NFT_REDUCE_READONLY;
+ 
+ 	if (family == NFPROTO_BRIDGE) {
+ 		ops->eval = nft_target_eval_bridge;
+diff --git a/net/netfilter/nft_connlimit.c b/net/netfilter/nft_connlimit.c
+index 5dd50b3ab5a452..18c439044d3ae7 100644
+--- a/net/netfilter/nft_connlimit.c
++++ b/net/netfilter/nft_connlimit.c
+@@ -247,7 +247,6 @@ static const struct nft_expr_ops nft_connlimit_ops = {
+ 	.destroy_clone	= nft_connlimit_destroy_clone,
+ 	.dump		= nft_connlimit_dump,
+ 	.gc		= nft_connlimit_gc,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_connlimit_type __read_mostly = {
+diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c
+index 0d70325280cc57..813c75cd2c259e 100644
+--- a/net/netfilter/nft_counter.c
++++ b/net/netfilter/nft_counter.c
+@@ -301,7 +301,6 @@ static const struct nft_expr_ops nft_counter_ops = {
+ 	.destroy_clone	= nft_counter_destroy,
+ 	.dump		= nft_counter_dump,
+ 	.clone		= nft_counter_clone,
+-	.reduce		= NFT_REDUCE_READONLY,
+ 	.offload	= nft_counter_offload,
+ 	.offload_stats	= nft_counter_offload_stats,
+ };
+diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
+index e83aa87a348e7d..1d1673f49ff751 100644
+--- a/net/netfilter/nft_ct.c
++++ b/net/netfilter/nft_ct.c
+@@ -679,29 +679,6 @@ nla_put_failure:
+ 	return -1;
+ }
+ 
+-static bool nft_ct_get_reduce(struct nft_regs_track *track,
+-			      const struct nft_expr *expr)
+-{
+-	const struct nft_ct *priv = nft_expr_priv(expr);
+-	const struct nft_ct *ct;
+-
+-	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	ct = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (priv->key != ct->key) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	if (!track->regs[priv->dreg].bitwise)
+-		return true;
+-
+-	return nft_expr_reduce_bitwise(track, expr);
+-}
+-
+ static int nft_ct_set_dump(struct sk_buff *skb,
+ 			   const struct nft_expr *expr, bool reset)
+ {
+@@ -736,27 +713,8 @@ static const struct nft_expr_ops nft_ct_get_ops = {
+ 	.init		= nft_ct_get_init,
+ 	.destroy	= nft_ct_get_destroy,
+ 	.dump		= nft_ct_get_dump,
+-	.reduce		= nft_ct_get_reduce,
+ };
+ 
+-static bool nft_ct_set_reduce(struct nft_regs_track *track,
+-			      const struct nft_expr *expr)
+-{
+-	int i;
+-
+-	for (i = 0; i < NFT_REG32_NUM; i++) {
+-		if (!track->regs[i].selector)
+-			continue;
+-
+-		if (track->regs[i].selector->ops != &nft_ct_get_ops)
+-			continue;
+-
+-		__nft_reg_track_cancel(track, i);
+-	}
+-
+-	return false;
+-}
+-
+ #ifdef CONFIG_RETPOLINE
+ static const struct nft_expr_ops nft_ct_get_fast_ops = {
+ 	.type		= &nft_ct_type,
+@@ -765,7 +723,6 @@ static const struct nft_expr_ops nft_ct_get_fast_ops = {
+ 	.init		= nft_ct_get_init,
+ 	.destroy	= nft_ct_get_destroy,
+ 	.dump		= nft_ct_get_dump,
+-	.reduce		= nft_ct_set_reduce,
+ };
+ #endif
+ 
+@@ -776,7 +733,6 @@ static const struct nft_expr_ops nft_ct_set_ops = {
+ 	.init		= nft_ct_set_init,
+ 	.destroy	= nft_ct_set_destroy,
+ 	.dump		= nft_ct_set_dump,
+-	.reduce		= nft_ct_set_reduce,
+ };
+ 
+ #ifdef CONFIG_NF_CONNTRACK_ZONES
+@@ -787,7 +743,6 @@ static const struct nft_expr_ops nft_ct_set_zone_ops = {
+ 	.init		= nft_ct_set_init,
+ 	.destroy	= nft_ct_set_destroy,
+ 	.dump		= nft_ct_set_dump,
+-	.reduce		= nft_ct_set_reduce,
+ };
+ #endif
+ 
+@@ -857,7 +812,6 @@ static const struct nft_expr_ops nft_notrack_ops = {
+ 	.type		= &nft_notrack_type,
+ 	.size		= NFT_EXPR_SIZE(0),
+ 	.eval		= nft_notrack_eval,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_notrack_type __read_mostly = {
+diff --git a/net/netfilter/nft_dup_netdev.c b/net/netfilter/nft_dup_netdev.c
+index 0573f96ce07913..06866799e9463e 100644
+--- a/net/netfilter/nft_dup_netdev.c
++++ b/net/netfilter/nft_dup_netdev.c
+@@ -80,7 +80,6 @@ static const struct nft_expr_ops nft_dup_netdev_ops = {
+ 	.eval		= nft_dup_netdev_eval,
+ 	.init		= nft_dup_netdev_init,
+ 	.dump		= nft_dup_netdev_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ 	.offload	= nft_dup_netdev_offload,
+ 	.offload_action	= nft_dup_netdev_offload_action,
+ };
+diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
+index 87c6a02675ba36..b1c6bb490d4624 100644
+--- a/net/netfilter/nft_dynset.c
++++ b/net/netfilter/nft_dynset.c
+@@ -430,7 +430,6 @@ static const struct nft_expr_ops nft_dynset_ops = {
+ 	.activate	= nft_dynset_activate,
+ 	.deactivate	= nft_dynset_deactivate,
+ 	.dump		= nft_dynset_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ struct nft_expr_type nft_dynset_type __read_mostly = {
+diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
+index cac46accf566b5..19d48577e77bd6 100644
+--- a/net/netfilter/nft_exthdr.c
++++ b/net/netfilter/nft_exthdr.c
+@@ -701,40 +701,12 @@ static int nft_exthdr_dump_strip(struct sk_buff *skb,
+ 	return nft_exthdr_dump_common(skb, priv);
+ }
+ 
+-static bool nft_exthdr_reduce(struct nft_regs_track *track,
+-			       const struct nft_expr *expr)
+-{
+-	const struct nft_exthdr *priv = nft_expr_priv(expr);
+-	const struct nft_exthdr *exthdr;
+-
+-	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	exthdr = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (priv->type != exthdr->type ||
+-	    priv->op != exthdr->op ||
+-	    priv->flags != exthdr->flags ||
+-	    priv->offset != exthdr->offset ||
+-	    priv->len != exthdr->len) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	if (!track->regs[priv->dreg].bitwise)
+-		return true;
+-
+-	return nft_expr_reduce_bitwise(track, expr);
+-}
+-
+ static const struct nft_expr_ops nft_exthdr_ipv6_ops = {
+ 	.type		= &nft_exthdr_type,
+ 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
+ 	.eval		= nft_exthdr_ipv6_eval,
+ 	.init		= nft_exthdr_init,
+ 	.dump		= nft_exthdr_dump,
+-	.reduce		= nft_exthdr_reduce,
+ };
+ 
+ static const struct nft_expr_ops nft_exthdr_ipv4_ops = {
+@@ -743,7 +715,6 @@ static const struct nft_expr_ops nft_exthdr_ipv4_ops = {
+ 	.eval		= nft_exthdr_ipv4_eval,
+ 	.init		= nft_exthdr_ipv4_init,
+ 	.dump		= nft_exthdr_dump,
+-	.reduce		= nft_exthdr_reduce,
+ };
+ 
+ static const struct nft_expr_ops nft_exthdr_tcp_ops = {
+@@ -752,7 +723,6 @@ static const struct nft_expr_ops nft_exthdr_tcp_ops = {
+ 	.eval		= nft_exthdr_tcp_eval,
+ 	.init		= nft_exthdr_init,
+ 	.dump		= nft_exthdr_dump,
+-	.reduce		= nft_exthdr_reduce,
+ };
+ 
+ static const struct nft_expr_ops nft_exthdr_tcp_set_ops = {
+@@ -761,7 +731,6 @@ static const struct nft_expr_ops nft_exthdr_tcp_set_ops = {
+ 	.eval		= nft_exthdr_tcp_set_eval,
+ 	.init		= nft_exthdr_tcp_set_init,
+ 	.dump		= nft_exthdr_dump_set,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static const struct nft_expr_ops nft_exthdr_tcp_strip_ops = {
+@@ -770,7 +739,6 @@ static const struct nft_expr_ops nft_exthdr_tcp_strip_ops = {
+ 	.eval		= nft_exthdr_tcp_strip_eval,
+ 	.init		= nft_exthdr_tcp_strip_init,
+ 	.dump		= nft_exthdr_dump_strip,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static const struct nft_expr_ops nft_exthdr_sctp_ops = {
+@@ -779,7 +747,6 @@ static const struct nft_expr_ops nft_exthdr_sctp_ops = {
+ 	.eval		= nft_exthdr_sctp_eval,
+ 	.init		= nft_exthdr_init,
+ 	.dump		= nft_exthdr_dump,
+-	.reduce		= nft_exthdr_reduce,
+ };
+ 
+ static const struct nft_expr_ops nft_exthdr_dccp_ops = {
+@@ -788,7 +755,6 @@ static const struct nft_expr_ops nft_exthdr_dccp_ops = {
+ 	.eval		= nft_exthdr_dccp_eval,
+ 	.init		= nft_exthdr_dccp_init,
+ 	.dump		= nft_exthdr_dump,
+-	.reduce		= nft_exthdr_reduce,
+ };
+ 
+ static const struct nft_expr_ops *
+diff --git a/net/netfilter/nft_fib.c b/net/netfilter/nft_fib.c
+index b4f49f65fc42fd..016957296db29c 100644
+--- a/net/netfilter/nft_fib.c
++++ b/net/netfilter/nft_fib.c
+@@ -31,6 +31,15 @@ int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr)
+ 	const struct nft_fib *priv = nft_expr_priv(expr);
+ 	unsigned int hooks;
+ 
++	switch (ctx->family) {
++	case NFPROTO_IPV4:
++	case NFPROTO_IPV6:
++	case NFPROTO_INET:
++		break;
++	default:
++		return -EOPNOTSUPP;
++	}
++
+ 	switch (priv->result) {
+ 	case NFT_FIB_RESULT_OIF:
+ 	case NFT_FIB_RESULT_OIFNAME:
+@@ -168,47 +177,5 @@ void nft_fib_store_result(void *reg, const struct nft_fib *priv,
+ }
+ EXPORT_SYMBOL_GPL(nft_fib_store_result);
+ 
+-bool nft_fib_reduce(struct nft_regs_track *track,
+-		    const struct nft_expr *expr)
+-{
+-	const struct nft_fib *priv = nft_expr_priv(expr);
+-	unsigned int len = NFT_REG32_SIZE;
+-	const struct nft_fib *fib;
+-
+-	switch (priv->result) {
+-	case NFT_FIB_RESULT_OIF:
+-		break;
+-	case NFT_FIB_RESULT_OIFNAME:
+-		if (priv->flags & NFTA_FIB_F_PRESENT)
+-			len = NFT_REG32_SIZE;
+-		else
+-			len = IFNAMSIZ;
+-		break;
+-	case NFT_FIB_RESULT_ADDRTYPE:
+-	     break;
+-	default:
+-		WARN_ON_ONCE(1);
+-		break;
+-	}
+-
+-	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
+-		nft_reg_track_update(track, expr, priv->dreg, len);
+-		return false;
+-	}
+-
+-	fib = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (priv->result != fib->result ||
+-	    priv->flags != fib->flags) {
+-		nft_reg_track_update(track, expr, priv->dreg, len);
+-		return false;
+-	}
+-
+-	if (!track->regs[priv->dreg].bitwise)
+-		return true;
+-
+-	return false;
+-}
+-EXPORT_SYMBOL_GPL(nft_fib_reduce);
+-
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Florian Westphal <[email protected]>");
+diff --git a/net/netfilter/nft_fib_inet.c b/net/netfilter/nft_fib_inet.c
+index 666a3741d20b6d..a88d44e163d19e 100644
+--- a/net/netfilter/nft_fib_inet.c
++++ b/net/netfilter/nft_fib_inet.c
+@@ -49,7 +49,6 @@ static const struct nft_expr_ops nft_fib_inet_ops = {
+ 	.init		= nft_fib_init,
+ 	.dump		= nft_fib_dump,
+ 	.validate	= nft_fib_validate,
+-	.reduce		= nft_fib_reduce,
+ };
+ 
+ static struct nft_expr_type nft_fib_inet_type __read_mostly = {
+diff --git a/net/netfilter/nft_fib_netdev.c b/net/netfilter/nft_fib_netdev.c
+index 9121ec64e918f4..5774a754402780 100644
+--- a/net/netfilter/nft_fib_netdev.c
++++ b/net/netfilter/nft_fib_netdev.c
+@@ -50,6 +50,33 @@ static void nft_fib_netdev_eval(const struct nft_expr *expr,
+ 	regs->verdict.code = NFT_BREAK;
+ }
+ 
++static int nft_fib_netdev_validate(const struct nft_ctx *ctx,
++				   const struct nft_expr *expr)
++{
++	const struct nft_fib *priv = nft_expr_priv(expr);
++	unsigned int hooks;
++
++	switch (priv->result) {
++	case NFT_FIB_RESULT_OIF:
++	case NFT_FIB_RESULT_OIFNAME:
++		hooks = (1 << NF_NETDEV_INGRESS);
++		break;
++	case NFT_FIB_RESULT_ADDRTYPE:
++		if (priv->flags & NFTA_FIB_F_IIF)
++			hooks = (1 << NF_NETDEV_INGRESS);
++		else if (priv->flags & NFTA_FIB_F_OIF)
++			hooks = (1 << NF_NETDEV_EGRESS);
++		else
++			hooks = (1 << NF_NETDEV_INGRESS) |
++				(1 << NF_NETDEV_EGRESS);
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	return nft_chain_validate_hooks(ctx->chain, hooks);
++}
++
+ static struct nft_expr_type nft_fib_netdev_type;
+ static const struct nft_expr_ops nft_fib_netdev_ops = {
+ 	.type		= &nft_fib_netdev_type,
+@@ -57,8 +84,7 @@ static const struct nft_expr_ops nft_fib_netdev_ops = {
+ 	.eval		= nft_fib_netdev_eval,
+ 	.init		= nft_fib_init,
+ 	.dump		= nft_fib_dump,
+-	.validate	= nft_fib_validate,
+-	.reduce		= nft_fib_reduce,
++	.validate	= nft_fib_netdev_validate,
+ };
+ 
+ static struct nft_expr_type nft_fib_netdev_type __read_mostly = {
+diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
+index 75dddcaa9aa37f..2df9178d423a6c 100644
+--- a/net/netfilter/nft_flow_offload.c
++++ b/net/netfilter/nft_flow_offload.c
+@@ -481,7 +481,6 @@ static const struct nft_expr_ops nft_flow_offload_ops = {
+ 	.destroy	= nft_flow_offload_destroy,
+ 	.validate	= nft_flow_offload_validate,
+ 	.dump		= nft_flow_offload_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_flow_offload_type __read_mostly = {
+diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c
+index 1223bdea1f00d4..f6c4b3356696f1 100644
+--- a/net/netfilter/nft_fwd_netdev.c
++++ b/net/netfilter/nft_fwd_netdev.c
+@@ -228,7 +228,6 @@ static const struct nft_expr_ops nft_fwd_neigh_netdev_ops = {
+ 	.init		= nft_fwd_neigh_init,
+ 	.dump		= nft_fwd_neigh_dump,
+ 	.validate	= nft_fwd_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static const struct nft_expr_ops nft_fwd_netdev_ops = {
+@@ -238,7 +237,6 @@ static const struct nft_expr_ops nft_fwd_netdev_ops = {
+ 	.init		= nft_fwd_netdev_init,
+ 	.dump		= nft_fwd_netdev_dump,
+ 	.validate	= nft_fwd_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ 	.offload	= nft_fwd_netdev_offload,
+ 	.offload_action	= nft_fwd_netdev_offload_action,
+ };
+diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c
+index c91f2bef58694e..722836b2c37720 100644
+--- a/net/netfilter/nft_hash.c
++++ b/net/netfilter/nft_hash.c
+@@ -165,16 +165,6 @@ nla_put_failure:
+ 	return -1;
+ }
+ 
+-static bool nft_jhash_reduce(struct nft_regs_track *track,
+-			     const struct nft_expr *expr)
+-{
+-	const struct nft_jhash *priv = nft_expr_priv(expr);
+-
+-	nft_reg_track_cancel(track, priv->dreg, sizeof(u32));
+-
+-	return false;
+-}
+-
+ static int nft_symhash_dump(struct sk_buff *skb,
+ 			    const struct nft_expr *expr, bool reset)
+ {
+@@ -195,30 +185,6 @@ nla_put_failure:
+ 	return -1;
+ }
+ 
+-static bool nft_symhash_reduce(struct nft_regs_track *track,
+-			       const struct nft_expr *expr)
+-{
+-	struct nft_symhash *priv = nft_expr_priv(expr);
+-	struct nft_symhash *symhash;
+-
+-	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
+-		nft_reg_track_update(track, expr, priv->dreg, sizeof(u32));
+-		return false;
+-	}
+-
+-	symhash = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (priv->offset != symhash->offset ||
+-	    priv->modulus != symhash->modulus) {
+-		nft_reg_track_update(track, expr, priv->dreg, sizeof(u32));
+-		return false;
+-	}
+-
+-	if (!track->regs[priv->dreg].bitwise)
+-		return true;
+-
+-	return false;
+-}
+-
+ static struct nft_expr_type nft_hash_type;
+ static const struct nft_expr_ops nft_jhash_ops = {
+ 	.type		= &nft_hash_type,
+@@ -226,7 +192,6 @@ static const struct nft_expr_ops nft_jhash_ops = {
+ 	.eval		= nft_jhash_eval,
+ 	.init		= nft_jhash_init,
+ 	.dump		= nft_jhash_dump,
+-	.reduce		= nft_jhash_reduce,
+ };
+ 
+ static const struct nft_expr_ops nft_symhash_ops = {
+@@ -235,7 +200,6 @@ static const struct nft_expr_ops nft_symhash_ops = {
+ 	.eval		= nft_symhash_eval,
+ 	.init		= nft_symhash_init,
+ 	.dump		= nft_symhash_dump,
+-	.reduce		= nft_symhash_reduce,
+ };
+ 
+ static const struct nft_expr_ops *
+diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c
+index 02ee5fb69871f8..37c29947b380b4 100644
+--- a/net/netfilter/nft_immediate.c
++++ b/net/netfilter/nft_immediate.c
+@@ -320,17 +320,6 @@ static bool nft_immediate_offload_action(const struct nft_expr *expr)
+ 	return false;
+ }
+ 
+-static bool nft_immediate_reduce(struct nft_regs_track *track,
+-				 const struct nft_expr *expr)
+-{
+-	const struct nft_immediate_expr *priv = nft_expr_priv(expr);
+-
+-	if (priv->dreg != NFT_REG_VERDICT)
+-		nft_reg_track_cancel(track, priv->dreg, priv->dlen);
+-
+-	return false;
+-}
+-
+ static const struct nft_expr_ops nft_imm_ops = {
+ 	.type		= &nft_imm_type,
+ 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
+@@ -341,7 +330,6 @@ static const struct nft_expr_ops nft_imm_ops = {
+ 	.destroy	= nft_immediate_destroy,
+ 	.dump		= nft_immediate_dump,
+ 	.validate	= nft_immediate_validate,
+-	.reduce		= nft_immediate_reduce,
+ 	.offload	= nft_immediate_offload,
+ 	.offload_action	= nft_immediate_offload_action,
+ };
+diff --git a/net/netfilter/nft_last.c b/net/netfilter/nft_last.c
+index de1b6066bfa856..e845779268d3a9 100644
+--- a/net/netfilter/nft_last.c
++++ b/net/netfilter/nft_last.c
+@@ -125,7 +125,6 @@ static const struct nft_expr_ops nft_last_ops = {
+ 	.destroy	= nft_last_destroy,
+ 	.clone		= nft_last_clone,
+ 	.dump		= nft_last_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ struct nft_expr_type nft_last_type __read_mostly = {
+diff --git a/net/netfilter/nft_limit.c b/net/netfilter/nft_limit.c
+index 21d26b79b46072..0daeb0b23c2052 100644
+--- a/net/netfilter/nft_limit.c
++++ b/net/netfilter/nft_limit.c
+@@ -243,7 +243,6 @@ static const struct nft_expr_ops nft_limit_pkts_ops = {
+ 	.destroy	= nft_limit_pkts_destroy,
+ 	.clone		= nft_limit_pkts_clone,
+ 	.dump		= nft_limit_pkts_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static void nft_limit_bytes_eval(const struct nft_expr *expr,
+@@ -299,7 +298,6 @@ static const struct nft_expr_ops nft_limit_bytes_ops = {
+ 	.dump		= nft_limit_bytes_dump,
+ 	.clone		= nft_limit_bytes_clone,
+ 	.destroy	= nft_limit_bytes_destroy,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static const struct nft_expr_ops *
+diff --git a/net/netfilter/nft_log.c b/net/netfilter/nft_log.c
+index bf01cf8a8907b5..da0c0d1c9cea28 100644
+--- a/net/netfilter/nft_log.c
++++ b/net/netfilter/nft_log.c
+@@ -235,7 +235,6 @@ static const struct nft_expr_ops nft_log_ops = {
+ 	.init		= nft_log_init,
+ 	.destroy	= nft_log_destroy,
+ 	.dump		= nft_log_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_log_type __read_mostly = {
+diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
+index aeaf6988efd672..c56cc6f3f8fad3 100644
+--- a/net/netfilter/nft_lookup.c
++++ b/net/netfilter/nft_lookup.c
+@@ -232,17 +232,6 @@ static int nft_lookup_validate(const struct nft_ctx *ctx,
+ 	return 0;
+ }
+ 
+-static bool nft_lookup_reduce(struct nft_regs_track *track,
+-			      const struct nft_expr *expr)
+-{
+-	const struct nft_lookup *priv = nft_expr_priv(expr);
+-
+-	if (priv->set->flags & NFT_SET_MAP)
+-		nft_reg_track_cancel(track, priv->dreg, priv->set->dlen);
+-
+-	return false;
+-}
+-
+ static const struct nft_expr_ops nft_lookup_ops = {
+ 	.type		= &nft_lookup_type,
+ 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_lookup)),
+@@ -253,7 +242,6 @@ static const struct nft_expr_ops nft_lookup_ops = {
+ 	.destroy	= nft_lookup_destroy,
+ 	.dump		= nft_lookup_dump,
+ 	.validate	= nft_lookup_validate,
+-	.reduce		= nft_lookup_reduce,
+ };
+ 
+ struct nft_expr_type nft_lookup_type __read_mostly = {
+diff --git a/net/netfilter/nft_masq.c b/net/netfilter/nft_masq.c
+index 868bd4d7355553..2b01128737a3a8 100644
+--- a/net/netfilter/nft_masq.c
++++ b/net/netfilter/nft_masq.c
+@@ -143,7 +143,6 @@ static const struct nft_expr_ops nft_masq_ipv4_ops = {
+ 	.destroy	= nft_masq_ipv4_destroy,
+ 	.dump		= nft_masq_dump,
+ 	.validate	= nft_masq_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_masq_ipv4_type __read_mostly = {
+@@ -171,7 +170,6 @@ static const struct nft_expr_ops nft_masq_ipv6_ops = {
+ 	.destroy	= nft_masq_ipv6_destroy,
+ 	.dump		= nft_masq_dump,
+ 	.validate	= nft_masq_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
+@@ -213,7 +211,6 @@ static const struct nft_expr_ops nft_masq_inet_ops = {
+ 	.destroy	= nft_masq_inet_destroy,
+ 	.dump		= nft_masq_dump,
+ 	.validate	= nft_masq_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_masq_inet_type __read_mostly = {
+diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
+index 05cd1e6e6a2f61..983158274c68dc 100644
+--- a/net/netfilter/nft_meta.c
++++ b/net/netfilter/nft_meta.c
+@@ -742,60 +742,16 @@ static int nft_meta_get_offload(struct nft_offload_ctx *ctx,
+ 	return 0;
+ }
+ 
+-bool nft_meta_get_reduce(struct nft_regs_track *track,
+-			 const struct nft_expr *expr)
+-{
+-	const struct nft_meta *priv = nft_expr_priv(expr);
+-	const struct nft_meta *meta;
+-
+-	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	meta = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (priv->key != meta->key ||
+-	    priv->dreg != meta->dreg) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	if (!track->regs[priv->dreg].bitwise)
+-		return true;
+-
+-	return nft_expr_reduce_bitwise(track, expr);
+-}
+-EXPORT_SYMBOL_GPL(nft_meta_get_reduce);
+-
+ static const struct nft_expr_ops nft_meta_get_ops = {
+ 	.type		= &nft_meta_type,
+ 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_meta)),
+ 	.eval		= nft_meta_get_eval,
+ 	.init		= nft_meta_get_init,
+ 	.dump		= nft_meta_get_dump,
+-	.reduce		= nft_meta_get_reduce,
+ 	.validate	= nft_meta_get_validate,
+ 	.offload	= nft_meta_get_offload,
+ };
+ 
+-static bool nft_meta_set_reduce(struct nft_regs_track *track,
+-				const struct nft_expr *expr)
+-{
+-	int i;
+-
+-	for (i = 0; i < NFT_REG32_NUM; i++) {
+-		if (!track->regs[i].selector)
+-			continue;
+-
+-		if (track->regs[i].selector->ops != &nft_meta_get_ops)
+-			continue;
+-
+-		__nft_reg_track_cancel(track, i);
+-	}
+-
+-	return false;
+-}
+-
+ static const struct nft_expr_ops nft_meta_set_ops = {
+ 	.type		= &nft_meta_type,
+ 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_meta)),
+@@ -803,7 +759,6 @@ static const struct nft_expr_ops nft_meta_set_ops = {
+ 	.init		= nft_meta_set_init,
+ 	.destroy	= nft_meta_set_destroy,
+ 	.dump		= nft_meta_set_dump,
+-	.reduce		= nft_meta_set_reduce,
+ 	.validate	= nft_meta_set_validate,
+ };
+ 
+diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c
+index 6e21f72c5b5741..e32cd9fbc7c2ec 100644
+--- a/net/netfilter/nft_nat.c
++++ b/net/netfilter/nft_nat.c
+@@ -320,7 +320,6 @@ static const struct nft_expr_ops nft_nat_ops = {
+ 	.destroy        = nft_nat_destroy,
+ 	.dump           = nft_nat_dump,
+ 	.validate	= nft_nat_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_nat_type __read_mostly = {
+@@ -351,7 +350,6 @@ static const struct nft_expr_ops nft_nat_inet_ops = {
+ 	.destroy        = nft_nat_destroy,
+ 	.dump           = nft_nat_dump,
+ 	.validate	= nft_nat_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_inet_nat_type __read_mostly = {
+diff --git a/net/netfilter/nft_numgen.c b/net/netfilter/nft_numgen.c
+index bd058babfc820c..06e87dfd76e741 100644
+--- a/net/netfilter/nft_numgen.c
++++ b/net/netfilter/nft_numgen.c
+@@ -84,16 +84,6 @@ err:
+ 	return err;
+ }
+ 
+-static bool nft_ng_inc_reduce(struct nft_regs_track *track,
+-				 const struct nft_expr *expr)
+-{
+-	const struct nft_ng_inc *priv = nft_expr_priv(expr);
+-
+-	nft_reg_track_cancel(track, priv->dreg, NFT_REG32_SIZE);
+-
+-	return false;
+-}
+-
+ static int nft_ng_dump(struct sk_buff *skb, enum nft_registers dreg,
+ 		       u32 modulus, enum nft_ng_types type, u32 offset)
+ {
+@@ -178,16 +168,6 @@ static int nft_ng_random_dump(struct sk_buff *skb,
+ 			   priv->offset);
+ }
+ 
+-static bool nft_ng_random_reduce(struct nft_regs_track *track,
+-				 const struct nft_expr *expr)
+-{
+-	const struct nft_ng_random *priv = nft_expr_priv(expr);
+-
+-	nft_reg_track_cancel(track, priv->dreg, NFT_REG32_SIZE);
+-
+-	return false;
+-}
+-
+ static struct nft_expr_type nft_ng_type;
+ static const struct nft_expr_ops nft_ng_inc_ops = {
+ 	.type		= &nft_ng_type,
+@@ -196,7 +176,6 @@ static const struct nft_expr_ops nft_ng_inc_ops = {
+ 	.init		= nft_ng_inc_init,
+ 	.destroy	= nft_ng_inc_destroy,
+ 	.dump		= nft_ng_inc_dump,
+-	.reduce		= nft_ng_inc_reduce,
+ };
+ 
+ static const struct nft_expr_ops nft_ng_random_ops = {
+@@ -205,7 +184,6 @@ static const struct nft_expr_ops nft_ng_random_ops = {
+ 	.eval		= nft_ng_random_eval,
+ 	.init		= nft_ng_random_init,
+ 	.dump		= nft_ng_random_dump,
+-	.reduce		= nft_ng_random_reduce,
+ };
+ 
+ static const struct nft_expr_ops *
+diff --git a/net/netfilter/nft_objref.c b/net/netfilter/nft_objref.c
+index 1ee17098de0c44..8228dc4369de99 100644
+--- a/net/netfilter/nft_objref.c
++++ b/net/netfilter/nft_objref.c
+@@ -123,7 +123,6 @@ static const struct nft_expr_ops nft_objref_ops = {
+ 	.deactivate	= nft_objref_deactivate,
+ 	.dump		= nft_objref_dump,
+ 	.validate	= nft_objref_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ struct nft_objref_map {
+@@ -246,7 +245,6 @@ static const struct nft_expr_ops nft_objref_map_ops = {
+ 	.destroy	= nft_objref_map_destroy,
+ 	.dump		= nft_objref_map_dump,
+ 	.validate	= nft_objref_map_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static const struct nft_expr_ops *
+diff --git a/net/netfilter/nft_osf.c b/net/netfilter/nft_osf.c
+index 23ec9b397f1ebc..66c8ddd2963571 100644
+--- a/net/netfilter/nft_osf.c
++++ b/net/netfilter/nft_osf.c
+@@ -136,30 +136,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx,
+ 	return nft_chain_validate_hooks(ctx->chain, hooks);
+ }
+ 
+-static bool nft_osf_reduce(struct nft_regs_track *track,
+-			   const struct nft_expr *expr)
+-{
+-	struct nft_osf *priv = nft_expr_priv(expr);
+-	struct nft_osf *osf;
+-
+-	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
+-		nft_reg_track_update(track, expr, priv->dreg, NFT_OSF_MAXGENRELEN);
+-		return false;
+-	}
+-
+-	osf = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (priv->flags != osf->flags ||
+-	    priv->ttl != osf->ttl) {
+-		nft_reg_track_update(track, expr, priv->dreg, NFT_OSF_MAXGENRELEN);
+-		return false;
+-	}
+-
+-	if (!track->regs[priv->dreg].bitwise)
+-		return true;
+-
+-	return false;
+-}
+-
+ static struct nft_expr_type nft_osf_type;
+ static const struct nft_expr_ops nft_osf_op = {
+ 	.eval		= nft_osf_eval,
+@@ -168,7 +144,6 @@ static const struct nft_expr_ops nft_osf_op = {
+ 	.dump		= nft_osf_dump,
+ 	.type		= &nft_osf_type,
+ 	.validate	= nft_osf_validate,
+-	.reduce		= nft_osf_reduce,
+ };
+ 
+ static struct nft_expr_type nft_osf_type __read_mostly = {
+diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
+index 7dfc5343dae46f..36c31ad2d64c14 100644
+--- a/net/netfilter/nft_payload.c
++++ b/net/netfilter/nft_payload.c
+@@ -250,31 +250,6 @@ nla_put_failure:
+ 	return -1;
+ }
+ 
+-static bool nft_payload_reduce(struct nft_regs_track *track,
+-			       const struct nft_expr *expr)
+-{
+-	const struct nft_payload *priv = nft_expr_priv(expr);
+-	const struct nft_payload *payload;
+-
+-	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	payload = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (priv->base != payload->base ||
+-	    priv->offset != payload->offset ||
+-	    priv->len != payload->len) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	if (!track->regs[priv->dreg].bitwise)
+-		return true;
+-
+-	return nft_expr_reduce_bitwise(track, expr);
+-}
+-
+ static bool nft_payload_offload_mask(struct nft_offload_reg *reg,
+ 				     u32 priv_len, u32 field_len)
+ {
+@@ -578,7 +553,6 @@ static const struct nft_expr_ops nft_payload_ops = {
+ 	.eval		= nft_payload_eval,
+ 	.init		= nft_payload_init,
+ 	.dump		= nft_payload_dump,
+-	.reduce		= nft_payload_reduce,
+ 	.offload	= nft_payload_offload,
+ };
+ 
+@@ -588,7 +562,6 @@ const struct nft_expr_ops nft_payload_fast_ops = {
+ 	.eval		= nft_payload_eval,
+ 	.init		= nft_payload_init,
+ 	.dump		= nft_payload_dump,
+-	.reduce		= nft_payload_reduce,
+ 	.offload	= nft_payload_offload,
+ };
+ 
+@@ -1008,32 +981,12 @@ nla_put_failure:
+ 	return -1;
+ }
+ 
+-static bool nft_payload_set_reduce(struct nft_regs_track *track,
+-				   const struct nft_expr *expr)
+-{
+-	int i;
+-
+-	for (i = 0; i < NFT_REG32_NUM; i++) {
+-		if (!track->regs[i].selector)
+-			continue;
+-
+-		if (track->regs[i].selector->ops != &nft_payload_ops &&
+-		    track->regs[i].selector->ops != &nft_payload_fast_ops)
+-			continue;
+-
+-		__nft_reg_track_cancel(track, i);
+-	}
+-
+-	return false;
+-}
+-
+ static const struct nft_expr_ops nft_payload_set_ops = {
+ 	.type		= &nft_payload_type,
+ 	.size		= NFT_EXPR_SIZE(sizeof(struct nft_payload_set)),
+ 	.eval		= nft_payload_set_eval,
+ 	.init		= nft_payload_set_init,
+ 	.dump		= nft_payload_set_dump,
+-	.reduce		= nft_payload_set_reduce,
+ };
+ 
+ static const struct nft_expr_ops *
+diff --git a/net/netfilter/nft_queue.c b/net/netfilter/nft_queue.c
+index 344fe311878fe0..8eb13a02942ed3 100644
+--- a/net/netfilter/nft_queue.c
++++ b/net/netfilter/nft_queue.c
+@@ -191,7 +191,6 @@ static const struct nft_expr_ops nft_queue_ops = {
+ 	.init		= nft_queue_init,
+ 	.dump		= nft_queue_dump,
+ 	.validate	= nft_queue_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static const struct nft_expr_ops nft_queue_sreg_ops = {
+@@ -201,7 +200,6 @@ static const struct nft_expr_ops nft_queue_sreg_ops = {
+ 	.init		= nft_queue_sreg_init,
+ 	.dump		= nft_queue_sreg_dump,
+ 	.validate	= nft_queue_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static const struct nft_expr_ops *
+diff --git a/net/netfilter/nft_quota.c b/net/netfilter/nft_quota.c
+index df0798da2329b9..870a2b87e0d52c 100644
+--- a/net/netfilter/nft_quota.c
++++ b/net/netfilter/nft_quota.c
+@@ -265,7 +265,6 @@ static const struct nft_expr_ops nft_quota_ops = {
+ 	.destroy	= nft_quota_destroy,
+ 	.clone		= nft_quota_clone,
+ 	.dump		= nft_quota_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_quota_type __read_mostly = {
+diff --git a/net/netfilter/nft_range.c b/net/netfilter/nft_range.c
+index ea382f7bbd78db..cbb02644b83626 100644
+--- a/net/netfilter/nft_range.c
++++ b/net/netfilter/nft_range.c
+@@ -138,7 +138,6 @@ static const struct nft_expr_ops nft_range_ops = {
+ 	.eval		= nft_range_eval,
+ 	.init		= nft_range_init,
+ 	.dump		= nft_range_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ struct nft_expr_type nft_range_type __read_mostly = {
+diff --git a/net/netfilter/nft_redir.c b/net/netfilter/nft_redir.c
+index 95eedad85c835c..58ae802db8f52d 100644
+--- a/net/netfilter/nft_redir.c
++++ b/net/netfilter/nft_redir.c
+@@ -146,7 +146,6 @@ static const struct nft_expr_ops nft_redir_ipv4_ops = {
+ 	.destroy	= nft_redir_ipv4_destroy,
+ 	.dump		= nft_redir_dump,
+ 	.validate	= nft_redir_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_redir_ipv4_type __read_mostly = {
+@@ -174,7 +173,6 @@ static const struct nft_expr_ops nft_redir_ipv6_ops = {
+ 	.destroy	= nft_redir_ipv6_destroy,
+ 	.dump		= nft_redir_dump,
+ 	.validate	= nft_redir_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_redir_ipv6_type __read_mostly = {
+@@ -203,7 +201,6 @@ static const struct nft_expr_ops nft_redir_inet_ops = {
+ 	.destroy	= nft_redir_inet_destroy,
+ 	.dump		= nft_redir_dump,
+ 	.validate	= nft_redir_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_redir_inet_type __read_mostly = {
+diff --git a/net/netfilter/nft_reject_inet.c b/net/netfilter/nft_reject_inet.c
+index 49020e67304ad7..dcae83ddc32e58 100644
+--- a/net/netfilter/nft_reject_inet.c
++++ b/net/netfilter/nft_reject_inet.c
+@@ -79,7 +79,6 @@ static const struct nft_expr_ops nft_reject_inet_ops = {
+ 	.init		= nft_reject_init,
+ 	.dump		= nft_reject_dump,
+ 	.validate	= nft_reject_inet_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_reject_inet_type __read_mostly = {
+diff --git a/net/netfilter/nft_reject_netdev.c b/net/netfilter/nft_reject_netdev.c
+index 2558ce1505d989..b53e81e4ca75db 100644
+--- a/net/netfilter/nft_reject_netdev.c
++++ b/net/netfilter/nft_reject_netdev.c
+@@ -158,7 +158,6 @@ static const struct nft_expr_ops nft_reject_netdev_ops = {
+ 	.init		= nft_reject_init,
+ 	.dump		= nft_reject_dump,
+ 	.validate	= nft_reject_netdev_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_reject_netdev_type __read_mostly = {
+diff --git a/net/netfilter/nft_rt.c b/net/netfilter/nft_rt.c
+index 9525f1e02a7d83..700656565b6560 100644
+--- a/net/netfilter/nft_rt.c
++++ b/net/netfilter/nft_rt.c
+@@ -195,7 +195,6 @@ static const struct nft_expr_ops nft_rt_get_ops = {
+ 	.init		= nft_rt_get_init,
+ 	.dump		= nft_rt_get_dump,
+ 	.validate	= nft_rt_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ struct nft_expr_type nft_rt_type __read_mostly = {
+diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
+index e55664ca2aadb7..4a6561ba6061c4 100644
+--- a/net/netfilter/nft_set_pipapo.c
++++ b/net/netfilter/nft_set_pipapo.c
+@@ -342,6 +342,8 @@
+ #include "nft_set_pipapo_avx2.h"
+ #include "nft_set_pipapo.h"
+ 
++static void nft_pipapo_abort(const struct nft_set *set);
++
+ /**
+  * pipapo_refill() - For each set bit, set bits from selected mapping table item
+  * @map:	Bitmap to be scanned for set bits
+@@ -502,9 +504,11 @@ out:
+  * pipapo_get() - Get matching element reference given key data
+  * @net:	Network namespace
+  * @set:	nftables API set representation
++ * @m:		storage containing active/existing elements
+  * @data:	Key data to be matched against existing elements
+  * @genmask:	If set, check that element is active in given genmask
+  * @tstamp:	timestamp to check for expired elements
++ * @gfp:	the type of memory to allocate (see kmalloc).
+  *
+  * This is essentially the same as the lookup function, except that it matches
+  * key data against the uncommitted copy and doesn't use preallocated maps for
+@@ -514,27 +518,25 @@ out:
+  */
+ static struct nft_pipapo_elem *pipapo_get(const struct net *net,
+ 					  const struct nft_set *set,
++					  const struct nft_pipapo_match *m,
+ 					  const u8 *data, u8 genmask,
+-					  u64 tstamp)
++					  u64 tstamp, gfp_t gfp)
+ {
+ 	struct nft_pipapo_elem *ret = ERR_PTR(-ENOENT);
+-	struct nft_pipapo *priv = nft_set_priv(set);
+ 	unsigned long *res_map, *fill_map = NULL;
+-	const struct nft_pipapo_match *m;
+ 	const struct nft_pipapo_field *f;
+ 	int i;
+ 
+-	m = priv->clone;
+ 	if (m->bsize_max == 0)
+ 		return ret;
+ 
+-	res_map = kmalloc_array(m->bsize_max, sizeof(*res_map), GFP_ATOMIC);
++	res_map = kmalloc_array(m->bsize_max, sizeof(*res_map), gfp);
+ 	if (!res_map) {
+ 		ret = ERR_PTR(-ENOMEM);
+ 		goto out;
+ 	}
+ 
+-	fill_map = kcalloc(m->bsize_max, sizeof(*res_map), GFP_ATOMIC);
++	fill_map = kcalloc(m->bsize_max, sizeof(*res_map), gfp);
+ 	if (!fill_map) {
+ 		ret = ERR_PTR(-ENOMEM);
+ 		goto out;
+@@ -608,8 +610,11 @@ out:
+ static void *nft_pipapo_get(const struct net *net, const struct nft_set *set,
+ 			    const struct nft_set_elem *elem, unsigned int flags)
+ {
+-	return pipapo_get(net, set, (const u8 *)elem->key.val.data,
+-			 nft_genmask_cur(net), get_jiffies_64());
++	struct nft_pipapo *priv = nft_set_priv(set);
++	struct nft_pipapo_match *m = rcu_dereference(priv->match);
++
++	return pipapo_get(net, set, m, (const u8 *)elem->key.val.data,
++			 nft_genmask_cur(net), get_jiffies_64(), GFP_ATOMIC);
+ }
+ 
+ 
+@@ -1216,6 +1221,40 @@ static int pipapo_realloc_scratch(struct nft_pipapo_match *clone,
+ 	return 0;
+ }
+ 
++static bool nft_pipapo_transaction_mutex_held(const struct nft_set *set)
++{
++#ifdef CONFIG_PROVE_LOCKING
++	const struct net *net = read_pnet(&set->net);
++
++	return lockdep_is_held(&nft_pernet(net)->commit_mutex);
++#else
++	return true;
++#endif
++}
++
++static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old);
++
++/**
++ * pipapo_maybe_clone() - Build clone for pending data changes, if not existing
++ * @set:	nftables API set representation
++ *
++ * Return: newly created or existing clone, if any. NULL on allocation failure
++ */
++static struct nft_pipapo_match *pipapo_maybe_clone(const struct nft_set *set)
++{
++	struct nft_pipapo *priv = nft_set_priv(set);
++	struct nft_pipapo_match *m;
++
++	if (priv->clone)
++		return priv->clone;
++
++	m = rcu_dereference_protected(priv->match,
++				      nft_pipapo_transaction_mutex_held(set));
++	priv->clone = pipapo_clone(m);
++
++	return priv->clone;
++}
++
+ /**
+  * nft_pipapo_insert() - Validate and insert ranged elements
+  * @net:	Network namespace
+@@ -1233,20 +1272,23 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
+ 	union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
+ 	const u8 *start = (const u8 *)elem->key.val.data, *end;
+ 	struct nft_pipapo_elem *e = elem->priv, *dup;
++	struct nft_pipapo_match *m = pipapo_maybe_clone(set);
+ 	struct nft_pipapo *priv = nft_set_priv(set);
+-	struct nft_pipapo_match *m = priv->clone;
+ 	u8 genmask = nft_genmask_next(net);
+ 	u64 tstamp = nft_net_tstamp(net);
+ 	struct nft_pipapo_field *f;
+ 	const u8 *start_p, *end_p;
+ 	int i, bsize_max, err = 0;
+ 
++	if (!m || m->state == NFT_PIPAPO_CLONE_ERR)
++		return -ENOMEM;
++
+ 	if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
+ 		end = (const u8 *)nft_set_ext_key_end(ext)->data;
+ 	else
+ 		end = start;
+ 
+-	dup = pipapo_get(net, set, start, genmask, tstamp);
++	dup = pipapo_get(net, set, m, start, genmask, tstamp, GFP_KERNEL);
+ 	if (!IS_ERR(dup)) {
+ 		/* Check if we already have the same exact entry */
+ 		const struct nft_data *dup_key, *dup_end;
+@@ -1268,7 +1310,8 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
+ 
+ 	if (PTR_ERR(dup) == -ENOENT) {
+ 		/* Look for partially overlapping entries */
+-		dup = pipapo_get(net, set, end, nft_genmask_next(net), tstamp);
++		dup = pipapo_get(net, set, m, end, nft_genmask_next(net), tstamp,
++				 GFP_KERNEL);
+ 	}
+ 
+ 	if (PTR_ERR(dup) != -ENOENT) {
+@@ -1310,8 +1353,10 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
+ 		else
+ 			ret = pipapo_expand(f, start, end, f->groups * f->bb);
+ 
+-		if (ret < 0)
+-			return ret;
++		if (ret < 0) {
++			err = ret;
++			goto abort;
++		}
+ 
+ 		if (f->bsize > bsize_max)
+ 			bsize_max = f->bsize;
+@@ -1327,7 +1372,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
+ 
+ 		err = pipapo_realloc_scratch(m, bsize_max);
+ 		if (err)
+-			return err;
++			goto abort;
+ 
+ 		m->bsize_max = bsize_max;
+ 	} else {
+@@ -1338,14 +1383,33 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set,
+ 
+ 	pipapo_map(m, rulemap, e);
+ 
++	m->state = NFT_PIPAPO_CLONE_MOD;
+ 	return 0;
++abort:
++	DEBUG_NET_WARN_ON_ONCE(m->state == NFT_PIPAPO_CLONE_ERR);
++
++	/* Two rollback cases:
++	 * 1) no previous changes.  nft_pipapo_abort is not
++	 * guaranteed to be invoked (there might be no further
++	 * add/delete requests coming after this).
++	 *
++	 * 2) we had previous changes: there are transaction
++	 * records pointing to this set.  Leave the rollback to
++	 * the transaction handling.
++	 */
++	if (m->state == NFT_PIPAPO_CLONE_NEW)
++		nft_pipapo_abort(set); /* releases m */
++	else
++		m->state = NFT_PIPAPO_CLONE_ERR;
++
++	return err;
+ }
+ 
+ /**
+  * pipapo_clone() - Clone matching data to create new working copy
+  * @old:	Existing matching data
+  *
+- * Return: copy of matching data passed as 'old', error pointer on failure
++ * Return: copy of matching data passed as 'old' or NULL.
+  */
+ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old)
+ {
+@@ -1355,7 +1419,7 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old)
+ 
+ 	new = kmalloc(struct_size(new, f, old->field_count), GFP_KERNEL_ACCOUNT);
+ 	if (!new)
+-		return ERR_PTR(-ENOMEM);
++		return NULL;
+ 
+ 	new->field_count = old->field_count;
+ 	new->bsize_max = old->bsize_max;
+@@ -1414,6 +1478,7 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old)
+ 		dst++;
+ 	}
+ 
++	new->state = NFT_PIPAPO_CLONE_NEW;
+ 	return new;
+ 
+ out_mt:
+@@ -1431,7 +1496,7 @@ out_scratch:
+ 	free_percpu(new->scratch);
+ 	kfree(new);
+ 
+-	return ERR_PTR(-ENOMEM);
++	return NULL;
+ }
+ 
+ /**
+@@ -1776,7 +1841,10 @@ static void pipapo_reclaim_match(struct rcu_head *rcu)
+ static void nft_pipapo_commit(struct nft_set *set)
+ {
+ 	struct nft_pipapo *priv = nft_set_priv(set);
+-	struct nft_pipapo_match *new_clone, *old;
++	struct nft_pipapo_match *old;
++
++	if (!priv->clone)
++		return;
+ 
+ 	if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set)))
+ 		pipapo_gc_scan(set, priv->clone);
+@@ -1784,51 +1852,29 @@ static void nft_pipapo_commit(struct nft_set *set)
+ 	if (!priv->dirty)
+ 		return;
+ 
+-	new_clone = pipapo_clone(priv->clone);
+-	if (IS_ERR(new_clone))
+-		return;
+-
++	old = rcu_replace_pointer(priv->match, priv->clone,
++				  nft_pipapo_transaction_mutex_held(set));
++	priv->clone = NULL;
+ 	priv->dirty = false;
+ 
+-	old = rcu_access_pointer(priv->match);
+-	rcu_assign_pointer(priv->match, priv->clone);
+ 	if (old)
+ 		call_rcu(&old->rcu, pipapo_reclaim_match);
+ 
+-	priv->clone = new_clone;
+-
+ 	pipapo_gc_queue(set);
+ }
+ 
+-static bool nft_pipapo_transaction_mutex_held(const struct nft_set *set)
+-{
+-#ifdef CONFIG_PROVE_LOCKING
+-	const struct net *net = read_pnet(&set->net);
+-
+-	return lockdep_is_held(&nft_pernet(net)->commit_mutex);
+-#else
+-	return true;
+-#endif
+-}
+-
+ static void nft_pipapo_abort(const struct nft_set *set)
+ {
+ 	struct nft_pipapo *priv = nft_set_priv(set);
+-	struct nft_pipapo_match *new_clone, *m;
+ 
+ 	if (!priv->dirty)
+ 		return;
+ 
+-	m = rcu_dereference_protected(priv->match, nft_pipapo_transaction_mutex_held(set));
+-
+-	new_clone = pipapo_clone(m);
+-	if (IS_ERR(new_clone))
++	if (!priv->clone)
+ 		return;
+-
+ 	priv->dirty = false;
+-
+ 	pipapo_free_match(priv->clone);
+-	priv->clone = new_clone;
++	priv->clone = NULL;
+ }
+ 
+ /**
+@@ -1852,24 +1898,28 @@ static void nft_pipapo_activate(const struct net *net,
+ }
+ 
+ /**
+- * pipapo_deactivate() - Check that element is in set, mark as inactive
++ * nft_pipapo_deactivate() - Search for element and make it inactive
+  * @net:	Network namespace
+  * @set:	nftables API set representation
+- * @data:	Input key data
+- * @ext:	nftables API extension pointer, used to check for end element
+- *
+- * This is a convenience function that can be called from both
+- * nft_pipapo_deactivate() and nft_pipapo_flush(), as they are in fact the same
+- * operation.
++ * @elem:	nftables API element representation containing key data
+  *
+  * Return: deactivated element if found, NULL otherwise.
+  */
+-static void *pipapo_deactivate(const struct net *net, const struct nft_set *set,
+-			       const u8 *data, const struct nft_set_ext *ext)
++static void *nft_pipapo_deactivate(const struct net *net,
++				   const struct nft_set *set,
++				   const struct nft_set_elem *elem)
+ {
++	struct nft_pipapo_match *m = pipapo_maybe_clone(set);
+ 	struct nft_pipapo_elem *e;
+ 
+-	e = pipapo_get(net, set, data, nft_genmask_next(net), nft_net_tstamp(net));
++	/* removal must occur on priv->clone, if we are low on memory
++	 * we have no choice and must fail the removal request.
++	 */
++	if (!m || m->state == NFT_PIPAPO_CLONE_ERR)
++		return NULL;
++
++	e = pipapo_get(net, set, m, (const u8 *)elem->key.val.data,
++		       nft_genmask_next(net), nft_net_tstamp(net), GFP_KERNEL);
+ 	if (IS_ERR(e))
+ 		return NULL;
+ 
+@@ -1879,24 +1929,7 @@ static void *pipapo_deactivate(const struct net *net, const struct nft_set *set,
+ }
+ 
+ /**
+- * nft_pipapo_deactivate() - Call pipapo_deactivate() to make element inactive
+- * @net:	Network namespace
+- * @set:	nftables API set representation
+- * @elem:	nftables API element representation containing key data
+- *
+- * Return: deactivated element if found, NULL otherwise.
+- */
+-static void *nft_pipapo_deactivate(const struct net *net,
+-				   const struct nft_set *set,
+-				   const struct nft_set_elem *elem)
+-{
+-	const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
+-
+-	return pipapo_deactivate(net, set, (const u8 *)elem->key.val.data, ext);
+-}
+-
+-/**
+- * nft_pipapo_flush() - Call pipapo_deactivate() to make element inactive
++ * nft_pipapo_flush() - make element inactive
+  * @net:	Network namespace
+  * @set:	nftables API set representation
+  * @elem:	nftables API element representation containing key data
+@@ -1918,8 +1951,9 @@ static bool nft_pipapo_flush(const struct net *net, const struct nft_set *set,
+ {
+ 	struct nft_pipapo_elem *e = elem;
+ 
+-	return pipapo_deactivate(net, set, (const u8 *)nft_set_ext_key(&e->ext),
+-				 &e->ext);
++	nft_set_elem_change_active(net, set, &e->ext);
++
++	return true;
+ }
+ 
+ /**
+@@ -2106,35 +2140,23 @@ static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
+ }
+ 
+ /**
+- * nft_pipapo_walk() - Walk over elements
++ * nft_pipapo_do_walk() - Walk over elements in m
+  * @ctx:	nftables API context
+  * @set:	nftables API set representation
++ * @m:		matching data pointing to key mapping array
+  * @iter:	Iterator
+  *
+  * As elements are referenced in the mapping array for the last field, directly
+  * scan that array: there's no need to follow rule mappings from the first
+- * field.
++ * field. @m is protected either by RCU read lock or by transaction mutex.
+  */
+-static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
+-			    struct nft_set_iter *iter)
++static void nft_pipapo_do_walk(const struct nft_ctx *ctx, struct nft_set *set,
++			       const struct nft_pipapo_match *m,
++			       struct nft_set_iter *iter)
+ {
+-	struct nft_pipapo *priv = nft_set_priv(set);
+-	const struct nft_pipapo_match *m;
+ 	const struct nft_pipapo_field *f;
+ 	int i, r;
+ 
+-	WARN_ON_ONCE(iter->type != NFT_ITER_READ &&
+-		     iter->type != NFT_ITER_UPDATE);
+-
+-	rcu_read_lock();
+-	if (iter->type == NFT_ITER_READ)
+-		m = rcu_dereference(priv->match);
+-	else
+-		m = priv->clone;
+-
+-	if (unlikely(!m))
+-		goto out;
+-
+ 	for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
+ 		;
+ 
+@@ -2154,14 +2176,49 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
+ 
+ 		iter->err = iter->fn(ctx, set, iter, &elem);
+ 		if (iter->err < 0)
+-			goto out;
++			return;
+ 
+ cont:
+ 		iter->count++;
+ 	}
++}
+ 
+-out:
+-	rcu_read_unlock();
++/**
++ * nft_pipapo_walk() - Walk over elements
++ * @ctx:	nftables API context
++ * @set:	nftables API set representation
++ * @iter:	Iterator
++ *
++ * Test if destructive action is needed or not, clone active backend if needed
++ * and call the real function to work on the data.
++ */
++static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
++			    struct nft_set_iter *iter)
++{
++	struct nft_pipapo *priv = nft_set_priv(set);
++	const struct nft_pipapo_match *m;
++
++	switch (iter->type) {
++	case NFT_ITER_UPDATE:
++		m = pipapo_maybe_clone(set);
++		if (!m) {
++			iter->err = -ENOMEM;
++			return;
++		}
++
++		nft_pipapo_do_walk(ctx, set, m, iter);
++		break;
++	case NFT_ITER_READ:
++		rcu_read_lock();
++		m = rcu_dereference(priv->match);
++		nft_pipapo_do_walk(ctx, set, m, iter);
++		rcu_read_unlock();
++		break;
++	default:
++		iter->err = -EINVAL;
++		WARN_ON_ONCE(1);
++		break;
++	}
+ }
+ 
+ /**
+@@ -2262,8 +2319,8 @@ static int nft_pipapo_init(const struct nft_set *set,
+ 
+ 	/* Create an initial clone of matching data for next insertion */
+ 	priv->clone = pipapo_clone(m);
+-	if (IS_ERR(priv->clone)) {
+-		err = PTR_ERR(priv->clone);
++	if (!priv->clone) {
++		err = -ENOMEM;
+ 		goto out_free;
+ 	}
+ 
+diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h
+index 743ba7c153ffe4..820f0ff9d686a0 100644
+--- a/net/netfilter/nft_set_pipapo.h
++++ b/net/netfilter/nft_set_pipapo.h
+@@ -142,9 +142,16 @@ struct nft_pipapo_scratch {
+ 	unsigned long map[];
+ };
+ 
++enum nft_pipapo_clone_state {
++	NFT_PIPAPO_CLONE_NEW,
++	NFT_PIPAPO_CLONE_MOD,
++	NFT_PIPAPO_CLONE_ERR,
++};
++
+ /**
+  * struct nft_pipapo_match - Data used for lookup and matching
+  * @field_count		Amount of fields in set
++ * @state:		add/delete state; used from control plane
+  * @scratch:		Preallocated per-CPU maps for partial matching results
+  * @bsize_max:		Maximum lookup table bucket size of all fields, in longs
+  * @rcu			Matching data is swapped on commits
+@@ -152,6 +159,7 @@ struct nft_pipapo_scratch {
+  */
+ struct nft_pipapo_match {
+ 	int field_count;
++	enum nft_pipapo_clone_state state:8;
+ 	struct nft_pipapo_scratch * __percpu *scratch;
+ 	size_t bsize_max;
+ 	struct rcu_head rcu;
+diff --git a/net/netfilter/nft_socket.c b/net/netfilter/nft_socket.c
+index 35d0409b009501..98326d585e0756 100644
+--- a/net/netfilter/nft_socket.c
++++ b/net/netfilter/nft_socket.c
+@@ -249,31 +249,6 @@ static int nft_socket_dump(struct sk_buff *skb,
+ 	return 0;
+ }
+ 
+-static bool nft_socket_reduce(struct nft_regs_track *track,
+-			      const struct nft_expr *expr)
+-{
+-	const struct nft_socket *priv = nft_expr_priv(expr);
+-	const struct nft_socket *socket;
+-
+-	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	socket = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (priv->key != socket->key ||
+-	    priv->dreg != socket->dreg ||
+-	    priv->level != socket->level) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	if (!track->regs[priv->dreg].bitwise)
+-		return true;
+-
+-	return nft_expr_reduce_bitwise(track, expr);
+-}
+-
+ static int nft_socket_validate(const struct nft_ctx *ctx,
+ 			       const struct nft_expr *expr)
+ {
+@@ -296,7 +271,6 @@ static const struct nft_expr_ops nft_socket_ops = {
+ 	.init		= nft_socket_init,
+ 	.dump		= nft_socket_dump,
+ 	.validate	= nft_socket_validate,
+-	.reduce		= nft_socket_reduce,
+ };
+ 
+ static struct nft_expr_type nft_socket_type __read_mostly = {
+diff --git a/net/netfilter/nft_synproxy.c b/net/netfilter/nft_synproxy.c
+index ad3e7d27f02e9d..a80bdce38546ff 100644
+--- a/net/netfilter/nft_synproxy.c
++++ b/net/netfilter/nft_synproxy.c
+@@ -290,7 +290,6 @@ static const struct nft_expr_ops nft_synproxy_ops = {
+ 	.dump		= nft_synproxy_dump,
+ 	.type		= &nft_synproxy_type,
+ 	.validate	= nft_synproxy_validate,
+-	.reduce		= NFT_REDUCE_READONLY,
+ };
+ 
+ static struct nft_expr_type nft_synproxy_type __read_mostly = {
+diff --git a/net/netfilter/nft_tproxy.c b/net/netfilter/nft_tproxy.c
+index 50481280abd265..f2101af8c867f4 100644
+--- a/net/netfilter/nft_tproxy.c
++++ b/net/netfilter/nft_tproxy.c
+@@ -331,7 +331,6 @@ static const struct nft_expr_ops nft_tproxy_ops = {
+ 	.init		= nft_tproxy_init,
+ 	.destroy	= nft_tproxy_destroy,
+ 	.dump		= nft_tproxy_dump,
+-	.reduce		= NFT_REDUCE_READONLY,
+ 	.validate	= nft_tproxy_validate,
+ };
+ 
+diff --git a/net/netfilter/nft_tunnel.c b/net/netfilter/nft_tunnel.c
+index 96784825855785..073e05636f6bbe 100644
+--- a/net/netfilter/nft_tunnel.c
++++ b/net/netfilter/nft_tunnel.c
+@@ -124,31 +124,6 @@ nla_put_failure:
+ 	return -1;
+ }
+ 
+-static bool nft_tunnel_get_reduce(struct nft_regs_track *track,
+-				  const struct nft_expr *expr)
+-{
+-	const struct nft_tunnel *priv = nft_expr_priv(expr);
+-	const struct nft_tunnel *tunnel;
+-
+-	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	tunnel = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (priv->key != tunnel->key ||
+-	    priv->dreg != tunnel->dreg ||
+-	    priv->mode != tunnel->mode) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	if (!track->regs[priv->dreg].bitwise)
+-		return true;
+-
+-	return false;
+-}
+-
+ static struct nft_expr_type nft_tunnel_type;
+ static const struct nft_expr_ops nft_tunnel_get_ops = {
+ 	.type		= &nft_tunnel_type,
+@@ -156,7 +131,6 @@ static const struct nft_expr_ops nft_tunnel_get_ops = {
+ 	.eval		= nft_tunnel_get_eval,
+ 	.init		= nft_tunnel_get_init,
+ 	.dump		= nft_tunnel_get_dump,
+-	.reduce		= nft_tunnel_get_reduce,
+ };
+ 
+ static struct nft_expr_type nft_tunnel_type __read_mostly = {
+diff --git a/net/netfilter/nft_xfrm.c b/net/netfilter/nft_xfrm.c
+index 8a07b46cc8fb73..81cbe8408c83cc 100644
+--- a/net/netfilter/nft_xfrm.c
++++ b/net/netfilter/nft_xfrm.c
+@@ -258,32 +258,6 @@ static int nft_xfrm_validate(const struct nft_ctx *ctx, const struct nft_expr *e
+ 	return nft_chain_validate_hooks(ctx->chain, hooks);
+ }
+ 
+-static bool nft_xfrm_reduce(struct nft_regs_track *track,
+-			    const struct nft_expr *expr)
+-{
+-	const struct nft_xfrm *priv = nft_expr_priv(expr);
+-	const struct nft_xfrm *xfrm;
+-
+-	if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	xfrm = nft_expr_priv(track->regs[priv->dreg].selector);
+-	if (priv->key != xfrm->key ||
+-	    priv->dreg != xfrm->dreg ||
+-	    priv->dir != xfrm->dir ||
+-	    priv->spnum != xfrm->spnum) {
+-		nft_reg_track_update(track, expr, priv->dreg, priv->len);
+-		return false;
+-	}
+-
+-	if (!track->regs[priv->dreg].bitwise)
+-		return true;
+-
+-	return nft_expr_reduce_bitwise(track, expr);
+-}
+-
+ static struct nft_expr_type nft_xfrm_type;
+ static const struct nft_expr_ops nft_xfrm_get_ops = {
+ 	.type		= &nft_xfrm_type,
+@@ -292,7 +266,6 @@ static const struct nft_expr_ops nft_xfrm_get_ops = {
+ 	.init		= nft_xfrm_get_init,
+ 	.dump		= nft_xfrm_get_dump,
+ 	.validate	= nft_xfrm_validate,
+-	.reduce		= nft_xfrm_reduce,
+ };
+ 
+ static struct nft_expr_type nft_xfrm_type __read_mostly = {
+diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
+index 0ea4fc2a755bfd..793f86e2475559 100644
+--- a/net/openvswitch/actions.c
++++ b/net/openvswitch/actions.c
+@@ -861,12 +861,8 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
+ 		u16 mru = OVS_CB(skb)->mru;
+ 		u32 cutlen = OVS_CB(skb)->cutlen;
+ 
+-		if (unlikely(cutlen > 0)) {
+-			if (skb->len - cutlen > ovs_mac_header_len(key))
+-				pskb_trim(skb, skb->len - cutlen);
+-			else
+-				pskb_trim(skb, ovs_mac_header_len(key));
+-		}
++		if (unlikely(cutlen < skb->len))
++			pskb_trim(skb, max(cutlen, ovs_mac_header_len(key)));
+ 
+ 		if (likely(!mru ||
+ 		           (skb->len <= mru + vport->dev->hard_header_len))) {
+@@ -1258,22 +1254,21 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
+ 			clone = skb_clone(skb, GFP_ATOMIC);
+ 			if (clone)
+ 				do_output(dp, clone, port, key);
+-			OVS_CB(skb)->cutlen = 0;
++			OVS_CB(skb)->cutlen = U32_MAX;
+ 			break;
+ 		}
+ 
+ 		case OVS_ACTION_ATTR_TRUNC: {
+ 			struct ovs_action_trunc *trunc = nla_data(a);
+ 
+-			if (skb->len > trunc->max_len)
+-				OVS_CB(skb)->cutlen = skb->len - trunc->max_len;
++			OVS_CB(skb)->cutlen = trunc->max_len;
+ 			break;
+ 		}
+ 
+ 		case OVS_ACTION_ATTR_USERSPACE:
+ 			output_userspace(dp, skb, key, a, attr,
+ 						     len, OVS_CB(skb)->cutlen);
+-			OVS_CB(skb)->cutlen = 0;
++			OVS_CB(skb)->cutlen = U32_MAX;
+ 			if (nla_is_last(a, rem)) {
+ 				consume_skb(skb);
+ 				return 0;
+diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
+index 857edc53739332..fb5b72700d82b1 100644
+--- a/net/openvswitch/datapath.c
++++ b/net/openvswitch/datapath.c
+@@ -273,7 +273,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
+ 			upcall.portid = ovs_vport_find_upcall_portid(p, skb);
+ 
+ 		upcall.mru = OVS_CB(skb)->mru;
+-		error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
++		error = ovs_dp_upcall(dp, skb, key, &upcall, U32_MAX);
+ 		switch (error) {
+ 		case 0:
+ 		case -EAGAIN:
+@@ -438,7 +438,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ 	struct sk_buff *nskb = NULL;
+ 	struct sk_buff *user_skb = NULL; /* to be queued to userspace */
+ 	struct nlattr *nla;
+-	size_t len;
++	size_t msg_size;
++	size_t skb_len;
+ 	unsigned int hlen;
+ 	int err, dp_ifindex;
+ 	u64 hash;
+@@ -459,7 +460,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ 		skb = nskb;
+ 	}
+ 
+-	if (nla_attr_size(skb->len) > USHRT_MAX) {
++	skb_len = min(skb->len, cutlen);
++	if (nla_attr_size(skb_len) > USHRT_MAX) {
+ 		err = -EFBIG;
+ 		goto out;
+ 	}
+@@ -474,13 +476,13 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ 	 * padding logic. Only perform zerocopy if padding is not required.
+ 	 */
+ 	if (dp->user_features & OVS_DP_F_UNALIGNED)
+-		hlen = skb_zerocopy_headlen(skb);
++		hlen = min(skb_zerocopy_headlen(skb), cutlen);
+ 	else
+-		hlen = skb->len;
++		hlen = skb_len;
+ 
+-	len = upcall_msg_size(upcall_info, hlen - cutlen,
+-			      OVS_CB(skb)->acts_origlen);
+-	user_skb = genlmsg_new(len, GFP_ATOMIC);
++	msg_size = upcall_msg_size(upcall_info, hlen,
++				   OVS_CB(skb)->acts_origlen);
++	user_skb = genlmsg_new(msg_size, GFP_ATOMIC);
+ 	if (!user_skb) {
+ 		err = -ENOMEM;
+ 		goto out;
+@@ -541,7 +543,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ 	}
+ 
+ 	/* Add OVS_PACKET_ATTR_LEN when packet is truncated */
+-	if (cutlen > 0 &&
++	if (skb_len < skb->len &&
+ 	    nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, skb->len)) {
+ 		err = -ENOBUFS;
+ 		goto out;
+@@ -566,9 +568,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
+ 		err = -ENOBUFS;
+ 		goto out;
+ 	}
+-	nla->nla_len = nla_attr_size(skb->len - cutlen);
++	nla->nla_len = nla_attr_size(skb_len);
+ 
+-	err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen);
++	err = skb_zerocopy(user_skb, skb, skb_len, hlen);
+ 	if (err)
+ 		goto out;
+ 
+@@ -625,6 +627,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
+ 		packet->ignore_df = 1;
+ 	}
+ 	OVS_CB(packet)->mru = mru;
++	OVS_CB(packet)->cutlen = U32_MAX;
+ 
+ 	if (a[OVS_PACKET_ATTR_HASH]) {
+ 		hash = nla_get_u64(a[OVS_PACKET_ATTR_HASH]);
+diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
+index 0cd29971a907ca..88156a677f22c5 100644
+--- a/net/openvswitch/datapath.h
++++ b/net/openvswitch/datapath.h
+@@ -114,7 +114,7 @@ struct datapath {
+  * @mru: The maximum received fragement size; 0 if the packet is not
+  * fragmented.
+  * @acts_origlen: The netlink size of the flow actions applied to this skb.
+- * @cutlen: The number of bytes from the packet end to be removed.
++ * @cutlen: The number of bytes in the packet to preserve on output.
+  */
+ struct ovs_skb_cb {
+ 	struct vport		*input_vport;
+diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
+index a0a8854e9f19e8..eb0eb57dabe2f9 100644
+--- a/net/openvswitch/vport.c
++++ b/net/openvswitch/vport.c
+@@ -503,7 +503,7 @@ int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
+ 
+ 	OVS_CB(skb)->input_vport = vport;
+ 	OVS_CB(skb)->mru = 0;
+-	OVS_CB(skb)->cutlen = 0;
++	OVS_CB(skb)->cutlen = U32_MAX;
+ 	if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) {
+ 		u32 mark;
+ 
+diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
+index 1de0ef429f9310..d435a48bc0e3b7 100644
+--- a/net/packet/af_packet.c
++++ b/net/packet/af_packet.c
+@@ -4608,7 +4608,11 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
+ 
+ 	spin_lock(&po->bind_lock);
+ 	WRITE_ONCE(po->num, num);
+-	if (was_running)
++	/*
++	 * NETDEV_UNREGISTER may have invalidated the binding while bind_lock
++	 * was dropped above.  Do not re-add a fanout hook to a dead device.
++	 */
++	if (was_running && READ_ONCE(po->ifindex) != -1)
+ 		register_prot_hook(sk);
+ 
+ 	spin_unlock(&po->bind_lock);
+diff --git a/net/phonet/pep.c b/net/phonet/pep.c
+index 72c77a313c8332..9f3f70829cb1a8 100644
+--- a/net/phonet/pep.c
++++ b/net/phonet/pep.c
+@@ -55,6 +55,8 @@ static unsigned char *pep_get_sb(struct sk_buff *skb, u8 *ptype, u8 *plen,
+ 	ph = skb_header_pointer(skb, 0, 2, &h);
+ 	if (ph == NULL || ph->sb_len < 2 || !pskb_may_pull(skb, ph->sb_len))
+ 		return NULL;
++	/* pskb_may_pull() may have reallocated the head; refetch ph. */
++	ph = skb_header_pointer(skb, 0, 2, &h);
+ 	ph->sb_len -= 2;
+ 	*ptype = ph->sb_type;
+ 	*plen = ph->sb_len;
+diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c
+index 305523cebe3baa..fcd24a7df3f00d 100644
+--- a/net/qrtr/af_qrtr.c
++++ b/net/qrtr/af_qrtr.c
+@@ -1261,6 +1261,14 @@ static int qrtr_create(struct net *net, struct socket *sock,
+ 	if (sock->type != SOCK_DGRAM)
+ 		return -EPROTOTYPE;
+ 
++	/* QRTR keeps its port and node state in module-global variables that
++	 * are not partitioned per network namespace, and the in-kernel name
++	 * service only operates in init_net. Confine the family to init_net so
++	 * a socket in another namespace cannot reach the global control plane.
++	 */
++	if (!net_eq(net, &init_net))
++		return -EAFNOSUPPORT;
++
+ 	sk = sk_alloc(net, AF_QIPCRTR, GFP_KERNEL, &qrtr_proto, kern);
+ 	if (!sk)
+ 		return -ENOMEM;
+diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
+index ecf49172307f1b..90244ce7e95e7a 100644
+--- a/net/qrtr/ns.c
++++ b/net/qrtr/ns.c
+@@ -85,9 +85,9 @@ struct qrtr_node {
+ /* Max nodes limit is chosen based on the current platform requirements.
+  * If the requirement changes in the future, this value can be increased.
+  */
+-#define QRTR_NS_MAX_NODES   64
++#define QRTR_NS_MAX_NODES   512
+ 
+-static u8 node_count;
++static u16 node_count;
+ 
+ static struct qrtr_node *node_get(unsigned int node_id)
+ {
+diff --git a/net/rds/recv.c b/net/rds/recv.c
+index 5627f80013f8b1..bd9d00326e94fd 100644
+--- a/net/rds/recv.c
++++ b/net/rds/recv.c
+@@ -366,6 +366,21 @@ void rds_recv_incoming(struct rds_connection *conn, struct in6_addr *saddr,
+ 		goto out;
+ 	}
+ 
++	/*
++	 * rds_find_bound() uses a global (netns-agnostic) hash table.
++	 * An RDS connection created in netns A can match a socket bound
++	 * in the init netns, delivering inc cross-netns with inc->i_conn
++	 * pointing into netns A.  When cleanup_net() then frees that conn,
++	 * any subsequent dereference of inc->i_conn is a use-after-free.
++	 * Drop the inc if the receiving socket lives in a different netns.
++	 */
++	if (!net_eq(sock_net(rds_rs_to_sk(rs)), rds_conn_net(conn))) {
++		rds_stats_inc(s_recv_drop_no_sock);
++		rds_sock_put(rs);
++		rs = NULL;
++		goto out;
++	}
++
+ 	/* Process extension headers */
+ 	rds_recv_incoming_exthdrs(inc, rs);
+ 
+diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
+index 0547c809876ed1..1a87cbd662c5a1 100644
+--- a/net/rxrpc/af_rxrpc.c
++++ b/net/rxrpc/af_rxrpc.c
+@@ -362,9 +362,9 @@ void rxrpc_kernel_shutdown_call(struct socket *sock, struct rxrpc_call *call)
+ 
+ 		/* Make sure we're not going to call back into a kernel service */
+ 		if (call->notify_rx) {
+-			spin_lock(&call->notify_lock);
++			spin_lock_irq(&call->notify_lock);
+ 			call->notify_rx = rxrpc_dummy_notify_rx;
+-			spin_unlock(&call->notify_lock);
++			spin_unlock_irq(&call->notify_lock);
+ 		}
+ 	}
+ 	mutex_unlock(&call->user_mutex);
+@@ -418,24 +418,20 @@ u32 rxrpc_kernel_get_epoch(struct socket *sock, struct rxrpc_call *call)
+ EXPORT_SYMBOL(rxrpc_kernel_get_epoch);
+ 
+ /**
+- * rxrpc_kernel_new_call_notification - Get notifications of new calls
+- * @sock: The socket to intercept received messages on
+- * @notify_new_call: Function to be called when new calls appear
+- * @discard_new_call: Function to discard preallocated calls
++ * rxrpc_kernel_set_notifications - Set table of callback operations
++ * @sock: The socket to install table upon
++ * @app_ops: Callback operation table to set
+  *
+- * Allow a kernel service to be given notifications about new calls.
++ * Allow a kernel service to set a table of event notifications on a socket.
+  */
+-void rxrpc_kernel_new_call_notification(
+-	struct socket *sock,
+-	rxrpc_notify_new_call_t notify_new_call,
+-	rxrpc_discard_new_call_t discard_new_call)
++void rxrpc_kernel_set_notifications(struct socket *sock,
++				    const struct rxrpc_kernel_ops *app_ops)
+ {
+ 	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+ 
+-	rx->notify_new_call = notify_new_call;
+-	rx->discard_new_call = discard_new_call;
++	rx->app_ops = app_ops;
+ }
+-EXPORT_SYMBOL(rxrpc_kernel_new_call_notification);
++EXPORT_SYMBOL(rxrpc_kernel_set_notifications);
+ 
+ /**
+  * rxrpc_kernel_set_max_life - Set maximum lifespan on a call
+diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
+index 3d0ee89f212456..5f5421680b2ebd 100644
+--- a/net/rxrpc/ar-internal.h
++++ b/net/rxrpc/ar-internal.h
+@@ -141,8 +141,7 @@ struct rxrpc_backlog {
+ struct rxrpc_sock {
+ 	/* WARNING: sk has to be the first member */
+ 	struct sock		sk;
+-	rxrpc_notify_new_call_t	notify_new_call; /* Func to notify of new call */
+-	rxrpc_discard_new_call_t discard_new_call; /* Func to discard a new call */
++	const struct rxrpc_kernel_ops *app_ops;	/* Table of kernel app notification funcs */
+ 	struct rxrpc_local	*local;		/* local endpoint */
+ 	struct rxrpc_backlog	*backlog;	/* Preallocation for services */
+ 	spinlock_t		incoming_lock;	/* Incoming call vs service shutdown lock */
+diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c
+index 37ac8a66567866..cbf6187d68edfd 100644
+--- a/net/rxrpc/call_accept.c
++++ b/net/rxrpc/call_accept.c
+@@ -34,7 +34,6 @@ static void rxrpc_dummy_notify(struct sock *sk, struct rxrpc_call *call,
+ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
+ 				      struct rxrpc_backlog *b,
+ 				      rxrpc_notify_rx_t notify_rx,
+-				      rxrpc_user_attach_call_t user_attach_call,
+ 				      unsigned long user_call_ID, gfp_t gfp,
+ 				      unsigned int debug_id)
+ {
+@@ -123,9 +122,10 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx,
+ 
+ 	call->user_call_ID = user_call_ID;
+ 	call->notify_rx = notify_rx;
+-	if (user_attach_call) {
++	if (rx->app_ops &&
++	    rx->app_ops->user_attach_call) {
+ 		rxrpc_get_call(call, rxrpc_call_get_kernel_service);
+-		user_attach_call(call, user_call_ID);
++		rx->app_ops->user_attach_call(call, user_call_ID);
+ 	}
+ 
+ 	rxrpc_get_call(call, rxrpc_call_get_userid);
+@@ -189,8 +189,8 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
+ 	/* Make sure that there aren't any incoming calls in progress before we
+ 	 * clear the preallocation buffers.
+ 	 */
+-	spin_lock(&rx->incoming_lock);
+-	spin_unlock(&rx->incoming_lock);
++	spin_lock_irq(&rx->incoming_lock);
++	spin_unlock_irq(&rx->incoming_lock);
+ 
+ 	head = b->peer_backlog_head;
+ 	tail = b->peer_backlog_tail;
+@@ -221,9 +221,10 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx)
+ 		struct rxrpc_call *call = b->call_backlog[tail];
+ 		rxrpc_see_call(call, rxrpc_call_see_discard);
+ 		rcu_assign_pointer(call->socket, rx);
+-		if (rx->discard_new_call) {
++		if (rx->app_ops &&
++		    rx->app_ops->discard_new_call) {
+ 			_debug("discard %lx", call->user_call_ID);
+-			rx->discard_new_call(call, call->user_call_ID);
++			rx->app_ops->discard_new_call(call, call->user_call_ID);
+ 			if (call->notify_rx)
+ 				call->notify_rx = rxrpc_dummy_notify;
+ 			rxrpc_put_call(call, rxrpc_call_put_kernel);
+@@ -348,7 +349,7 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,
+ 	if (sp->hdr.type != RXRPC_PACKET_TYPE_DATA)
+ 		return rxrpc_protocol_error(skb, rxrpc_eproto_no_service_call);
+ 
+-	read_lock(&local->services_lock);
++	read_lock_irq(&local->services_lock);
+ 
+ 	/* Weed out packets to services we're not offering.  Packets that would
+ 	 * begin a call are explicitly rejected and the rest are just
+@@ -392,8 +393,9 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,
+ 	rxrpc_incoming_call(rx, call, skb);
+ 	conn = call->conn;
+ 
+-	if (rx->notify_new_call)
+-		rx->notify_new_call(&rx->sk, call, call->user_call_ID);
++	if (rx->app_ops &&
++	    rx->app_ops->notify_new_call)
++		rx->app_ops->notify_new_call(&rx->sk, call, call->user_call_ID);
+ 
+ 	spin_lock(&conn->state_lock);
+ 	if (conn->state == RXRPC_CONN_SERVICE_UNSECURED) {
+@@ -404,12 +406,12 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,
+ 	spin_unlock(&conn->state_lock);
+ 
+ 	spin_unlock(&rx->incoming_lock);
+-	read_unlock(&local->services_lock);
++	read_unlock_irq(&local->services_lock);
+ 
+ 	if (hlist_unhashed(&call->error_link)) {
+-		spin_lock(&call->peer->lock);
++		spin_lock_irq(&call->peer->lock);
+ 		hlist_add_head(&call->error_link, &call->peer->error_targets);
+-		spin_unlock(&call->peer->lock);
++		spin_unlock_irq(&call->peer->lock);
+ 	}
+ 
+ 	_leave(" = %p{%d}", call, call->debug_id);
+@@ -418,20 +420,20 @@ bool rxrpc_new_incoming_call(struct rxrpc_local *local,
+ 	return true;
+ 
+ unsupported_service:
+-	read_unlock(&local->services_lock);
++	read_unlock_irq(&local->services_lock);
+ 	return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
+ 				  RX_INVALID_OPERATION, -EOPNOTSUPP);
+ unsupported_security:
+-	read_unlock(&local->services_lock);
++	read_unlock_irq(&local->services_lock);
+ 	return rxrpc_direct_abort(skb, rxrpc_abort_service_not_offered,
+ 				  RX_INVALID_OPERATION, -EKEYREJECTED);
+ no_call:
+ 	spin_unlock(&rx->incoming_lock);
+-	read_unlock(&local->services_lock);
++	read_unlock_irq(&local->services_lock);
+ 	_leave(" = f [%u]", skb->mark);
+ 	return false;
+ discard:
+-	read_unlock(&local->services_lock);
++	read_unlock_irq(&local->services_lock);
+ 	return true;
+ }
+ 
+@@ -445,8 +447,7 @@ int rxrpc_user_charge_accept(struct rxrpc_sock *rx, unsigned long user_call_ID)
+ 	if (rx->sk.sk_state == RXRPC_CLOSE)
+ 		return -ESHUTDOWN;
+ 
+-	return rxrpc_service_prealloc_one(rx, b, NULL, NULL, user_call_ID,
+-					  GFP_KERNEL,
++	return rxrpc_service_prealloc_one(rx, b, NULL, user_call_ID, GFP_KERNEL,
+ 					  atomic_inc_return(&rxrpc_debug_id));
+ }
+ 
+@@ -454,31 +455,41 @@ int rxrpc_user_charge_accept(struct rxrpc_sock *rx, unsigned long user_call_ID)
+  * rxrpc_kernel_charge_accept - Charge up socket with preallocated calls
+  * @sock: The socket on which to preallocate
+  * @notify_rx: Event notification function for the call
+- * @user_attach_call: Func to attach call to user_call_ID
+  * @user_call_ID: The tag to attach to the preallocated call
+  * @gfp: The allocation conditions.
+  * @debug_id: The tracing debug ID.
+  *
+- * Charge up the socket with preallocated calls, each with a user ID.  A
+- * function should be provided to effect the attachment from the user's side.
+- * The user is given a ref to hold on the call.
++ * Charge up the socket with preallocated calls, each with a user ID.  The
++ * ->user_attach_call() callback function should be provided to effect the
++ * attachment from the user's side.  The user is given a ref to hold on the
++ * call.
+  *
+  * Note that the call may be come connected before this function returns.
+  */
+-int rxrpc_kernel_charge_accept(struct socket *sock,
+-			       rxrpc_notify_rx_t notify_rx,
+-			       rxrpc_user_attach_call_t user_attach_call,
++int rxrpc_kernel_charge_accept(struct socket *sock, rxrpc_notify_rx_t notify_rx,
+ 			       unsigned long user_call_ID, gfp_t gfp,
+ 			       unsigned int debug_id)
+ {
+-	struct rxrpc_sock *rx = rxrpc_sk(sock->sk);
+-	struct rxrpc_backlog *b = rx->backlog;
++	struct rxrpc_backlog *b;
++	struct rxrpc_sock *rx;
++	struct sock *sk;
++	int ret;
+ 
+-	if (sock->sk->sk_state == RXRPC_CLOSE)
+-		return -ESHUTDOWN;
++	sk = sock->sk;
++	rx = rxrpc_sk(sk);
++
++	lock_sock(sk);
++	if (sk->sk_state != RXRPC_SERVER_LISTENING || !rx->backlog) {
++		ret = -ESHUTDOWN;
++		goto out;
++	}
++
++	b = rx->backlog;
++	ret = rxrpc_service_prealloc_one(rx, b, notify_rx, user_call_ID,
++					 gfp, debug_id);
+ 
+-	return rxrpc_service_prealloc_one(rx, b, notify_rx,
+-					  user_attach_call, user_call_ID,
+-					  gfp, debug_id);
++out:
++	release_sock(sk);
++	return ret;
+ }
+ EXPORT_SYMBOL(rxrpc_kernel_charge_accept);
+diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c
+index ede2fbc6611352..b9b48050c22d19 100644
+--- a/net/rxrpc/call_object.c
++++ b/net/rxrpc/call_object.c
+@@ -48,7 +48,7 @@ void rxrpc_poke_call(struct rxrpc_call *call, enum rxrpc_call_poke_trace what)
+ 	bool busy;
+ 
+ 	if (!test_bit(RXRPC_CALL_DISCONNECTED, &call->flags)) {
+-		spin_lock_bh(&local->lock);
++		spin_lock_irq(&local->lock);
+ 		busy = !list_empty(&call->attend_link);
+ 		trace_rxrpc_poke_call(call, busy, what);
+ 		if (!busy && !rxrpc_try_get_call(call, rxrpc_call_get_poke))
+@@ -56,7 +56,7 @@ void rxrpc_poke_call(struct rxrpc_call *call, enum rxrpc_call_poke_trace what)
+ 		if (!busy) {
+ 			list_add_tail(&call->attend_link, &local->call_attend_q);
+ 		}
+-		spin_unlock_bh(&local->lock);
++		spin_unlock_irq(&local->lock);
+ 		if (!busy)
+ 			rxrpc_wake_up_io_thread(local);
+ 	}
+@@ -311,9 +311,9 @@ static int rxrpc_connect_call(struct rxrpc_call *call, gfp_t gfp)
+ 
+ 	trace_rxrpc_client(NULL, -1, rxrpc_client_queue_new_call);
+ 	rxrpc_get_call(call, rxrpc_call_get_io_thread);
+-	spin_lock(&local->client_call_lock);
++	spin_lock_irq(&local->client_call_lock);
+ 	list_add_tail(&call->wait_link, &local->new_client_calls);
+-	spin_unlock(&local->client_call_lock);
++	spin_unlock_irq(&local->client_call_lock);
+ 	rxrpc_wake_up_io_thread(local);
+ 	return 0;
+ 
+@@ -439,7 +439,7 @@ error_attached_to_socket:
+ 
+ /*
+  * Set up an incoming call.  call->conn points to the connection.
+- * This is called in BH context and isn't allowed to fail.
++ * This is called with interrupts disabled and isn't allowed to fail.
+  */
+ void rxrpc_incoming_call(struct rxrpc_sock *rx,
+ 			 struct rxrpc_call *call,
+@@ -550,7 +550,7 @@ static void rxrpc_cleanup_ring(struct rxrpc_call *call)
+ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
+ {
+ 	struct rxrpc_connection *conn = call->conn;
+-	bool put = false, putu = false;
++	bool putu = false;
+ 
+ 	_enter("{%d,%d}", call->debug_id, refcount_read(&call->ref));
+ 
+@@ -562,23 +562,13 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call)
+ 
+ 	rxrpc_put_call_slot(call);
+ 
+-	/* Make sure we don't get any more notifications */
+-	spin_lock(&rx->recvmsg_lock);
+-
+-	if (!list_empty(&call->recvmsg_link)) {
+-		_debug("unlinking once-pending call %p { e=%lx f=%lx }",
+-		       call, call->events, call->flags);
+-		list_del(&call->recvmsg_link);
+-		put = true;
+-	}
+-
+-	/* list_empty() must return false in rxrpc_notify_socket() */
+-	call->recvmsg_link.next = NULL;
+-	call->recvmsg_link.prev = NULL;
+-
+-	spin_unlock(&rx->recvmsg_lock);
+-	if (put)
+-		rxrpc_put_call(call, rxrpc_call_put_unnotify);
++	/* Note that at this point, the call may still be on or may have been
++	 * added back on to the socket receive queue.  recvmsg() must discard
++	 * released calls.  The CALL_RELEASED flag should prevent further
++	 * notifications.
++	 */
++	spin_lock_irq(&rx->recvmsg_lock);
++	spin_unlock_irq(&rx->recvmsg_lock);
+ 
+ 	write_lock(&rx->call_lock);
+ 
+@@ -627,6 +617,12 @@ void rxrpc_release_calls_on_socket(struct rxrpc_sock *rx)
+ 		rxrpc_put_call(call, rxrpc_call_put_release_sock);
+ 	}
+ 
++	while ((call = list_first_entry_or_null(&rx->recvmsg_q,
++						struct rxrpc_call, recvmsg_link))) {
++		list_del_init(&call->recvmsg_link);
++		rxrpc_put_call(call, rxrpc_call_put_release_recvmsg_q);
++	}
++
+ 	_leave("");
+ }
+ 
+diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
+index a0231b64fb6ef0..05d851ed7f5aec 100644
+--- a/net/rxrpc/conn_client.c
++++ b/net/rxrpc/conn_client.c
+@@ -505,10 +505,10 @@ void rxrpc_connect_client_calls(struct rxrpc_local *local)
+ 	       ) {
+ 		struct rxrpc_bundle *bundle = call->bundle;
+ 
+-		spin_lock(&local->client_call_lock);
++		spin_lock_irq(&local->client_call_lock);
+ 		list_move_tail(&call->wait_link, &bundle->waiting_calls);
+ 		rxrpc_see_call(call, rxrpc_call_see_waiting_call);
+-		spin_unlock(&local->client_call_lock);
++		spin_unlock_irq(&local->client_call_lock);
+ 
+ 		if (rxrpc_bundle_has_space(bundle))
+ 			rxrpc_activate_channels(bundle);
+@@ -536,9 +536,9 @@ void rxrpc_expose_client_call(struct rxrpc_call *call)
+ 			set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
+ 		trace_rxrpc_client(conn, channel, rxrpc_client_exposed);
+ 
+-		spin_lock(&call->peer->lock);
++		spin_lock_irq(&call->peer->lock);
+ 		hlist_add_head(&call->error_link, &call->peer->error_targets);
+-		spin_unlock(&call->peer->lock);
++		spin_unlock_irq(&call->peer->lock);
+ 	}
+ }
+ 
+@@ -579,9 +579,9 @@ void rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call
+ 		ASSERTCMP(call->call_id, ==, 0);
+ 		ASSERT(!test_bit(RXRPC_CALL_EXPOSED, &call->flags));
+ 		/* May still be on ->new_client_calls. */
+-		spin_lock(&local->client_call_lock);
++		spin_lock_irq(&local->client_call_lock);
+ 		list_del_init(&call->wait_link);
+-		spin_unlock(&local->client_call_lock);
++		spin_unlock_irq(&local->client_call_lock);
+ 		return;
+ 	}
+ 
+diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
+index ab66903e4d72fd..25fbef44ca9d6a 100644
+--- a/net/rxrpc/conn_event.c
++++ b/net/rxrpc/conn_event.c
+@@ -26,7 +26,7 @@ static bool rxrpc_set_conn_aborted(struct rxrpc_connection *conn, struct sk_buff
+ 	bool aborted = false;
+ 
+ 	if (conn->state != RXRPC_CONN_ABORTED) {
+-		spin_lock(&conn->state_lock);
++		spin_lock_irq(&conn->state_lock);
+ 		if (conn->state != RXRPC_CONN_ABORTED) {
+ 			conn->abort_code = abort_code;
+ 			conn->error	 = err;
+@@ -37,7 +37,7 @@ static bool rxrpc_set_conn_aborted(struct rxrpc_connection *conn, struct sk_buff
+ 			set_bit(RXRPC_CONN_EV_ABORT_CALLS, &conn->events);
+ 			aborted = true;
+ 		}
+-		spin_unlock(&conn->state_lock);
++		spin_unlock_irq(&conn->state_lock);
+ 	}
+ 
+ 	return aborted;
+@@ -268,12 +268,12 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
+ 		return conn->security->respond_to_challenge(conn, skb);
+ 
+ 	case RXRPC_PACKET_TYPE_RESPONSE:
+-		spin_lock(&conn->state_lock);
++		spin_lock_irq(&conn->state_lock);
+ 		if (conn->state != RXRPC_CONN_SERVICE_CHALLENGING) {
+-			spin_unlock(&conn->state_lock);
++			spin_unlock_irq(&conn->state_lock);
+ 			return 0;
+ 		}
+-		spin_unlock(&conn->state_lock);
++		spin_unlock_irq(&conn->state_lock);
+ 
+ 		ret = rxrpc_verify_response(conn, skb);
+ 		if (ret < 0)
+@@ -284,12 +284,12 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
+ 		if (ret < 0)
+ 			return ret;
+ 
+-		spin_lock(&conn->state_lock);
++		spin_lock_irq(&conn->state_lock);
+ 		if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
+ 			conn->state = RXRPC_CONN_SERVICE;
+ 			secured = true;
+ 		}
+-		spin_unlock(&conn->state_lock);
++		spin_unlock_irq(&conn->state_lock);
+ 
+ 		if (secured) {
+ 			/* Offload call state flipping to the I/O thread.  As
+diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
+index f0c77f437b6167..90652f6e85159b 100644
+--- a/net/rxrpc/conn_object.c
++++ b/net/rxrpc/conn_object.c
+@@ -31,13 +31,13 @@ void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
+ 	if (WARN_ON_ONCE(!local))
+ 		return;
+ 
+-	spin_lock_bh(&local->lock);
++	spin_lock_irq(&local->lock);
+ 	busy = !list_empty(&conn->attend_link);
+ 	if (!busy) {
+ 		rxrpc_get_connection(conn, why);
+ 		list_add_tail(&conn->attend_link, &local->conn_attend_q);
+ 	}
+-	spin_unlock_bh(&local->lock);
++	spin_unlock_irq(&local->lock);
+ 	rxrpc_wake_up_io_thread(local);
+ }
+ 
+@@ -196,9 +196,9 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)
+ 	call->peer->cong_ssthresh = call->cong_ssthresh;
+ 
+ 	if (!hlist_unhashed(&call->error_link)) {
+-		spin_lock(&call->peer->lock);
++		spin_lock_irq(&call->peer->lock);
+ 		hlist_del_init(&call->error_link);
+-		spin_unlock(&call->peer->lock);
++		spin_unlock_irq(&call->peer->lock);
+ 	}
+ 
+ 	if (rxrpc_is_client_call(call)) {
+diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c
+index 1157bf75ef9c8c..0503698af46d6f 100644
+--- a/net/rxrpc/input.c
++++ b/net/rxrpc/input.c
+@@ -366,7 +366,7 @@ static void rxrpc_input_queue_data(struct rxrpc_call *call, struct sk_buff *skb,
+ 	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+ 	bool last = sp->hdr.flags & RXRPC_LAST_PACKET;
+ 
+-	__skb_queue_tail(&call->recvmsg_queue, skb);
++	skb_queue_tail(&call->recvmsg_queue, skb);
+ 	rxrpc_input_update_ack_window(call, window, wtop);
+ 	trace_rxrpc_receive(call, last ? why + 1 : why, sp->hdr.serial, sp->hdr.seq);
+ 	if (last)
+@@ -443,7 +443,6 @@ static void rxrpc_input_data_one(struct rxrpc_call *call, struct sk_buff *skb,
+ 
+ 		rxrpc_get_skb(skb, rxrpc_skb_get_to_recvmsg);
+ 
+-		spin_lock(&call->recvmsg_queue.lock);
+ 		rxrpc_input_queue_data(call, skb, window, wtop, rxrpc_receive_queue);
+ 		*_notify = true;
+ 
+@@ -465,8 +464,6 @@ static void rxrpc_input_data_one(struct rxrpc_call *call, struct sk_buff *skb,
+ 					       rxrpc_receive_queue_oos);
+ 		}
+ 
+-		spin_unlock(&call->recvmsg_queue.lock);
+-
+ 		call->ackr_sack_base = sack;
+ 	} else {
+ 		unsigned int slot;
+diff --git a/net/rxrpc/io_thread.c b/net/rxrpc/io_thread.c
+index f542eda13ff0bf..d2046f7504f801 100644
+--- a/net/rxrpc/io_thread.c
++++ b/net/rxrpc/io_thread.c
+@@ -423,9 +423,9 @@ int rxrpc_io_thread(void *data)
+ 						struct rxrpc_connection,
+ 						attend_link);
+ 		if (conn) {
+-			spin_lock_bh(&local->lock);
++			spin_lock_irq(&local->lock);
+ 			list_del_init(&conn->attend_link);
+-			spin_unlock_bh(&local->lock);
++			spin_unlock_irq(&local->lock);
+ 
+ 			rxrpc_input_conn_event(conn, NULL);
+ 			rxrpc_put_connection(conn, rxrpc_conn_put_poke);
+@@ -440,9 +440,9 @@ int rxrpc_io_thread(void *data)
+ 		if ((call = list_first_entry_or_null(&local->call_attend_q,
+ 						     struct rxrpc_call,
+ 						     attend_link))) {
+-			spin_lock_bh(&local->lock);
++			spin_lock_irq(&local->lock);
+ 			list_del_init(&call->attend_link);
+-			spin_unlock_bh(&local->lock);
++			spin_unlock_irq(&local->lock);
+ 
+ 			trace_rxrpc_call_poked(call);
+ 			rxrpc_input_call_event(call, NULL);
+diff --git a/net/rxrpc/peer_event.c b/net/rxrpc/peer_event.c
+index 8c7fad55da74d7..fd66d18b94df4b 100644
+--- a/net/rxrpc/peer_event.c
++++ b/net/rxrpc/peer_event.c
+@@ -205,23 +205,23 @@ static void rxrpc_distribute_error(struct rxrpc_peer *peer, struct sk_buff *skb,
+ 	struct rxrpc_call *call;
+ 	HLIST_HEAD(error_targets);
+ 
+-	spin_lock(&peer->lock);
++	spin_lock_irq(&peer->lock);
+ 	hlist_move_list(&peer->error_targets, &error_targets);
+ 
+ 	while (!hlist_empty(&error_targets)) {
+ 		call = hlist_entry(error_targets.first,
+ 				   struct rxrpc_call, error_link);
+ 		hlist_del_init(&call->error_link);
+-		spin_unlock(&peer->lock);
++		spin_unlock_irq(&peer->lock);
+ 
+ 		rxrpc_see_call(call, rxrpc_call_see_distribute_error);
+ 		rxrpc_set_call_completion(call, compl, 0, -err);
+ 		rxrpc_input_call_event(call, skb);
+ 
+-		spin_lock(&peer->lock);
++		spin_lock_irq(&peer->lock);
+ 	}
+ 
+-	spin_unlock(&peer->lock);
++	spin_unlock_irq(&peer->lock);
+ }
+ 
+ /*
+diff --git a/net/rxrpc/peer_object.c b/net/rxrpc/peer_object.c
+index 8d7a715a0bb1ca..3a4cf95ecddfce 100644
+--- a/net/rxrpc/peer_object.c
++++ b/net/rxrpc/peer_object.c
+@@ -302,6 +302,7 @@ static void rxrpc_free_peer(struct rxrpc_peer *peer)
+  * Set up a new incoming peer.  There shouldn't be any other matching peers
+  * since we've already done a search in the list from the non-reentrant context
+  * (the data_ready handler) that is the only place we can add new peers.
++ * Called with interrupts disabled.
+  */
+ void rxrpc_new_incoming_peer(struct rxrpc_local *local, struct rxrpc_peer *peer)
+ {
+diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
+index 4f4094d0c5cc23..beb0eb426592a7 100644
+--- a/net/rxrpc/recvmsg.c
++++ b/net/rxrpc/recvmsg.c
+@@ -27,8 +27,10 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
+ 
+ 	_enter("%d", call->debug_id);
+ 
+-	if (!list_empty(&call->recvmsg_link))
++	if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) {
++		rxrpc_see_call(call, rxrpc_call_see_notify_released);
+ 		return;
++	}
+ 
+ 	rcu_read_lock();
+ 
+@@ -36,16 +38,16 @@ void rxrpc_notify_socket(struct rxrpc_call *call)
+ 	sk = &rx->sk;
+ 	if (rx && sk->sk_state < RXRPC_CLOSE) {
+ 		if (call->notify_rx) {
+-			spin_lock(&call->notify_lock);
++			spin_lock_irq(&call->notify_lock);
+ 			call->notify_rx(sk, call, call->user_call_ID);
+-			spin_unlock(&call->notify_lock);
++			spin_unlock_irq(&call->notify_lock);
+ 		} else {
+-			spin_lock(&rx->recvmsg_lock);
++			spin_lock_irq(&rx->recvmsg_lock);
+ 			if (list_empty(&call->recvmsg_link)) {
+ 				rxrpc_get_call(call, rxrpc_call_get_notify_socket);
+ 				list_add_tail(&call->recvmsg_link, &rx->recvmsg_q);
+ 			}
+-			spin_unlock(&rx->recvmsg_lock);
++			spin_unlock_irq(&rx->recvmsg_lock);
+ 
+ 			if (!sock_flag(sk, SOCK_DEAD)) {
+ 				_debug("call %ps", sk->sk_data_ready);
+@@ -379,14 +381,14 @@ try_again:
+ 	 * We also want to weed out calls that got requeued whilst we were
+ 	 * shovelling data out.
+ 	 */
+-	spin_lock(&rx->recvmsg_lock);
++	spin_lock_irq(&rx->recvmsg_lock);
+ 	l = rx->recvmsg_q.next;
+ 	call = list_entry(l, struct rxrpc_call, recvmsg_link);
+ 
+ 	if (!rxrpc_call_is_complete(call) &&
+ 	    skb_queue_empty(&call->recvmsg_queue)) {
+ 		list_del_init(&call->recvmsg_link);
+-		spin_unlock(&rx->recvmsg_lock);
++		spin_unlock_irq(&rx->recvmsg_lock);
+ 		release_sock(&rx->sk);
+ 		trace_rxrpc_recvmsg(call->debug_id, rxrpc_recvmsg_unqueue, 0);
+ 		rxrpc_put_call(call, rxrpc_call_put_recvmsg);
+@@ -407,7 +409,7 @@ try_again:
+ 		list_del_init(&call->recvmsg_link);
+ 	else
+ 		rxrpc_get_call(call, rxrpc_call_get_recvmsg);
+-	spin_unlock(&rx->recvmsg_lock);
++	spin_unlock_irq(&rx->recvmsg_lock);
+ 
+ 	call_debug_id = call->debug_id;
+ 	trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_dequeue, 0);
+@@ -502,17 +504,17 @@ error_unlock_call:
+ 
+ error_requeue_call:
+ 	if (!(flags & MSG_PEEK)) {
+-		spin_lock(&rx->recvmsg_lock);
++		spin_lock_irq(&rx->recvmsg_lock);
+ 		if (list_empty(&call->recvmsg_link)) {
+ 			list_add(&call->recvmsg_link, &rx->recvmsg_q);
+ 			rxrpc_see_call(call, rxrpc_call_see_recvmsg_requeue);
+-			spin_unlock(&rx->recvmsg_lock);
++			spin_unlock_irq(&rx->recvmsg_lock);
+ 		} else if (list_is_first(&call->recvmsg_link, &rx->recvmsg_q)) {
+-			spin_unlock(&rx->recvmsg_lock);
++			spin_unlock_irq(&rx->recvmsg_lock);
+ 			rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_first);
+ 		} else {
+ 			list_move(&call->recvmsg_link, &rx->recvmsg_q);
+-			spin_unlock(&rx->recvmsg_lock);
++			spin_unlock_irq(&rx->recvmsg_lock);
+ 			rxrpc_put_call(call, rxrpc_call_see_recvmsg_requeue_move);
+ 		}
+ 		trace_rxrpc_recvmsg(call_debug_id, rxrpc_recvmsg_requeue, 0);
+diff --git a/net/rxrpc/rxperf.c b/net/rxrpc/rxperf.c
+index b1536da2246b82..7b53e06da45876 100644
+--- a/net/rxrpc/rxperf.c
++++ b/net/rxrpc/rxperf.c
+@@ -136,6 +136,12 @@ static void rxperf_notify_end_reply_tx(struct sock *sock,
+ 			      RXPERF_CALL_SV_AWAIT_ACK);
+ }
+ 
++static const struct rxrpc_kernel_ops rxperf_rxrpc_callback_ops = {
++	.notify_new_call	= rxperf_rx_new_call,
++	.discard_new_call	= rxperf_rx_discard_new_call,
++	.user_attach_call	= rxperf_rx_attach,
++};
++
+ /*
+  * Charge the incoming call preallocation.
+  */
+@@ -161,7 +167,6 @@ static void rxperf_charge_preallocation(struct work_struct *work)
+ 
+ 		if (rxrpc_kernel_charge_accept(rxperf_socket,
+ 					       rxperf_notify_rx,
+-					       rxperf_rx_attach,
+ 					       (unsigned long)call,
+ 					       GFP_KERNEL,
+ 					       call->debug_id) < 0)
+@@ -209,8 +214,7 @@ static int rxperf_open_socket(void)
+ 	if (ret < 0)
+ 		goto error_2;
+ 
+-	rxrpc_kernel_new_call_notification(socket, rxperf_rx_new_call,
+-					   rxperf_rx_discard_new_call);
++	rxrpc_kernel_set_notifications(socket, &rxperf_rxrpc_callback_ops);
+ 
+ 	ret = kernel_listen(socket, INT_MAX);
+ 	if (ret < 0)
+diff --git a/net/rxrpc/security.c b/net/rxrpc/security.c
+index cb8dd1d3b1d49e..9784adc8f27593 100644
+--- a/net/rxrpc/security.c
++++ b/net/rxrpc/security.c
+@@ -114,10 +114,10 @@ found:
+ 	if (conn->state == RXRPC_CONN_CLIENT_UNSECURED) {
+ 		ret = conn->security->init_connection_security(conn, token);
+ 		if (ret == 0) {
+-			spin_lock(&conn->state_lock);
++			spin_lock_irq(&conn->state_lock);
+ 			if (conn->state == RXRPC_CONN_CLIENT_UNSECURED)
+ 				conn->state = RXRPC_CONN_CLIENT;
+-			spin_unlock(&conn->state_lock);
++			spin_unlock_irq(&conn->state_lock);
+ 		}
+ 	}
+ 	mutex_unlock(&conn->security_lock);
+diff --git a/net/rxrpc/sendmsg.c b/net/rxrpc/sendmsg.c
+index 6939617afc7bcd..3dc54d6d4e316f 100644
+--- a/net/rxrpc/sendmsg.c
++++ b/net/rxrpc/sendmsg.c
+@@ -93,9 +93,11 @@ no_wait:
+  */
+ static bool rxrpc_check_tx_space(struct rxrpc_call *call, rxrpc_seq_t *_tx_win)
+ {
++	rxrpc_seq_t tx_bottom = READ_ONCE(call->tx_bottom);
++
+ 	if (_tx_win)
+-		*_tx_win = call->tx_bottom;
+-	return call->tx_prepared - call->tx_bottom < 256;
++		*_tx_win = tx_bottom;
++	return call->tx_prepared - tx_bottom < 256;
+ }
+ 
+ /*
+@@ -137,7 +139,7 @@ static int rxrpc_wait_for_tx_window_waitall(struct rxrpc_sock *rx,
+ 		rtt = 2;
+ 
+ 	timeout = rtt;
+-	tx_start = smp_load_acquire(&call->acks_hard_ack);
++	tx_start = READ_ONCE(call->acks_hard_ack);
+ 
+ 	for (;;) {
+ 		set_current_state(TASK_UNINTERRUPTIBLE);
+diff --git a/net/rxrpc/txbuf.c b/net/rxrpc/txbuf.c
+index d43be851238640..84d067fbc2fd10 100644
+--- a/net/rxrpc/txbuf.c
++++ b/net/rxrpc/txbuf.c
+@@ -112,14 +112,14 @@ void rxrpc_shrink_call_tx_buffer(struct rxrpc_call *call)
+ 
+ 	while ((txb = list_first_entry_or_null(&call->tx_buffer,
+ 					       struct rxrpc_txbuf, call_link))) {
+-		hard_ack = smp_load_acquire(&call->acks_hard_ack);
++		hard_ack = call->acks_hard_ack;
+ 		if (before(hard_ack, txb->seq))
+ 			break;
+ 
+ 		if (txb->seq != call->tx_bottom + 1)
+ 			rxrpc_see_txbuf(txb, rxrpc_txbuf_see_out_of_step);
+ 		ASSERTCMP(txb->seq, ==, call->tx_bottom + 1);
+-		smp_store_release(&call->tx_bottom, call->tx_bottom + 1);
++		WRITE_ONCE(call->tx_bottom, call->tx_bottom + 1);
+ 		list_del_rcu(&txb->call_link);
+ 
+ 		trace_rxrpc_txqueue(call, rxrpc_txqueue_dequeue);
+diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
+index 99fb869aee91b7..65664e530c73b5 100644
+--- a/net/sched/act_tunnel_key.c
++++ b/net/sched/act_tunnel_key.c
+@@ -344,14 +344,20 @@ static const struct nla_policy tunnel_key_policy[TCA_TUNNEL_KEY_MAX + 1] = {
+ 	[TCA_TUNNEL_KEY_ENC_TTL]      = { .type = NLA_U8 },
+ };
+ 
+-static void tunnel_key_release_params(struct tcf_tunnel_key_params *p)
++static void tunnel_key_release_params_rcu(struct rcu_head *head)
+ {
+-	if (!p)
+-		return;
++	struct tcf_tunnel_key_params *p = container_of(head, typeof(*p), rcu);
++
+ 	if (p->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
+ 		dst_release(&p->tcft_enc_metadata->dst);
++	kfree(p);
++}
+ 
+-	kfree_rcu(p, rcu);
++static void tunnel_key_release_params(struct tcf_tunnel_key_params *p)
++{
++	if (!p)
++		return;
++	call_rcu(&p->rcu, tunnel_key_release_params_rcu);
+ }
+ 
+ static int tunnel_key_init(struct net *net, struct nlattr *nla,
+diff --git a/net/sctp/auth.c b/net/sctp/auth.c
+index c58fffc86a0c2d..8320764b16b928 100644
+--- a/net/sctp/auth.c
++++ b/net/sctp/auth.c
+@@ -766,7 +766,7 @@ int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id)
+ 	/* Check if we can add this chunk to the array */
+ 	param_len = ntohs(p->param_hdr.length);
+ 	nchunks = param_len - sizeof(struct sctp_paramhdr);
+-	if (nchunks == SCTP_NUM_CHUNK_TYPES)
++	if (nchunks == SCTP_AUTH_MAX_CHUNKS)
+ 		return -EINVAL;
+ 
+ 	p->chunks[nchunks] = chunk_id;
+diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
+index 611bddad36d4ac..9ed8f502a9c1f4 100644
+--- a/net/sctp/sm_make_chunk.c
++++ b/net/sctp/sm_make_chunk.c
+@@ -3171,6 +3171,12 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
+ 		if (!peer)
+ 			return SCTP_ERROR_DNS_FAILED;
+ 
++		/* Don't free asconf->transport; a later wildcard DEL-IP
++		 * parameter reuses it.
++		 */
++		if (peer == asconf->transport)
++			return SCTP_ERROR_REQ_REFUSED;
++
+ 		sctp_assoc_rm_peer(asoc, peer);
+ 		break;
+ 	case SCTP_PARAM_SET_PRIMARY:
+diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
+index fc04bea029dc1d..ce0b5d6b4c5239 100644
+--- a/net/sctp/sm_statefuns.c
++++ b/net/sctp/sm_statefuns.c
+@@ -640,7 +640,7 @@ static bool sctp_auth_chunk_verify(struct net *net, struct sctp_chunk *chunk,
+ 	struct sctp_chunk auth;
+ 
+ 	if (!chunk->auth_chunk)
+-		return true;
++		return !sctp_auth_recv_cid(chunk->chunk_hdr->type, asoc);
+ 
+ 	/* SCTP-AUTH:  auth_chunk pointer is only set when the cookie-echo
+ 	 * is supposed to be authenticated and we have to do delayed
+diff --git a/net/sctp/stream.c b/net/sctp/stream.c
+index e8922f350bafe6..0f81820c730bae 100644
+--- a/net/sctp/stream.c
++++ b/net/sctp/stream.c
+@@ -308,7 +308,8 @@ int sctp_send_reset_streams(struct sctp_association *asoc,
+ 					goto out;
+ 
+ 			param_len += str_nums * sizeof(__u16) +
+-				     sizeof(struct sctp_strreset_inreq);
++				     (out ? sizeof(struct sctp_strreset_inreq)
++					  : sizeof(struct sctp_strreset_outreq));
+ 		}
+ 
+ 		if (param_len > SCTP_MAX_CHUNK_LEN -
+@@ -639,6 +640,9 @@ struct sctp_chunk *sctp_process_strreset_inreq(
+ 
+ 	nums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
+ 	str_p = inreq->list_of_streams;
++	if (nums * sizeof(__u16) + sizeof(struct sctp_strreset_outreq) >
++	    SCTP_MAX_CHUNK_LEN - sizeof(struct sctp_reconf_chunk))
++		goto out;
+ 	for (i = 0; i < nums; i++) {
+ 		if (ntohs(str_p[i]) >= stream->outcnt) {
+ 			result = SCTP_STRRESET_ERR_WRONG_SSN;
+diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
+index ec09154bd4b2e9..2c226775633309 100644
+--- a/net/sunrpc/svcsock.c
++++ b/net/sunrpc/svcsock.c
+@@ -68,6 +68,17 @@
+ 
+ #define RPCDBG_FACILITY	RPCDBG_SVCXPRT
+ 
++/*
++ * For UDP:
++ * 1 for header page
++ * enough pages for RPCSVC_MAXPAYLOAD_UDP
++ * 1 in case payload is not aligned
++ * 1 for tail page
++ */
++enum {
++	SUNRPC_MAX_UDP_SENDPAGES = 1 + RPCSVC_MAXPAYLOAD_UDP / PAGE_SIZE + 1 + 1
++};
++
+ /* To-do: to avoid tying up an nfsd thread while waiting for a
+  * handshake request, the request could instead be deferred.
+  */
+@@ -737,7 +748,7 @@ static int svc_udp_sendto(struct svc_rqst *rqstp)
+ 		.msg_flags	= MSG_SPLICE_PAGES,
+ 		.msg_controllen	= sizeof(buffer),
+ 	};
+-	unsigned int count;
++	int count;
+ 	int err;
+ 
+ 	svc_udp_release_ctxt(xprt, rqstp->rq_xprt_ctxt);
+@@ -750,19 +761,23 @@ static int svc_udp_sendto(struct svc_rqst *rqstp)
+ 	if (svc_xprt_is_dead(xprt))
+ 		goto out_notconn;
+ 
+-	count = xdr_buf_to_bvec(rqstp->rq_bvec,
+-				ARRAY_SIZE(rqstp->rq_bvec), xdr);
++	count = xdr_buf_to_bvec(svsk->sk_bvec, SUNRPC_MAX_UDP_SENDPAGES, xdr);
++	if (count < 0) {
++		err = count;
++		goto out_trace;
++	}
+ 
+-	iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, rqstp->rq_bvec,
++	iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, svsk->sk_bvec,
+ 		      count, rqstp->rq_res.len);
+ 	err = sock_sendmsg(svsk->sk_sock, &msg);
+ 	if (err == -ECONNREFUSED) {
+ 		/* ICMP error on earlier request. */
+-		iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, rqstp->rq_bvec,
++		iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, svsk->sk_bvec,
+ 			      count, rqstp->rq_res.len);
+ 		err = sock_sendmsg(svsk->sk_sock, &msg);
+ 	}
+ 
++out_trace:
+ 	trace_svcsock_udp_send(xprt, err);
+ 
+ 	mutex_unlock(&xprt->xpt_mutex);
+@@ -1250,28 +1265,33 @@ static int svc_tcp_sendmsg(struct svc_sock *svsk, struct svc_rqst *rqstp,
+ 	struct msghdr msg = {
+ 		.msg_flags	= MSG_SPLICE_PAGES,
+ 	};
+-	unsigned int count;
++	int count;
+ 	void *buf;
+ 	int ret;
+ 
+ 	*sentp = 0;
+ 
+ 	/* The stream record marker is copied into a temporary page
+-	 * fragment buffer so that it can be included in rq_bvec.
++	 * fragment buffer so that it can be included in sk_bvec.
+ 	 */
+ 	buf = page_frag_alloc(&svsk->sk_frag_cache, sizeof(marker),
+ 			      GFP_KERNEL);
+ 	if (!buf)
+ 		return -ENOMEM;
+ 	memcpy(buf, &marker, sizeof(marker));
+-	bvec_set_virt(rqstp->rq_bvec, buf, sizeof(marker));
++	bvec_set_virt(svsk->sk_bvec, buf, sizeof(marker));
+ 
+-	count = xdr_buf_to_bvec(rqstp->rq_bvec + 1,
+-				ARRAY_SIZE(rqstp->rq_bvec) - 1, &rqstp->rq_res);
++	count = xdr_buf_to_bvec(svsk->sk_bvec + 1, RPCSVC_MAXPAGES,
++				&rqstp->rq_res);
++	if (count < 0) {
++		ret = count;
++		goto out;
++	}
+ 
+-	iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, rqstp->rq_bvec,
++	iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, svsk->sk_bvec,
+ 		      1 + count, sizeof(marker) + rqstp->rq_res.len);
+ 	ret = sock_sendmsg(svsk->sk_sock, &msg);
++out:
+ 	page_frag_free(buf);
+ 	if (ret < 0)
+ 		return ret;
+@@ -1432,6 +1452,13 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
+ 	if (!svsk)
+ 		return ERR_PTR(-ENOMEM);
+ 
++	svsk->sk_bvec = kcalloc(RPCSVC_MAXPAGES + 1, sizeof(*svsk->sk_bvec),
++				GFP_KERNEL);
++	if (!svsk->sk_bvec) {
++		kfree(svsk);
++		return ERR_PTR(-ENOMEM);
++	}
++
+ 	inet = sock->sk;
+ 
+ 	if (pmap_register) {
+@@ -1441,6 +1468,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
+ 				     inet->sk_protocol,
+ 				     ntohs(inet_sk(inet)->inet_sport));
+ 		if (err < 0) {
++			kfree(svsk->sk_bvec);
+ 			kfree(svsk);
+ 			return ERR_PTR(err);
+ 		}
+@@ -1660,5 +1688,6 @@ static void svc_sock_free(struct svc_xprt *xprt)
+ 	if (pfc->va)
+ 		__page_frag_cache_drain(virt_to_head_page(pfc->va),
+ 					pfc->pagecnt_bias);
++	kfree(svsk->sk_bvec);
+ 	kfree(svsk);
+ }
+diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
+index 80250af10777ab..94912fc0805111 100644
+--- a/net/sunrpc/xdr.c
++++ b/net/sunrpc/xdr.c
+@@ -167,13 +167,14 @@ xdr_free_bvec(struct xdr_buf *buf)
+ /**
+  * xdr_buf_to_bvec - Copy components of an xdr_buf into a bio_vec array
+  * @bvec: bio_vec array to populate
+- * @bvec_size: element count of @bio_vec
++ * @bvec_size: element count of @bvec
+  * @xdr: xdr_buf to be copied
+  *
+- * Returns the number of entries consumed in @bvec.
++ * Returns the number of entries consumed in @bvec on success, or
++ * -ESERVERFAULT when @xdr does not fit within @bvec_size entries.
+  */
+-unsigned int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
+-			     const struct xdr_buf *xdr)
++int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
++		    const struct xdr_buf *xdr)
+ {
+ 	const struct kvec *head = xdr->head;
+ 	const struct kvec *tail = xdr->tail;
+@@ -215,8 +216,207 @@ unsigned int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
+ 
+ bvec_overflow:
+ 	pr_warn_once("%s: bio_vec array overflow\n", __func__);
+-	return count;
++	return -ESERVERFAULT;
++}
++
++/**
++ * xdr_buf_to_sg - Populate a scatterlist from an xdr_buf range
++ * @buf: xdr_buf to map
++ * @offset: starting byte offset within @buf
++ * @len: number of bytes to cover
++ * @sg: scatterlist array initialized with sg_init_table()
++ * @nsg: number of entries available in @sg
++ *
++ * @sg is traversed with sg_next(), so callers may pass a list
++ * assembled with sg_chain().
++ *
++ * Return: on success, the number of scatterlist entries used; the
++ * last used entry is marked with sg_mark_end().  On failure, a
++ * negative errno.
++ */
++int xdr_buf_to_sg(const struct xdr_buf *buf, unsigned int offset,
++		  unsigned int len, struct scatterlist *sg, unsigned int nsg)
++{
++	unsigned int page_len, thislen, page_offset;
++	struct scatterlist *cur = sg, *prev = NULL;
++	int nents = 0;
++	int i;
++
++	if (len == 0)
++		return 0;
++
++	if (offset >= buf->head[0].iov_len) {
++		offset -= buf->head[0].iov_len;
++	} else {
++		thislen = min_t(unsigned int,
++				buf->head[0].iov_len - offset, len);
++		if (nents >= nsg)
++			return -ENOSPC;
++		sg_set_buf(cur, buf->head[0].iov_base + offset,
++			   thislen);
++		prev = cur;
++		cur = sg_next(cur);
++		nents++;
++		len -= thislen;
++		offset = 0;
++	}
++	if (len == 0)
++		goto done;
++
++	if (offset >= buf->page_len) {
++		offset -= buf->page_len;
++	} else {
++		page_len = min(buf->page_len - offset, len);
++		len -= page_len;
++		page_offset = (offset + buf->page_base) & (PAGE_SIZE - 1);
++		i = (offset + buf->page_base) >> PAGE_SHIFT;
++		thislen = PAGE_SIZE - page_offset;
++		do {
++			if (thislen > page_len)
++				thislen = page_len;
++			if (nents >= nsg)
++				return -ENOSPC;
++			sg_set_page(cur, buf->pages[i],
++				    thislen, page_offset);
++			prev = cur;
++			cur = sg_next(cur);
++			nents++;
++			page_len -= thislen;
++			i++;
++			page_offset = 0;
++			thislen = PAGE_SIZE;
++		} while (page_len != 0);
++		offset = 0;
++	}
++	if (len == 0)
++		goto done;
++
++	if (offset < buf->tail[0].iov_len) {
++		thislen = min_t(unsigned int,
++				buf->tail[0].iov_len - offset, len);
++		if (nents >= nsg)
++			return -ENOSPC;
++		sg_set_buf(cur, buf->tail[0].iov_base + offset,
++			   thislen);
++		prev = cur;
++		nents++;
++		len -= thislen;
++	}
++	if (len != 0)
++		return -EINVAL;
++
++done:
++	if (prev)
++		sg_mark_end(prev);
++	return nents;
++}
++EXPORT_SYMBOL_GPL(xdr_buf_to_sg);
++
++/*
++ * Count the scatterlist entries needed to cover [offset, offset + len)
++ * within @buf.  Mirrors the walk in xdr_buf_to_sg() so the caller can
++ * size an allocation that matches the requested sub-range rather than
++ * the full xdr_buf.
++ */
++static unsigned int xdr_buf_sg_nents(const struct xdr_buf *buf,
++				     unsigned int offset, unsigned int len)
++{
++	unsigned int nsg = 0, thislen, page_offset;
++
++	if (len == 0)
++		return 0;
++
++	if (offset < buf->head[0].iov_len) {
++		thislen = min_t(unsigned int,
++				buf->head[0].iov_len - offset, len);
++		nsg++;
++		len -= thislen;
++		offset = 0;
++	} else {
++		offset -= buf->head[0].iov_len;
++	}
++	if (len == 0)
++		return nsg;
++
++	if (offset < buf->page_len) {
++		thislen = min(buf->page_len - offset, len);
++		page_offset = (offset + buf->page_base) & (PAGE_SIZE - 1);
++		nsg += DIV_ROUND_UP(page_offset + thislen, PAGE_SIZE);
++		len -= thislen;
++		offset = 0;
++	} else {
++		offset -= buf->page_len;
++	}
++	if (len == 0)
++		return nsg;
++
++	if (offset < buf->tail[0].iov_len)
++		nsg++;
++	return nsg;
++}
++
++/**
++ * xdr_buf_to_sg_alloc - Populate a scatterlist for an xdr_buf range
++ * @buf: xdr_buf to map
++ * @offset: starting byte offset within @buf
++ * @len: number of bytes to cover
++ * @sg_head: caller-provided scatterlist array (typically stack-allocated)
++ * @sg_head_nents: number of entries in @sg_head
++ * @sg_overflow: OUT: chained extension, or NULL when @sg_head sufficed
++ * @gfp: memory allocation flags for overflow
++ *
++ * Populates @sg_head directly when the xdr_buf fits.  When more
++ * entries are needed, an overflow scatterlist is allocated and
++ * chained from @sg_head so that the result is traversable with
++ * sg_next().
++ *
++ * Return: on success, the number of populated scatterlist entries
++ * (counting only data entries, not chain entries).  @sg_head is
++ * the head of the resulting list.  Caller must kfree @sg_overflow
++ * when done.  On failure, a negative errno.
++ */
++int xdr_buf_to_sg_alloc(const struct xdr_buf *buf, unsigned int offset,
++			unsigned int len, struct scatterlist *sg_head,
++			unsigned int sg_head_nents,
++			struct scatterlist **sg_overflow, gfp_t gfp)
++{
++	unsigned int nsg;
++	int ret;
++
++	*sg_overflow = NULL;
++	if (len == 0)
++		return 0;
++
++	nsg = xdr_buf_sg_nents(buf, offset, len);
++	if (nsg == 0)
++		return -EINVAL;
++
++	if (nsg <= sg_head_nents) {
++		sg_init_table(sg_head, nsg);
++	} else {
++		/* +1 replaces the slot sg_chain() consumes as the link. */
++		unsigned int overflow_nents = nsg - sg_head_nents + 1;
++		struct scatterlist *overflow;
++
++		overflow = kmalloc_array(overflow_nents, sizeof(*overflow),
++					 gfp);
++		if (!overflow)
++			return -ENOMEM;
++
++		sg_init_table(sg_head, sg_head_nents);
++		sg_init_table(overflow, overflow_nents);
++		sg_chain(sg_head, sg_head_nents, overflow);
++		*sg_overflow = overflow;
++	}
++
++	ret = xdr_buf_to_sg(buf, offset, len, sg_head, nsg);
++	if (ret < 0) {
++		kfree(*sg_overflow);
++		*sg_overflow = NULL;
++	}
++	return ret;
+ }
++EXPORT_SYMBOL_GPL(xdr_buf_to_sg_alloc);
+ 
+ /**
+  * xdr_inline_pages - Prepare receive buffer for a large reply
+diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
+index e201b37578a70e..aa57e057ff451f 100644
+--- a/net/sunrpc/xprtrdma/rpc_rdma.c
++++ b/net/sunrpc/xprtrdma/rpc_rdma.c
+@@ -542,6 +542,7 @@ void rpcrdma_sendctx_unmap(struct rpcrdma_sendctx *sc)
+ 
+ 	rpcrdma_sendctx_dma_unmap(sc);
+ 	sc->sc_req = NULL;
++	req->rl_sendctx = NULL;
+ 	rpcrdma_req_put(req);
+ }
+ 
+@@ -550,8 +551,11 @@ void rpcrdma_sendctx_unmap(struct rpcrdma_sendctx *sc)
+  */
+ static void rpcrdma_sendctx_cancel(struct rpcrdma_sendctx *sc)
+ {
++	struct rpcrdma_req *req = sc->sc_req;
++
+ 	rpcrdma_sendctx_dma_unmap(sc);
+ 	sc->sc_req = NULL;
++	req->rl_sendctx = NULL;
+ }
+ 
+ /* Prepare an SGE for the RPC-over-RDMA transport header.
+diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
+index 27bb176f082f63..a97f0b18ac4294 100644
+--- a/net/sunrpc/xprtrdma/verbs.c
++++ b/net/sunrpc/xprtrdma/verbs.c
+@@ -1067,9 +1067,15 @@ static struct rpcrdma_rep *rpcrdma_rep_get_locked(struct rpcrdma_buffer *buf)
+  * @buf: buffer pool
+  * @rep: rep to release
+  *
++ * The rep's transient association with an rpc_rqst, established
++ * by rpcrdma_reply_handler() and torn down here, must not survive
++ * onto rb_free_reps: rpcrdma_post_recvs() pulls reps from the free
++ * list to re-post them, and a non-NULL rr_rqst on a free-listed rep
++ * would imply the rep is still referenced by a req.
+  */
+ void rpcrdma_rep_put(struct rpcrdma_buffer *buf, struct rpcrdma_rep *rep)
+ {
++	rep->rr_rqst = NULL;
+ 	llist_add(&rep->rr_node, &buf->rb_free_reps);
+ }
+ 
+@@ -1252,9 +1258,11 @@ rpcrdma_mr_get(struct rpcrdma_xprt *r_xprt)
+  */
+ void rpcrdma_reply_put(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req)
+ {
+-	if (req->rl_reply) {
+-		rpcrdma_rep_put(buffers, req->rl_reply);
++	struct rpcrdma_rep *rep = req->rl_reply;
++
++	if (rep) {
+ 		req->rl_reply = NULL;
++		rpcrdma_rep_put(buffers, rep);
+ 	}
+ 	/* I2: rl_reply NULL after the put closes the
+ 	 * 'rep on rb_free_reps still referenced by req' window.
+diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
+index 8336a9664703fe..575b6f71c09ecf 100644
+--- a/net/tipc/netlink.c
++++ b/net/tipc/netlink.c
+@@ -113,12 +113,16 @@ const struct nla_policy tipc_nl_node_policy[TIPC_NLA_NODE_MAX + 1] = {
+ };
+ 
+ /* Properties valid for media, bearer and link */
++static struct netlink_range_validation tipc_nl_mtu_range = {
++	.max = U16_MAX,
++};
++
+ const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = {
+ 	[TIPC_NLA_PROP_UNSPEC]		= { .type = NLA_UNSPEC },
+ 	[TIPC_NLA_PROP_PRIO]		= { .type = NLA_U32 },
+ 	[TIPC_NLA_PROP_TOL]		= { .type = NLA_U32 },
+ 	[TIPC_NLA_PROP_WIN]		= { .type = NLA_U32 },
+-	[TIPC_NLA_PROP_MTU]		= { .type = NLA_U32 },
++	[TIPC_NLA_PROP_MTU]		= NLA_POLICY_FULL_RANGE(NLA_U32, &tipc_nl_mtu_range),
+ 	[TIPC_NLA_PROP_BROADCAST]	= { .type = NLA_U32 },
+ 	[TIPC_NLA_PROP_BROADCAST_RATIO]	= { .type = NLA_U32 }
+ };
+diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
+index c763008a8adbaa..c760ba270547e1 100644
+--- a/net/tipc/netlink_compat.c
++++ b/net/tipc/netlink_compat.c
+@@ -222,6 +222,10 @@ static int __tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
+ 		int rem;
+ 
+ 		len = (*cmd->dumpit)(buf, &cb);
++		if (len < 0) {
++			err = len;
++			goto err_out;
++		}
+ 
+ 		nlmsg_for_each_msg(nlmsg, nlmsg_hdr(buf), len, rem) {
+ 			err = nlmsg_parse_deprecated(nlmsg, GENL_HDRLEN,
+diff --git a/net/tipc/socket.c b/net/tipc/socket.c
+index 31c6b61f0b0fd9..4fefe9cf721f5e 100644
+--- a/net/tipc/socket.c
++++ b/net/tipc/socket.c
+@@ -504,6 +504,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
+ 	tipc_set_sk_state(sk, TIPC_OPEN);
+ 	if (tipc_sk_insert(tsk)) {
+ 		sk_free(sk);
++		sock->sk = NULL;
+ 		pr_warn("Socket create failed; port number exhausted\n");
+ 		return -EINVAL;
+ 	}
+@@ -2460,17 +2461,17 @@ static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk,
+ 			atomic_set(dcnt, 0);
+ 		lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt);
+ 		if (likely(!sk_add_backlog(sk, skb, lim))) {
+-			trace_tipc_sk_overlimit1(sk, skb, TIPC_DUMP_ALL,
++			trace_tipc_sk_overlimit1(sk, skb, TIPC_DUMP_SK_BKLGQ,
+ 						 "bklg & rcvq >90% allocated!");
+ 			continue;
+ 		}
+ 
+-		trace_tipc_sk_dump(sk, skb, TIPC_DUMP_ALL, "err_overload!");
++		trace_tipc_sk_dump(sk, skb, TIPC_DUMP_SK_BKLGQ, "err_overload!");
+ 		/* Overload => reject message back to sender */
+ 		onode = tipc_own_addr(sock_net(sk));
+ 		atomic_inc(&sk->sk_drops);
+ 		if (tipc_msg_reverse(onode, &skb, TIPC_ERR_OVERLOAD)) {
+-			trace_tipc_sk_rej_msg(sk, skb, TIPC_DUMP_ALL,
++			trace_tipc_sk_rej_msg(sk, skb, TIPC_DUMP_SK_BKLGQ,
+ 					      "@sk_enqueue!");
+ 			__skb_queue_tail(xmitq, skb);
+ 		}
+diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c
+index 1fc1e8e2a9cb2c..7fce47197d0a45 100644
+--- a/net/tls/tls_device.c
++++ b/net/tls/tls_device.c
+@@ -600,13 +600,15 @@ void tls_device_splice_eof(struct socket *sock)
+ 	struct tls_context *tls_ctx = tls_get_ctx(sk);
+ 	struct iov_iter iter = {};
+ 
+-	if (!tls_is_partially_sent_record(tls_ctx))
++	if (!tls_is_partially_sent_record(tls_ctx) &&
++	    !tls_is_pending_open_record(tls_ctx))
+ 		return;
+ 
+ 	mutex_lock(&tls_ctx->tx_lock);
+ 	lock_sock(sk);
+ 
+-	if (tls_is_partially_sent_record(tls_ctx)) {
++	if (tls_is_partially_sent_record(tls_ctx) ||
++	    tls_is_pending_open_record(tls_ctx)) {
+ 		iov_iter_bvec(&iter, ITER_SOURCE, NULL, 0, 0);
+ 		tls_push_data(sk, &iter, 0, 0, TLS_RECORD_TYPE_DATA);
+ 	}
+diff --git a/net/wireless/core.c b/net/wireless/core.c
+index d07c4baa32d9f4..800fbfd5919491 100644
+--- a/net/wireless/core.c
++++ b/net/wireless/core.c
+@@ -1132,6 +1132,7 @@ void wiphy_unregister(struct wiphy *wiphy)
+ 	/* this has nothing to do now but make sure it's gone */
+ 	cancel_work_sync(&rdev->wiphy_work);
+ 
++	cancel_work_sync(&rdev->sched_scan_res_wk);
+ 	cancel_work_sync(&rdev->rfkill_block);
+ 	cancel_work_sync(&rdev->conn_work);
+ 	flush_work(&rdev->event_work);
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index e4a490d12b504e..545f7ecaad76ff 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -309,7 +309,9 @@ nl80211_ftm_responder_policy[NL80211_FTM_RESP_ATTR_MAX + 1] = {
+ static const struct nla_policy
+ nl80211_pmsr_ftm_req_attr_policy[NL80211_PMSR_FTM_REQ_ATTR_MAX + 1] = {
+ 	[NL80211_PMSR_FTM_REQ_ATTR_ASAP] = { .type = NLA_FLAG },
+-	[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] = { .type = NLA_U32 },
++	[NL80211_PMSR_FTM_REQ_ATTR_PREAMBLE] =
++		NLA_POLICY_RANGE(NLA_U32, NL80211_PREAMBLE_LEGACY,
++				 NL80211_PREAMBLE_HE),
+ 	[NL80211_PMSR_FTM_REQ_ATTR_NUM_BURSTS_EXP] =
+ 		NLA_POLICY_MAX(NLA_U8, 15),
+ 	[NL80211_PMSR_FTM_REQ_ATTR_BURST_PERIOD] = { .type = NLA_U16 },
+@@ -5453,7 +5455,8 @@ static int nl80211_parse_mbssid_config(struct wiphy *wiphy,
+ }
+ 
+ static struct cfg80211_mbssid_elems *
+-nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs)
++nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs,
++			   struct netlink_ext_ack *extack)
+ {
+ 	struct nlattr *nl_elems;
+ 	struct cfg80211_mbssid_elems *elems;
+@@ -5464,6 +5467,12 @@ nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs)
+ 		return ERR_PTR(-EINVAL);
+ 
+ 	nla_for_each_nested(nl_elems, attrs, rem_elems) {
++		int ret;
++
++		ret = validate_ie_attr(nl_elems, extack);
++		if (ret)
++			return ERR_PTR(ret);
++
+ 		if (num_elems >= 255)
+ 			return ERR_PTR(-EINVAL);
+ 		num_elems++;
+@@ -5635,7 +5644,8 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
+ 	if (attrs[NL80211_ATTR_MBSSID_ELEMS]) {
+ 		struct cfg80211_mbssid_elems *mbssid =
+ 			nl80211_parse_mbssid_elems(&rdev->wiphy,
+-						   attrs[NL80211_ATTR_MBSSID_ELEMS]);
++						   attrs[NL80211_ATTR_MBSSID_ELEMS],
++						   extack);
+ 
+ 		if (IS_ERR(mbssid))
+ 			return PTR_ERR(mbssid);
+@@ -5651,8 +5661,10 @@ static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
+ 			if (IS_ERR(rnr))
+ 				return PTR_ERR(rnr);
+ 
+-			if (rnr && rnr->cnt < bcn->mbssid_ies->cnt)
++			if (rnr && rnr->cnt < bcn->mbssid_ies->cnt) {
++				kfree(rnr);
+ 				return -EINVAL;
++			}
+ 
+ 			bcn->rnr_ies = rnr;
+ 		}
+diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c
+index 77cb1de9fc13b4..678bbe5bf455fe 100644
+--- a/net/wireless/pmsr.c
++++ b/net/wireless/pmsr.c
+@@ -114,6 +114,7 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev,
+ 		NL_SET_ERR_MSG_ATTR(info->extack,
+ 				    tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI],
+ 				    "FTM: LCI request not supported");
++		return -EOPNOTSUPP;
+ 	}
+ 
+ 	out->ftm.request_civicloc =
+@@ -122,6 +123,7 @@ static int pmsr_parse_ftm(struct cfg80211_registered_device *rdev,
+ 		NL_SET_ERR_MSG_ATTR(info->extack,
+ 				    tb[NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC],
+ 			    "FTM: civic location request not supported");
++		return -EOPNOTSUPP;
+ 	}
+ 
+ 	out->ftm.trigger_based =
+@@ -188,6 +190,7 @@ static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
+ {
+ 	struct nlattr *tb[NL80211_PMSR_PEER_ATTR_MAX + 1];
+ 	struct nlattr *req[NL80211_PMSR_REQ_ATTR_MAX + 1];
++	bool have_measurement_type = false;
+ 	struct nlattr *treq;
+ 	int err, rem;
+ 
+@@ -240,6 +243,14 @@ static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
+ 	}
+ 
+ 	nla_for_each_nested(treq, req[NL80211_PMSR_REQ_ATTR_DATA], rem) {
++		if (have_measurement_type) {
++			NL_SET_ERR_MSG_ATTR(info->extack, treq,
++					    "multiple measurement types in request data");
++			return -EINVAL;
++		}
++
++		have_measurement_type = true;
++
+ 		switch (nla_type(treq)) {
+ 		case NL80211_PMSR_TYPE_FTM:
+ 			err = pmsr_parse_ftm(rdev, treq, out, info);
+@@ -249,10 +260,16 @@ static int pmsr_parse_peer(struct cfg80211_registered_device *rdev,
+ 					    "unsupported measurement type");
+ 			err = -EINVAL;
+ 		}
++		if (err)
++			return err;
+ 	}
+ 
+-	if (err)
+-		return err;
++	if (!have_measurement_type) {
++		NL_SET_ERR_MSG_ATTR(info->extack,
++				    req[NL80211_PMSR_REQ_ATTR_DATA],
++				    "missing measurement type in request data");
++		return -EINVAL;
++	}
+ 
+ 	return 0;
+ }
+diff --git a/net/wireless/scan.c b/net/wireless/scan.c
+index b12508188a18d2..c978e6252f7a1e 100644
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -243,7 +243,7 @@ bool cfg80211_is_element_inherited(const struct element *elem,
+ 		return true;
+ 
+ 	if (elem->id == WLAN_EID_EXTENSION) {
+-		if (!ext_id_len)
++		if (!ext_id_len || !elem->datalen)
+ 			return true;
+ 		loop_len = ext_id_len;
+ 		list = &non_inherit_elem->data[3 + id_len];
+diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
+index f15a4493eb0bf1..31f18f45b34597 100644
+--- a/net/x25/af_x25.c
++++ b/net/x25/af_x25.c
+@@ -1772,15 +1772,19 @@ void x25_kill_by_neigh(struct x25_neigh *nb)
+ {
+ 	struct sock *s;
+ 
++again:
+ 	write_lock_bh(&x25_list_lock);
+ 
+ 	sk_for_each(s, &x25_list) {
+ 		if (x25_sk(s)->neighbour == nb) {
++			sock_hold(s);
+ 			write_unlock_bh(&x25_list_lock);
+ 			lock_sock(s);
+-			x25_disconnect(s, ENETUNREACH, 0, 0);
++			if (x25_sk(s)->neighbour == nb)
++				x25_disconnect(s, ENETUNREACH, 0, 0);
+ 			release_sock(s);
+-			write_lock_bh(&x25_list_lock);
++			sock_put(s);
++			goto again;
+ 		}
+ 	}
+ 	write_unlock_bh(&x25_list_lock);
+diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
+index 7eaaaf56e631a0..00d9693c13ae72 100644
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -1298,8 +1298,8 @@ static void xfrm_hash_rebuild(struct work_struct *work)
+ 			}
+ 		}
+ 
+-		if (policy->selector.prefixlen_d < dbits ||
+-		    policy->selector.prefixlen_s < sbits)
++		if (policy->selector.prefixlen_d >= dbits &&
++		    policy->selector.prefixlen_s >= sbits)
+ 			continue;
+ 
+ 		bin = xfrm_policy_inexact_alloc_bin(policy, dir);
+diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
+index aa8515af677f0e..97ea4d0c607ce1 100644
+--- a/security/apparmor/include/net.h
++++ b/security/apparmor/include/net.h
+@@ -51,8 +51,12 @@ struct aa_sk_ctx {
+ 	struct aa_label *peer;
+ };
+ 
+-#define SK_CTX(X) ((X)->sk_security)
+ #define SOCK_ctx(X) SOCK_INODE(X)->i_security
++static inline struct aa_sk_ctx *aa_sock(const struct sock *sk)
++{
++	return sk->sk_security + apparmor_blob_sizes.lbs_sock;
++}
++
+ #define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P)				  \
+ 	struct lsm_network_audit NAME ## _net = { .sk = (SK),		  \
+ 						  .family = (F)};	  \
+diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
+index 79d0a9c1a99b11..7daf142b99de01 100644
+--- a/security/apparmor/lsm.c
++++ b/security/apparmor/lsm.c
+@@ -850,33 +850,15 @@ static int apparmor_task_kill(struct task_struct *target, struct kernel_siginfo
+ 	return error;
+ }
+ 
+-/**
+- * apparmor_sk_alloc_security - allocate and attach the sk_security field
+- */
+-static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags)
+-{
+-	struct aa_sk_ctx *ctx;
+-
+-	ctx = kzalloc(sizeof(*ctx), flags);
+-	if (!ctx)
+-		return -ENOMEM;
+-
+-	SK_CTX(sk) = ctx;
+-
+-	return 0;
+-}
+-
+ /**
+  * apparmor_sk_free_security - free the sk_security field
+  */
+ static void apparmor_sk_free_security(struct sock *sk)
+ {
+-	struct aa_sk_ctx *ctx = SK_CTX(sk);
++	struct aa_sk_ctx *ctx = aa_sock(sk);
+ 
+-	SK_CTX(sk) = NULL;
+ 	aa_put_label(ctx->label);
+ 	aa_put_label(ctx->peer);
+-	kfree(ctx);
+ }
+ 
+ /**
+@@ -885,8 +867,8 @@ static void apparmor_sk_free_security(struct sock *sk)
+ static void apparmor_sk_clone_security(const struct sock *sk,
+ 				       struct sock *newsk)
+ {
+-	struct aa_sk_ctx *ctx = SK_CTX(sk);
+-	struct aa_sk_ctx *new = SK_CTX(newsk);
++	struct aa_sk_ctx *ctx = aa_sock(sk);
++	struct aa_sk_ctx *new = aa_sock(newsk);
+ 
+ 	if (new->label)
+ 		aa_put_label(new->label);
+@@ -940,7 +922,7 @@ static int apparmor_socket_post_create(struct socket *sock, int family,
+ 		label = aa_get_current_label();
+ 
+ 	if (sock->sk) {
+-		struct aa_sk_ctx *ctx = SK_CTX(sock->sk);
++		struct aa_sk_ctx *ctx = aa_sock(sock->sk);
+ 
+ 		aa_put_label(ctx->label);
+ 		ctx->label = aa_get_label(label);
+@@ -1139,7 +1121,7 @@ static int apparmor_socket_shutdown(struct socket *sock, int how)
+  */
+ static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+ {
+-	struct aa_sk_ctx *ctx = SK_CTX(sk);
++	struct aa_sk_ctx *ctx = aa_sock(sk);
+ 
+ 	if (!skb->secmark)
+ 		return 0;
+@@ -1159,7 +1141,7 @@ static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+ 
+ static struct aa_label *sk_peer_label(struct sock *sk)
+ {
+-	struct aa_sk_ctx *ctx = SK_CTX(sk);
++	struct aa_sk_ctx *ctx = aa_sock(sk);
+ 
+ 	if (ctx->peer)
+ 		return ctx->peer;
+@@ -1240,7 +1222,7 @@ static int apparmor_socket_getpeersec_dgram(struct socket *sock,
+  */
+ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
+ {
+-	struct aa_sk_ctx *ctx = SK_CTX(sk);
++	struct aa_sk_ctx *ctx = aa_sock(sk);
+ 
+ 	if (!ctx->label)
+ 		ctx->label = aa_get_current_label();
+@@ -1250,7 +1232,7 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
+ static int apparmor_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
+ 				      struct request_sock *req)
+ {
+-	struct aa_sk_ctx *ctx = SK_CTX(sk);
++	struct aa_sk_ctx *ctx = aa_sock(sk);
+ 
+ 	if (!skb->secmark)
+ 		return 0;
+@@ -1267,6 +1249,7 @@ struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = {
+ 	.lbs_cred = sizeof(struct aa_label *),
+ 	.lbs_file = sizeof(struct aa_file_ctx),
+ 	.lbs_task = sizeof(struct aa_task_ctx),
++	.lbs_sock = sizeof(struct aa_sk_ctx),
+ };
+ 
+ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
+@@ -1305,7 +1288,6 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
+ 	LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
+ 	LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
+ 
+-	LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security),
+ 	LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security),
+ 	LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security),
+ 
+@@ -1864,7 +1846,7 @@ static unsigned int apparmor_ip_postroute(void *priv,
+ 	if (sk == NULL)
+ 		return NF_ACCEPT;
+ 
+-	ctx = SK_CTX(sk);
++	ctx = aa_sock(sk);
+ 	if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND,
+ 				    skb->secmark, sk))
+ 		return NF_ACCEPT;
+diff --git a/security/apparmor/net.c b/security/apparmor/net.c
+index 390947c9302082..6e989184e40863 100644
+--- a/security/apparmor/net.c
++++ b/security/apparmor/net.c
+@@ -152,7 +152,7 @@ static int aa_label_sk_perm(const struct cred *subj_cred,
+ 			    const char *op, u32 request,
+ 			    struct sock *sk)
+ {
+-	struct aa_sk_ctx *ctx = SK_CTX(sk);
++	struct aa_sk_ctx *ctx = aa_sock(sk);
+ 	int error = 0;
+ 
+ 	AA_BUG(!label);
+diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c
+index 35933ae53b92cf..2e9c247c3a6327 100644
+--- a/security/bpf/hooks.c
++++ b/security/bpf/hooks.c
+@@ -6,6 +6,8 @@
+ #include <linux/lsm_hooks.h>
+ #include <linux/bpf_lsm.h>
+ 
++bool bpf_lsm_initialized __ro_after_init;
++
+ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
+ 	#define LSM_HOOK(RET, DEFAULT, NAME, ...) \
+ 	LSM_HOOK_INIT(NAME, bpf_lsm_##NAME),
+@@ -18,6 +20,7 @@ static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = {
+ static int __init bpf_lsm_init(void)
+ {
+ 	security_add_hooks(bpf_lsm_hooks, ARRAY_SIZE(bpf_lsm_hooks), "bpf");
++	bpf_lsm_initialized = true;
+ 	pr_info("LSM support for eBPF active\n");
+ 	return 0;
+ }
+diff --git a/security/security.c b/security/security.c
+index 4b61766c3d27bd..d90507fd008e7c 100644
+--- a/security/security.c
++++ b/security/security.c
+@@ -30,6 +30,7 @@
+ #include <linux/string.h>
+ #include <linux/msg.h>
+ #include <net/flow.h>
++#include <net/sock.h>
+ 
+ /* How many LSMs were built into the kernel? */
+ #define LSM_COUNT (__end_lsm_info - __start_lsm_info)
+@@ -212,6 +213,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
+ 	lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
+ 	lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
+ 	lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
++	lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
+ 	lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
+ 	lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
+ 	lsm_set_blob_size(&needed->lbs_xattr_count,
+@@ -381,6 +383,7 @@ static void __init ordered_lsm_init(void)
+ 	init_debug("inode blob size      = %d\n", blob_sizes.lbs_inode);
+ 	init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
+ 	init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
++	init_debug("sock blob size       = %d\n", blob_sizes.lbs_sock);
+ 	init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
+ 	init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
+ 	init_debug("xattr slots          = %d\n", blob_sizes.lbs_xattr_count);
+@@ -4559,6 +4562,28 @@ int security_socket_getpeersec_dgram(struct socket *sock,
+ }
+ EXPORT_SYMBOL(security_socket_getpeersec_dgram);
+ 
++/**
++ * lsm_sock_alloc - allocate a composite sock blob
++ * @sock: the sock that needs a blob
++ * @priority: allocation mode
++ *
++ * Allocate the sock blob for all the modules
++ *
++ * Returns 0, or -ENOMEM if memory can't be allocated.
++ */
++static int lsm_sock_alloc(struct sock *sock, gfp_t priority)
++{
++	if (blob_sizes.lbs_sock == 0) {
++		sock->sk_security = NULL;
++		return 0;
++	}
++
++	sock->sk_security = kzalloc(blob_sizes.lbs_sock, priority);
++	if (sock->sk_security == NULL)
++		return -ENOMEM;
++	return 0;
++}
++
+ /**
+  * security_sk_alloc() - Allocate and initialize a sock's LSM blob
+  * @sk: sock
+@@ -4572,7 +4597,14 @@ EXPORT_SYMBOL(security_socket_getpeersec_dgram);
+  */
+ int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
+ {
+-	return call_int_hook(sk_alloc_security, 0, sk, family, priority);
++	int rc = lsm_sock_alloc(sk, priority);
++
++	if (unlikely(rc))
++		return rc;
++	rc = call_int_hook(sk_alloc_security, 0, sk, family, priority);
++	if (unlikely(rc))
++		security_sk_free(sk);
++	return rc;
+ }
+ 
+ /**
+@@ -4584,6 +4616,8 @@ int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
+ void security_sk_free(struct sock *sk)
+ {
+ 	call_void_hook(sk_free_security, sk);
++	kfree(sk->sk_security);
++	sk->sk_security = NULL;
+ }
+ 
+ /**
+diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
+index fbfec33bc43ec9..e82113fc85b5cb 100644
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -4695,7 +4695,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
+ 
+ static int sock_has_perm(struct sock *sk, u32 perms)
+ {
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	struct common_audit_data ad;
+ 	struct lsm_network_audit net;
+ 
+@@ -4748,7 +4748,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
+ 	isec->initialized = LABEL_INITIALIZED;
+ 
+ 	if (sock->sk) {
+-		sksec = sock->sk->sk_security;
++		sksec = selinux_sock(sock->sk);
+ 		sksec->sclass = sclass;
+ 		sksec->sid = sid;
+ 		/* Allows detection of the first association on this socket */
+@@ -4764,8 +4764,8 @@ static int selinux_socket_post_create(struct socket *sock, int family,
+ static int selinux_socket_socketpair(struct socket *socka,
+ 				     struct socket *sockb)
+ {
+-	struct sk_security_struct *sksec_a = socka->sk->sk_security;
+-	struct sk_security_struct *sksec_b = sockb->sk->sk_security;
++	struct sk_security_struct *sksec_a = selinux_sock(socka->sk);
++	struct sk_security_struct *sksec_b = selinux_sock(sockb->sk);
+ 
+ 	sksec_a->peer_sid = sksec_b->sid;
+ 	sksec_b->peer_sid = sksec_a->sid;
+@@ -4777,10 +4777,9 @@ static int selinux_socket_socketpair(struct socket *socka,
+    Need to determine whether we should perform a name_bind
+    permission check between the socket and the port number. */
+ 
+-static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
++static int __selinux_socket_bind(struct sock *sk, struct sockaddr *address, int addrlen)
+ {
+-	struct sock *sk = sock->sk;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	u16 family;
+ 	int err;
+ 
+@@ -4913,14 +4912,18 @@ err_af:
+ 	return -EAFNOSUPPORT;
+ }
+ 
++static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
++{
++	return __selinux_socket_bind(sock->sk, address, addrlen);
++}
++
+ /* This supports connect(2) and SCTP connect services such as sctp_connectx(3)
+  * and sctp_sendmsg(3) as described in Documentation/security/SCTP.rst
+  */
+-static int selinux_socket_connect_helper(struct socket *sock,
++static int selinux_socket_connect_helper(struct sock *sk,
+ 					 struct sockaddr *address, int addrlen)
+ {
+-	struct sock *sk = sock->sk;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	int err;
+ 
+ 	err = sock_has_perm(sk, SOCKET__CONNECT);
+@@ -5012,7 +5015,7 @@ static int selinux_socket_connect(struct socket *sock,
+ 	int err;
+ 	struct sock *sk = sock->sk;
+ 
+-	err = selinux_socket_connect_helper(sock, address, addrlen);
++	err = selinux_socket_connect_helper(sk, address, addrlen);
+ 	if (err)
+ 		return err;
+ 
+@@ -5115,9 +5118,9 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
+ 					      struct sock *other,
+ 					      struct sock *newsk)
+ {
+-	struct sk_security_struct *sksec_sock = sock->sk_security;
+-	struct sk_security_struct *sksec_other = other->sk_security;
+-	struct sk_security_struct *sksec_new = newsk->sk_security;
++	struct sk_security_struct *sksec_sock = selinux_sock(sock);
++	struct sk_security_struct *sksec_other = selinux_sock(other);
++	struct sk_security_struct *sksec_new = selinux_sock(newsk);
+ 	struct common_audit_data ad;
+ 	struct lsm_network_audit net;
+ 	int err;
+@@ -5146,8 +5149,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
+ static int selinux_socket_unix_may_send(struct socket *sock,
+ 					struct socket *other)
+ {
+-	struct sk_security_struct *ssec = sock->sk->sk_security;
+-	struct sk_security_struct *osec = other->sk->sk_security;
++	struct sk_security_struct *ssec = selinux_sock(sock->sk);
++	struct sk_security_struct *osec = selinux_sock(other->sk);
+ 	struct common_audit_data ad;
+ 	struct lsm_network_audit net;
+ 
+@@ -5184,7 +5187,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
+ 				       u16 family)
+ {
+ 	int err = 0;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	u32 sk_sid = sksec->sid;
+ 	struct common_audit_data ad;
+ 	struct lsm_network_audit net;
+@@ -5213,7 +5216,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
+ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+ {
+ 	int err, peerlbl_active, secmark_active;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	u16 family = sk->sk_family;
+ 	u32 sk_sid = sksec->sid;
+ 	struct common_audit_data ad;
+@@ -5281,7 +5284,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock,
+ 	int err = 0;
+ 	char *scontext = NULL;
+ 	u32 scontext_len;
+-	struct sk_security_struct *sksec = sock->sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sock->sk);
+ 	u32 peer_sid = SECSID_NULL;
+ 
+ 	if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
+@@ -5339,34 +5342,27 @@ out:
+ 
+ static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
+ {
+-	struct sk_security_struct *sksec;
+-
+-	sksec = kzalloc(sizeof(*sksec), priority);
+-	if (!sksec)
+-		return -ENOMEM;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 
+ 	sksec->peer_sid = SECINITSID_UNLABELED;
+ 	sksec->sid = SECINITSID_UNLABELED;
+ 	sksec->sclass = SECCLASS_SOCKET;
+ 	selinux_netlbl_sk_security_reset(sksec);
+-	sk->sk_security = sksec;
+ 
+ 	return 0;
+ }
+ 
+ static void selinux_sk_free_security(struct sock *sk)
+ {
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 
+-	sk->sk_security = NULL;
+ 	selinux_netlbl_sk_security_free(sksec);
+-	kfree(sksec);
+ }
+ 
+ static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
+ {
+-	struct sk_security_struct *sksec = sk->sk_security;
+-	struct sk_security_struct *newsksec = newsk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
++	struct sk_security_struct *newsksec = selinux_sock(newsk);
+ 
+ 	newsksec->sid = sksec->sid;
+ 	newsksec->peer_sid = sksec->peer_sid;
+@@ -5380,7 +5376,7 @@ static void selinux_sk_getsecid(const struct sock *sk, u32 *secid)
+ 	if (!sk)
+ 		*secid = SECINITSID_ANY_SOCKET;
+ 	else {
+-		const struct sk_security_struct *sksec = sk->sk_security;
++		const struct sk_security_struct *sksec = selinux_sock(sk);
+ 
+ 		*secid = sksec->sid;
+ 	}
+@@ -5390,7 +5386,7 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
+ {
+ 	struct inode_security_struct *isec =
+ 		inode_security_novalidate(SOCK_INODE(parent));
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 
+ 	if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
+ 	    sk->sk_family == PF_UNIX)
+@@ -5407,7 +5403,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
+ {
+ 	struct sock *sk = asoc->base.sk;
+ 	u16 family = sk->sk_family;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	struct common_audit_data ad;
+ 	struct lsm_network_audit net;
+ 	int err;
+@@ -5462,7 +5458,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
+ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
+ 				      struct sk_buff *skb)
+ {
+-	struct sk_security_struct *sksec = asoc->base.sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
+ 	u32 conn_sid;
+ 	int err;
+ 
+@@ -5495,7 +5491,7 @@ static int selinux_sctp_assoc_request(struct sctp_association *asoc,
+ static int selinux_sctp_assoc_established(struct sctp_association *asoc,
+ 					  struct sk_buff *skb)
+ {
+-	struct sk_security_struct *sksec = asoc->base.sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
+ 
+ 	if (!selinux_policycap_extsockclass())
+ 		return 0;
+@@ -5519,13 +5515,11 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
+ 	int len, err = 0, walk_size = 0;
+ 	void *addr_buf;
+ 	struct sockaddr *addr;
+-	struct socket *sock;
+ 
+ 	if (!selinux_policycap_extsockclass())
+ 		return 0;
+ 
+ 	/* Process one or more addresses that may be IPv4 or IPv6 */
+-	sock = sk->sk_socket;
+ 	addr_buf = address;
+ 
+ 	while (walk_size < addrlen) {
+@@ -5554,14 +5548,14 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
+ 		case SCTP_PRIMARY_ADDR:
+ 		case SCTP_SET_PEER_PRIMARY_ADDR:
+ 		case SCTP_SOCKOPT_BINDX_ADD:
+-			err = selinux_socket_bind(sock, addr, len);
++			err = __selinux_socket_bind(sk, addr, len);
+ 			break;
+ 		/* Connect checks */
+ 		case SCTP_SOCKOPT_CONNECTX:
+ 		case SCTP_PARAM_SET_PRIMARY:
+ 		case SCTP_PARAM_ADD_IP:
+ 		case SCTP_SENDMSG_CONNECT:
+-			err = selinux_socket_connect_helper(sock, addr, len);
++			err = selinux_socket_connect_helper(sk, addr, len);
+ 			if (err)
+ 				return err;
+ 
+@@ -5594,8 +5588,8 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
+ static void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk,
+ 				  struct sock *newsk)
+ {
+-	struct sk_security_struct *sksec = sk->sk_security;
+-	struct sk_security_struct *newsksec = newsk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
++	struct sk_security_struct *newsksec = selinux_sock(newsk);
+ 
+ 	/* If policy does not support SECCLASS_SCTP_SOCKET then call
+ 	 * the non-sctp clone version.
+@@ -5611,8 +5605,8 @@ static void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk
+ 
+ static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
+ {
+-	struct sk_security_struct *ssksec = ssk->sk_security;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *ssksec = selinux_sock(ssk);
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 
+ 	ssksec->sclass = sksec->sclass;
+ 	ssksec->sid = sksec->sid;
+@@ -5627,7 +5621,7 @@ static int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
+ static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
+ 				     struct request_sock *req)
+ {
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	int err;
+ 	u16 family = req->rsk_ops->family;
+ 	u32 connsid;
+@@ -5648,7 +5642,7 @@ static int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
+ static void selinux_inet_csk_clone(struct sock *newsk,
+ 				   const struct request_sock *req)
+ {
+-	struct sk_security_struct *newsksec = newsk->sk_security;
++	struct sk_security_struct *newsksec = selinux_sock(newsk);
+ 
+ 	newsksec->sid = req->secid;
+ 	newsksec->peer_sid = req->peer_secid;
+@@ -5665,7 +5659,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
+ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
+ {
+ 	u16 family = sk->sk_family;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 
+ 	/* handle mapped IPv4 packets arriving via IPv6 sockets */
+ 	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
+@@ -5746,7 +5740,7 @@ static int selinux_tun_dev_attach_queue(void *security)
+ static int selinux_tun_dev_attach(struct sock *sk, void *security)
+ {
+ 	struct tun_security_struct *tunsec = security;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 
+ 	/* we don't currently perform any NetLabel based labeling here and it
+ 	 * isn't clear that we would want to do so anyway; while we could apply
+@@ -5869,7 +5863,7 @@ static unsigned int selinux_ip_output(void *priv, struct sk_buff *skb,
+ 			return NF_ACCEPT;
+ 
+ 		/* standard practice, label using the parent socket */
+-		sksec = sk->sk_security;
++		sksec = selinux_sock(sk);
+ 		sid = sksec->sid;
+ 	} else
+ 		sid = SECINITSID_KERNEL;
+@@ -5892,7 +5886,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
+ 	sk = skb_to_full_sk(skb);
+ 	if (sk == NULL)
+ 		return NF_ACCEPT;
+-	sksec = sk->sk_security;
++	sksec = selinux_sock(sk);
+ 
+ 	ad_net_init_from_iif(&ad, &net, state->out->ifindex, state->pf);
+ 	if (selinux_parse_skb(skb, &ad, NULL, 0, &proto))
+@@ -5981,7 +5975,7 @@ static unsigned int selinux_ip_postroute(void *priv,
+ 		u32 skb_sid;
+ 		struct sk_security_struct *sksec;
+ 
+-		sksec = sk->sk_security;
++		sksec = selinux_sock(sk);
+ 		if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
+ 			return NF_DROP;
+ 		/* At this point, if the returned skb peerlbl is SECSID_NULL
+@@ -6010,7 +6004,7 @@ static unsigned int selinux_ip_postroute(void *priv,
+ 	} else {
+ 		/* Locally generated packet, fetch the security label from the
+ 		 * associated socket. */
+-		struct sk_security_struct *sksec = sk->sk_security;
++		struct sk_security_struct *sksec = selinux_sock(sk);
+ 		peer_sid = sksec->sid;
+ 		secmark_perm = PACKET__SEND;
+ 	}
+@@ -6053,7 +6047,7 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
+ 	unsigned int data_len = skb->len;
+ 	unsigned char *data = skb->data;
+ 	struct nlmsghdr *nlh;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	u16 sclass = sksec->sclass;
+ 	u32 perm;
+ 
+@@ -7008,6 +7002,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
+ 	.lbs_inode = sizeof(struct inode_security_struct),
+ 	.lbs_ipc = sizeof(struct ipc_security_struct),
+ 	.lbs_msg_msg = sizeof(struct msg_security_struct),
++	.lbs_sock = sizeof(struct sk_security_struct),
+ 	.lbs_superblock = sizeof(struct superblock_security_struct),
+ 	.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
+ };
+diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
+index 541933dd295c07..b9c61b2ac482e8 100644
+--- a/security/selinux/include/objsec.h
++++ b/security/selinux/include/objsec.h
+@@ -205,4 +205,9 @@ static inline struct superblock_security_struct *selinux_superblock(
+ 	return superblock->s_security + selinux_blob_sizes.lbs_superblock;
+ }
+ 
++static inline struct sk_security_struct *selinux_sock(const struct sock *sock)
++{
++	return sock->sk_security + selinux_blob_sizes.lbs_sock;
++}
++
+ #endif /* _SELINUX_OBJSEC_H_ */
+diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
+index 8f182800e41245..e8832726bd8692 100644
+--- a/security/selinux/netlabel.c
++++ b/security/selinux/netlabel.c
+@@ -17,6 +17,7 @@
+ #include <linux/gfp.h>
+ #include <linux/ip.h>
+ #include <linux/ipv6.h>
++#include <linux/lsm_hooks.h>
+ #include <net/sock.h>
+ #include <net/netlabel.h>
+ #include <net/ip.h>
+@@ -68,7 +69,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
+ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
+ {
+ 	int rc;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	struct netlbl_lsm_secattr *secattr;
+ 
+ 	if (sksec->nlbl_secattr != NULL)
+@@ -100,7 +101,7 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
+ 							const struct sock *sk,
+ 							u32 sid)
+ {
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
+ 
+ 	if (secattr == NULL)
+@@ -240,7 +241,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
+ 	 * being labeled by it's parent socket, if it is just exit */
+ 	sk = skb_to_full_sk(skb);
+ 	if (sk != NULL) {
+-		struct sk_security_struct *sksec = sk->sk_security;
++		struct sk_security_struct *sksec = selinux_sock(sk);
+ 
+ 		if (sksec->nlbl_state != NLBL_REQSKB)
+ 			return 0;
+@@ -277,7 +278,7 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
+ {
+ 	int rc;
+ 	struct netlbl_lsm_secattr secattr;
+-	struct sk_security_struct *sksec = asoc->base.sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
+ 	struct sockaddr_in addr4;
+ 	struct sockaddr_in6 addr6;
+ 
+@@ -356,7 +357,7 @@ inet_conn_request_return:
+  */
+ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
+ {
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 
+ 	if (family == PF_INET)
+ 		sksec->nlbl_state = NLBL_LABELED;
+@@ -374,8 +375,8 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
+  */
+ void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
+ {
+-	struct sk_security_struct *sksec = sk->sk_security;
+-	struct sk_security_struct *newsksec = newsk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
++	struct sk_security_struct *newsksec = selinux_sock(newsk);
+ 
+ 	newsksec->nlbl_state = sksec->nlbl_state;
+ }
+@@ -393,7 +394,7 @@ void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
+ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
+ {
+ 	int rc;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	struct netlbl_lsm_secattr *secattr;
+ 
+ 	if (family != PF_INET && family != PF_INET6)
+@@ -507,7 +508,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
+ {
+ 	int rc = 0;
+ 	struct sock *sk = sock->sk;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	struct netlbl_lsm_secattr secattr;
+ 
+ 	if (selinux_netlbl_option(level, optname) &&
+@@ -545,7 +546,7 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
+ 						struct sockaddr *addr)
+ {
+ 	int rc;
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 	struct netlbl_lsm_secattr *secattr;
+ 
+ 	/* connected sockets are allowed to disconnect when the address family
+@@ -584,7 +585,7 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
+ int selinux_netlbl_socket_connect_locked(struct sock *sk,
+ 					 struct sockaddr *addr)
+ {
+-	struct sk_security_struct *sksec = sk->sk_security;
++	struct sk_security_struct *sksec = selinux_sock(sk);
+ 
+ 	if (sksec->nlbl_state != NLBL_REQSKB &&
+ 	    sksec->nlbl_state != NLBL_CONNLABELED)
+diff --git a/security/smack/smack.h b/security/smack/smack.h
+index 5e4a3c3144dd98..aac0574cdfad30 100644
+--- a/security/smack/smack.h
++++ b/security/smack/smack.h
+@@ -361,6 +361,11 @@ static inline struct superblock_smack *smack_superblock(
+ 	return superblock->s_security + smack_blob_sizes.lbs_superblock;
+ }
+ 
++static inline struct socket_smack *smack_sock(const struct sock *sock)
++{
++	return sock->sk_security + smack_blob_sizes.lbs_sock;
++}
++
+ /*
+  * Is the directory transmuting?
+  */
+diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
+index 8d38f4a813171a..54e22c1afe6cd1 100644
+--- a/security/smack/smack_lsm.c
++++ b/security/smack/smack_lsm.c
+@@ -1572,7 +1572,7 @@ static int smack_inode_getsecurity(struct mnt_idmap *idmap,
+ 		if (sock == NULL || sock->sk == NULL)
+ 			return -EOPNOTSUPP;
+ 
+-		ssp = sock->sk->sk_security;
++		ssp = smack_sock(sock->sk);
+ 
+ 		if (strcmp(name, XATTR_SMACK_IPIN) == 0)
+ 			isp = ssp->smk_in;
+@@ -1960,7 +1960,7 @@ static int smack_file_receive(struct file *file)
+ 
+ 	if (inode->i_sb->s_magic == SOCKFS_MAGIC) {
+ 		sock = SOCKET_I(inode);
+-		ssp = sock->sk->sk_security;
++		ssp = smack_sock(sock->sk);
+ 		tsp = smack_cred(current_cred());
+ 		/*
+ 		 * If the receiving process can't write to the
+@@ -2380,11 +2380,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
+ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
+ {
+ 	struct smack_known *skp = smk_of_current();
+-	struct socket_smack *ssp;
+-
+-	ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
+-	if (ssp == NULL)
+-		return -ENOMEM;
++	struct socket_smack *ssp = smack_sock(sk);
+ 
+ 	/*
+ 	 * Sockets created by kernel threads receive web label.
+@@ -2398,11 +2394,10 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
+ 	}
+ 	ssp->smk_packet = NULL;
+ 
+-	sk->sk_security = ssp;
+-
+ 	return 0;
+ }
+ 
++#ifdef SMACK_IPV6_PORT_LABELING
+ /**
+  * smack_sk_free_security - Free a socket blob
+  * @sk: the socket
+@@ -2411,7 +2406,6 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
+  */
+ static void smack_sk_free_security(struct sock *sk)
+ {
+-#ifdef SMACK_IPV6_PORT_LABELING
+ 	struct smk_port_label *spp;
+ 
+ 	if (sk->sk_family == PF_INET6) {
+@@ -2424,9 +2418,8 @@ static void smack_sk_free_security(struct sock *sk)
+ 		}
+ 		rcu_read_unlock();
+ 	}
+-#endif
+-	kfree(sk->sk_security);
+ }
++#endif
+ 
+ /**
+  * smack_sk_clone_security - Copy security context
+@@ -2437,8 +2430,8 @@ static void smack_sk_free_security(struct sock *sk)
+  */
+ static void smack_sk_clone_security(const struct sock *sk, struct sock *newsk)
+ {
+-	struct socket_smack *ssp_old = sk->sk_security;
+-	struct socket_smack *ssp_new = newsk->sk_security;
++	struct socket_smack *ssp_old = smack_sock(sk);
++	struct socket_smack *ssp_new = smack_sock(newsk);
+ 
+ 	*ssp_new = *ssp_old;
+ }
+@@ -2556,7 +2549,7 @@ static struct smack_known *smack_ipv6host_label(struct sockaddr_in6 *sip)
+  */
+ static int smack_netlbl_add(struct sock *sk)
+ {
+-	struct socket_smack *ssp = sk->sk_security;
++	struct socket_smack *ssp = smack_sock(sk);
+ 	struct smack_known *skp = ssp->smk_out;
+ 	int rc;
+ 
+@@ -2588,7 +2581,7 @@ static int smack_netlbl_add(struct sock *sk)
+  */
+ static void smack_netlbl_delete(struct sock *sk)
+ {
+-	struct socket_smack *ssp = sk->sk_security;
++	struct socket_smack *ssp = smack_sock(sk);
+ 
+ 	/*
+ 	 * Take the label off the socket if one is set.
+@@ -2620,7 +2613,7 @@ static int smk_ipv4_check(struct sock *sk, struct sockaddr_in *sap)
+ 	struct smack_known *skp;
+ 	int rc = 0;
+ 	struct smack_known *hkp;
+-	struct socket_smack *ssp = sk->sk_security;
++	struct socket_smack *ssp = smack_sock(sk);
+ 	struct smk_audit_info ad;
+ 
+ 	rcu_read_lock();
+@@ -2695,7 +2688,7 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
+ {
+ 	struct sock *sk = sock->sk;
+ 	struct sockaddr_in6 *addr6;
+-	struct socket_smack *ssp = sock->sk->sk_security;
++	struct socket_smack *ssp = smack_sock(sock->sk);
+ 	struct smk_port_label *spp;
+ 	unsigned short port = 0;
+ 
+@@ -2783,7 +2776,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
+ 				int act)
+ {
+ 	struct smk_port_label *spp;
+-	struct socket_smack *ssp = sk->sk_security;
++	struct socket_smack *ssp = smack_sock(sk);
+ 	struct smack_known *skp = NULL;
+ 	unsigned short port;
+ 	struct smack_known *object;
+@@ -2886,7 +2879,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
+ 	if (sock == NULL || sock->sk == NULL)
+ 		return -EOPNOTSUPP;
+ 
+-	ssp = sock->sk->sk_security;
++	ssp = smack_sock(sock->sk);
+ 
+ 	if (strcmp(name, XATTR_SMACK_IPIN) == 0)
+ 		ssp->smk_in = skp;
+@@ -2934,7 +2927,7 @@ static int smack_socket_post_create(struct socket *sock, int family,
+ 	 * Sockets created by kernel threads receive web label.
+ 	 */
+ 	if (unlikely(current->flags & PF_KTHREAD)) {
+-		ssp = sock->sk->sk_security;
++		ssp = smack_sock(sock->sk);
+ 		ssp->smk_in = &smack_known_web;
+ 		ssp->smk_out = &smack_known_web;
+ 	}
+@@ -2959,8 +2952,8 @@ static int smack_socket_post_create(struct socket *sock, int family,
+ static int smack_socket_socketpair(struct socket *socka,
+ 		                   struct socket *sockb)
+ {
+-	struct socket_smack *asp = socka->sk->sk_security;
+-	struct socket_smack *bsp = sockb->sk->sk_security;
++	struct socket_smack *asp = smack_sock(socka->sk);
++	struct socket_smack *bsp = smack_sock(sockb->sk);
+ 
+ 	asp->smk_packet = bsp->smk_out;
+ 	bsp->smk_packet = asp->smk_out;
+@@ -3025,7 +3018,7 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
+ 		if (__is_defined(SMACK_IPV6_SECMARK_LABELING))
+ 			rsp = smack_ipv6host_label(sip);
+ 		if (rsp != NULL) {
+-			struct socket_smack *ssp = sock->sk->sk_security;
++			struct socket_smack *ssp = smack_sock(sock->sk);
+ 
+ 			rc = smk_ipv6_check(ssp->smk_out, rsp, sip,
+ 					    SMK_CONNECTING);
+@@ -3763,9 +3756,9 @@ static int smack_unix_stream_connect(struct sock *sock,
+ {
+ 	struct smack_known *skp;
+ 	struct smack_known *okp;
+-	struct socket_smack *ssp = sock->sk_security;
+-	struct socket_smack *osp = other->sk_security;
+-	struct socket_smack *nsp = newsk->sk_security;
++	struct socket_smack *ssp = smack_sock(sock);
++	struct socket_smack *osp = smack_sock(other);
++	struct socket_smack *nsp = smack_sock(newsk);
+ 	struct smk_audit_info ad;
+ 	int rc = 0;
+ #ifdef CONFIG_AUDIT
+@@ -3817,8 +3810,8 @@ static int smack_unix_stream_connect(struct sock *sock,
+  */
+ static int smack_unix_may_send(struct socket *sock, struct socket *other)
+ {
+-	struct socket_smack *ssp = sock->sk->sk_security;
+-	struct socket_smack *osp = other->sk->sk_security;
++	struct socket_smack *ssp = smack_sock(sock->sk);
++	struct socket_smack *osp = smack_sock(other->sk);
+ 	struct smk_audit_info ad;
+ 	int rc;
+ 
+@@ -3855,7 +3848,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
+ 	struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
+ #endif
+ #ifdef SMACK_IPV6_SECMARK_LABELING
+-	struct socket_smack *ssp = sock->sk->sk_security;
++	struct socket_smack *ssp = smack_sock(sock->sk);
+ 	struct smack_known *rsp;
+ #endif
+ 	int rc = 0;
+@@ -4067,7 +4060,7 @@ static struct smack_known *smack_from_netlbl(const struct sock *sk, u16 family,
+ 	netlbl_secattr_init(&secattr);
+ 
+ 	if (sk)
+-		ssp = sk->sk_security;
++		ssp = smack_sock(sk);
+ 
+ 	if (netlbl_skbuff_getattr(skb, family, &secattr) == 0) {
+ 		skp = smack_from_secattr(&secattr, ssp);
+@@ -4089,7 +4082,7 @@ static struct smack_known *smack_from_netlbl(const struct sock *sk, u16 family,
+  */
+ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+ {
+-	struct socket_smack *ssp = sk->sk_security;
++	struct socket_smack *ssp = smack_sock(sk);
+ 	struct smack_known *skp = NULL;
+ 	int rc = 0;
+ 	struct smk_audit_info ad;
+@@ -4193,7 +4186,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
+ 	u32 slen = 1;
+ 	int rc = 0;
+ 
+-	ssp = sock->sk->sk_security;
++	ssp = smack_sock(sock->sk);
+ 	if (ssp->smk_packet != NULL) {
+ 		rcp = ssp->smk_packet->smk_known;
+ 		slen = strlen(rcp) + 1;
+@@ -4243,7 +4236,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
+ 
+ 	switch (family) {
+ 	case PF_UNIX:
+-		ssp = sock->sk->sk_security;
++		ssp = smack_sock(sock->sk);
+ 		s = ssp->smk_out->smk_secid;
+ 		break;
+ 	case PF_INET:
+@@ -4292,7 +4285,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
+ 	    (sk->sk_family != PF_INET && sk->sk_family != PF_INET6))
+ 		return;
+ 
+-	ssp = sk->sk_security;
++	ssp = smack_sock(sk);
+ 	ssp->smk_in = skp;
+ 	ssp->smk_out = skp;
+ 	/* cssp->smk_packet is already set in smack_inet_csk_clone() */
+@@ -4312,7 +4305,7 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
+ {
+ 	u16 family = sk->sk_family;
+ 	struct smack_known *skp;
+-	struct socket_smack *ssp = sk->sk_security;
++	struct socket_smack *ssp = smack_sock(sk);
+ 	struct sockaddr_in addr;
+ 	struct iphdr *hdr;
+ 	struct smack_known *hskp;
+@@ -4398,7 +4391,7 @@ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
+ static void smack_inet_csk_clone(struct sock *sk,
+ 				 const struct request_sock *req)
+ {
+-	struct socket_smack *ssp = sk->sk_security;
++	struct socket_smack *ssp = smack_sock(sk);
+ 	struct smack_known *skp;
+ 
+ 	if (req->peer_secid != 0) {
+@@ -4968,6 +4961,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
+ 	.lbs_inode = sizeof(struct inode_smack),
+ 	.lbs_ipc = sizeof(struct smack_known *),
+ 	.lbs_msg_msg = sizeof(struct smack_known *),
++	.lbs_sock = sizeof(struct socket_smack),
+ 	.lbs_superblock = sizeof(struct superblock_smack),
+ 	.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
+ };
+@@ -5084,7 +5078,9 @@ static struct security_hook_list smack_hooks[] __ro_after_init = {
+ 	LSM_HOOK_INIT(socket_getpeersec_stream, smack_socket_getpeersec_stream),
+ 	LSM_HOOK_INIT(socket_getpeersec_dgram, smack_socket_getpeersec_dgram),
+ 	LSM_HOOK_INIT(sk_alloc_security, smack_sk_alloc_security),
++#ifdef SMACK_IPV6_PORT_LABELING
+ 	LSM_HOOK_INIT(sk_free_security, smack_sk_free_security),
++#endif
+ 	LSM_HOOK_INIT(sk_clone_security, smack_sk_clone_security),
+ 	LSM_HOOK_INIT(sock_graft, smack_sock_graft),
+ 	LSM_HOOK_INIT(inet_conn_request, smack_inet_conn_request),
+diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
+index b945c1d3a7431a..bad71b7e648da7 100644
+--- a/security/smack/smack_netfilter.c
++++ b/security/smack/smack_netfilter.c
+@@ -26,8 +26,8 @@ static unsigned int smack_ip_output(void *priv,
+ 	struct socket_smack *ssp;
+ 	struct smack_known *skp;
+ 
+-	if (sk && sk->sk_security) {
+-		ssp = sk->sk_security;
++	if (sk) {
++		ssp = smack_sock(sk);
+ 		skp = ssp->smk_out;
+ 		skb->secmark = skp->smk_secid;
+ 	}
+diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
+index 9863be6fd43e1a..09874291125e42 100644
+--- a/sound/core/seq/seq_timer.c
++++ b/sound/core/seq/seq_timer.c
+@@ -58,12 +58,23 @@ struct snd_seq_timer *snd_seq_timer_new(void)
+ void snd_seq_timer_delete(struct snd_seq_timer **tmr)
+ {
+ 	struct snd_seq_timer *t = *tmr;
+-	*tmr = NULL;
++	struct snd_timer_instance *ti;
+ 
+ 	if (t == NULL) {
+ 		pr_debug("ALSA: seq: snd_seq_timer_delete() called with NULL timer\n");
+ 		return;
+ 	}
++
++	scoped_guard(spinlock_irq, &t->lock) {
++		ti = t->timeri;
++		t->timeri = NULL;
++	}
++	if (ti) {
++		snd_timer_close(ti);
++		snd_timer_instance_free(ti);
++	}
++
++	*tmr = NULL;
+ 	t->running = 0;
+ 
+ 	/* reset time */
+diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c
+index 97cee096a2864f..1ebc6dcc66893f 100644
+--- a/sound/hda/hdac_regmap.c
++++ b/sound/hda/hdac_regmap.c
+@@ -214,7 +214,7 @@ static int hda_reg_read_coef(struct hdac_device *codec, unsigned int reg,
+ 	err = snd_hdac_exec_verb(codec, verb, 0, NULL);
+ 	if (err < 0)
+ 		return err;
+-	verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8);
++	verb = (reg & ~0xfffff) | (AC_VERB_GET_PROC_COEF << 8);
+ 	return snd_hdac_exec_verb(codec, verb, 0, val);
+ }
+ 
+@@ -232,7 +232,7 @@ static int hda_reg_write_coef(struct hdac_device *codec, unsigned int reg,
+ 	err = snd_hdac_exec_verb(codec, verb, 0, NULL);
+ 	if (err < 0)
+ 		return err;
+-	verb = (reg & ~0xfffff) | (AC_VERB_GET_COEF_INDEX << 8) |
++	verb = (reg & ~0xfffff) | (AC_VERB_SET_PROC_COEF << 8) |
+ 		(val & 0xffff);
+ 	return snd_hdac_exec_verb(codec, verb, 0, NULL);
+ }
+diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
+index f6e563e03edf2d..ec1c92db7cd67a 100644
+--- a/sound/pci/hda/patch_conexant.c
++++ b/sound/pci/hda/patch_conexant.c
+@@ -168,9 +168,6 @@ static void cx_fixup_headset_recog(struct hda_codec *codec)
+ {
+ 	unsigned int mic_present;
+ 
+-	/* fix some headset type recognize fail issue, such as EDIFIER headset */
+-	/* set micbias output current comparator threshold from 66% to 55%. */
+-	snd_hda_codec_write(codec, 0x1c, 0, 0x320, 0x010);
+ 	/* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias register
+ 	 * value adjustment trim from 2.2K ohms to 2.0K ohms.
+ 	 */
+diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c
+index 4af3c3665387db..8fe602c0b690cc 100644
+--- a/sound/soc/amd/ps/pci-ps.c
++++ b/sound/soc/amd/ps/pci-ps.c
+@@ -599,7 +599,7 @@ static int snd_acp63_probe(struct pci_dev *pci,
+ 		return -ENODEV;
+ 	}
+ 
+-	ret = pci_request_regions(pci, "AMD ACP6.2 audio");
++	ret = pci_request_regions(pci, "AMD ACP6.3 audio");
+ 	if (ret < 0) {
+ 		dev_err(&pci->dev, "pci_request_regions failed\n");
+ 		goto disable_pci;
+diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c
+index 3afcef2dfa3529..c0bf45b76cb8c5 100644
+--- a/sound/soc/codecs/bt-sco.c
++++ b/sound/soc/codecs/bt-sco.c
+@@ -17,11 +17,17 @@ static const struct snd_soc_dapm_widget bt_sco_widgets[] = {
+ 			    SND_SOC_NOPM, 0, 0),
+ 	SND_SOC_DAPM_AIF_OUT("BT_SCO_TX", "Capture", 0,
+ 			     SND_SOC_NOPM, 0, 0),
++	SND_SOC_DAPM_AIF_IN("BT_SCO_RX_WB", "WB Playback", 0,
++			    SND_SOC_NOPM, 0, 0),
++	SND_SOC_DAPM_AIF_OUT("BT_SCO_TX_WB", "WB Capture", 0,
++			     SND_SOC_NOPM, 0, 0),
+ };
+ 
+ static const struct snd_soc_dapm_route bt_sco_routes[] = {
+ 	{ "BT_SCO_TX", NULL, "RX" },
+ 	{ "TX", NULL, "BT_SCO_RX" },
++	{ "BT_SCO_TX_WB", NULL, "RX" },
++	{ "TX", NULL, "BT_SCO_RX_WB" },
+ };
+ 
+ static struct snd_soc_dai_driver bt_sco_dai[] = {
+@@ -45,14 +51,14 @@ static struct snd_soc_dai_driver bt_sco_dai[] = {
+ 	{
+ 		.name = "bt-sco-pcm-wb",
+ 		.playback = {
+-			.stream_name = "Playback",
++			.stream_name = "WB Playback",
+ 			.channels_min = 1,
+ 			.channels_max = 1,
+ 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+ 		},
+ 		.capture = {
+-			 .stream_name = "Capture",
++			 .stream_name = "WB Capture",
+ 			.channels_min = 1,
+ 			.channels_max = 1,
+ 			.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+diff --git a/sound/soc/codecs/cs35l56-i2c.c b/sound/soc/codecs/cs35l56-i2c.c
+index d10e0e2380e852..61dde15d5a5f55 100644
+--- a/sound/soc/codecs/cs35l56-i2c.c
++++ b/sound/soc/codecs/cs35l56-i2c.c
+@@ -39,9 +39,7 @@ static int cs35l56_i2c_probe(struct i2c_client *client)
+ 	if (ret != 0)
+ 		return ret;
+ 
+-	ret = cs35l56_init(cs35l56);
+-	if (ret == 0)
+-		ret = cs35l56_irq_request(&cs35l56->base, client->irq);
++	ret = cs35l56_irq_request(&cs35l56->base, client->irq);
+ 	if (ret < 0)
+ 		cs35l56_remove(cs35l56);
+ 
+diff --git a/sound/soc/codecs/cs35l56-spi.c b/sound/soc/codecs/cs35l56-spi.c
+index 9962703915e1f1..df23d19308d4a2 100644
+--- a/sound/soc/codecs/cs35l56-spi.c
++++ b/sound/soc/codecs/cs35l56-spi.c
+@@ -37,9 +37,7 @@ static int cs35l56_spi_probe(struct spi_device *spi)
+ 	if (ret != 0)
+ 		return ret;
+ 
+-	ret = cs35l56_init(cs35l56);
+-	if (ret == 0)
+-		ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
++	ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
+ 	if (ret < 0)
+ 		cs35l56_remove(cs35l56);
+ 
+diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
+index 832ff2cd3d24e9..987bd7a3cf1d48 100644
+--- a/sound/soc/codecs/cs35l56.c
++++ b/sound/soc/codecs/cs35l56.c
+@@ -1318,9 +1318,19 @@ int cs35l56_common_probe(struct cs35l56_private *cs35l56)
+ 		goto err;
+ 	}
+ 
+-	ret = devm_snd_soc_register_component(cs35l56->base.dev,
+-					      &soc_component_dev_cs35l56,
+-					      cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
++	/*
++	 * On SoundWire the cs35l56_init() cannot be run until after the
++	 * device has been enumerated by the SoundWire core.
++	 */
++	if (!cs35l56->sdw_peripheral) {
++		ret = cs35l56_init(cs35l56);
++		if (ret)
++			goto err_remove_wm_adsp;
++	}
++
++	ret = snd_soc_register_component(cs35l56->base.dev,
++					 &soc_component_dev_cs35l56,
++					 cs35l56_dai, ARRAY_SIZE(cs35l56_dai));
+ 	if (ret < 0) {
+ 		dev_err_probe(cs35l56->base.dev, ret, "Register codec failed\n");
+ 		goto err_remove_wm_adsp;
+@@ -1332,6 +1342,11 @@ err_remove_wm_adsp:
+ 	wm_adsp2_remove(&cs35l56->dsp);
+ 
+ err:
++	if (pm_runtime_enabled(cs35l56->base.dev)) {
++		pm_runtime_dont_use_autosuspend(cs35l56->base.dev);
++		pm_runtime_disable(cs35l56->base.dev);
++	}
++
+ 	gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+ 	regulator_bulk_disable(ARRAY_SIZE(cs35l56->supplies), cs35l56->supplies);
+ 
+@@ -1408,7 +1423,7 @@ post_soft_reset:
+ 		return dev_err_probe(cs35l56->base.dev, ret, "Failed to write ASP1_CONTROL3\n");
+ 
+ 	cs35l56->base.init_done = true;
+-	complete(&cs35l56->init_completion);
++	complete_all(&cs35l56->init_completion);
+ 
+ 	return 0;
+ }
+@@ -1416,6 +1431,8 @@ EXPORT_SYMBOL_NS_GPL(cs35l56_init, SND_SOC_CS35L56_CORE);
+ 
+ void cs35l56_remove(struct cs35l56_private *cs35l56)
+ {
++	snd_soc_unregister_component(cs35l56->base.dev);
++
+ 	cs35l56->base.init_done = false;
+ 
+ 	/*
+diff --git a/sound/soc/codecs/cs42l43-jack.c b/sound/soc/codecs/cs42l43-jack.c
+index ba60acc4b2f094..d0f424d2e32650 100644
+--- a/sound/soc/codecs/cs42l43-jack.c
++++ b/sound/soc/codecs/cs42l43-jack.c
+@@ -283,6 +283,7 @@ irqreturn_t cs42l43_bias_detect_clamp(int irq, void *data)
+ #define CS42L43_JACK_ABSENT 0x0
+ 
+ #define CS42L43_JACK_OPTICAL (SND_JACK_MECHANICAL | SND_JACK_AVOUT)
++#define CS42L43_JACK_MICROPHONE (SND_JACK_MECHANICAL | SND_JACK_MICROPHONE)
+ #define CS42L43_JACK_HEADPHONE (SND_JACK_MECHANICAL | SND_JACK_HEADPHONE)
+ #define CS42L43_JACK_HEADSET (SND_JACK_MECHANICAL | SND_JACK_HEADSET)
+ #define CS42L43_JACK_LINEOUT (SND_JACK_MECHANICAL | SND_JACK_LINEOUT)
+@@ -867,7 +868,7 @@ static const struct cs42l43_jack_override_mode {
+ 		.hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+ 		.mic_ctrl = (0x3 << CS42L43_JACK_STEREO_CONFIG_SHIFT) |
+ 			    CS42L43_HS1_BIAS_EN_MASK | CS42L43_HS2_BIAS_EN_MASK,
+-		.report = CS42L43_JACK_LINEIN,
++		.report = CS42L43_JACK_MICROPHONE,
+ 	},
+ 	[CS42L43_JACK_RAW_OPTICAL] = {
+ 		.hsdet_mode = CS42L43_JACK_3_POLE_SWITCHES,
+diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c
+index 962c2cdfa01744..a109315a8c0533 100644
+--- a/sound/soc/codecs/tas2562.c
++++ b/sound/soc/codecs/tas2562.c
+@@ -684,11 +684,12 @@ static int tas2562_parse_dt(struct tas2562_data *tas2562)
+ 	if (tas2562->sdz_gpio == NULL) {
+ 		tas2562->sdz_gpio = devm_gpiod_get_optional(dev, "shut-down",
+ 							      GPIOD_OUT_HIGH);
+-		if (IS_ERR(tas2562->sdz_gpio))
++		if (IS_ERR(tas2562->sdz_gpio)) {
+ 			if (PTR_ERR(tas2562->sdz_gpio) == -EPROBE_DEFER)
+ 				return -EPROBE_DEFER;
+ 
+-		tas2562->sdz_gpio = NULL;
++			tas2562->sdz_gpio = NULL;
++		}
+ 	}
+ 
+ 	if (tas2562->model_id == TAS2110)
+diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
+index 1cc64ed8de6da8..4b6bed6bf11567 100644
+--- a/sound/soc/codecs/tas2781-fmwlib.c
++++ b/sound/soc/codecs/tas2781-fmwlib.c
+@@ -11,6 +11,7 @@
+ #include <linux/i2c.h>
+ #include <linux/init.h>
+ #include <linux/interrupt.h>
++#include <linux/limits.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
+ #include <linux/of_irq.h>
+@@ -921,13 +922,42 @@ static int tasdevice_load_block_kernel(
+ 	return 0;
+ }
+ 
++static int tasdevice_fw_strnlen(const struct firmware *fmw, int offset)
++{
++	const u8 *start;
++	const u8 *nul;
++	size_t remaining;
++	size_t len;
++
++	if (offset < 0 || offset >= fmw->size)
++		return -EINVAL;
++
++	start = fmw->data + offset;
++	remaining = fmw->size - offset;
++	nul = memchr(start, '\0', remaining);
++	if (!nul)
++		return -EINVAL;
++
++	len = nul - start;
++	if (len > INT_MAX)
++		return -EOVERFLOW;
++
++	return len;
++}
++
+ static int fw_parse_variable_hdr(struct tasdevice_priv
+ 	*tas_priv, struct tasdevice_dspfw_hdr *fw_hdr,
+ 	const struct firmware *fmw, int offset)
+ {
+ 	const unsigned char *buf = fmw->data;
+-	int len = strlen((char *)&buf[offset]);
++	int len;
+ 
++	len = tasdevice_fw_strnlen(fmw, offset);
++	if (len < 0) {
++		dev_err(tas_priv->dev, "%s: Description error\n", __func__);
++		offset = len;
++		goto out;
++	}
+ 	len++;
+ 
+ 	if (offset + len + 8 > fmw->size) {
+@@ -1059,7 +1089,12 @@ static int fw_parse_data(struct tasdevice_fw *tas_fmw,
+ 	memcpy(img_data->name, &data[offset], 64);
+ 	offset += 64;
+ 
+-	n = strlen((char *)&data[offset]);
++	n = tasdevice_fw_strnlen(fmw, offset);
++	if (n < 0) {
++		dev_err(tas_fmw->dev, "%s: Description error\n", __func__);
++		offset = n;
++		goto out;
++	}
+ 	n++;
+ 	if (offset + n + 2 > fmw->size) {
+ 		dev_err(tas_fmw->dev, "%s: Description error\n", __func__);
+@@ -1132,7 +1167,12 @@ static int fw_parse_program_data(struct tasdevice_priv *tas_priv,
+ 		}
+ 		offset += 64;
+ 
+-		n = strlen((char *)&buf[offset]);
++		n = tasdevice_fw_strnlen(fmw, offset);
++		if (n < 0) {
++			dev_err(tas_priv->dev, "Description err\n");
++			offset = n;
++			goto out;
++		}
+ 		/* skip '\0' and 5 unused bytes */
+ 		n += 6;
+ 		if (offset + n > fmw->size) {
+@@ -1195,7 +1235,12 @@ static int fw_parse_configuration_data(
+ 		memcpy(config->name, &data[offset], 64);
+ 		offset += 64;
+ 
+-		n = strlen((char *)&data[offset]);
++		n = tasdevice_fw_strnlen(fmw, offset);
++		if (n < 0) {
++			dev_err(tas_priv->dev, "Description err\n");
++			offset = n;
++			goto out;
++		}
+ 		n += 15;
+ 		if (offset + n > fmw->size) {
+ 			dev_err(tas_priv->dev, "Description err\n");
+@@ -1849,7 +1894,8 @@ static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv,
+ {
+ 	struct tasdevice_calibration *calibration;
+ 	unsigned char *data = (unsigned char *)fmw->data;
+-	unsigned int i, n;
++	unsigned int i;
++	int n;
+ 
+ 	if (offset + 2 > fmw->size) {
+ 		dev_err(tas_priv->dev, "%s: Calibrations error\n", __func__);
+@@ -1881,7 +1927,12 @@ static int fw_parse_calibration_data(struct tasdevice_priv *tas_priv,
+ 		calibration = &(tas_fmw->calibrations[i]);
+ 		offset += 64;
+ 
+-		n = strlen((char *)&data[offset]);
++		n = tasdevice_fw_strnlen(fmw, offset);
++		if (n < 0) {
++			dev_err(tas_priv->dev, "Description err\n");
++			offset = n;
++			goto out;
++		}
+ 		/* skip '\0' and 2 unused bytes */
+ 		n += 3;
+ 		if (offset + n > fmw->size) {
+diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
+index 43038444c43dce..5c9b464f026c10 100644
+--- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
++++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c
+@@ -704,18 +704,6 @@ static int mt6797_afe_runtime_resume(struct device *dev)
+ 	return 0;
+ }
+ 
+-static int mt6797_afe_component_probe(struct snd_soc_component *component)
+-{
+-	return mtk_afe_add_sub_dai_control(component);
+-}
+-
+-static const struct snd_soc_component_driver mt6797_afe_component = {
+-	.name		= AFE_PCM_NAME,
+-	.probe		= mt6797_afe_component_probe,
+-	.pointer	= mtk_afe_pcm_pointer,
+-	.pcm_construct	= mtk_afe_pcm_new,
+-};
+-
+ static int mt6797_dai_memif_register(struct mtk_base_afe *afe)
+ {
+ 	struct mtk_base_afe_dai *dai;
+@@ -852,7 +840,7 @@ static int mt6797_afe_pcm_dev_probe(struct platform_device *pdev)
+ 	pm_runtime_get_sync(&pdev->dev);
+ 
+ 	/* register component */
+-	ret = devm_snd_soc_register_component(dev, &mt6797_afe_component,
++	ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform,
+ 					      NULL, 0);
+ 	if (ret) {
+ 		dev_warn(dev, "err_platform\n");
+diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
+index d497e112988993..c1c486e275b9d3 100644
+--- a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
++++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c
+@@ -429,18 +429,6 @@ static int mt7986_afe_runtime_resume(struct device *dev)
+ 	return 0;
+ }
+ 
+-static int mt7986_afe_component_probe(struct snd_soc_component *component)
+-{
+-	return mtk_afe_add_sub_dai_control(component);
+-}
+-
+-static const struct snd_soc_component_driver mt7986_afe_component = {
+-	.name = AFE_PCM_NAME,
+-	.probe = mt7986_afe_component_probe,
+-	.pointer	= mtk_afe_pcm_pointer,
+-	.pcm_construct	= mtk_afe_pcm_new,
+-};
+-
+ static int mt7986_dai_memif_register(struct mtk_base_afe *afe)
+ {
+ 	struct mtk_base_afe_dai *dai;
+@@ -573,7 +561,7 @@ static int mt7986_afe_pcm_dev_probe(struct platform_device *pdev)
+ 
+ 	/* register component */
+ 	ret = devm_snd_soc_register_component(&pdev->dev,
+-					      &mt7986_afe_component,
++					      &mtk_afe_pcm_platform,
+ 					      NULL, 0);
+ 	if (ret)
+ 		return dev_err_probe(dev, ret, "Cannot register AFE component\n");
+diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
+index 865c6182461335..0b4083d155034d 100644
+--- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
++++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c
+@@ -1043,18 +1043,6 @@ skip_regmap:
+ 	return 0;
+ }
+ 
+-static int mt8183_afe_component_probe(struct snd_soc_component *component)
+-{
+-	return mtk_afe_add_sub_dai_control(component);
+-}
+-
+-static const struct snd_soc_component_driver mt8183_afe_component = {
+-	.name		= AFE_PCM_NAME,
+-	.probe		= mt8183_afe_component_probe,
+-	.pointer	= mtk_afe_pcm_pointer,
+-	.pcm_construct	= mtk_afe_pcm_new,
+-};
+-
+ static int mt8183_dai_memif_register(struct mtk_base_afe *afe)
+ {
+ 	struct mtk_base_afe_dai *dai;
+@@ -1161,17 +1149,21 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
+ 
+ 	/* enable clock for regcache get default value from hw */
+ 	afe_priv->pm_runtime_bypass_reg_ctl = true;
+-	pm_runtime_get_sync(&pdev->dev);
++	ret = pm_runtime_resume_and_get(dev);
++	if (ret) {
++		afe_priv->pm_runtime_bypass_reg_ctl = false;
++		goto err_pm_disable;
++	}
+ 
+ 	ret = regmap_reinit_cache(afe->regmap, &mt8183_afe_regmap_config);
++	pm_runtime_put_sync(dev);
++	afe_priv->pm_runtime_bypass_reg_ctl = false;
++
+ 	if (ret) {
+ 		dev_err(dev, "regmap_reinit_cache fail, ret %d\n", ret);
+ 		goto err_pm_disable;
+ 	}
+ 
+-	pm_runtime_put_sync(&pdev->dev);
+-	afe_priv->pm_runtime_bypass_reg_ctl = false;
+-
+ 	regcache_cache_only(afe->regmap, true);
+ 	regcache_mark_dirty(afe->regmap);
+ 
+@@ -1250,7 +1242,7 @@ static int mt8183_afe_pcm_dev_probe(struct platform_device *pdev)
+ 
+ 	/* register component */
+ 	ret = devm_snd_soc_register_component(&pdev->dev,
+-					      &mt8183_afe_component,
++					      &mtk_afe_pcm_platform,
+ 					      NULL, 0);
+ 	if (ret) {
+ 		dev_warn(dev, "err_platform\n");
+diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+index 4a304bffef8bab..b2e2eb959aa5f5 100644
+--- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
++++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
+@@ -3027,25 +3027,6 @@ skip_regmap:
+ 	return 0;
+ }
+ 
+-static int mt8188_afe_component_probe(struct snd_soc_component *component)
+-{
+-	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+-	int ret;
+-
+-	snd_soc_component_init_regmap(component, afe->regmap);
+-
+-	ret = mtk_afe_add_sub_dai_control(component);
+-
+-	return ret;
+-}
+-
+-static const struct snd_soc_component_driver mt8188_afe_component = {
+-	.name = AFE_PCM_NAME,
+-	.pointer       = mtk_afe_pcm_pointer,
+-	.pcm_construct = mtk_afe_pcm_new,
+-	.probe         = mt8188_afe_component_probe,
+-};
+-
+ static int init_memif_priv_data(struct mtk_base_afe *afe)
+ {
+ 	struct mt8188_afe_private *afe_priv = afe->platform_priv;
+@@ -3347,7 +3328,7 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
+ 	}
+ 
+ 	/* register component */
+-	ret = devm_snd_soc_register_component(dev, &mt8188_afe_component,
++	ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform,
+ 					      afe->dai_drivers, afe->num_dai_drivers);
+ 	if (ret) {
+ 		dev_warn(dev, "err_platform\n");
+diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
+index 06af6eb0e80ca2..988d9b2d28bf4f 100644
+--- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
++++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c
+@@ -2126,22 +2126,6 @@ skip_regmap:
+ 	return 0;
+ }
+ 
+-static int mt8192_afe_component_probe(struct snd_soc_component *component)
+-{
+-	return mtk_afe_add_sub_dai_control(component);
+-}
+-
+-static const struct snd_soc_component_driver mt8192_afe_component = {
+-	.name = AFE_PCM_NAME,
+-	.probe = mt8192_afe_component_probe,
+-	.pointer = mtk_afe_pcm_pointer,
+-	.pcm_construct = mtk_afe_pcm_new,
+-};
+-
+-static const struct snd_soc_component_driver mt8192_afe_pcm_component = {
+-	.name = "mt8192-afe-pcm-dai",
+-};
+-
+ static int mt8192_dai_memif_register(struct mtk_base_afe *afe)
+ {
+ 	struct mtk_base_afe_dai *dai;
+@@ -2180,27 +2164,26 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
+ {
+ 	struct mtk_base_afe *afe;
+ 	struct mt8192_afe_private *afe_priv;
+-	struct device *dev;
++	struct device *dev = &pdev->dev;
+ 	struct reset_control *rstc;
+ 	int i, ret, irq_id;
+ 
+-	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
++	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34));
+ 	if (ret)
+ 		return ret;
+ 
+-	afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL);
++	afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL);
+ 	if (!afe)
+ 		return -ENOMEM;
+ 	platform_set_drvdata(pdev, afe);
+ 
+-	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
++	afe->platform_priv = devm_kzalloc(dev, sizeof(*afe_priv),
+ 					  GFP_KERNEL);
+ 	if (!afe->platform_priv)
+ 		return -ENOMEM;
+ 	afe_priv = afe->platform_priv;
+ 
+-	afe->dev = &pdev->dev;
+-	dev = afe->dev;
++	afe->dev = dev;
+ 
+ 	ret = of_reserved_mem_device_init(dev);
+ 	if (ret) {
+@@ -2221,48 +2204,42 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
+ 
+ 	/* reset controller to reset audio regs before regmap cache */
+ 	rstc = devm_reset_control_get_exclusive(dev, "audiosys");
+-	if (IS_ERR(rstc)) {
+-		ret = PTR_ERR(rstc);
+-		dev_err(dev, "could not get audiosys reset:%d\n", ret);
+-		return ret;
+-	}
++	if (IS_ERR(rstc))
++		return dev_err_probe(dev, PTR_ERR(rstc), "could not get audiosys reset\n");
+ 
+ 	ret = reset_control_reset(rstc);
+-	if (ret) {
+-		dev_err(dev, "failed to trigger audio reset:%d\n", ret);
+-		return ret;
+-	}
++	if (ret)
++		return dev_err_probe(dev, ret, "failed to trigger audio reset\n");
+ 
+-	pm_runtime_enable(&pdev->dev);
+-	if (!pm_runtime_enabled(&pdev->dev))
+-		goto err_pm_disable;
++	ret = devm_pm_runtime_enable(dev);
++	if (ret)
++		return ret;
+ 
+ 	/* regmap init */
+ 	afe->regmap = syscon_node_to_regmap(dev->parent->of_node);
+-	if (IS_ERR(afe->regmap)) {
+-		dev_err(dev, "could not get regmap from parent\n");
+-		ret = PTR_ERR(afe->regmap);
+-		goto err_pm_disable;
+-	}
++	if (IS_ERR(afe->regmap))
++		return dev_err_probe(dev, PTR_ERR(afe->regmap),
++				     "could not get regmap from parent");
++
+ 	ret = regmap_attach_dev(dev, afe->regmap, &mt8192_afe_regmap_config);
+-	if (ret) {
+-		dev_warn(dev, "regmap_attach_dev fail, ret %d\n", ret);
+-		goto err_pm_disable;
+-	}
++	if (ret)
++		return dev_err_probe(dev, ret, "regmap_attach_dev fail\n");
+ 
+ 	/* enable clock for regcache get default value from hw */
+ 	afe_priv->pm_runtime_bypass_reg_ctl = true;
+-	pm_runtime_get_sync(&pdev->dev);
+-
+-	ret = regmap_reinit_cache(afe->regmap, &mt8192_afe_regmap_config);
++	ret = pm_runtime_resume_and_get(dev);
+ 	if (ret) {
+-		dev_err(dev, "regmap_reinit_cache fail, ret %d\n", ret);
+-		goto err_pm_disable;
++		afe_priv->pm_runtime_bypass_reg_ctl = false;
++		return dev_err_probe(dev, ret, "failed to resume device\n");
+ 	}
+ 
+-	pm_runtime_put_sync(&pdev->dev);
++	ret = regmap_reinit_cache(afe->regmap, &mt8192_afe_regmap_config);
++	pm_runtime_put_sync(dev);
+ 	afe_priv->pm_runtime_bypass_reg_ctl = false;
+ 
++	if (ret)
++		return dev_err_probe(dev, ret, "regmap_reinit_cache fail\n");
++
+ 	regcache_cache_only(afe->regmap, true);
+ 	regcache_mark_dirty(afe->regmap);
+ 
+@@ -2270,10 +2247,8 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
+ 	afe->memif_size = MT8192_MEMIF_NUM;
+ 	afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif),
+ 				  GFP_KERNEL);
+-	if (!afe->memif) {
+-		ret = -ENOMEM;
+-		goto err_pm_disable;
+-	}
++	if (!afe->memif)
++		return -ENOMEM;
+ 
+ 	for (i = 0; i < afe->memif_size; i++) {
+ 		afe->memif[i].data = &memif_data[i];
+@@ -2287,47 +2262,35 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
+ 	afe->irqs_size = MT8192_IRQ_NUM;
+ 	afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs),
+ 				 GFP_KERNEL);
+-	if (!afe->irqs) {
+-		ret = -ENOMEM;
+-		goto err_pm_disable;
+-	}
++	if (!afe->irqs)
++		return -ENOMEM;
+ 
+ 	for (i = 0; i < afe->irqs_size; i++)
+ 		afe->irqs[i].irq_data = &irq_data[i];
+ 
+ 	/* request irq */
+ 	irq_id = platform_get_irq(pdev, 0);
+-	if (irq_id < 0) {
+-		ret = irq_id;
+-		goto err_pm_disable;
+-	}
++	if (irq_id < 0)
++		return irq_id;
+ 
+ 	ret = devm_request_irq(dev, irq_id, mt8192_afe_irq_handler,
+ 			       IRQF_TRIGGER_NONE, "asys-isr", (void *)afe);
+-	if (ret) {
+-		dev_err(dev, "could not request_irq for Afe_ISR_Handle\n");
+-		goto err_pm_disable;
+-	}
++	if (ret)
++		return dev_err_probe(dev, ret, "could not request_irq for Afe_ISR_Handle\n");
+ 
+ 	/* init sub_dais */
+ 	INIT_LIST_HEAD(&afe->sub_dais);
+ 
+ 	for (i = 0; i < ARRAY_SIZE(dai_register_cbs); i++) {
+ 		ret = dai_register_cbs[i](afe);
+-		if (ret) {
+-			dev_warn(afe->dev, "dai register i %d fail, ret %d\n",
+-				 i, ret);
+-			goto err_pm_disable;
+-		}
++		if (ret)
++			return dev_err_probe(afe->dev, ret, "dai %d register fail", i);
+ 	}
+ 
+ 	/* init dai_driver and component_driver */
+ 	ret = mtk_afe_combine_sub_dai(afe);
+-	if (ret) {
+-		dev_warn(afe->dev, "mtk_afe_combine_sub_dai fail, ret %d\n",
+-			 ret);
+-		goto err_pm_disable;
+-	}
++	if (ret)
++		return dev_err_probe(afe->dev, ret, "mtk_afe_combine_sub_dai fail\n");
+ 
+ 	/* others */
+ 	afe->mtk_afe_hardware = &mt8192_afe_hardware;
+@@ -2341,28 +2304,14 @@ static int mt8192_afe_pcm_dev_probe(struct platform_device *pdev)
+ 	afe->runtime_suspend = mt8192_afe_runtime_suspend;
+ 
+ 	/* register platform */
+-	ret = devm_snd_soc_register_component(&pdev->dev,
+-					      &mt8192_afe_component, NULL, 0);
+-	if (ret) {
+-		dev_warn(dev, "err_platform\n");
+-		goto err_pm_disable;
+-	}
+-
+-	ret = devm_snd_soc_register_component(&pdev->dev,
+-					      &mt8192_afe_pcm_component,
++	ret = devm_snd_soc_register_component(dev,
++					      &mtk_afe_pcm_platform,
+ 					      afe->dai_drivers,
+ 					      afe->num_dai_drivers);
+-	if (ret) {
+-		dev_warn(dev, "err_dai_component\n");
+-		goto err_pm_disable;
+-	}
++	if (ret)
++		return dev_err_probe(dev, ret, "Couldn't register AFE component\n");
+ 
+ 	return 0;
+-
+-err_pm_disable:
+-	pm_runtime_disable(&pdev->dev);
+-
+-	return ret;
+ }
+ 
+ static void mt8192_afe_pcm_dev_remove(struct platform_device *pdev)
+diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
+index a0f2012211fb30..c83126a1b75428 100644
+--- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
++++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
+@@ -1795,10 +1795,6 @@ static const struct snd_kcontrol_new mt8195_memif_controls[] = {
+ 			    MT8195_AFE_IRQ_28),
+ };
+ 
+-static const struct snd_soc_component_driver mt8195_afe_pcm_dai_component = {
+-	.name = "mt8195-afe-pcm-dai",
+-};
+-
+ static const struct mtk_base_memif_data memif_data[MT8195_AFE_MEMIF_NUM] = {
+ 	[MT8195_AFE_MEMIF_DL2] = {
+ 		.name = "DL2",
+@@ -2948,25 +2944,6 @@ skip_regmap:
+ 	return 0;
+ }
+ 
+-static int mt8195_afe_component_probe(struct snd_soc_component *component)
+-{
+-	struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component);
+-	int ret = 0;
+-
+-	snd_soc_component_init_regmap(component, afe->regmap);
+-
+-	ret = mtk_afe_add_sub_dai_control(component);
+-
+-	return ret;
+-}
+-
+-static const struct snd_soc_component_driver mt8195_afe_component = {
+-	.name = AFE_PCM_NAME,
+-	.pointer = mtk_afe_pcm_pointer,
+-	.pcm_construct = mtk_afe_pcm_new,
+-	.probe = mt8195_afe_component_probe,
+-};
+-
+ static int init_memif_priv_data(struct mtk_base_afe *afe)
+ {
+ 	struct mt8195_afe_private *afe_priv = afe->platform_priv;
+@@ -3037,7 +3014,6 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev)
+ 	struct device *dev = &pdev->dev;
+ 	struct reset_control *rstc;
+ 	int i, irq_id, ret;
+-	struct snd_soc_component *component;
+ 
+ 	ret = of_reserved_mem_device_init(dev);
+ 	if (ret)
+@@ -3169,37 +3145,13 @@ static int mt8195_afe_pcm_dev_probe(struct platform_device *pdev)
+ 	}
+ 
+ 	/* register component */
+-	ret = devm_snd_soc_register_component(dev, &mt8195_afe_component,
+-					      NULL, 0);
++	ret = devm_snd_soc_register_component(dev, &mtk_afe_pcm_platform,
++					      afe->dai_drivers, afe->num_dai_drivers);
+ 	if (ret) {
+ 		dev_warn(dev, "err_platform\n");
+ 		goto err_pm_put;
+ 	}
+ 
+-	component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
+-	if (!component) {
+-		ret = -ENOMEM;
+-		goto err_pm_put;
+-	}
+-
+-	ret = snd_soc_component_initialize(component,
+-					   &mt8195_afe_pcm_dai_component,
+-					   dev);
+-	if (ret)
+-		goto err_pm_put;
+-
+-#ifdef CONFIG_DEBUG_FS
+-	component->debugfs_prefix = "pcm";
+-#endif
+-
+-	ret = snd_soc_add_component(component,
+-				    afe->dai_drivers,
+-				    afe->num_dai_drivers);
+-	if (ret) {
+-		dev_warn(dev, "err_dai_component\n");
+-		goto err_pm_put;
+-	}
+-
+ 	ret = regmap_multi_reg_write(afe->regmap, mt8195_afe_reg_defaults,
+ 				     ARRAY_SIZE(mt8195_afe_reg_defaults));
+ 	if (ret)
+@@ -3224,8 +3176,6 @@ err_pm_put:
+ 
+ static void mt8195_afe_pcm_dev_remove(struct platform_device *pdev)
+ {
+-	snd_soc_unregister_component(&pdev->dev);
+-
+ 	pm_runtime_disable(&pdev->dev);
+ 	if (!pm_runtime_status_suspended(&pdev->dev))
+ 		mt8195_afe_runtime_suspend(&pdev->dev);
+diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
+index ceca882ecff7b2..33b66a90e6fa5b 100644
+--- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c
++++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c
+@@ -1237,8 +1237,6 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
+ 			SND_SOC_DAIFMT_NB_NF |
+ 			SND_SOC_DAIFMT_CBS_CFS,
+ 		.dpcm_capture = 1,
+-		.init = mt8195_rt5682_init,
+-		.ops = &mt8195_rt5682_etdm_ops,
+ 		.be_hw_params_fixup = mt8195_etdm_hw_params_fixup,
+ 		SND_SOC_DAILINK_REG(ETDM2_IN_BE),
+ 	},
+@@ -1249,7 +1247,6 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = {
+ 			SND_SOC_DAIFMT_NB_NF |
+ 			SND_SOC_DAIFMT_CBS_CFS,
+ 		.dpcm_playback = 1,
+-		.ops = &mt8195_rt5682_etdm_ops,
+ 		.be_hw_params_fixup = mt8195_etdm_hw_params_fixup,
+ 		SND_SOC_DAILINK_REG(ETDM1_OUT_BE),
+ 	},
+@@ -1381,7 +1378,7 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
+ 	struct snd_soc_dai_link *dai_link;
+ 	struct mtk_soc_card_data *soc_card_data;
+ 	struct mt8195_mt6359_priv *mach_priv;
+-	struct device_node *platform_node, *adsp_node, *dp_node, *hdmi_node;
++	struct device_node *platform_node, *adsp_node, *codec_node, *dp_node, *hdmi_node;
+ 	struct mt8195_card_data *card_data;
+ 	int is5682s = 0;
+ 	int init6359 = 0;
+@@ -1401,8 +1398,12 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
+ 	if (!card->name)
+ 		card->name = card_data->name;
+ 
+-	if (strstr(card->name, "_5682s"))
++	if (strstr(card->name, "_5682s")) {
++		codec_node = of_find_compatible_node(NULL, NULL, "realtek,rt5682s");
+ 		is5682s = 1;
++	} else
++		codec_node = of_find_compatible_node(NULL, NULL, "realtek,rt5682i");
++
+ 	soc_card_data = devm_kzalloc(&pdev->dev, sizeof(*card_data), GFP_KERNEL);
+ 	if (!soc_card_data)
+ 		return -ENOMEM;
+@@ -1488,12 +1489,27 @@ static int mt8195_mt6359_dev_probe(struct platform_device *pdev)
+ 				dai_link->codecs->dai_name = "i2s-hifi";
+ 				dai_link->init = mt8195_hdmi_codec_init;
+ 			}
+-		} else if (strcmp(dai_link->name, "ETDM1_OUT_BE") == 0 ||
+-			   strcmp(dai_link->name, "ETDM2_IN_BE") == 0) {
+-			dai_link->codecs->name =
+-				is5682s ? RT5682S_DEV0_NAME : RT5682_DEV0_NAME;
+-			dai_link->codecs->dai_name =
+-				is5682s ? RT5682S_CODEC_DAI : RT5682_CODEC_DAI;
++		} else if (strcmp(dai_link->name, "ETDM1_OUT_BE") == 0) {
++			if (!codec_node) {
++				dev_err(&pdev->dev, "Codec not found!\n");
++			} else {
++				dai_link->codecs->of_node = codec_node;
++				dai_link->codecs->name = NULL;
++				dai_link->codecs->dai_name =
++					is5682s ? RT5682S_CODEC_DAI : RT5682_CODEC_DAI;
++				dai_link->init = mt8195_rt5682_init;
++				dai_link->ops = &mt8195_rt5682_etdm_ops;
++			}
++		} else if (strcmp(dai_link->name, "ETDM2_IN_BE") == 0) {
++			if (!codec_node) {
++				dev_err(&pdev->dev, "Codec not found!\n");
++			} else {
++				dai_link->codecs->of_node = codec_node;
++				dai_link->codecs->name = NULL;
++				dai_link->codecs->dai_name =
++					is5682s ? RT5682S_CODEC_DAI : RT5682_CODEC_DAI;
++				dai_link->ops = &mt8195_rt5682_etdm_ops;
++			}
+ 		} else if (strcmp(dai_link->name, "DL_SRC_BE") == 0 ||
+ 			   strcmp(dai_link->name, "UL_SRC1_BE") == 0 ||
+ 			   strcmp(dai_link->name, "UL_SRC2_BE") == 0) {
+diff --git a/sound/soc/meson/aiu-fifo-spdif.c b/sound/soc/meson/aiu-fifo-spdif.c
+index fa91f3c53fa462..fe75deafdb69fd 100644
+--- a/sound/soc/meson/aiu-fifo-spdif.c
++++ b/sound/soc/meson/aiu-fifo-spdif.c
+@@ -24,6 +24,7 @@
+ #define AIU_MEM_IEC958_CONTROL_MODE_16BIT	BIT(7)
+ #define AIU_MEM_IEC958_CONTROL_MODE_LINEAR	BIT(8)
+ #define AIU_MEM_IEC958_BUF_CNTL_INIT		BIT(0)
++#define AIU_RST_SOFT_958_FAST			BIT(2)
+ 
+ #define AIU_FIFO_SPDIF_BLOCK			8
+ 
+@@ -68,11 +69,15 @@ static int fifo_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
+ 	case SNDRV_PCM_TRIGGER_START:
+ 	case SNDRV_PCM_TRIGGER_RESUME:
+ 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
++		snd_soc_component_write(component, AIU_RST_SOFT,
++					AIU_RST_SOFT_958_FAST);
+ 		fifo_spdif_dcu_enable(component, true);
+ 		break;
+ 	case SNDRV_PCM_TRIGGER_SUSPEND:
+ 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ 	case SNDRV_PCM_TRIGGER_STOP:
++		snd_soc_component_write(component, AIU_RST_SOFT,
++					AIU_RST_SOFT_958_FAST);
+ 		fifo_spdif_dcu_enable(component, false);
+ 		break;
+ 	default:
+diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
+index ed625d5bbe9ab0..8d77662d344f79 100644
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -2269,6 +2269,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
+ 		   QUIRK_FLAG_DSD_RAW),
+ 	DEVICE_FLG(0x2708, 0x0002, /* Audient iD14 */
+ 		   QUIRK_FLAG_IGNORE_CTL_ERROR),
++	DEVICE_FLG(0x2772, 0x0502, /* Musical Fidelity M6s DAC */
++		   0), /* for avoiding QUIRK_FLAG_DSD_RAW with vendor match */
+ 	DEVICE_FLG(0x2912, 0x30c8, /* Audioengine D1 */
+ 		   QUIRK_FLAG_GET_SAMPLE_RATE),
+ 	DEVICE_FLG(0x2a70, 0x1881, /* OnePlus Technology (Shenzhen) Co., Ltd. BE02T */
+diff --git a/tools/testing/selftests/alsa/mixer-test.c b/tools/testing/selftests/alsa/mixer-test.c
+index df942149c6f6c5..6fe4be43072fb1 100644
+--- a/tools/testing/selftests/alsa/mixer-test.c
++++ b/tools/testing/selftests/alsa/mixer-test.c
+@@ -82,6 +82,7 @@ static void find_controls(void)
+ 		if (err < 0) {
+ 			ksft_print_msg("Failed to get hctl for card %d: %s\n",
+ 				       card, snd_strerror(err));
++			free(card_data);
+ 			goto next_card;
+ 		}
+ 
+diff --git a/tools/testing/selftests/bpf/progs/verifier_ld_ind.c b/tools/testing/selftests/bpf/progs/verifier_ld_ind.c
+index c925ba9a2e74c2..09e81b99eecb4e 100644
+--- a/tools/testing/selftests/bpf/progs/verifier_ld_ind.c
++++ b/tools/testing/selftests/bpf/progs/verifier_ld_ind.c
+@@ -107,4 +107,146 @@ __naked void ind_check_calling_conv_r7(void)
+ 	: __clobber_all);
+ }
+ 
++/*
++ * ld_{abs,ind} subprog that always sets r0=1 on the success path.
++ * bpf_gen_ld_abs() emits a hidden exit with r0=0 when the load helper
++ * fails. The verifier must model this failure return so that callers
++ * account for r0=0 as a possible return value.
++ */
++__naked __noinline __used
++static int ldabs_subprog(void)
++{
++	asm volatile (
++	"r6 = r1;"
++	".8byte %[ld_abs];"
++	"r0 = 1;"
++	"exit;"
++	:
++	: __imm_insn(ld_abs, BPF_LD_ABS(BPF_W, 0))
++	: __clobber_all);
++}
++
++__naked __noinline __used
++static int ldind_subprog(void)
++{
++	asm volatile (
++	"r6 = r1;"
++	"r7 = 0;"
++	".8byte %[ld_ind];"
++	"r0 = 1;"
++	"exit;"
++	:
++	: __imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, 0))
++	: __clobber_all);
++}
++
++SEC("socket")
++__description("ld_abs: subprog early exit on ld_abs failure")
++__failure __msg("R9 !read_ok")
++__naked void ld_abs_subprog_early_exit(void)
++{
++	asm volatile (
++	"call ldabs_subprog;"
++	"if r0 != 0 goto l_exit_%=;"
++	"r0 = r9;"
++	"l_exit_%=:"
++	"r0 = 0;"
++	"exit;"
++	::: __clobber_all);
++}
++
++SEC("socket")
++__description("ld_ind: subprog early exit on ld_ind failure")
++__failure __msg("R9 !read_ok")
++__naked void ld_ind_subprog_early_exit(void)
++{
++	asm volatile (
++	"call ldind_subprog;"
++	"if r0 != 0 goto l_exit_%=;"
++	"r0 = r9;"
++	"l_exit_%=:"
++	"r0 = 0;"
++	"exit;"
++	::: __clobber_all);
++}
++
++SEC("socket")
++__description("ld_abs: subprog with both paths safe")
++__success
++__naked void ld_abs_subprog_both_paths_safe(void)
++{
++	asm volatile (
++	"call ldabs_subprog;"
++	"r0 = 0;"
++	"exit;"
++	::: __clobber_all);
++}
++
++SEC("socket")
++__description("ld_ind: subprog with both paths safe")
++__success
++__naked void ld_ind_subprog_both_paths_safe(void)
++{
++	asm volatile (
++	"call ldind_subprog;"
++	"r0 = 0;"
++	"exit;"
++	::: __clobber_all);
++}
++
++/*
++ * ld_{abs,ind} in subprogs require scalar (int) return type in BTF.
++ * A test with void return must be rejected.
++ */
++__naked __noinline __used
++static void ldabs_void_subprog(void)
++{
++	asm volatile (
++	"r6 = r1;"
++	".8byte %[ld_abs];"
++	"r0 = 1;"
++	"exit;"
++	:
++	: __imm_insn(ld_abs, BPF_LD_ABS(BPF_W, 0))
++	: __clobber_all);
++}
++
++SEC("socket")
++__description("ld_abs: reject void return subprog")
++__failure __msg("LD_ABS is only allowed in functions that return 'int'")
++__naked void ld_abs_void_subprog_reject(void)
++{
++	asm volatile (
++	"call ldabs_void_subprog;"
++	"r0 = 0;"
++	"exit;"
++	::: __clobber_all);
++}
++
++__naked __noinline __used
++static void ldind_void_subprog(void)
++{
++	asm volatile (
++	"r6 = r1;"
++	"r7 = 0;"
++	".8byte %[ld_ind];"
++	"r0 = 1;"
++	"exit;"
++	:
++	: __imm_insn(ld_ind, BPF_LD_IND(BPF_W, BPF_REG_7, 0))
++	: __clobber_all);
++}
++
++SEC("socket")
++__description("ld_ind: reject void return subprog")
++__failure __msg("LD_ABS is only allowed in functions that return 'int'")
++__naked void ld_ind_void_subprog_reject(void)
++{
++	asm volatile (
++	"call ldind_void_subprog;"
++	"r0 = 0;"
++	"exit;"
++	::: __clobber_all);
++}
++
+ char _license[] SEC("license") = "GPL";
+diff --git a/tools/testing/selftests/net/af_unix/config b/tools/testing/selftests/net/af_unix/config
+new file mode 100644
+index 00000000000000..9c4fb9c31c9506
+--- /dev/null
++++ b/tools/testing/selftests/net/af_unix/config
+@@ -0,0 +1,4 @@
++CONFIG_UNIX=y
++CONFIG_AF_UNIX_OOB=y
++CONFIG_UNIX_DIAG=m
++CONFIG_USER_NS=y
+diff --git a/tools/testing/selftests/net/openvswitch/config b/tools/testing/selftests/net/openvswitch/config
+new file mode 100644
+index 00000000000000..c659749cd086c7
+--- /dev/null
++++ b/tools/testing/selftests/net/openvswitch/config
+@@ -0,0 +1,16 @@
++CONFIG_GENEVE=m
++CONFIG_INET_DIAG=y
++CONFIG_IPV6=y
++CONFIG_NETFILTER=y
++CONFIG_NET_IPGRE=m
++CONFIG_NET_IPGRE_DEMUX=m
++CONFIG_NF_CONNTRACK=m
++CONFIG_NF_CONNTRACK_OVS=y
++CONFIG_OPENVSWITCH=m
++CONFIG_OPENVSWITCH_GENEVE=m
++CONFIG_OPENVSWITCH_GRE=m
++CONFIG_OPENVSWITCH_VXLAN=m
++CONFIG_PSAMPLE=m
++CONFIG_VETH=y
++CONFIG_VLAN_8021Q=y
++CONFIG_VXLAN=m
+diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
+index b83f7612f2506c..81024cee82cba3 100644
+--- a/virt/kvm/kvm_main.c
++++ b/virt/kvm/kvm_main.c
+@@ -4160,7 +4160,10 @@ static long kvm_vcpu_ioctl(struct file *filp,
+ 				synchronize_rcu();
+ 			put_pid(oldpid);
+ 		}
++		vcpu->wants_to_run = !READ_ONCE(vcpu->run->immediate_exit);
+ 		r = kvm_arch_vcpu_ioctl_run(vcpu);
++		vcpu->wants_to_run = false;
++
+ 		trace_kvm_userspace_exit(vcpu->run->exit_reason, r);
+ 		break;
+ 	}