From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F3A362AD03; Sun, 11 Oct 2026 13:53:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791726834; cv=none; b=GrlkJzhl1uFs9EBSSoh+cZO9559gj9jukikelCv9YTgpRCRRmahxFogINOIi/UmGY4U0N82mKDBCRYAUDzwn+CH5Ne3mFYZT/D1ppS79YZDtINBoC5OTvlnCTTnKQBRe/7CVESK2LmUZVk349PwNA+3IY65UZRu5g48UK+0Z3ig= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791726834; c=relaxed/simple; bh=R246AL8naEnVGrbusmDiRqthoome3L6U67dXF4vp9Z8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=od1v8Y1lqgOIUI478zrMDwNdy5Py2eyjJAKfI/zf1xGkqZGU27eErNOqlHjcamJvaRLUWR3H2g80eZhGrlPFeweU2P9Kuf5kiTWSjPUg0KBy3GZ43QT8geQg84o8lZxbNkSgitHGTw1+Sr4sQ9jZtnwAWQDGCWgr6tmCoVnlXkQ= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=ME0SN9gM; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="ME0SN9gM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0DA4B1F0089B; Sun, 11 Oct 2026 13:53:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1791726812; bh=0l+vWC/APq/7FBX7Cyh5H/0vbwq2KfIGqZzidV+gmfY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ME0SN9gMORsfM+s11E4DFiHb/1im4LLXPabC+slpdJuj3MAlLjwvel/ZteAlKcu2V KfIK27WEFLuap0gsInWpBVuqO2Sev94o38V/KVKt+2XNC5VoVYaOjN0Adw/Bl7TBhL iqbY3gfmw1L0cNLrIniuLnNG+atmBZvQczB6ebH4= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org, akpm@linux-foundation.org, torvalds@linux-foundation.org, stable@vger.kernel.org Cc: lwn@lwn.net, jslaby@suse.cz, Greg Kroah-Hartman Subject: Re: Linux 6.18.56 Date: Sun, 11 Oct 2026 15:53:16 +0200 Message-ID: <2026101116-lunchbox-unmapped-151b@gregkh> X-Mailer: git-send-email 2.56.0 In-Reply-To: <2026101116-engulf-puzzle-d3bf@gregkh> References: <2026101116-engulf-puzzle-d3bf@gregkh> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst index 1c5accd6dec4..75c6ba532c20 100644 --- a/Documentation/arch/arm64/silicon-errata.rst +++ b/Documentation/arch/arm64/silicon-errata.rst @@ -168,6 +168,8 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-A725 | #3456106 | ARM64_ERRATUM_3194386 | +----------------+-----------------+-----------------+-----------------------------+ +| ARM | Cortex-A725 | #3821522 | ARM64_ERRATUM_3821522 | ++----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-X1 | #1502854 | N/A | +----------------+-----------------+-----------------+-----------------------------+ | ARM | Cortex-X1 | #3324344 | ARM64_ERRATUM_3194386 | diff --git a/Documentation/filesystems/netfs_library.rst b/Documentation/filesystems/netfs_library.rst index ddd799df6ce3..2f0bc3002976 100644 --- a/Documentation/filesystems/netfs_library.rst +++ b/Documentation/filesystems/netfs_library.rst @@ -451,6 +451,32 @@ one. The inode should be marked ``NETFS_ICTX_SINGLE_NO_UPLOAD`` if this API is to be used. The writeback function requires the buffer to be of ITER_FOLIOQ type. +Clearing Stale Post-EOF Pagecache +--------------------------------- + +When a file is extended, data left in the pagecache past the old EOF by a write +through an mmap must not be exposed as file content. Netfslib clears this on +its own write paths, and exports a helper so a filesystem can do the same from +a resize path (truncate, setattr, fallocate and the like) that holds the +inode's ``i_rwsem`` exclusively across the whole resize:: + + void netfs_clear_stale_post_isize(struct inode *inode, unsigned long long from, + unsigned long long to); + +This zeroes any such data within the ``[from, to)`` hole to be made, where +@from is the old EOF and @to is the new one, and the caller must have already +updated ``i_size`` to @to before calling it. Only the folio straddling @from +can hold data written past the EOF through an mmap, as pages wholly beyond the +EOF can't be faulted in, so the zeroing is limited to that folio. The folio is +zeroed rather than dropped so that a concurrent extending write can't lose +data. + +This overlaps with ``pagecache_isize_extended()`` but can't reuse it: that +helper is keyed on a sub-page block size and is a no-op when the block size is +``>= PAGE_SIZE`` (as on network filesystems), and it doesn't wait for +writeback. As both address the same problem, a change to one should probably +be reflected in the other to keep them in sync. + High-Level VM API ================== diff --git a/Makefile b/Makefile index 84df9673f9b6..3af976c5dd34 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 18 -SUBLEVEL = 55 +SUBLEVEL = 56 EXTRAVERSION = NAME = Baby Opossum Posse diff --git a/arch/arc/include/asm/atomic64-arcv2.h b/arch/arc/include/asm/atomic64-arcv2.h index 73080a664369..1ca4a1047fb3 100644 --- a/arch/arc/include/asm/atomic64-arcv2.h +++ b/arch/arc/include/asm/atomic64-arcv2.h @@ -156,6 +156,12 @@ static inline u64 __arch_cmpxchg64_relaxed(volatile void *ptr, u64 old, u64 new) } #define arch_cmpxchg64_relaxed __arch_cmpxchg64_relaxed +static inline s64 arch_atomic64_cmpxchg_relaxed(atomic64_t *v, s64 old, s64 new) +{ + return arch_cmpxchg64_relaxed(&v->counter, old, new); +} +#define arch_atomic64_cmpxchg_relaxed arch_atomic64_cmpxchg_relaxed + static inline s64 arch_atomic64_xchg(atomic64_t *ptr, s64 new) { s64 prev; diff --git a/arch/arc/include/asm/cmpxchg.h b/arch/arc/include/asm/cmpxchg.h index 76f43db0890f..66b3743c9400 100644 --- a/arch/arc/include/asm/cmpxchg.h +++ b/arch/arc/include/asm/cmpxchg.h @@ -46,7 +46,7 @@ __typeof__(*(ptr)) _n_ = (new); \ __typeof__(*(ptr)) _prev_; \ \ - switch(sizeof((_p_))) { \ + switch (sizeof(*(_p_))) { \ case 1: \ _prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *__force)_p_, (uintptr_t)_o_, (uintptr_t)_n_); \ break; \ @@ -102,7 +102,7 @@ __typeof__(ptr) _p_ = (ptr); \ __typeof__(*(ptr)) _val_ = (val); \ \ - switch(sizeof(*(_p_))) { \ + switch (sizeof(*(_p_))) { \ case 4: \ _val_ = __arch_xchg(_p_, _val_); \ break; \ diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index f7c4cb4fbaf1..2e567a7d89c9 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1049,9 +1049,17 @@ config ARM64_ERRATUM_1902691 If unsure, say Y. +config ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT + bool + # Targeting errata affecting AMEVCNTR01, the AMU constant counter. + # On affected CPUs the counter may not increment at the expected rate, + # making it unreliable. As a result, AMU users should treat it as + # unavailable rather than relying on misleading counter values. + config ARM64_ERRATUM_2457168 bool "Cortex-A510: 2457168: workaround for AMEVCNTR01 incrementing incorrectly" depends on ARM64_AMU_EXTN + select ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT default y help This option adds the workaround for ARM Cortex-A510 erratum 2457168. @@ -1082,6 +1090,28 @@ config ARM64_ERRATUM_2645198 If unsure, say Y. +config ARM64_ERRATUM_3821522 + bool "Cortex-A725: 3821522: workaround for possible CNT_CYCLES increment error due to WFE/WFI" + depends on ARM64_AMU_EXTN + select ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT + default y + help + This option adds the workaround for ARM Cortex-A725 erratum 3821522. + + On affected A725 cores, the CNT_CYCLES event may incur a significant + increment error when entering and subsequently exiting WFx. + As a result, the CNT_CYCLES may diverge from the system counter + frequency at which it is expected to increment. + This renders the AMU counter AMEVCNTR01, that implements CNT_CYCLES, + being unreliable and unsuitable for use. + + Since there is no hardware workaround, reads of the affected CNT_CYCLES + counter return 0 in the relevant paths. This causes users of the counter + to treat it as unavailable and is functionally equivalent to firmware + disabling the affected counter. + + If unsure, say Y. + config ARM64_WORKAROUND_SPECULATIVE_UNPRIV_LOAD bool diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index feff0d13f052..ca26460bde65 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -307,7 +307,7 @@ struct kvm_arch { * Stage 2 paging state for VMs with nested S2 using a virtual * VMID. */ - struct kvm_s2_mmu *nested_mmus; + struct kvm_s2_mmu **nested_mmus; size_t nested_mmus_size; int nested_mmus_next; diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h index b9d86614994d..dda7fffe0bd9 100644 --- a/arch/arm64/include/asm/kvm_nested.h +++ b/arch/arm64/include/asm/kvm_nested.h @@ -65,7 +65,8 @@ static inline u64 translate_ttbr0_el2_to_ttbr0_el1(u64 ttbr0) extern bool forward_smc_trap(struct kvm_vcpu *vcpu); extern bool forward_debug_exception(struct kvm_vcpu *vcpu); -extern void kvm_init_nested(struct kvm *kvm); +extern int kvm_init_nested(struct kvm *kvm); +extern void kvm_destroy_nested(struct kvm *kvm); extern int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu); extern void kvm_init_nested_s2_mmu(struct kvm_s2_mmu *mmu); extern struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu); diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 1a7425375d0e..516a1e37a51f 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -353,6 +353,20 @@ static const struct arm64_cpu_capabilities arm64_repeat_tlbi_list[] = { }; #endif +#ifdef CONFIG_ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT +static const struct midr_range workaround_amu_constcnt_list[] = { +#ifdef CONFIG_ARM64_ERRATUM_2457168 + /* Cortex-A510 r0p0-r1p1 */ + MIDR_RANGE(MIDR_CORTEX_A510, 0, 0, 1, 1), +#endif +#ifdef CONFIG_ARM64_ERRATUM_3821522 + /* Cortex-A725 r0p0 - r0p2 */ + MIDR_RANGE(MIDR_CORTEX_A725, 0, 0, 0, 2), +#endif + {} +}; +#endif /* CONFIG_ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT */ + #ifdef CONFIG_CAVIUM_ERRATUM_23154 static const struct midr_range cavium_erratum_23154_cpus[] = { MIDR_ALL_VERSIONS(MIDR_THUNDERX), @@ -869,14 +883,12 @@ const struct arm64_cpu_capabilities arm64_errata[] = { ERRATA_MIDR_REV_RANGE(MIDR_CORTEX_A510, 0, 0, 2) }, #endif -#ifdef CONFIG_ARM64_ERRATUM_2457168 +#ifdef CONFIG_ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT { - .desc = "ARM erratum 2457168", - .capability = ARM64_WORKAROUND_2457168, + .desc = "Broken AMU AMEVCNTR01 (const counter)", + .capability = ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT, .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE, - - /* Cortex-A510 r0p0-r1p1 */ - CAP_MIDR_RANGE(MIDR_CORTEX_A510, 0, 0, 1, 1) + CAP_MIDR_RANGE_LIST(workaround_amu_constcnt_list) }, #endif #ifdef CONFIG_ARM64_ERRATUM_2038923 diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 39a798f74778..bb73d05318a9 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -2054,7 +2054,7 @@ static void cpu_amu_enable(struct arm64_cpu_capabilities const *cap) cpumask_set_cpu(smp_processor_id(), &amu_cpus); /* 0 reference values signal broken/disabled counters */ - if (!this_cpu_has_cap(ARM64_WORKAROUND_2457168)) + if (!this_cpu_has_cap(ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT)) update_freq_counters_refs(); } } diff --git a/arch/arm64/kernel/signal.c b/arch/arm64/kernel/signal.c index 38e6fa204c17..6a06a4e352b1 100644 --- a/arch/arm64/kernel/signal.c +++ b/arch/arm64/kernel/signal.c @@ -433,6 +433,7 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user) unsigned int vl, vq; struct user_fpsimd_state fpsimd; u16 user_vl, flags; + bool fpsimd_only; bool sm; if (user->sve_size < sizeof(*user->sve)) @@ -443,19 +444,33 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user) if (err) return err; + fpsimd_only = (user->sve_size == sizeof(*user->sve)); sm = flags & SVE_SIG_FLAG_SM; + if (sm) { if (!system_supports_sme()) return -EINVAL; + /* + * Streaming SVE state is always preserved with an SVE payload. + * Only accept streaming state which has an SVE payload. + */ + if (fpsimd_only) + return -EINVAL; + vl = task_get_sme_vl(current); } else { /* - * A SME only system use SVE for streaming mode so can - * have a SVE formatted context with a zero VL and no - * payload data. + * Non-streaming SVE state may be preserved without an SVE + * payload, in which case all state is saved in the FPSIMD + * context. + * + * On SME-only systems, non-streaming (FPSIMD-only) state is + * always preserved without an SVE payload, and with VL==0. On + * such systems, only accept non-streaming state without an SVE + * payload. */ - if (!system_supports_sve() && !system_supports_sme()) + if (!system_supports_sve() && !fpsimd_only) return -EINVAL; vl = task_get_sve_vl(current); @@ -464,16 +479,7 @@ static int restore_sve_fpsimd_context(struct user_ctxs *user) if (user_vl != vl) return -EINVAL; - /* - * Non-streaming SVE state may be preserved without an SVE payload, in - * which case the SVE context only has a header with VL==0, and all - * state can be restored from the FPSIMD context. - * - * Streaming SVE state is always preserved with an SVE payload. For - * consistency and robustness, reject restoring streaming SVE state - * without an SVE payload. - */ - if (!sm && user->sve_size == sizeof(*user->sve)) + if (fpsimd_only) return restore_fpsimd_context(user); vq = sve_vq_from_vl(vl); diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 5d07ee85bdae..202f677e2b0f 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -287,7 +287,6 @@ int arch_freq_get_on_cpu(int cpu) struct amu_cntr_sample *amu_sample; unsigned int start_cpu = cpu; unsigned long last_update; - unsigned int freq = 0; u64 scale; if (!amu_fie_cpu_supported(cpu) || !arch_scale_freq_ref(cpu)) @@ -346,9 +345,8 @@ int arch_freq_get_on_cpu(int cpu) * (see amu_scale_freq_tick for details) */ scale = arch_scale_freq_capacity(cpu); - freq = scale * arch_scale_freq_ref(cpu); - freq >>= SCHED_CAPACITY_SHIFT; - return freq; + + return (scale * arch_scale_freq_ref(cpu)) >> SCHED_CAPACITY_SHIFT; } static void amu_fie_setup(const struct cpumask *cpus) @@ -428,12 +426,13 @@ static void cpu_read_corecnt(void *val) static void cpu_read_constcnt(void *val) { /* - * Return 0 if the current CPU is affected by erratum 2457168. A value - * of 0 is also returned if the current CPU does not support AMUs or if - * the counter is disabled. A return value of 0 at counter read is - * properly handled as an error case by the users of the counter. + * Return 0 if the current CPU is affected by a HW erratum. + * A value of 0 is also returned if the current CPU does not + * support AMUs or if the counter is disabled. A return + * value of 0 at counter read is properly handled as an error + * case by the users of the counter. */ - *(u64 *)val = this_cpu_has_cap(ARM64_WORKAROUND_2457168) ? + *(u64 *)val = this_cpu_has_cap(ARM64_WORKAROUND_BROKEN_AMU_CONSTCNT) ? 0UL : read_constcnt(); } diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile index 7dec05dd33b7..f6619e1cb2ce 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile @@ -41,7 +41,7 @@ CC_FLAGS_REMOVE_VDSO := $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS) \ $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) \ -Wmissing-prototypes -Wmissing-declarations -CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables +CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables $(CONFIG_CC_OPT_INLINE_MEMSET) CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO) CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 52549bebb782..b52c162cb380 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -176,8 +176,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) mutex_unlock(&kvm->lock); #endif - kvm_init_nested(kvm); - ret = kvm_share_hyp(kvm, kvm + 1); if (ret) return ret; @@ -192,6 +190,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) if (ret) goto err_free_cpumask; + ret = kvm_init_nested(kvm); + if (ret) + goto err_uninit_mmu; + if (is_protected_kvm_enabled()) { /* * If any failures occur after this is successful, make sure to @@ -199,7 +201,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) */ ret = pkvm_init_host_vm(kvm); if (ret) - goto err_free_cpumask; + goto err_uninit_mmu; } kvm_vgic_early_init(kvm); @@ -215,6 +217,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) return 0; +err_uninit_mmu: + kvm_uninit_stage2_mmu(kvm); + kvm_destroy_nested(kvm); err_free_cpumask: free_cpumask_var(kvm->arch.supported_cpus); err_unshare_kvm: @@ -271,6 +276,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm) kvm_unshare_hyp(kvm, kvm + 1); + kvm_destroy_nested(kvm); kvm_arm_teardown_hypercalls(kvm); } diff --git a/arch/arm64/kvm/emulate-nested.c b/arch/arm64/kvm/emulate-nested.c index fbb37edfbaba..60812caaa080 100644 --- a/arch/arm64/kvm/emulate-nested.c +++ b/arch/arm64/kvm/emulate-nested.c @@ -2269,9 +2269,6 @@ int __init populate_nv_trap_config(void) kvm_info("nv: %ld coarse grained trap handlers\n", ARRAY_SIZE(encoding_to_cgt)); - if (!cpus_have_final_cap(ARM64_HAS_FGT)) - goto check_mcb; - for (int i = 0; i < ARRAY_SIZE(encoding_to_fgt); i++) { const struct encoding_to_trap_config *fgt = &encoding_to_fgt[i]; union trap_config tc; @@ -2291,6 +2288,12 @@ int __init populate_nv_trap_config(void) } tc.val |= fgt->tc.val; + + if (!aggregate_fgt(tc)) { + ret = -EINVAL; + print_nv_trap_error(fgt, "FGT bit is reserved", ret); + } + prev = xa_store(&sr_forward_xa, enc, xa_mk_value(tc.val), GFP_KERNEL); @@ -2298,11 +2301,6 @@ int __init populate_nv_trap_config(void) ret = xa_err(prev); print_nv_trap_error(fgt, "Failed FGT insertion", ret); } - - if (!aggregate_fgt(tc)) { - ret = -EINVAL; - print_nv_trap_error(fgt, "FGT bit is reserved", ret); - } } } @@ -2318,7 +2316,6 @@ int __init populate_nv_trap_config(void) kvm_info("nv: %ld fine grained trap handlers\n", ARRAY_SIZE(encoding_to_fgt)); -check_mcb: for (int id = __MULTIPLE_CONTROL_BITS__; id < __COMPLEX_CONDITIONS__; id++) { const enum cgt_group_id *cgids; diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c index 6eade6babbbd..bf0250806a78 100644 --- a/arch/arm64/kvm/hyp/nvhe/pkvm.c +++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c @@ -52,6 +52,15 @@ static void pkvm_vcpu_reset_hcr(struct kvm_vcpu *vcpu) else vcpu->arch.hcr_el2 |= HCR_TID2; + /* + * Without AArch32 EL1, leave RW set and let the entry fail with an + * illegal exception return: the *32_EL2 registers EL2 would otherwise + * switch are UNDEFINED there. + */ + if (vcpu_has_feature(vcpu, KVM_ARM_VCPU_EL1_32BIT) && + cpus_have_final_cap(ARM64_HAS_32BIT_EL1)) + vcpu->arch.hcr_el2 &= ~HCR_EL2_RW; + if (vcpu_has_ptrauth(vcpu)) vcpu->arch.hcr_el2 |= (HCR_API | HCR_APK); diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 2dae3fcb7a7f..af50fed5b597 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -1406,32 +1406,11 @@ transparent_hugepage_adjust(struct kvm *kvm, struct kvm_memory_slot *memslot, return PAGE_SIZE; } -static int get_vma_page_shift(struct vm_area_struct *vma, unsigned long hva) +static int get_vma_page_shift(struct vm_area_struct *vma) { - unsigned long pa; - - if (is_vm_hugetlb_page(vma) && !(vma->vm_flags & VM_PFNMAP)) + if (is_vm_hugetlb_page(vma)) return huge_page_shift(hstate_vma(vma)); - if (!(vma->vm_flags & VM_PFNMAP)) - return PAGE_SHIFT; - - VM_BUG_ON(is_vm_hugetlb_page(vma)); - - pa = (vma->vm_pgoff << PAGE_SHIFT) + (hva - vma->vm_start); - -#ifndef __PAGETABLE_PMD_FOLDED - if ((hva & (PUD_SIZE - 1)) == (pa & (PUD_SIZE - 1)) && - ALIGN_DOWN(hva, PUD_SIZE) >= vma->vm_start && - ALIGN(hva, PUD_SIZE) <= vma->vm_end) - return PUD_SHIFT; -#endif - - if ((hva & (PMD_SIZE - 1)) == (pa & (PMD_SIZE - 1)) && - ALIGN_DOWN(hva, PMD_SIZE) >= vma->vm_start && - ALIGN(hva, PMD_SIZE) <= vma->vm_end) - return PMD_SHIFT; - return PAGE_SHIFT; } @@ -1655,10 +1634,6 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (ret) return ret; - /* - * Let's check if we will get back a huge page backed by hugetlbfs, or - * get block mapping for device MMIO region. - */ mmap_read_lock(current->mm); vma = vma_lookup(current->mm, hva); if (unlikely(!vma)) { @@ -1670,7 +1645,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (force_pte) vma_shift = PAGE_SHIFT; else - vma_shift = get_vma_page_shift(vma, hva); + vma_shift = get_vma_page_shift(vma); switch (vma_shift) { #ifndef __PAGETABLE_PMD_FOLDED @@ -1786,16 +1761,6 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, if (!kvm_supports_cacheable_pfnmap()) ret = -EFAULT; } else { - /* - * If the page was identified as device early by looking at - * the VMA flags, vma_pagesize is already representing the - * largest quantity we can map. If instead it was mapped - * via __kvm_faultin_pfn(), vma_pagesize is set to PAGE_SIZE - * and must not be upgraded. - * - * In both cases, we don't let transparent_hugepage_adjust() - * change things at the last minute. - */ s2_force_noncacheable = true; } } else if (logging_active && !write_fault) { @@ -1826,9 +1791,10 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, /* * If we are not forced to use page mapping, check if we are - * backed by a THP and thus use block mapping if possible. + * backed by a huge stage-1 mapping and thus use block mapping if + * possible. */ - if (vma_pagesize == PAGE_SIZE && !(force_pte || s2_force_noncacheable)) { + if (vma_pagesize == PAGE_SIZE && !force_pte) { if (fault_is_perm && fault_granule > PAGE_SIZE) vma_pagesize = fault_granule; else diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c index 9be5346140ce..3184fff22442 100644 --- a/arch/arm64/kvm/nested.c +++ b/arch/arm64/kvm/nested.c @@ -44,10 +44,23 @@ struct vncr_tlb { */ #define S2_MMU_PER_VCPU 2 -void kvm_init_nested(struct kvm *kvm) +int kvm_init_nested(struct kvm *kvm) { - kvm->arch.nested_mmus = NULL; + kvm->arch.nested_mmus = kvmalloc_objs(struct kvm_s2_mmu *, + KVM_MAX_VCPUS * S2_MMU_PER_VCPU, + GFP_KERNEL_ACCOUNT); kvm->arch.nested_mmus_size = 0; + + return kvm->arch.nested_mmus ? 0 : -ENOMEM; +} + +void kvm_destroy_nested(struct kvm *kvm) +{ + for (int i = 0; i < kvm->arch.nested_mmus_size; i+= S2_MMU_PER_VCPU) + kvfree(kvm->arch.nested_mmus[i]); + + kvm->arch.nested_mmus_size = 0; + kvfree(kvm->arch.nested_mmus); } static int init_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu) @@ -68,8 +81,9 @@ static int init_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu) int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu) { struct kvm *kvm = vcpu->kvm; - struct kvm_s2_mmu *tmp; - int num_mmus, ret = 0; + int num_mmus; + + lockdep_assert_held(&kvm->arch.config_lock); if (test_bit(KVM_ARM_VCPU_HAS_EL2_E2H0, kvm->arch.vcpu_features) && !cpus_have_final_cap(ARM64_HAS_HCR_NV1)) @@ -82,51 +96,40 @@ int kvm_vcpu_init_nested(struct kvm_vcpu *vcpu) if (!vcpu->arch.ctxt.vncr_array) return -ENOMEM; - /* - * Let's treat memory allocation failures as benign: If we fail to - * allocate anything, return an error and keep the allocated array - * alive. Userspace may try to recover by intializing the vcpu - * again, and there is no reason to affect the whole VM for this. - */ num_mmus = atomic_read(&kvm->online_vcpus) * S2_MMU_PER_VCPU; if (num_mmus > kvm->arch.nested_mmus_size) { - tmp = kvcalloc(num_mmus, sizeof(*tmp), GFP_KERNEL_ACCOUNT); - if (!tmp) - return -ENOMEM; - - write_lock(&kvm->mmu_lock); + struct kvm_s2_mmu *tmp; + int i, ret = 0; - if (kvm->arch.nested_mmus_size) { - memcpy(tmp, kvm->arch.nested_mmus, - size_mul(sizeof(*tmp), kvm->arch.nested_mmus_size)); + tmp = kvzalloc_objs(*tmp, S2_MMU_PER_VCPU, GFP_KERNEL_ACCOUNT); + if (!tmp) + ret = -ENOMEM; - for (int i = 0; i < kvm->arch.nested_mmus_size; i++) - tmp[i].pgt->mmu = &tmp[i]; + for (i = 0; !ret && i < S2_MMU_PER_VCPU; i++) { + ret = init_nested_s2_mmu(kvm, &tmp[i]); + if (ret) + break; } - swap(kvm->arch.nested_mmus, tmp); - - write_unlock(&kvm->mmu_lock); - - kvfree(tmp); - } + if (ret) { + while (--i >= 0) + kvm_free_stage2_pgd(&tmp[i]); - for (int i = kvm->arch.nested_mmus_size; !ret && i < num_mmus; i++) - ret = init_nested_s2_mmu(kvm, &kvm->arch.nested_mmus[i]); + kvfree(tmp); + free_page((unsigned long)vcpu->arch.ctxt.vncr_array); + vcpu->arch.ctxt.vncr_array = NULL; + return ret; + } - if (ret) { - for (int i = kvm->arch.nested_mmus_size; i < num_mmus; i++) - kvm_free_stage2_pgd(&kvm->arch.nested_mmus[i]); + guard(write_lock)(&kvm->mmu_lock); - free_page((unsigned long)vcpu->arch.ctxt.vncr_array); - vcpu->arch.ctxt.vncr_array = NULL; + for (i = 0; i < S2_MMU_PER_VCPU; i++) + kvm->arch.nested_mmus[i + kvm->arch.nested_mmus_size] = &tmp[i]; - return ret; + kvm->arch.nested_mmus_size += S2_MMU_PER_VCPU; } - kvm->arch.nested_mmus_size = num_mmus; - return 0; } @@ -620,7 +623,7 @@ void kvm_s2_mmu_iterate_by_vmid(struct kvm *kvm, u16 vmid, write_lock(&kvm->mmu_lock); for (int i = 0; i < kvm->arch.nested_mmus_size; i++) { - struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; if (!kvm_s2_mmu_valid(mmu)) continue; @@ -662,7 +665,7 @@ struct kvm_s2_mmu *lookup_s2_mmu(struct kvm_vcpu *vcpu) * if S2 translation is disabled. */ for (int i = 0; i < kvm->arch.nested_mmus_size; i++) { - struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; if (!kvm_s2_mmu_valid(mmu)) continue; @@ -701,7 +704,7 @@ static struct kvm_s2_mmu *get_s2_mmu_nested(struct kvm_vcpu *vcpu) for (i = kvm->arch.nested_mmus_next; i < (kvm->arch.nested_mmus_size + kvm->arch.nested_mmus_next); i++) { - s2_mmu = &kvm->arch.nested_mmus[i % kvm->arch.nested_mmus_size]; + s2_mmu = kvm->arch.nested_mmus[i % kvm->arch.nested_mmus_size]; if (atomic_read(&s2_mmu->refcnt) == 0) break; @@ -1147,7 +1150,7 @@ void kvm_nested_s2_wp(struct kvm *kvm) lockdep_assert_held_write(&kvm->mmu_lock); for (i = 0; i < kvm->arch.nested_mmus_size; i++) { - struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; if (kvm_s2_mmu_valid(mmu)) kvm_stage2_wp_range(mmu, 0, kvm_phys_size(mmu)); @@ -1163,7 +1166,7 @@ void kvm_nested_s2_unmap(struct kvm *kvm, bool may_block) lockdep_assert_held_write(&kvm->mmu_lock); for (i = 0; i < kvm->arch.nested_mmus_size; i++) { - struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; if (kvm_s2_mmu_valid(mmu)) kvm_stage2_unmap_range(mmu, 0, kvm_phys_size(mmu), may_block); @@ -1179,7 +1182,7 @@ void kvm_nested_s2_flush(struct kvm *kvm) lockdep_assert_held_write(&kvm->mmu_lock); for (i = 0; i < kvm->arch.nested_mmus_size; i++) { - struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; if (kvm_s2_mmu_valid(mmu)) kvm_stage2_flush_range(mmu, 0, kvm_phys_size(mmu)); @@ -1188,17 +1191,12 @@ void kvm_nested_s2_flush(struct kvm *kvm) void kvm_arch_flush_shadow_all(struct kvm *kvm) { - int i; - - for (i = 0; i < kvm->arch.nested_mmus_size; i++) { - struct kvm_s2_mmu *mmu = &kvm->arch.nested_mmus[i]; + for (int i = 0; i < kvm->arch.nested_mmus_size; i++) { + struct kvm_s2_mmu *mmu = kvm->arch.nested_mmus[i]; if (!WARN_ON(atomic_read(&mmu->refcnt))) kvm_free_stage2_pgd(mmu); } - kvfree(kvm->arch.nested_mmus); - kvm->arch.nested_mmus = NULL; - kvm->arch.nested_mmus_size = 0; kvm_uninit_stage2_mmu(kvm); } diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index 763fa5dff167..e3c182352ffc 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -310,12 +310,16 @@ static int update_lpi_config(struct kvm *kvm, struct vgic_irq *irq, return ret; } -static int update_affinity(struct vgic_irq *irq, struct kvm_vcpu *vcpu) +static int update_affinity(struct vgic_irq *irq, + struct kvm_vcpu *from_vcpu, struct kvm_vcpu *vcpu) { struct its_vlpi_map map; int ret; guard(raw_spinlock_irqsave)(&irq->irq_lock); + if (from_vcpu && irq->target_vcpu != from_vcpu) + return 0; + irq->target_vcpu = vcpu; if (!irq->hw) @@ -353,7 +357,7 @@ static void update_affinity_ite(struct kvm *kvm, struct its_ite *ite) return; vcpu = collection_to_vcpu(kvm, ite->collection); - update_affinity(ite->irq, vcpu); + update_affinity(ite->irq, NULL, vcpu); } /* @@ -846,7 +850,7 @@ static int vgic_its_cmd_handle_movi(struct kvm *kvm, struct vgic_its *its, vgic_its_invalidate_cache(its); - return update_affinity(ite->irq, vcpu); + return update_affinity(ite->irq, NULL, vcpu); } static bool __is_visible_gfn_locked(struct vgic_its *its, gpa_t gpa) @@ -1373,7 +1377,7 @@ static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its, if (!irq) continue; - update_affinity(irq, vcpu2); + update_affinity(irq, vcpu1, vcpu2); vgic_put_irq(kvm, irq); } diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index a4503910afb8..71841b5c3192 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -2150,7 +2150,7 @@ pte_t modify_prot_start_ptes(struct vm_area_struct *vma, unsigned long addr, * in cases where cpu is affected with errata #2645198. */ if (pte_accessible(vma->vm_mm, pte) && pte_user_exec(pte)) - __flush_tlb_range(vma, addr, nr * PAGE_SIZE, + __flush_tlb_range(vma, addr, addr + nr * PAGE_SIZE, PAGE_SIZE, true, 3); } diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps index 16d123088ddd..3e2c5c1914d8 100644 --- a/arch/arm64/tools/cpucaps +++ b/arch/arm64/tools/cpucaps @@ -98,7 +98,6 @@ WORKAROUND_1902691 WORKAROUND_2038923 WORKAROUND_2064142 WORKAROUND_2077057 -WORKAROUND_2457168 WORKAROUND_2645198 WORKAROUND_2658417 WORKAROUND_4193714 @@ -122,3 +121,4 @@ WORKAROUND_REPEAT_TLBI WORKAROUND_SPECULATIVE_AT WORKAROUND_SPECULATIVE_SSBS WORKAROUND_SPECULATIVE_UNPRIV_LOAD +WORKAROUND_BROKEN_AMU_CONSTCNT diff --git a/arch/loongarch/vdso/Makefile b/arch/loongarch/vdso/Makefile index f4d076ce1843..5db5a650ed44 100644 --- a/arch/loongarch/vdso/Makefile +++ b/arch/loongarch/vdso/Makefile @@ -13,6 +13,7 @@ ccflags-vdso := \ $(filter -E%,$(KBUILD_CFLAGS)) \ $(filter -march=%,$(KBUILD_CFLAGS)) \ $(filter -m%-float,$(KBUILD_CFLAGS)) \ + $(CONFIG_CC_OPT_INLINE_MEMSET) \ $(CLANG_FLAGS) \ -D__VDSO__ diff --git a/arch/powerpc/kernel/vdso/Makefile b/arch/powerpc/kernel/vdso/Makefile index 8834dfe9d727..4d465d2024d9 100644 --- a/arch/powerpc/kernel/vdso/Makefile +++ b/arch/powerpc/kernel/vdso/Makefile @@ -43,6 +43,7 @@ ccflags-y := -fno-common -fno-builtin -DBUILD_VDSO ccflags-y += $(DISABLE_LATENT_ENTROPY_PLUGIN) ccflags-y += $(call cc-option, -fno-stack-protector) ccflags-y += -DDISABLE_BRANCH_PROFILING +ccflags-y += $(CONFIG_CC_OPT_INLINE_MEMSET) ccflags-y += -ffreestanding -fasynchronous-unwind-tables ccflags-remove-y := $(CC_FLAGS_FTRACE) ldflags-y := -Wl,--hash-style=both -nostdlib -shared -z noexecstack $(CLANG_FLAGS) diff --git a/arch/powerpc/perf/imc-pmu.c b/arch/powerpc/perf/imc-pmu.c index 8664a7d297ad..1e6de9b4e757 100644 --- a/arch/powerpc/perf/imc-pmu.c +++ b/arch/powerpc/perf/imc-pmu.c @@ -1280,6 +1280,8 @@ static int trace_imc_prepare_sample(struct trace_imc_data *mem, struct perf_event_header *header, struct perf_event *event) { + u16 misc = 0; + /* Sanity checks for a valid record */ if (be64_to_cpu(READ_ONCE(mem->tb1)) > *prev_tb) *prev_tb = be64_to_cpu(READ_ONCE(mem->tb1)); @@ -1294,23 +1296,19 @@ static int trace_imc_prepare_sample(struct trace_imc_data *mem, data->ip = be64_to_cpu(READ_ONCE(mem->ip)); data->period = event->hw.last_period; - header->type = PERF_RECORD_SAMPLE; - header->size = sizeof(*header) + event->header_size; - header->misc = 0; - if (cpu_has_feature(CPU_FTR_ARCH_31)) { switch (IMC_TRACE_RECORD_VAL_HVPR(be64_to_cpu(READ_ONCE(mem->val)))) { case 0:/* when MSR HV and PR not set in the trace-record */ - header->misc |= PERF_RECORD_MISC_GUEST_KERNEL; + misc |= PERF_RECORD_MISC_GUEST_KERNEL; break; case 1: /* MSR HV is 0 and PR is 1 */ - header->misc |= PERF_RECORD_MISC_GUEST_USER; + misc |= PERF_RECORD_MISC_GUEST_USER; break; case 2: /* MSR HV is 1 and PR is 0 */ - header->misc |= PERF_RECORD_MISC_KERNEL; + misc |= PERF_RECORD_MISC_KERNEL; break; case 3: /* MSR HV is 1 and PR is 1 */ - header->misc |= PERF_RECORD_MISC_USER; + misc |= PERF_RECORD_MISC_USER; break; default: pr_info("IMC: Unable to set the flag based on MSR bits\n"); @@ -1318,11 +1316,14 @@ static int trace_imc_prepare_sample(struct trace_imc_data *mem, } } else { if (is_kernel_addr(data->ip)) - header->misc |= PERF_RECORD_MISC_KERNEL; + misc |= PERF_RECORD_MISC_KERNEL; else - header->misc |= PERF_RECORD_MISC_USER; + misc |= PERF_RECORD_MISC_USER; } - perf_event_header__init_id(header, data, event); + perf_event_header__init(header, data, + PERF_RECORD_SAMPLE, misc, + sizeof(*header) + event->header_size, + event); return 0; } diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile index 340bbd945591..e67d9bae96de 100644 --- a/arch/riscv/kernel/vdso/Makefile +++ b/arch/riscv/kernel/vdso/Makefile @@ -27,6 +27,7 @@ endif ccflags-y := -fno-stack-protector ccflags-y += -DDISABLE_BRANCH_PROFILING ccflags-y += -fno-builtin +ccflags-y += $(CONFIG_CC_OPT_INLINE_MEMSET) ifneq ($(c-gettimeofday-y),) CFLAGS_vgettimeofday.o += -fPIC -include $(c-gettimeofday-y) diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c index a357ea73516f..b4fee9840217 100644 --- a/arch/riscv/kvm/aia_imsic.c +++ b/arch/riscv/kvm/aia_imsic.c @@ -1002,8 +1002,11 @@ int kvm_riscv_aia_imsic_has_attr(struct kvm *kvm, unsigned long type) if (!vcpu) return -ENODEV; - isel = KVM_DEV_RISCV_AIA_IMSIC_GET_ISEL(type); imsic = vcpu->arch.aia_context.imsic_state; + if (!imsic) + return -ENODEV; + + isel = KVM_DEV_RISCV_AIA_IMSIC_GET_ISEL(type); return imsic_mrif_isel_check(imsic->nr_eix, isel); } diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile index d8f0df742809..b6b6d1d62c61 100644 --- a/arch/s390/kernel/vdso64/Makefile +++ b/arch/s390/kernel/vdso64/Makefile @@ -32,6 +32,7 @@ KBUILD_CFLAGS_64 := $(filter-out -mno-pic-data-is-text-relative,$(KBUILD_CFLAGS_ KBUILD_CFLAGS_64 := $(filter-out -munaligned-symbols,$(KBUILD_CFLAGS_64)) KBUILD_CFLAGS_64 := $(filter-out -fno-asynchronous-unwind-tables,$(KBUILD_CFLAGS_64)) KBUILD_CFLAGS_64 += -m64 -fPIC -fno-common -fno-builtin -fasynchronous-unwind-tables +KBUILD_CFLAGS_64 += $(CONFIG_CC_OPT_INLINE_MEMSET) ldflags-y := -shared -soname=linux-vdso64.so.1 \ --hash-style=both --build-id=sha1 -T diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c index d953ac470aae..129de9c29e28 100644 --- a/arch/x86/crypto/aesni-intel_glue.c +++ b/arch/x86/crypto/aesni-intel_glue.c @@ -1286,6 +1286,7 @@ static void gcm_process_assoc(const struct aes_gcm_key *key, u8 ghash_acc[16], unsigned int len; const u8 *src = walk.addr; + assoclen -= orig_len_this_step; if (unlikely(pos)) { len = min(len_this_step, 16 - pos); memcpy(&buf[pos], src, len); @@ -1313,7 +1314,6 @@ static void gcm_process_assoc(const struct aes_gcm_key *key, u8 ghash_acc[16], kernel_fpu_end(); kernel_fpu_begin(); } - assoclen -= orig_len_this_step; } if (unlikely(pos)) aes_gcm_aad_update(key, ghash_acc, buf, pos, flags); diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile index f247f5f5cb44..5836d77aa974 100644 --- a/arch/x86/entry/vdso/Makefile +++ b/arch/x86/entry/vdso/Makefile @@ -54,6 +54,7 @@ $(obj)/vdso-image-%.c: $(obj)/vdso%.so.dbg $(obj)/vdso%.so $(obj)/vdso2c FORCE CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \ $(filter -g%,$(KBUILD_CFLAGS)) -fno-stack-protector \ -fno-omit-frame-pointer -foptimize-sibling-calls \ + $(CONFIG_CC_OPT_INLINE_MEMSET) \ -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO ifdef CONFIG_MITIGATION_RETPOLINE diff --git a/arch/x86/include/asm/kvm-x86-nested-ops.h b/arch/x86/include/asm/kvm-x86-nested-ops.h new file mode 100644 index 000000000000..66360aa440c4 --- /dev/null +++ b/arch/x86/include/asm/kvm-x86-nested-ops.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#if !defined(KVM_X86_NESTED_OP) || \ + !defined(KVM_X86_NESTED_OP_OPTIONAL) || \ + !defined(KVM_X86_NESTED_OP_OPTIONAL_RET0) +#error Missing one or more KVM_X86_NESTED_OP #defines +#else +/* + * KVM_X86_NESTED_OP() and KVM_X86_NESTED_OP_OPTIONAL() are used to help + * generate both DECLARE/DEFINE_STATIC_CALL() invocations and + * "static_call_update()" calls. + * + * KVM_X86_NESTED_OP_OPTIONAL() can be used for those functions that can have + * a NULL definition. KVM_X86_NESTED_OP_OPTIONAL_RET0() can be used likewise + * to make a definition optional, but in this case the default will + * be __static_call_return0. + */ +KVM_X86_NESTED_OP(leave_nested) +KVM_X86_NESTED_OP(is_exception_vmexit) +KVM_X86_NESTED_OP(check_events) +KVM_X86_NESTED_OP_OPTIONAL_RET0(has_events) +KVM_X86_NESTED_OP(triple_fault) +KVM_X86_NESTED_OP(get_state) +KVM_X86_NESTED_OP(set_state) +KVM_X86_NESTED_OP(get_nested_state_pages) +KVM_X86_NESTED_OP_OPTIONAL_RET0(write_log_dirty) +#ifdef CONFIG_KVM_HYPERV +KVM_X86_NESTED_OP_OPTIONAL(enable_evmcs) +KVM_X86_NESTED_OP_OPTIONAL_RET0(get_evmcs_version) +KVM_X86_NESTED_OP(hv_inject_synthetic_vmexit_post_tlb_flush) +#endif +#endif + +#undef KVM_X86_NESTED_OP +#undef KVM_X86_NESTED_OP_OPTIONAL +#undef KVM_X86_NESTED_OP_OPTIONAL_RET0 diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 03866683ac33..b2cf3431e259 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1954,6 +1954,8 @@ struct kvm_x86_ops { }; struct kvm_x86_nested_ops { + bool enabled; + void (*leave_nested)(struct kvm_vcpu *vcpu); bool (*is_exception_vmexit)(struct kvm_vcpu *vcpu, u8 vector, u32 error_code); @@ -2007,6 +2009,14 @@ extern struct kvm_x86_ops kvm_x86_ops; #define KVM_X86_OP_OPTIONAL_RET0 KVM_X86_OP #include +#define kvm_nested_call(func) static_call(kvm_x86_nested_##func) + +#define KVM_X86_NESTED_OP(func) \ + DECLARE_STATIC_CALL(kvm_x86_nested_##func, *(((struct kvm_x86_nested_ops *)0)->func)); +#define KVM_X86_NESTED_OP_OPTIONAL KVM_X86_NESTED_OP +#define KVM_X86_NESTED_OP_OPTIONAL_RET0 KVM_X86_NESTED_OP +#include + int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops); void kvm_x86_vendor_exit(void); @@ -2350,13 +2360,6 @@ static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code) kvm_queue_exception_e(vcpu, GP_VECTOR, error_code); } -#define TSS_IOPB_BASE_OFFSET 0x66 -#define TSS_BASE_SIZE 0x68 -#define TSS_IOPB_SIZE (65536 / 8) -#define TSS_REDIRECTION_SIZE (256 / 8) -#define RMODE_TSS_SIZE \ - (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1) - enum { TASK_SWITCH_CALL = 0, TASK_SWITCH_IRET = 1, @@ -2379,12 +2382,7 @@ enum { # define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, 0) #endif -int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v); -int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); -int kvm_cpu_has_extint(struct kvm_vcpu *v); int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu); -int kvm_cpu_get_extint(struct kvm_vcpu *v); -int kvm_cpu_get_interrupt(struct kvm_vcpu *v); void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event); int kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap_low, diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 776ae6fa7f2d..4c078827f26a 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -50,9 +50,16 @@ static unsigned long get_align_mask(struct file *filp) * value before calling vm_unmapped_area() or ORed directly to the * address. */ -static unsigned long get_align_bits(void) +static unsigned long get_align_bits(struct file *filp) { - return va_align.bits & get_align_mask(NULL); + /* + * va_align.bits is smaller than the huge page size and will + * lead to misaligned huge pages. Ignore it for huge mappings. + */ + if (is_file_hugepages(filp)) + return 0; + + return va_align.bits & get_align_mask(filp); } static int __init control_va_addr_alignment(char *str) @@ -157,7 +164,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, } if (filp) { info.align_mask = get_align_mask(filp); - info.align_offset += get_align_bits(); + info.align_offset += get_align_bits(filp); } return vm_unmapped_area(&info); @@ -222,7 +229,7 @@ arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr0, if (filp) { info.align_mask = get_align_mask(filp); - info.align_offset += get_align_bits(); + info.align_offset += get_align_bits(filp); } addr = vm_unmapped_area(&info); if (!(addr & ~PAGE_MASK)) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 380a211f56f0..56325ba9ef36 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -2415,7 +2415,7 @@ static int kvm_hv_hypercall_complete(struct kvm_vcpu *vcpu, u64 result) ret = kvm_skip_emulated_instruction(vcpu); if (tlb_lock_count) - kvm_x86_ops.nested_ops->hv_inject_synthetic_vmexit_post_tlb_flush(vcpu); + kvm_nested_call(hv_inject_synthetic_vmexit_post_tlb_flush)(vcpu); return ret; } @@ -2799,8 +2799,8 @@ int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, }; int i, nent = ARRAY_SIZE(cpuid_entries); - if (kvm_x86_ops.nested_ops->get_evmcs_version) - evmcs_ver = kvm_x86_ops.nested_ops->get_evmcs_version(vcpu); + if (kvm_x86_ops.nested_ops->enabled) + evmcs_ver = kvm_nested_call(get_evmcs_version)(vcpu); if (cpuid->nent < nent) return -E2BIG; diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 34f4a78a7a01..1a84ea31e7fd 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h @@ -112,6 +112,12 @@ static inline int irqchip_in_kernel(struct kvm *kvm) return mode != KVM_IRQCHIP_NONE; } +int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v); +int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu); +int kvm_cpu_has_extint(struct kvm_vcpu *v); +int kvm_cpu_get_extint(struct kvm_vcpu *v); +int kvm_cpu_get_interrupt(struct kvm_vcpu *v); + void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index e6985e00cba0..66e18702e5a3 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -2479,6 +2479,12 @@ static void shadow_walk_init_using_root(struct kvm_shadow_walk_iterator *iterato { iterator->addr = addr; iterator->shadow_addr = root; + + if (WARN_ON_ONCE(!VALID_PAGE(root)) || kvm_mmu_is_dummy_root(root)) { + iterator->level = 0; + return; + } + iterator->level = vcpu->arch.mmu->root_role.level; if (iterator->level >= PT64_ROOT_4LEVEL && diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index af220c9c8ab8..6e2ce54a13b3 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -222,7 +222,7 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu, !(pte & PT_GUEST_DIRTY_MASK)) { trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte)); #if PTTYPE == PTTYPE_EPT - if (kvm_x86_ops.nested_ops->write_log_dirty(vcpu, addr)) + if (kvm_nested_call(write_log_dirty)(vcpu, addr)) return -EINVAL; #endif pte |= PT_GUEST_DIRTY_MASK; diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 66b8955a1658..df54df7ae201 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -23,6 +23,7 @@ #include "kvm_emulate.h" #include "trace.h" +#include "irq.h" #include "mmu.h" #include "x86.h" #include "smm.h" diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 3d2f0006a087..2b45481f3a9c 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -429,6 +429,20 @@ static void snp_guest_req_cleanup(struct kvm *kvm) sev->guest_resp_buf = NULL; } +static int sev_alloc_have_run_cpus(struct kvm_sev_info *sev) +{ + if (!zalloc_cpumask_var(&sev->have_run_cpus, GFP_KERNEL_ACCOUNT)) + return -ENOMEM; + + return 0; +} + +static void sev_free_have_run_cpus(struct kvm_sev_info *sev) +{ + free_cpumask_var(sev->have_run_cpus); + memset(&sev->have_run_cpus, 0, sizeof(sev->have_run_cpus)); +} + static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, struct kvm_sev_init *data, unsigned long vm_type) @@ -486,10 +500,9 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, if (ret) goto e_free_asid; - if (!zalloc_cpumask_var(&sev->have_run_cpus, GFP_KERNEL_ACCOUNT)) { - ret = -ENOMEM; + ret = sev_alloc_have_run_cpus(sev); + if (ret) goto e_free_asid; - } /* This needs to happen after SEV/SNP firmware initialization. */ if (snp_active) { @@ -507,7 +520,7 @@ static int __sev_guest_init(struct kvm *kvm, struct kvm_sev_cmd *argp, return 0; e_free: - free_cpumask_var(sev->have_run_cpus); + sev_free_have_run_cpus(sev); e_free_asid: argp->error = init_args.error; sev_asid_free(sev); @@ -1973,6 +1986,13 @@ static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm) struct kvm_sev_info *mirror; unsigned long i; + /* + * Do cache maintenance on the source VM *before* clearing "SEV active", + * as memory reclaim flows won't trigger cache maintenance on the VM + * once it's no longer an SEV VM. + */ + sev_writeback_caches(src_kvm); + dst->active = true; dst->asid = src->asid; dst->handle = src->handle; @@ -1986,12 +2006,6 @@ static void sev_migrate_from(struct kvm *dst_kvm, struct kvm *src_kvm) src->pages_locked = 0; src->es_active = false; - /* - * Do cache maintenance on the source VM as it is no longer an SEV VM, - * i.e. memory reclaim flows won't trigger cache maintenance on the VM. - */ - sev_writeback_caches(src_kvm); - list_cut_before(&dst->regions_list, &src->regions_list, &src->regions_list); mutex_lock(&sev_mirror_lock); @@ -2136,10 +2150,9 @@ int sev_vm_move_enc_context_from(struct kvm *kvm, unsigned int source_fd) * does not, i.e. KVM could skip flushes if memory is reclaimed from * the old VM but not the new VM. */ - if (!zalloc_cpumask_var(&dst_sev->have_run_cpus, GFP_KERNEL_ACCOUNT)) { - ret = -ENOMEM; + ret = sev_alloc_have_run_cpus(dst_sev); + if (ret) goto out_source_vcpu; - } sev_migrate_from(kvm, source_kvm); kvm_vm_dead(source_kvm); @@ -2860,10 +2873,9 @@ int sev_vm_copy_enc_context_from(struct kvm *kvm, unsigned int source_fd) } mirror_sev = to_kvm_sev_info(kvm); - if (!zalloc_cpumask_var(&mirror_sev->have_run_cpus, GFP_KERNEL_ACCOUNT)) { - ret = -ENOMEM; + ret = sev_alloc_have_run_cpus(mirror_sev); + if (ret) goto e_unlock; - } /* * The mirror kvm holds an enc_context_owner ref so its asid can't @@ -2934,7 +2946,7 @@ void sev_vm_destroy(struct kvm *kvm) * Free the mask even if the VM is not *currently* an SEV VM, as it may * have been an SEV VM prior to intra-host migration. */ - free_cpumask_var(sev->have_run_cpus); + sev_free_have_run_cpus(sev); if (!sev_guest(kvm)) return; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index a24a6871b693..ba7b0a67ad29 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -654,17 +654,7 @@ static void clr_dr_intercepts(struct vcpu_svm *svm) static bool msr_write_intercepted(struct kvm_vcpu *vcpu, u32 msr) { - /* - * For non-nested case: - * If the L01 MSR bitmap does not intercept the MSR, then we need to - * save it. - * - * For nested case: - * If the L02 MSR bitmap does not intercept the MSR, then we need to - * save it. - */ - void *msrpm = is_guest_mode(vcpu) ? to_svm(vcpu)->nested.msrpm : - to_svm(vcpu)->msrpm; + void *msrpm = __va(__sme_clr(to_svm(vcpu)->vmcb->control.msrpm_base_pa)); return svm_test_msr_bitmap_write(msrpm, msr); } @@ -5461,6 +5451,7 @@ static __init int svm_hardware_setup(void) if (r) return r; } + svm_nested_ops.enabled = nested; /* * KVM's MMU doesn't support using 2-level paging for itself, and thus diff --git a/arch/x86/kvm/tss.h b/arch/x86/kvm/tss.h index 3f9150125e70..117bf8bec07d 100644 --- a/arch/x86/kvm/tss.h +++ b/arch/x86/kvm/tss.h @@ -57,4 +57,11 @@ struct tss_segment_16 { u16 ldt; }; +#define TSS_IOPB_BASE_OFFSET 0x66 +#define TSS_BASE_SIZE 0x68 +#define TSS_IOPB_SIZE (65536 / 8) +#define TSS_REDIRECTION_SIZE (256 / 8) +#define RMODE_TSS_SIZE \ + (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1) + #endif diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index bc5aa7456aac..97ef2ebc2477 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -11,6 +11,7 @@ #include "x86.h" #include "cpuid.h" #include "hyperv.h" +#include "irq.h" #include "mmu.h" #include "nested.h" #include "pmu.h" @@ -1700,6 +1701,9 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx) static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields) { #ifdef CONFIG_KVM_HYPERV + const u64 runtime_controls = HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP1 | + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_GRP2 | + HV_VMX_ENLIGHTENED_CLEAN_FIELD_CONTROL_PROC; struct vmcs12 *vmcs12 = vmx->nested.cached_vmcs12; struct hv_enlightened_vmcs *evmcs = nested_vmx_evmcs(vmx); struct kvm_vcpu_hv *hv_vcpu = to_hv_vcpu(&vmx->vcpu); @@ -1708,6 +1712,9 @@ static void copy_enlightened_to_vmcs12(struct vcpu_vmx *vmx, u32 hv_clean_fields vmcs12->tpr_threshold = evmcs->tpr_threshold; vmcs12->guest_rip = evmcs->guest_rip; + if ((hv_clean_fields & runtime_controls) != runtime_controls) + vmx->nested.force_msr_bitmap_recalc = true; + if (unlikely(!(hv_clean_fields & HV_VMX_ENLIGHTENED_CLEAN_FIELD_ENLIGHTENMENTSCONTROL))) { hv_vcpu->nested.pa_page_gpa = evmcs->partition_assist_page; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index f65081330c8a..5bae3d5ce6ee 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -71,6 +71,7 @@ #include "x86.h" #include "x86_ops.h" #include "smm.h" +#include "tss.h" #include "vmx_onhyperv.h" #include "posted_intr.h" @@ -8641,6 +8642,7 @@ __init int vmx_hardware_setup(void) if (r) return r; } + vmx_nested_ops.enabled = nested; r = alloc_kvm_area(); if (r && nested) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f08a34d3ff3d..ae33393c9b47 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -139,6 +139,13 @@ struct kvm_x86_ops kvm_x86_ops __read_mostly; EXPORT_STATIC_CALL_GPL(kvm_x86_get_cs_db_l_bits); EXPORT_STATIC_CALL_GPL(kvm_x86_cache_reg); +#define KVM_X86_NESTED_OP(func) \ + DEFINE_STATIC_CALL_NULL(kvm_x86_nested_##func, \ + *(((struct kvm_x86_nested_ops *)0)->func)); +#define KVM_X86_NESTED_OP_OPTIONAL KVM_X86_NESTED_OP +#define KVM_X86_NESTED_OP_OPTIONAL_RET0 KVM_X86_NESTED_OP +#include + static bool __read_mostly ignore_msrs = 0; module_param(ignore_msrs, bool, 0644); @@ -836,7 +843,7 @@ static void kvm_multiple_exception(struct kvm_vcpu *vcpu, unsigned int nr, * wants to intercept the exception. */ if (is_guest_mode(vcpu) && - kvm_x86_ops.nested_ops->is_exception_vmexit(vcpu, nr, error_code)) { + kvm_nested_call(is_exception_vmexit)(vcpu, nr, error_code)) { kvm_queue_exception_vmexit(vcpu, nr, has_error, error_code, has_payload, payload); return; @@ -4604,15 +4611,16 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r &= ~KVM_X2APIC_ENABLE_SUPPRESS_EOI_BROADCAST; break; case KVM_CAP_NESTED_STATE: - r = kvm_x86_ops.nested_ops->get_state ? - kvm_x86_ops.nested_ops->get_state(NULL, NULL, 0) : 0; + r = kvm_x86_ops.nested_ops->enabled ? + kvm_nested_call(get_state)(NULL, NULL, 0) : 0; break; #ifdef CONFIG_KVM_HYPERV case KVM_CAP_HYPERV_DIRECT_TLBFLUSH: r = kvm_x86_ops.enable_l2_tlb_flush != NULL; break; case KVM_CAP_HYPERV_ENLIGHTENED_VMCS: - r = kvm_x86_ops.nested_ops->enable_evmcs != NULL; + r = kvm_x86_ops.nested_ops->enabled && + kvm_x86_ops.nested_ops->enable_evmcs != NULL; break; #endif case KVM_CAP_SMALLER_MAXPHYADDR: @@ -5650,9 +5658,10 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, uint16_t vmcs_version; void __user *user_ptr; - if (!kvm_x86_ops.nested_ops->enable_evmcs) + if (!kvm_x86_ops.nested_ops->enabled || + !kvm_x86_ops.nested_ops->enable_evmcs) return -ENOTTY; - r = kvm_x86_ops.nested_ops->enable_evmcs(vcpu, &vmcs_version); + r = kvm_nested_call(enable_evmcs)(vcpu, &vmcs_version); if (!r) { user_ptr = (void __user *)(uintptr_t)cap->args[0]; if (copy_to_user(user_ptr, &vmcs_version, @@ -6150,7 +6159,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, u32 user_data_size; r = -EINVAL; - if (!kvm_x86_ops.nested_ops->get_state) + if (!kvm_x86_ops.nested_ops->enabled) break; BUILD_BUG_ON(sizeof(user_data_size) != sizeof(user_kvm_nested_state->size)); @@ -6158,8 +6167,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, if (get_user(user_data_size, &user_kvm_nested_state->size)) break; - r = kvm_x86_ops.nested_ops->get_state(vcpu, user_kvm_nested_state, - user_data_size); + r = kvm_nested_call(get_state)(vcpu, user_kvm_nested_state, user_data_size); if (r < 0) break; @@ -6180,7 +6188,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, int idx; r = -EINVAL; - if (!kvm_x86_ops.nested_ops->set_state) + if (!kvm_x86_ops.nested_ops->enabled) break; r = -EFAULT; @@ -6203,7 +6211,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, break; idx = srcu_read_lock(&vcpu->kvm->srcu); - r = kvm_x86_ops.nested_ops->set_state(vcpu, user_kvm_nested_state, &kvm_state); + r = kvm_nested_call(set_state)(vcpu, user_kvm_nested_state, &kvm_state); srcu_read_unlock(&vcpu->kvm->srcu, idx); break; } @@ -9600,6 +9608,8 @@ EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_setup_xss_caps); static inline void kvm_ops_update(struct kvm_x86_init_ops *ops) { + const struct kvm_x86_nested_ops *nested_ops = ops->runtime_ops->nested_ops; + memcpy(&kvm_x86_ops, ops->runtime_ops, sizeof(kvm_x86_ops)); #define __KVM_X86_OP(func) \ @@ -9613,6 +9623,17 @@ static inline void kvm_ops_update(struct kvm_x86_init_ops *ops) #include #undef __KVM_X86_OP +#define __KVM_X86_NESTED_OP(func) \ + static_call_update(kvm_x86_nested_##func, nested_ops->func); +#define KVM_X86_NESTED_OP(func) \ + WARN_ON(!nested_ops->func); __KVM_X86_NESTED_OP(func) +#define KVM_X86_NESTED_OP_OPTIONAL __KVM_X86_NESTED_OP +#define KVM_X86_NESTED_OP_OPTIONAL_RET0(func) \ + static_call_update(kvm_x86_nested_##func, (void *)nested_ops->func ? : \ + (void *)__static_call_return0); +#include +#undef __KVM_X86_NESTED_OP + kvm_pmu_ops_update(ops->pmu_ops); } @@ -10155,11 +10176,11 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu) int kvm_check_nested_events(struct kvm_vcpu *vcpu) { if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) { - kvm_x86_ops.nested_ops->triple_fault(vcpu); + kvm_nested_call(triple_fault)(vcpu); return 1; } - return kvm_x86_ops.nested_ops->check_events(vcpu); + return kvm_nested_call(check_events)(vcpu); } static void kvm_inject_exception(struct kvm_vcpu *vcpu) @@ -10399,9 +10420,7 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu, kvm_x86_call(enable_irq_window)(vcpu); } - if (is_guest_mode(vcpu) && - kvm_x86_ops.nested_ops->has_events && - kvm_x86_ops.nested_ops->has_events(vcpu, true)) + if (is_guest_mode(vcpu) && kvm_nested_call(has_events)(vcpu, true)) *req_immediate_exit = true; /* @@ -10688,7 +10707,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) } if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) { - if (unlikely(!kvm_x86_ops.nested_ops->get_nested_state_pages(vcpu))) { + if (unlikely(!kvm_nested_call(get_nested_state_pages)(vcpu))) { + kvm_make_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu); r = 0; goto out; } @@ -10740,7 +10760,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) } if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) { if (is_guest_mode(vcpu)) - kvm_x86_ops.nested_ops->triple_fault(vcpu); + kvm_nested_call(triple_fault)(vcpu); if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) { vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN; @@ -11142,9 +11162,7 @@ bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu) if (kvm_hv_has_stimer_pending(vcpu)) return true; - if (is_guest_mode(vcpu) && - kvm_x86_ops.nested_ops->has_events && - kvm_x86_ops.nested_ops->has_events(vcpu, false)) + if (is_guest_mode(vcpu) && kvm_nested_call(has_events)(vcpu, false)) return true; if (kvm_xen_has_pending_events(vcpu)) @@ -11562,8 +11580,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) * a pending VM-Exit if L1 wants to intercept the exception. */ if (vcpu->arch.exception_from_userspace && is_guest_mode(vcpu) && - kvm_x86_ops.nested_ops->is_exception_vmexit(vcpu, ex->vector, - ex->error_code)) { + kvm_nested_call(is_exception_vmexit)(vcpu, ex->vector, ex->error_code)) { kvm_queue_exception_vmexit(vcpu, ex->vector, ex->has_error_code, ex->error_code, ex->has_payload, ex->payload); diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index f4cd73a07490..6eddad77ab7c 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -165,7 +165,7 @@ int kvm_check_nested_events(struct kvm_vcpu *vcpu); /* Forcibly leave the nested mode in cases like a vCPU reset */ static inline void kvm_leave_nested(struct kvm_vcpu *vcpu) { - kvm_x86_ops.nested_ops->leave_nested(vcpu); + kvm_nested_call(leave_nested)(vcpu); } /* diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index 2e5ecfdce73c..612df76ec540 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -716,47 +716,37 @@ int pmd_clear_huge(pmd_t *pmd) } #ifdef CONFIG_X86_64 -/** - * pud_free_pmd_page - Clear PUD entry and free PMD page - * @pud: Pointer to a PUD - * @addr: Virtual address associated with PUD - * - * Context: The PUD range has been unmapped and TLB purged. - * Return: 1 if clearing the entry succeeded. 0 otherwise. - * - * NOTE: Callers must allow a single page allocation. +/* + * Given a PUD poitner, detach and free the pointed-to + * PMD page and any PTE page children. The entire range + * under the PUD must not have any valid translations + * and the TLB must have already been flushed. */ int pud_free_pmd_page(pud_t *pud, unsigned long addr) { - pmd_t *pmd, *pmd_sv; struct ptdesc *pt; + pmd_t *pmd; int i; pmd = pud_pgtable(*pud); - pmd_sv = (pmd_t *)__get_free_page(GFP_KERNEL); - if (!pmd_sv) - return 0; - - for (i = 0; i < PTRS_PER_PMD; i++) { - pmd_sv[i] = pmd[i]; - if (!pmd_none(pmd[i])) - pmd_clear(&pmd[i]); - } + /* Detach the PMD page: */ pud_clear(pud); - /* INVLPG to clear all paging-structure caches */ + /* + * PMD and all its descendents are unreachable + * via normal page walks. Make them unreachable + * in cached mid-level walks too: + */ flush_tlb_kernel_range(addr, addr + PAGE_SIZE-1); for (i = 0; i < PTRS_PER_PMD; i++) { - if (!pmd_none(pmd_sv[i])) { - pt = page_ptdesc(pmd_page(pmd_sv[i])); + if (!pmd_none(pmd[i])) { + pt = page_ptdesc(pmd_page(pmd[i])); pagetable_dtor_free(pt); } } - free_page((unsigned long)pmd_sv); - pmd_free(&init_mm, pmd); return 1; diff --git a/block/blk-mq.c b/block/blk-mq.c index e050ea631cda..ba0c48d58e13 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -447,16 +447,6 @@ static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data, WRITE_ONCE(rq->deadline, 0); req_ref_set(rq, 1); - if (rq->rq_flags & RQF_USE_SCHED) { - struct elevator_queue *e = data->q->elevator; - - INIT_HLIST_NODE(&rq->hash); - RB_CLEAR_NODE(&rq->rb_node); - - if (e->type->ops.prepare_request) - e->type->ops.prepare_request(rq); - } - return rq; } @@ -493,6 +483,69 @@ __blk_mq_alloc_requests_batch(struct blk_mq_alloc_data *data) return rq_list_pop(data->cached_rqs); } +static bool blk_op_bypass_sched(blk_opf_t opf) +{ + return (opf & REQ_OP_MASK) == REQ_OP_FLUSH || + blk_op_is_passthrough(opf); +} + +static void blk_mq_limit_depth(struct blk_mq_alloc_data *data) +{ + struct elevator_mq_ops *ops; + + /* If no I/O scheduler has been configured, don't limit requests */ + if (!data->q->elevator) { + blk_mq_tag_busy(data->hctx); + return; + } + + /* + * All requests use scheduler tags when an I/O scheduler is + * enabled for the queue. + */ + data->rq_flags |= RQF_SCHED_TAGS; + + /* + * Flush/passthrough requests are special and go directly to the + * dispatch list, they are not subject to the async_depth limit. + */ + if (blk_op_bypass_sched(data->cmd_flags)) + return; + + WARN_ON_ONCE(data->flags & BLK_MQ_REQ_RESERVED); + + /* + * By default, sync requests have no limit, and async requests are + * limited to async_depth. + */ + ops = &data->q->elevator->type->ops; + if (ops->limit_depth) + ops->limit_depth(data->cmd_flags, data); +} + +/* + * Finish initializing a request once it has been claimed for an operation. + * Cached requests are allocated before that operation is known. + */ +static void blk_mq_rq_late_init(struct request *rq, u64 alloc_time_ns) +{ + struct elevator_queue *e; + + blk_mq_rq_time_init(rq, alloc_time_ns); + + if (!(rq->rq_flags & RQF_SCHED_TAGS) || (rq->rq_flags & RQF_RESV) || + blk_op_bypass_sched(rq->cmd_flags)) + return; + + rq->rq_flags |= RQF_USE_SCHED; + INIT_HLIST_NODE(&rq->hash); + RB_CLEAR_NODE(&rq->rb_node); + + e = rq->q->elevator; + if (e->type->ops.prepare_request) + e->type->ops.prepare_request(rq); +} + static struct request *__blk_mq_alloc_requests(struct blk_mq_alloc_data *data) { struct request_queue *q = data->q; @@ -511,31 +564,7 @@ static struct request *__blk_mq_alloc_requests(struct blk_mq_alloc_data *data) data->ctx = blk_mq_get_ctx(q); data->hctx = blk_mq_map_queue(data->cmd_flags, data->ctx); - if (q->elevator) { - /* - * All requests use scheduler tags when an I/O scheduler is - * enabled for the queue. - */ - data->rq_flags |= RQF_SCHED_TAGS; - - /* - * Flush/passthrough requests are special and go directly to the - * dispatch list. - */ - if ((data->cmd_flags & REQ_OP_MASK) != REQ_OP_FLUSH && - !blk_op_is_passthrough(data->cmd_flags)) { - struct elevator_mq_ops *ops = &q->elevator->type->ops; - - WARN_ON_ONCE(data->flags & BLK_MQ_REQ_RESERVED); - - data->rq_flags |= RQF_USE_SCHED; - if (ops->limit_depth) - ops->limit_depth(data->cmd_flags, data); - } - } else { - blk_mq_tag_busy(data->hctx); - } - + blk_mq_limit_depth(data); if (data->flags & BLK_MQ_REQ_RESERVED) data->rq_flags |= RQF_RESV; @@ -545,7 +574,7 @@ static struct request *__blk_mq_alloc_requests(struct blk_mq_alloc_data *data) if (data->nr_tags > 1) { rq = __blk_mq_alloc_requests_batch(data); if (rq) { - blk_mq_rq_time_init(rq, alloc_time_ns); + blk_mq_rq_late_init(rq, alloc_time_ns); return rq; } data->nr_tags = 1; @@ -573,7 +602,7 @@ static struct request *__blk_mq_alloc_requests(struct blk_mq_alloc_data *data) if (!(data->rq_flags & RQF_SCHED_TAGS)) blk_mq_inc_active_requests(data->hctx); rq = blk_mq_rq_ctx_init(data, blk_mq_tags_from_data(data), tag); - blk_mq_rq_time_init(rq, alloc_time_ns); + blk_mq_rq_late_init(rq, alloc_time_ns); return rq; } @@ -620,8 +649,6 @@ static struct request *blk_mq_alloc_cached_request(struct request_queue *q, if (plug->nr_ios == 1) return NULL; rq = blk_mq_rq_cache_fill(q, plug, opf, flags); - if (!rq) - return NULL; } else { rq = rq_list_peek(&plug->cached_rqs); if (!rq || rq->q != q) @@ -633,11 +660,11 @@ static struct request *blk_mq_alloc_cached_request(struct request_queue *q, return NULL; rq_list_pop(&plug->cached_rqs); - blk_mq_rq_time_init(rq, blk_time_get_ns()); + rq->cmd_flags = opf; + INIT_LIST_HEAD(&rq->queuelist); + blk_mq_rq_late_init(rq, blk_time_get_ns()); } - rq->cmd_flags = opf; - INIT_LIST_HEAD(&rq->queuelist); return rq; } @@ -749,7 +776,7 @@ struct request *blk_mq_alloc_request_hctx(struct request_queue *q, if (!(data.rq_flags & RQF_SCHED_TAGS)) blk_mq_inc_active_requests(data.hctx); rq = blk_mq_rq_ctx_init(&data, blk_mq_tags_from_data(&data), tag); - blk_mq_rq_time_init(rq, alloc_time_ns); + blk_mq_rq_late_init(rq, alloc_time_ns); rq->__data_len = 0; rq->phys_gap_bit = 0; rq->__sector = (sector_t) -1; @@ -3177,9 +3204,9 @@ void blk_mq_submit_bio(struct bio *bio) new_request: if (rq) { rq_qos_throttle(rq->q, bio); - blk_mq_rq_time_init(rq, blk_time_get_ns()); rq->cmd_flags = bio->bi_opf; INIT_LIST_HEAD(&rq->queuelist); + blk_mq_rq_late_init(rq, blk_time_get_ns()); } else { rq = blk_mq_get_new_requests(q, plug, bio); if (unlikely(!rq)) { diff --git a/block/fops.c b/block/fops.c index bbc89773e07f..cc9cb54fcd41 100644 --- a/block/fops.c +++ b/block/fops.c @@ -409,6 +409,11 @@ static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter) if (blkdev_dio_invalid(bdev, iocb, iter)) return -EINVAL; + /* HIPRI needs private as bio; HAS_METADATA keeps it as uio_meta */ + if ((iocb->ki_flags & IOCB_HIPRI) && + (iocb->ki_flags & IOCB_HAS_METADATA)) + return -EOPNOTSUPP; + if (iov_iter_rw(iter) == WRITE) { u16 max_write_streams = bdev_max_write_streams(bdev); diff --git a/block/mq-deadline.c b/block/mq-deadline.c index 29d00221fbea..555ab81bc12a 100644 --- a/block/mq-deadline.c +++ b/block/mq-deadline.c @@ -704,7 +704,7 @@ static void dd_insert_requests(struct blk_mq_hw_ctx *hctx, blk_mq_free_requests(&free); } -/* Callback from inside blk_mq_rq_ctx_init(). */ +/* Callback from inside blk_mq_rq_late_init(). */ static void dd_prepare_request(struct request *rq) { rq->elv.priv[0] = NULL; diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 81f1d92b2701..ca8e5ddf991b 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2930,8 +2930,9 @@ static int binder_proc_transaction(struct binder_transaction *t, t_outdated->buffer = NULL; buffer->transaction = NULL; trace_binder_transaction_update_buffer_release(buffer); - binder_release_entire_buffer(proc, NULL, buffer, false); + binder_release_entire_buffer(proc, NULL, buffer, true); binder_alloc_free_buf(&proc->alloc, buffer); + binder_free_txn_fixups(t_outdated); kfree(t_outdated); binder_stats_deleted(BINDER_STAT_TRANSACTION); } diff --git a/drivers/android/binder/thread.rs b/drivers/android/binder/thread.rs index 93b550e6b60e..e2320704c722 100644 --- a/drivers/android/binder/thread.rs +++ b/drivers/android/binder/thread.rs @@ -656,6 +656,12 @@ pub(crate) fn push_return_work(&self, reply: u32) { self.inner.lock().push_return_work(reply); } + pub(crate) fn pop_work_even_if_deferred(&self) -> Option> { + let mut thread_inner = self.inner.lock(); + thread_inner.process_work_list = true; + thread_inner.pop_work() + } + fn translate_object( &self, obj_index: usize, @@ -1606,7 +1612,7 @@ pub(crate) fn release(self: &Arc) { self.unwind_transaction_stack(); // Cancel all pending work items. - while let Ok(Some(work)) = self.get_work_local(false) { + while let Some(work) = self.pop_work_even_if_deferred() { work.into_arc().cancel(); } } diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index f061420dfb10..e577b02cf400 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -740,6 +740,7 @@ static int virtblk_read_zoned_limits(struct virtio_blk *vblk, dev_warn(&vdev->dev, "zero write granularity reported\n"); return -ENODEV; } + lim->zone_write_granularity = wg; lim->physical_block_size = wg; lim->io_min = wg; diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 0e5c2d389371..cdcd3b20f1b4 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -274,7 +274,8 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code) goto unlock; } - bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1)); + bt_dev_err(hdev, "Exception info %.*s", (int)(skb->len - 1), + (char *)(skb->data + 1)); kfree_skb(skb); @@ -393,8 +394,16 @@ int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name) /* DDC file contains one or more DDC structure which has * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2). */ - while (fw->size > fw_ptr - fw->data) { - u8 cmd_plen = fw_ptr[0] + sizeof(u8); + while (fw->size > (size_t)(fw_ptr - fw->data)) { + size_t remaining = fw->size - (fw_ptr - fw->data); + unsigned int cmd_plen = fw_ptr[0] + 1U; + + if (cmd_plen < 3 || cmd_plen > U8_MAX || cmd_plen > remaining) { + bt_dev_err(hdev, "Malformed DDC record (plen=%u, remaining=%zu)", + cmd_plen, remaining); + release_firmware(fw); + return -EINVAL; + } skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr, HCI_INIT_TIMEOUT); diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 3d1ed8568877..cee774032106 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -1116,7 +1116,7 @@ static int btintel_pcie_recv_frame(struct btintel_pcie_data *data, { int ret; u8 pkt_type; - u16 plen; + u32 plen; u32 pcie_pkt_type; void *pdata; struct hci_dev *hdev = data->hdev; @@ -1968,6 +1968,16 @@ static int btintel_pcie_send_frame(struct hci_dev *hdev, if (test_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags)) return -ENODEV; + /* Account for the 4-byte PCIe type header prepended before the + * DMA copy. Written as a subtraction to avoid wrap-around on + * attacker-controlled skb->len. + */ + if (skb->len > BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN) { + bt_dev_err(hdev, "Packet too large: %u > %u", skb->len, + BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN); + return -EMSGSIZE; + } + /* Due to the fw limitation, the type header of the packet should be * 4 bytes unlike 1 byte for UART. In UART, the firmware can read * the first byte to get the packet type and redirect the rest of data diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c496f746fafa..59fff918fd2d 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -307,6 +307,8 @@ static const struct usb_device_id quirks_table[] = { BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x13d3, 0x3501), .driver_info = BTUSB_QCA_ROME | BTUSB_WIDEBAND_SPEECH }, + { USB_DEVICE(0x13d3, 0x3503), .driver_info = BTUSB_QCA_ROME | + BTUSB_WIDEBAND_SPEECH }, /* QCA WCN6855 chipset */ { USB_DEVICE(0x0489, 0xe0c7), .driver_info = BTUSB_QCA_WCN6855 | diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 2f506cdb5f45..c5465834396a 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -298,7 +298,7 @@ int tpm2_get_random(struct tpm_chip *chip, u8 *dest, size_t max) out = (struct tpm2_get_random_out *)&buf.data[offset]; recd = min_t(u32, be16_to_cpu(out->size), num_bytes); if (tpm_buf_length(&buf) < - TPM_HEADER_SIZE + + offset + offsetof(struct tpm2_get_random_out, buffer) + recd) { err = -EFAULT; diff --git a/drivers/char/tpm/tpm2-sessions.c b/drivers/char/tpm/tpm2-sessions.c index c4cd58f1f9e9..c330f3bae8b2 100644 --- a/drivers/char/tpm/tpm2-sessions.c +++ b/drivers/char/tpm/tpm2-sessions.c @@ -983,6 +983,7 @@ static int tpm2_load_null(struct tpm_chip *chip, u32 *null_key) /* Deduce from the name change TPM interference: */ dev_err(&chip->dev, "null key integrity check failed\n"); tpm2_flush_context(chip, tmp_null_key); + rc = -ENODEV; err: if (rc) { diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index a6e8e76c8abd..9aca472e126e 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -453,15 +453,6 @@ static int altr_sdram_probe(struct platform_device *pdev) return res; } -static void altr_sdram_remove(struct platform_device *pdev) -{ - struct mem_ctl_info *mci = platform_get_drvdata(pdev); - - edac_mc_del_mc(&pdev->dev); - edac_mc_free(mci); - platform_set_drvdata(pdev, NULL); -} - /* * If you want to suspend, need to disable EDAC by removing it * from the device tree or defconfig. @@ -481,13 +472,13 @@ static const struct dev_pm_ops altr_sdram_pm_ops = { static struct platform_driver altr_sdram_edac_driver = { .probe = altr_sdram_probe, - .remove = altr_sdram_remove, .driver = { .name = "altr_sdram_edac", #ifdef CONFIG_PM .pm = &altr_sdram_pm_ops, #endif .of_match_table = altr_sdram_ctrl_of_match, + .suppress_bind_attrs = true, }, }; @@ -517,6 +508,7 @@ static struct platform_driver altr_edac_driver = { .driver = { .name = "socfpga_ecc_manager", .of_match_table = altr_edac_of_match, + .suppress_bind_attrs = true, }, }; module_platform_driver(altr_edac_driver); @@ -803,22 +795,12 @@ static int altr_edac_device_probe(struct platform_device *pdev) return res; } -static void altr_edac_device_remove(struct platform_device *pdev) -{ - struct edac_device_ctl_info *dci = platform_get_drvdata(pdev); - struct altr_edac_device_dev *drvdata = dci->pvt_info; - - debugfs_remove_recursive(drvdata->debugfs_dir); - edac_device_del_device(&pdev->dev); - edac_device_free_ctl_info(dci); -} - static struct platform_driver altr_edac_device_driver = { .probe = altr_edac_device_probe, - .remove = altr_edac_device_remove, .driver = { .name = "altr_edac_device", .of_match_table = altr_edac_device_of_match, + .suppress_bind_attrs = true, }, }; module_platform_driver(altr_edac_device_driver); @@ -944,7 +926,7 @@ static int __maybe_unused altr_init_memory_port(void __iomem *ioaddr, int port) return ret; } -static __init int __maybe_unused +static int __maybe_unused altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask, u32 ecc_ctrl_en_mask, bool dual_port) { @@ -1019,7 +1001,7 @@ altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask, static int validate_parent_available(struct device_node *np); static const struct of_device_id altr_edac_a10_device_of_match[]; -static int __init __maybe_unused altr_init_a10_ecc_device_type(char *compat) +static int __maybe_unused altr_init_a10_ecc_device_type(char *compat) { int irq; struct device_node *child, *np; @@ -1348,7 +1330,7 @@ static const struct edac_device_prv_data a10_l2ecc_data = { #ifdef CONFIG_EDAC_ALTERA_ETHERNET -static int __init socfpga_init_ethernet_ecc(struct altr_edac_device_dev *dev) +static int socfpga_init_ethernet_ecc(struct altr_edac_device_dev *dev) { int ret; @@ -1378,7 +1360,7 @@ static const struct edac_device_prv_data a10_enetecc_data = { #ifdef CONFIG_EDAC_ALTERA_NAND -static int __init socfpga_init_nand_ecc(struct altr_edac_device_dev *device) +static int socfpga_init_nand_ecc(struct altr_edac_device_dev *device) { int ret; @@ -1408,7 +1390,7 @@ static const struct edac_device_prv_data a10_nandecc_data = { #ifdef CONFIG_EDAC_ALTERA_DMA -static int __init socfpga_init_dma_ecc(struct altr_edac_device_dev *device) +static int socfpga_init_dma_ecc(struct altr_edac_device_dev *device) { int ret; @@ -1438,7 +1420,7 @@ static const struct edac_device_prv_data a10_dmaecc_data = { #ifdef CONFIG_EDAC_ALTERA_USB -static int __init socfpga_init_usb_ecc(struct altr_edac_device_dev *device) +static int socfpga_init_usb_ecc(struct altr_edac_device_dev *device) { int ret; @@ -1468,7 +1450,7 @@ static const struct edac_device_prv_data a10_usbecc_data = { #ifdef CONFIG_EDAC_ALTERA_QSPI -static int __init socfpga_init_qspi_ecc(struct altr_edac_device_dev *device) +static int socfpga_init_qspi_ecc(struct altr_edac_device_dev *device) { int ret; @@ -1524,6 +1506,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) dci = edac_device_alloc_ctl_info(sizeof(*altdev), ecc_name, 1, ecc_name, 1, 0, edac_idx); if (!dci) { + of_node_put(np); edac_printk(KERN_ERR, EDAC_DEVICE, "%s: Unable to allocate PortB EDAC device\n", ecc_name); @@ -1534,8 +1517,11 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) altdev = dci->pvt_info; *altdev = *device; - if (!devres_open_group(device->edac->dev, altr_portb_setup, GFP_KERNEL)) + if (!devres_open_group(device->edac->dev, altr_portb_setup, GFP_KERNEL)) { + edac_device_free_ctl_info(dci); + of_node_put(np); return -ENOMEM; + } /* Update PortB specific values */ altdev->edac_dev_name = ecc_name; @@ -1600,6 +1586,8 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) rc = -ENOMEM; goto err_release_group_1; } + of_node_put(np); + altr_create_edacdev_dbgfs(dci, prv); list_add(&altdev->next, &altdev->edac->a10_ecc_devices); @@ -1609,14 +1597,20 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) return 0; err_release_group_1: - edac_device_free_ctl_info(dci); + /* + * Release the devres group first so the managed IRQs are + * unregistered before dci (which contains the IRQ handler's + * data via dci->pvt_info) is freed, avoiding a use-after-free. + */ devres_release_group(device->edac->dev, altr_portb_setup); + edac_device_free_ctl_info(dci); + of_node_put(np); edac_printk(KERN_ERR, EDAC_DEVICE, "%s:Error setting up EDAC device: %d\n", ecc_name, rc); return rc; } -static int __init socfpga_init_sdmmc_ecc(struct altr_edac_device_dev *device) +static int socfpga_init_sdmmc_ecc(struct altr_edac_device_dev *device) { int rc = -ENODEV; struct device_node *child; @@ -1638,7 +1632,7 @@ static int __init socfpga_init_sdmmc_ecc(struct altr_edac_device_dev *device) goto exit; /* Setup portB */ - return altr_portb_setup(device); + rc = altr_portb_setup(device); exit: of_node_put(child); @@ -2013,9 +2007,17 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac, return 0; err_release_group1: + /* + * Release the devres group first so the managed IRQs are + * unregistered before dci (which contains the IRQ handler's + * data via dci->pvt_info) is freed, avoiding a use-after-free. + */ + devres_release_group(edac->dev, NULL); edac_device_free_ctl_info(dci); + goto err_print; err_release_group: devres_release_group(edac->dev, NULL); +err_print: edac_printk(KERN_ERR, EDAC_DEVICE, "%s:Error setting up EDAC device: %d\n", ecc_name, rc); @@ -2218,6 +2220,7 @@ static struct platform_driver altr_edac_a10_driver = { .driver = { .name = "socfpga_a10_ecc_manager", .of_match_table = altr_edac_a10_of_match, + .suppress_bind_attrs = true, }, }; module_platform_driver(altr_edac_a10_driver); diff --git a/drivers/edac/versalnet_edac.c b/drivers/edac/versalnet_edac.c index 4053ee2e0bee..ef5e62688ef8 100644 --- a/drivers/edac/versalnet_edac.c +++ b/drivers/edac/versalnet_edac.c @@ -938,6 +938,7 @@ static void mc_remove(struct platform_device *pdev) remove_versalnet(priv); rproc_shutdown(priv->mcdi->r5_rproc); cdx_mcdi_finish(priv->mcdi); + rproc_put(priv->mcdi->r5_rproc); kfree(priv->mcdi); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c index fe39b150ee53..37ef67eb81a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c @@ -318,7 +318,7 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block) r = device_for_each_child(adev->acp.parent, &adev->acp.acp_genpd->gpd, acp_genpd_add_device); if (r) - goto failure; + goto failure_remove_mfd; break; } default: @@ -440,7 +440,7 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block) r = device_for_each_child(adev->acp.parent, &adev->acp.acp_genpd->gpd, acp_genpd_add_device); if (r) - goto failure; + goto failure_remove_mfd; } /* Assert Soft reset of ACP */ @@ -458,7 +458,7 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block) if (--count == 0) { dev_err(&adev->pdev->dev, "Failed to reset ACP\n"); r = -ETIMEDOUT; - goto failure; + goto failure_remove_mfd; } udelay(100); } @@ -476,7 +476,7 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block) if (--count == 0) { dev_err(&adev->pdev->dev, "Failed to reset ACP\n"); r = -ETIMEDOUT; - goto failure; + goto failure_remove_mfd; } udelay(100); } @@ -486,6 +486,11 @@ static int acp_hw_init(struct amdgpu_ip_block *ip_block) cgs_write_register(adev->acp.cgs_device, mmACP_SOFT_RESET, val); return 0; +failure_remove_mfd: + device_for_each_child(adev->acp.parent, NULL, + acp_genpd_remove_device); + mfd_remove_devices(adev->acp.parent); + failure: kfree(i2s_pdata); kfree(adev->acp.acp_res); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index 54a045a0bda9..f6c7d6436014 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -1151,6 +1151,8 @@ static int amdgpu_discovery_sysfs_ips(struct amdgpu_device *adev, ip_hw_instance->kobj.kset = &ip_hw_id->hw_id_kset; res = kobject_add(&ip_hw_instance->kobj, NULL, "%d", ip_hw_instance->num_instance); + if (res) + kobject_put(&ip_hw_instance->kobj); next_ip: if (reg_base_64) ip_offset += struct_size(ip, base_address_64, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index fb753613e00d..376a7cd2667f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -2643,6 +2643,14 @@ static int amdgpu_pmops_suspend_noirq(struct device *dev) struct amdgpu_device *adev = drm_to_adev(drm_dev); int r; + /* + * A GPU parked by vga_switcheroo has no power and no PCIe link, so the + * ASIC reset below would fail and abort the whole noirq suspend phase. + * Bail out like amdgpu_device_prepare/suspend/resume() already do. + */ + if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; + if (amdgpu_acpi_should_gpu_reset(adev)) { amdgpu_device_lock_reset_domain(adev->reset_domain); r = amdgpu_asic_reset(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index ef399fce3ef3..e8041ab2bd98 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -322,6 +322,14 @@ static const u32 verde_rlc_save_restore_register_list[] = 0x00000000 }; +static void gfx_v6_0_free_microcode(struct amdgpu_device *adev) +{ + amdgpu_ucode_release(&adev->gfx.pfp_fw); + amdgpu_ucode_release(&adev->gfx.me_fw); + amdgpu_ucode_release(&adev->gfx.ce_fw); + amdgpu_ucode_release(&adev->gfx.rlc_fw); +} + static int gfx_v6_0_init_microcode(struct amdgpu_device *adev) { const char *chip_name; @@ -3187,6 +3195,7 @@ static int gfx_v6_0_sw_fini(struct amdgpu_ip_block *ip_block) amdgpu_ring_fini(&adev->gfx.compute_ring[i]); amdgpu_gfx_rlc_fini(adev); + gfx_v6_0_free_microcode(adev); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index a611a7345125..ce54e2938107 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -1407,10 +1407,31 @@ static uint64_t vi_get_pcie_replay_count(struct amdgpu_device *adev) return (nak_r + nak_g); } +struct vi_reset_quirk { + u16 device; + u16 subsystem_vendor; + u16 subsystem_device; + u8 revision; +}; + +static const struct vi_reset_quirk vi_reset_quirks[] = { + { 0x67ef, PCI_VENDOR_ID_APPLE, 0x0190, 0xe3 }, /* Radeon Pro 555X */ + { 0x67ef, PCI_VENDOR_ID_APPLE, 0x018f, 0xc2 }, /* Radeon Pro 560X */ + { 0x67ef, PCI_VENDOR_ID_APPLE, 0x017a, 0xc7 }, /* Radeon Pro 555 */ +}; + static bool vi_need_reset_on_init(struct amdgpu_device *adev) { + unsigned int i; u32 clock_cntl, pc; + for (i = 0; i < ARRAY_SIZE(vi_reset_quirks); i++) + if (adev->pdev->device == vi_reset_quirks[i].device && + adev->pdev->subsystem_vendor == vi_reset_quirks[i].subsystem_vendor && + adev->pdev->subsystem_device == vi_reset_quirks[i].subsystem_device && + adev->pdev->revision == vi_reset_quirks[i].revision) + return true; + if (adev->flags & AMD_IS_APU) return false; 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 c2479e2e964b..19c3f56017ce 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3266,9 +3266,14 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block) dc_allow_idle_optimizations(adev->dm.dc, false); dm->cached_dc_state = dc_state_create_copy(dm->dc->current_state); + if (!dm->cached_dc_state) { + drm_err(adev_to_drm(adev), + "Failed to allocate cached DC state during suspend\n"); + mutex_unlock(&dm->dc_lock); + return -ENOMEM; + } - if (dm->cached_dc_state) - dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, false); + dm_gpureset_toggle_interrupts(adev, dm->cached_dc_state, false); res = amdgpu_dm_commit_zero_streams(dm->dc); if (res != DC_OK) { diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 390f948dad39..a24a225f3de8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1624,6 +1624,7 @@ struct dc_scratch_space { struct ddc_service *ddc; enum dp_panel_mode panel_mode; + bool panel_mode_initialized; bool aux_mode; /* Private to DC core */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index 5e806edbb9f6..4d2d4b7fb580 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -91,6 +91,7 @@ void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode) } link->panel_mode = panel_mode; + link->panel_mode_initialized = true; DC_LOG_DETECTION_DP_CAPS("Link: %d eDP panel mode supported: %d " "eDP panel mode enabled: %d \n", link->link_index, @@ -1293,7 +1294,8 @@ void edp_set_panel_assr(struct dc_link *link, struct pipe_ctx *pipe_ctx, result = cp_psp->funcs.enable_assr(cp_psp->handle, link); - if (!result && link->panel_mode != DP_PANEL_MODE_EDP) + if (!result && link->panel_mode_initialized && + link->panel_mode != DP_PANEL_MODE_EDP) *panel_mode = DP_PANEL_MODE_DEFAULT; } } diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c index e94af8522083..e67c73807f37 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c @@ -1306,7 +1306,6 @@ static bool dce64_construct( dc->caps.max_downscale_ratio = 200; dc->caps.i2c_speed_in_khz = 40; dc->caps.max_cursor_size = 64; - dc->caps.is_apu = true; /************************************************* * Create resources * diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c index b645c0c8ec3c..9874d2cb632c 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c @@ -1121,6 +1121,7 @@ static bool dce81_construct( dc->caps.max_cursor_size = 128; dc->caps.min_horizontal_blanking_period = 80; dc->caps.is_apu = true; + dc->debug = debug_defaults; /************************************************* * Create resources * diff --git a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c index 39928eb71d66..cd17bf4ab296 100644 --- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c @@ -5263,7 +5263,8 @@ static int si_init_smc_table(struct amdgpu_device *adev) break; } - if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC) + if ((adev->flags & AMD_IS_MOBILITY) && + (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC)) table->systemFlags |= PPSMC_SYSTEMFLAG_GPIO_DC; if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT) { @@ -7230,6 +7231,19 @@ static void si_parse_pplib_non_clock_info(struct amdgpu_device *adev, adev->pm.dpm.uvd_ps = rps; } +static void si_update_limits(struct amdgpu_clock_and_voltage_limits *limits, + struct rv7xx_pl *pl) +{ + if (pl->sclk > limits->sclk) + limits->sclk = pl->sclk; + if (pl->mclk > limits->mclk) + limits->mclk = pl->mclk; + if (pl->vddc > limits->vddc) + limits->vddc = pl->vddc; + if (pl->vddci > limits->vddci) + limits->vddci = pl->vddci; +} + static void si_parse_pplib_clock_info(struct amdgpu_device *adev, struct amdgpu_ps *rps, int index, union pplib_clock_info *clock_info) @@ -7238,7 +7252,6 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev, struct evergreen_power_info *eg_pi = evergreen_get_pi(adev); struct si_power_info *si_pi = si_get_pi(adev); struct si_ps *ps = si_get_ps(rps); - struct amdgpu_clock_and_voltage_limits *limits; u16 leakage_voltage; struct rv7xx_pl *pl = &ps->performance_levels[index]; int ret; @@ -7303,26 +7316,14 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev, * VBIOS can contain conflicting values between: * - the maximum allowed clocks and voltages on AC or DC * - the clocks and voltages in power states on AC or DC + * + * Assume that the AC limits are the maximum of all power states, + * and the DC limits are the maximum of battery power states. */ + si_update_limits(&adev->pm.dpm.dyn_state.max_clock_voltage_on_ac, pl); if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == - ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) - limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_ac; - else if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) - limits = &adev->pm.dpm.dyn_state.max_clock_voltage_on_dc; - else - limits = NULL; - - if (limits) { - if (pl->sclk > limits->sclk) - limits->sclk = pl->sclk; - if (pl->mclk > limits->mclk) - limits->mclk = pl->mclk; - if (pl->vddc > limits->vddc) - limits->vddc = pl->vddc; - if (pl->vddci > limits->vddci) - limits->vddci = pl->vddci; - } + si_update_limits(&adev->pm.dpm.dyn_state.max_clock_voltage_on_dc, pl); } union pplib_power_state { diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c index ce166a7f8e42..1fff7567bca2 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c @@ -268,15 +268,21 @@ static const ATOM_VOLTAGE_OBJECT_V3 *atomctrl_lookup_voltage_type_v3( unsigned int offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]); uint8_t *start = (uint8_t *)voltage_object_info_table; - while (offset < size) { + while (offset + sizeof(ATOM_VOLTAGE_OBJECT_HEADER_V3) <= size) { const ATOM_VOLTAGE_OBJECT_V3 *voltage_object = (const ATOM_VOLTAGE_OBJECT_V3 *)(start + offset); + u16 obj_size; + + obj_size = le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize); + if (obj_size < sizeof(voltage_object->asGpioVoltageObj.sHeader) || + offset + obj_size > size) + break; if (voltage_type == voltage_object->asGpioVoltageObj.sHeader.ucVoltageType && voltage_mode == voltage_object->asGpioVoltageObj.sHeader.ucVoltageMode) return voltage_object; - offset += le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize); + offset += obj_size; } return NULL; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c index 6120f14caab0..69aee8661d1e 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c @@ -36,16 +36,21 @@ static const union atom_voltage_object_v4 *pp_atomfwctrl_lookup_voltage_type_v4( offsetof(struct atom_voltage_objects_info_v4_1, voltage_object[0]); unsigned long start = (unsigned long)voltage_object_info_table; - while (offset < size) { + while (offset + sizeof(struct atom_voltage_object_header_v4) <= size) { const union atom_voltage_object_v4 *voltage_object = (const union atom_voltage_object_v4 *)(start + offset); + u16 obj_size; + + obj_size = le16_to_cpu(voltage_object->gpio_voltage_obj.header.object_size); + if (obj_size < sizeof(voltage_object->gpio_voltage_obj.header) || + offset + obj_size > size) + break; if (voltage_type == voltage_object->gpio_voltage_obj.header.voltage_type && voltage_mode == voltage_object->gpio_voltage_obj.header.voltage_mode) return voltage_object; - offset += le16_to_cpu(voltage_object->gpio_voltage_obj.header.object_size); - + offset += obj_size; } return NULL; diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c index a94c51a83261..32fe574745e2 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c @@ -652,8 +652,10 @@ static int mtk_drm_bind(struct device *dev) private->mtk_drm_bound = true; private->dev = dev; - if (!mtk_drm_get_all_drm_priv(dev)) + if (!mtk_drm_get_all_drm_priv(dev)) { + put_device(private->mutex_dev); return 0; + } drm = drm_dev_alloc(&mtk_drm_driver, dev); if (IS_ERR(drm)) { @@ -1070,7 +1072,7 @@ static int mtk_drm_probe(struct platform_device *pdev) struct mtk_mmsys_driver_data *mtk_drm_data; struct device_node *node; struct component_match *match = NULL; - struct platform_device *ovl_adaptor; + struct platform_device *ovl_adaptor = NULL; int ret; int i; @@ -1122,6 +1124,9 @@ static int mtk_drm_probe(struct platform_device *pdev) PLATFORM_DEVID_AUTO, (void *)private->mmsys_dev, sizeof(*private->mmsys_dev)); + if (IS_ERR(ovl_adaptor)) + return PTR_ERR(ovl_adaptor); + private->ddp_comp[DDP_COMPONENT_DRM_OVL_ADAPTOR].dev = &ovl_adaptor->dev; mtk_ddp_comp_init(dev, NULL, &private->ddp_comp[DDP_COMPONENT_DRM_OVL_ADAPTOR], DDP_COMPONENT_DRM_OVL_ADAPTOR); @@ -1215,6 +1220,8 @@ static int mtk_drm_probe(struct platform_device *pdev) err_pm: pm_runtime_disable(dev); err_node: + if (ovl_adaptor) + platform_device_unregister(ovl_adaptor); of_node_put(private->mutex_node); for (i = 0; i < DDP_COMPONENT_DRM_ID_MAX; i++) of_node_put(private->comp_node[i]); @@ -1224,9 +1231,15 @@ static int mtk_drm_probe(struct platform_device *pdev) static void mtk_drm_remove(struct platform_device *pdev) { struct mtk_drm_private *private = platform_get_drvdata(pdev); + struct device *ovl_adaptor_dev; int i; + ovl_adaptor_dev = + private->ddp_comp[DDP_COMPONENT_DRM_OVL_ADAPTOR].dev; + component_master_del(&pdev->dev, &mtk_drm_ops); + if (ovl_adaptor_dev) + platform_device_unregister(to_platform_device(ovl_adaptor_dev)); pm_runtime_disable(&pdev->dev); of_node_put(private->mutex_node); for (i = 0; i < DDP_COMPONENT_DRM_ID_MAX; i++) diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 3a8c5199a0fe..ef2567f1a37a 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -49,6 +49,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev) { uint8_t __iomem *bios; + uint8_t val1, val2; resource_size_t vram_base; resource_size_t size = 256 * 1024; /* ??? */ @@ -63,7 +64,10 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev) return false; } - if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) { + val1 = readb(&bios[0]); + val2 = readb(&bios[1]); + + if (size == 0 || val1 != 0x55 || val2 != 0xaa) { iounmap(bios); return false; } diff --git a/drivers/hid/bpf/hid_bpf_dispatch.c b/drivers/hid/bpf/hid_bpf_dispatch.c index 9fbbf59cefa1..7d6edfd9b09a 100644 --- a/drivers/hid/bpf/hid_bpf_dispatch.c +++ b/drivers/hid/bpf/hid_bpf_dispatch.c @@ -456,7 +456,7 @@ hid_bpf_hw_request(struct hid_bpf_ctx *ctx, __u8 *buf, size_t buf__sz, (u64)(long)ctx, true); /* prevent infinite recursions */ - if (ret > size) + if (ret > (ssize_t)size) ret = size; if (ret > 0) memcpy(buf, dma_data, ret); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 4b736cd012db..2461d84eb0e9 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -2250,7 +2250,7 @@ static void mt_remove(struct hid_device *hdev) { struct mt_device *td = hid_get_drvdata(hdev); - timer_delete_sync(&td->release_timer); + timer_shutdown_sync(&td->release_timer); sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); hid_hw_stop(hdev); diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c index 68238cc8aee0..e0c3de5e8203 100644 --- a/drivers/i2c/busses/i2c-at91-master.c +++ b/drivers/i2c/busses/i2c-at91-master.c @@ -921,8 +921,14 @@ int at91_twi_probe_master(struct platform_device *pdev, at91_calc_twi_clock(dev); rc = at91_init_twi_recovery_info(pdev, dev); - if (rc == -EPROBE_DEFER) + if (rc == -EPROBE_DEFER) { + /* + * The DMA channels were already set up above, release them + * before deferring the probe so they are not leaked. + */ + at91_twi_dma_release(dev); return rc; + } dev->adapter.algo = &at91_twi_algorithm; dev->adapter.quirks = &at91_twi_quirks; diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 28015d77599d..bc47aaa7da39 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -74,6 +74,9 @@ enum i2c_scl_freq { * @prev_msg_tx: Previous message is Tx * @quirks: To hold platform specific bug info * @smbus_block_read: Flag to handle block read + * @smbus_actual_len: Valid byte count (length + payload + optional PEC) of a + * padded SMBus block read. msg->len is trimmed to this on completion. + * Zero when no trimming is needed. * @input_clk: Input clock to I2C controller * @i2c_clk: I2C SCL frequency * @atomic: Mode of transfer @@ -99,6 +102,7 @@ struct xiic_i2c { bool prev_msg_tx; u32 quirks; bool smbus_block_read; + unsigned int smbus_actual_len; unsigned long input_clk; unsigned int i2c_clk; bool atomic; @@ -540,30 +544,38 @@ static void xiic_smbus_block_read_setup(struct xiic_i2c *i2c) /* Check if received length is valid */ if (rxmsg_len <= I2C_SMBUS_BLOCK_MAX) { + unsigned int pec_len = i2c->rx_msg->len - 1; + /* Set Receive fifo depth */ - if (rxmsg_len > IIC_RX_FIFO_DEPTH) { + if (rxmsg_len + pec_len > IIC_RX_FIFO_DEPTH) { /* - * When Rx msg len greater than or equal to Rx fifo capacity - * Receive fifo depth should set to Rx fifo capacity minus 1 + * Trailing bytes (payload plus any PEC) exceed Rx FIFO + * capacity, so drain in chunks. This also keeps the + * else branch below from pushing rfd_set past the + * 4-bit XIIC_RFD_REG_OFFSET field. */ rfd_set = IIC_RX_FIFO_DEPTH - 1; - i2c->rx_msg->len = rxmsg_len + 1; - } else if ((rxmsg_len == 1) || - (rxmsg_len == 0)) { + i2c->rx_msg->len = rxmsg_len + 1 + pec_len; + } else if (1 + rxmsg_len + pec_len < SMBUS_BLOCK_READ_MIN_LEN) { /* - * Minimum of 3 bytes required to exit cleanly. 1 byte - * already received, Second byte is being received. Have - * to set NACK in read_rx before receiving the last byte + * The HW needs SMBUS_BLOCK_READ_MIN_LEN bytes on the + * bus to exit cleanly: by the time the ISR reads the + * length byte the second byte is already being clocked + * in, too late to NACK. Pad the drain target and record + * the real length, trimmed back on completion so the + * PEC check sees the right byte. */ rfd_set = 0; i2c->rx_msg->len = SMBUS_BLOCK_READ_MIN_LEN; + i2c->smbus_actual_len = 1 + rxmsg_len + pec_len; } else { /* - * When Rx msg len less than Rx fifo capacity - * Receive fifo depth should set to Rx msg len minus 2 + * All trailing bytes fit in the Rx FIFO. The widened + * condition above guarantees rxmsg_len + pec_len >= 2, + * so this cannot underflow. */ - rfd_set = rxmsg_len - 2; - i2c->rx_msg->len = rxmsg_len + 1; + rfd_set = rxmsg_len + pec_len - 2; + i2c->rx_msg->len = rxmsg_len + 1 + pec_len; } xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rfd_set); @@ -576,6 +588,16 @@ static void xiic_smbus_block_read_setup(struct xiic_i2c *i2c) dev_err(i2c->adap.dev.parent, "smbus_block_read Invalid msg length\n"); } +/* + * Undo the setup-time padding of a short SMBus block read before rx_msg is + * cleared, so the PEC check sees the right byte. + */ +static void xiic_smbus_trim_len(struct xiic_i2c *i2c) +{ + if (i2c->rx_msg && i2c->smbus_actual_len) + i2c->rx_msg->len = i2c->smbus_actual_len; +} + static void xiic_read_rx(struct xiic_i2c *i2c) { u8 bytes_in_fifo, cr = 0, bytes_to_read = 0; @@ -798,6 +820,8 @@ static irqreturn_t xiic_process(int irq, void *dev_id) xiic_read_rx(i2c); if (xiic_rx_space(i2c) == 0) { + xiic_smbus_trim_len(i2c); + /* this is the last part of the message */ i2c->rx_msg = NULL; @@ -866,8 +890,11 @@ static irqreturn_t xiic_process(int irq, void *dev_id) if (i2c->tx_msg && i2c->smbus_block_read) { i2c->smbus_block_read = false; - /* Set requested message len=1 to indicate STATE_DONE */ - i2c->tx_msg->len = 1; + /* + * Drive xiic_tx_space() to 0 to signal STATE_DONE + * without truncating the rx_msg length. + */ + i2c->tx_pos = i2c->tx_msg->len; } if (!i2c->tx_msg) @@ -939,6 +966,7 @@ static void xiic_recv_atomic(struct xiic_i2c *i2c) return; } + xiic_smbus_trim_len(i2c); i2c->rx_msg = NULL; xiic_irq_clr_en(i2c, XIIC_INTR_TX_ERROR_MASK); @@ -956,6 +984,9 @@ static void xiic_start_recv(struct xiic_i2c *i2c) u8 cr = 0, rfd_set = 0; struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg; + /* A stale value from an aborted block read would truncate this msg. */ + i2c->smbus_actual_len = 0; + if (!i2c->atomic) dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n", __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), diff --git a/drivers/iio/accel/kionix-kx022a.c b/drivers/iio/accel/kionix-kx022a.c index 39485572a76b..8caa6551d2db 100644 --- a/drivers/iio/accel/kionix-kx022a.c +++ b/drivers/iio/accel/kionix-kx022a.c @@ -649,7 +649,7 @@ static int kx022a_read_raw(struct iio_dev *idev, if (ret) return ret; - if ((regval & KX022A_MASK_ODR) > + if ((regval & KX022A_MASK_ODR) >= ARRAY_SIZE(kx022a_accel_samp_freq_table)) { dev_err(data->dev, "Invalid ODR\n"); return -EINVAL; @@ -980,26 +980,44 @@ static int kx022a_fifo_enable(struct kx022a_data *data) guard(mutex)(&data->mutex); ret = __kx022a_turn_on_off(data, false); if (ret) - return ret; + goto err_free_out; /* Update watermark to HW */ ret = kx022a_fifo_set_wmi(data); if (ret) - return ret; + goto err_turn_on_out; /* Enable buffer */ ret = regmap_set_bits(data->regmap, data->chip_info->buf_cntl2, KX022A_MASK_BUF_EN); if (ret) - return ret; + goto err_turn_on_out; data->state |= KX022A_STATE_FIFO; ret = regmap_set_bits(data->regmap, data->ien_reg, KX022A_MASK_WMI); if (ret) - return ret; + goto err_buf_disable_out; - return __kx022a_turn_on_off(data, true); + ret = __kx022a_turn_on_off(data, true); + if (ret) + goto err_wmi_clear_out; + + return ret; + +err_wmi_clear_out: + regmap_clear_bits(data->regmap, data->ien_reg, + KX022A_MASK_WMI); +err_buf_disable_out: + regmap_clear_bits(data->regmap, data->chip_info->buf_cntl2, + KX022A_MASK_BUF_EN); + data->state &= ~KX022A_STATE_FIFO; +err_turn_on_out: + __kx022a_turn_on_off(data, true); +err_free_out: + kfree(data->fifo_buffer); + + return ret; } static int kx022a_buffer_postenable(struct iio_dev *idev) diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 2823ddde4bf2..297853cd39e5 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1031,7 +1031,7 @@ static int kxcjk1013_write_event_config(struct iio_dev *indio_dev, struct kxcjk1013_data *data = iio_priv(indio_dev); int ret; - if (state && data->ev_enable_state) + if (state == data->ev_enable_state) return 0; mutex_lock(&data->mutex); diff --git a/drivers/iio/accel/sca3000.c b/drivers/iio/accel/sca3000.c index 9ef4d6e27466..f858720b3912 100644 --- a/drivers/iio/accel/sca3000.c +++ b/drivers/iio/accel/sca3000.c @@ -647,7 +647,7 @@ static int sca3000_write_raw_samp_freq(struct sca3000_state *st, int val) if (val == base_freq / 2) ctrlval |= SCA3000_REG_OUT_CTRL_BUF_DIV_2; - if (val == base_freq / 4) + else if (val == base_freq / 4) ctrlval |= SCA3000_REG_OUT_CTRL_BUF_DIV_4; else if (val != base_freq) return -EINVAL; diff --git a/drivers/iio/adc/ad4030.c b/drivers/iio/adc/ad4030.c index d8bee6a4215a..b7cb589168c3 100644 --- a/drivers/iio/adc/ad4030.c +++ b/drivers/iio/adc/ad4030.c @@ -232,10 +232,16 @@ struct ad4030_state { .num_ext_scan_type = ARRAY_SIZE(_scan_type), \ } +/* + * AD4030 can average over 2^N samples, where N = 1, 2, 3, ..., 16. + * We use N = 0 to mean no sample averaging. + */ static const int ad4030_average_modes[] = { - 1, 2, 4, 8, 16, 32, 64, 128, - 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, - 65536, + BIT(0), /* No sampling average */ + BIT(1), BIT(2), BIT(3), BIT(4), + BIT(5), BIT(6), BIT(7), BIT(8), + BIT(9), BIT(10), BIT(11), BIT(12), + BIT(13), BIT(14), BIT(15), BIT(16), }; static int ad4030_enter_config_mode(struct ad4030_state *st) @@ -508,13 +514,20 @@ static int ad4030_set_chan_calibbias(struct iio_dev *indio_dev, static int ad4030_set_avg_frame_len(struct iio_dev *dev, int avg_val) { struct ad4030_state *st = iio_priv(dev); - unsigned int avg_log2 = ilog2(avg_val); unsigned int last_avg_idx = ARRAY_SIZE(ad4030_average_modes) - 1; + unsigned int avg_log2; int ret; - if (avg_val < 0 || avg_val > ad4030_average_modes[last_avg_idx]) + /* Reject unsupported modes */ + if (avg_val > ad4030_average_modes[last_avg_idx]) return -EINVAL; + /* Avoid invalid values for logarithm since it's undefined */ + if (avg_val < 1) + return -EINVAL; + + avg_log2 = ilog2(avg_val); + ret = regmap_write(st->regmap, AD4030_REG_AVG, AD4030_REG_AVG_MASK_AVG_SYNC | FIELD_PREP(AD4030_REG_AVG_MASK_AVG_VAL, avg_log2)); diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index d36612352b44..5a340327d0d8 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -776,9 +776,9 @@ static int ad7173_load_config(struct ad7173_state *st, return ad_sd_write_reg(&st->sd, AD7173_REG_FILTER(free_cfg_slot), 2, FIELD_PREP(AD7173_FILTER_SINC3_MAP, 0) | - FIELD_PREP(AD7173_FILTER_ENHFILT_MASK, - post_filter_enable) | FIELD_PREP(AD7173_FILTER_ENHFILTEN, + post_filter_enable) | + FIELD_PREP(AD7173_FILTER_ENHFILT_MASK, post_filter_select) | FIELD_PREP(AD7173_FILTER_ORDER, 0) | FIELD_PREP(AD7173_FILTER_ODR_MASK, diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index e2cf5f913670..f5c42f28ad0f 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -496,7 +496,6 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) const struct iio_scan_type *scan_type = &indio_dev->channels[0].scan_type; struct spi_transfer *xfer = sigma_delta->sample_xfer; unsigned int i, slot, channel; - u8 *samples_buf; int ret; if (sigma_delta->num_slots == 1) { @@ -528,7 +527,7 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) xfer[1].bits_per_word = scan_type->realbits; xfer[1].len = spi_bpw_to_bytes(scan_type->realbits); } else { - unsigned int samples_buf_size, scan_size; + unsigned int scan_size; if (sigma_delta->active_slots > 1) { ret = ad_sigma_delta_append_status(sigma_delta, true); @@ -536,17 +535,6 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) return ret; } - samples_buf_size = - ALIGN(slot * BITS_TO_BYTES(scan_type->storagebits), - sizeof(s64)); - samples_buf_size += sizeof(s64); - samples_buf = devm_krealloc(&sigma_delta->spi->dev, - sigma_delta->samples_buf, - samples_buf_size, GFP_KERNEL); - if (!samples_buf) - return -ENOMEM; - - sigma_delta->samples_buf = samples_buf; scan_size = BITS_TO_BYTES(scan_type->realbits + scan_type->shift); /* For 24-bit data, there is an extra byte of padding. */ xfer[1].rx_buf = &sigma_delta->rx_buf[scan_size == 3 ? 1 : 0]; @@ -853,6 +841,23 @@ int devm_ad_sd_setup_buffer_and_trigger(struct device *dev, struct iio_dev *indi indio_dev->setup_ops = &ad_sd_buffer_setup_ops; } else { + const struct iio_scan_type *scan_type = + &indio_dev->channels[0].scan_type; + unsigned int samples_buf_size; + + /* + * Worst-case size: all sequencer slots can be active, capped + * at num_slots by ad_sd_validate_scan_mask(). + */ + samples_buf_size = + ALIGN(sigma_delta->num_slots * + BITS_TO_BYTES(scan_type->storagebits), + sizeof(s64)); + samples_buf_size += sizeof(s64); + sigma_delta->samples_buf = devm_kzalloc(dev, samples_buf_size, GFP_KERNEL); + if (!sigma_delta->samples_buf) + return -ENOMEM; + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, &iio_pollfunc_store_time, &ad_sd_trigger_handler, diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c index f87fa64562eb..b8a908664b8e 100644 --- a/drivers/iio/adc/ade9000.c +++ b/drivers/iio/adc/ade9000.c @@ -222,7 +222,7 @@ (ADE9000_ST1_ERROR0 | ADE9000_ST1_ERROR1 | \ ADE9000_ST1_ERROR2 | ADE9000_ST1_ERROR3) #define ADE9000_ST1_CROSSING_FIRST 6 -#define ADE9000_ST1_CROSSING_DEPTH 25 +#define ADE9000_ST1_CROSSING_DEPTH 26 #define ADE9000_WFB_TRG_DIP_BIT BIT(0) #define ADE9000_WFB_TRG_SWELL_BIT BIT(1) @@ -448,7 +448,7 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = { BIT(IIO_CHAN_INFO_CALIBSCALE), \ .event_spec = ade9000_current_events, \ .num_event_specs = ARRAY_SIZE(ade9000_current_events), \ - .scan_index = num, \ + .scan_index = num * 2, \ .indexed = 1, \ .scan_type = { \ .sign = 's', \ @@ -468,7 +468,7 @@ static const struct iio_chan_spec_ext_info ade9000_ext_info[] = { BIT(IIO_CHAN_INFO_FREQUENCY), \ .event_spec = ade9000_voltage_events, \ .num_event_specs = ARRAY_SIZE(ade9000_voltage_events), \ - .scan_index = num + 1, /* interleave with current channels */ \ + .scan_index = num * 2 + 1, /* interleave with current channels */ \ .indexed = 1, \ .scan_type = { \ .sign = 's', \ @@ -1652,8 +1652,9 @@ static int ade9000_setup_clkout(struct device *dev, struct ade9000_state *st) return 0; /* CLKOUT passes through CLKIN with divider of 1 */ - clkout_hw = devm_clk_hw_register_divider(dev, "clkout", __clk_get_name(st->clkin), - CLK_SET_RATE_PARENT, NULL, 0, 1, 0, NULL); + clkout_hw = devm_clk_hw_register_fixed_factor(dev, "clkout", + __clk_get_name(st->clkin), + CLK_SET_RATE_PARENT, 1, 1); if (IS_ERR(clkout_hw)) return dev_err_probe(dev, PTR_ERR(clkout_hw), "Failed to register clkout"); @@ -1710,18 +1711,6 @@ static int ade9000_probe(struct spi_device *spi) if (ret) return ret; - ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev); - if (ret) - return ret; - - ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev); - if (ret) - return ret; - - ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev); - if (ret) - return ret; - /* External CMOS clock input (optional - crystal can be used instead) */ st->clkin = devm_clk_get_optional_enabled(dev, NULL); if (IS_ERR(st->clkin)) @@ -1741,6 +1730,19 @@ static int ade9000_probe(struct spi_device *spi) return dev_err_probe(&spi->dev, ret, "Failed to get and enable vdd regulator\n"); + /* Request IRQs only after powering the chip; the handlers do SPI access. */ + ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev); + if (ret) + return ret; + + ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev); + if (ret) + return ret; + + ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev); + if (ret) + return ret; + indio_dev->channels = ade9000_channels; indio_dev->num_channels = ARRAY_SIZE(ade9000_channels); diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index 61f7a07f501f..2945e7ea0ae2 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -704,34 +704,38 @@ static const struct iio_backend_info axi_ad408x = { static int adi_axi_adc_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct adi_axi_adc_state *st; void __iomem *base; unsigned int ver; struct clk *clk; int ret; - st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL); + st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); if (!st) return -ENOMEM; + ret = devm_mutex_init(dev, &st->lock); + if (ret) + return ret; + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); - st->dev = &pdev->dev; - st->regmap = devm_regmap_init_mmio(&pdev->dev, base, - &axi_adc_regmap_config); + st->dev = dev; + st->regmap = devm_regmap_init_mmio(dev, base, &axi_adc_regmap_config); if (IS_ERR(st->regmap)) - return dev_err_probe(&pdev->dev, PTR_ERR(st->regmap), + return dev_err_probe(dev, PTR_ERR(st->regmap), "failed to init register map\n"); - st->info = device_get_match_data(&pdev->dev); + st->info = device_get_match_data(dev); if (!st->info) return -ENODEV; - clk = devm_clk_get_enabled(&pdev->dev, NULL); + clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(clk)) - return dev_err_probe(&pdev->dev, PTR_ERR(clk), + return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n"); /* @@ -746,47 +750,42 @@ static int adi_axi_adc_probe(struct platform_device *pdev) if (ret) return ret; - if (ADI_AXI_PCORE_VER_MAJOR(ver) != - ADI_AXI_PCORE_VER_MAJOR(st->info->version)) { - dev_err(&pdev->dev, - "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", - ADI_AXI_PCORE_VER_MAJOR(st->info->version), - ADI_AXI_PCORE_VER_MINOR(st->info->version), - ADI_AXI_PCORE_VER_PATCH(st->info->version), - ADI_AXI_PCORE_VER_MAJOR(ver), - ADI_AXI_PCORE_VER_MINOR(ver), - ADI_AXI_PCORE_VER_PATCH(ver)); - return -ENODEV; - } - - ret = devm_iio_backend_register(&pdev->dev, st->info->backend_info, st); + if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(st->info->version)) + return dev_err_probe(dev, -ENODEV, + "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", + ADI_AXI_PCORE_VER_MAJOR(st->info->version), + ADI_AXI_PCORE_VER_MINOR(st->info->version), + ADI_AXI_PCORE_VER_PATCH(st->info->version), + ADI_AXI_PCORE_VER_MAJOR(ver), + ADI_AXI_PCORE_VER_MINOR(ver), + ADI_AXI_PCORE_VER_PATCH(ver)); + + ret = devm_iio_backend_register(dev, st->info->backend_info, st); if (ret) - return dev_err_probe(&pdev->dev, ret, - "failed to register iio backend\n"); + return dev_err_probe(dev, ret, "failed to register iio backend\n"); - device_for_each_child_node_scoped(&pdev->dev, child) { + device_for_each_child_node_scoped(dev, child) { int val; if (!st->info->has_child_nodes) - return dev_err_probe(&pdev->dev, -EINVAL, + return dev_err_probe(dev, -EINVAL, "invalid fdt axi-dac compatible."); /* Processing only reg 0 node */ ret = fwnode_property_read_u32(child, "reg", &val); if (ret) - return dev_err_probe(&pdev->dev, ret, - "invalid reg property."); + return dev_err_probe(dev, ret, "invalid reg property."); if (val != 0) - return dev_err_probe(&pdev->dev, -EINVAL, + return dev_err_probe(dev, -EINVAL, "invalid node address."); ret = axi_adc_create_platform_device(st, child); if (ret) - return dev_err_probe(&pdev->dev, -EINVAL, + return dev_err_probe(dev, -EINVAL, "cannot create device."); } - dev_info(&pdev->dev, "AXI ADC IP core (%d.%.2d.%c) probed\n", + dev_info(dev, "AXI ADC IP core (%d.%.2d.%c) probed\n", ADI_AXI_PCORE_VER_MAJOR(ver), ADI_AXI_PCORE_VER_MINOR(ver), ADI_AXI_PCORE_VER_PATCH(ver)); diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c index 8ab29948214a..8039370e1cd2 100644 --- a/drivers/iio/adc/aspeed_adc.c +++ b/drivers/iio/adc/aspeed_adc.c @@ -536,12 +536,13 @@ static int aspeed_adc_probe(struct platform_device *pdev) return PTR_ERR(data->clk_scaler); data->rst = devm_reset_control_get_shared(&pdev->dev, NULL); - if (IS_ERR(data->rst)) { - dev_err(&pdev->dev, - "invalid or missing reset controller device tree entry"); - return PTR_ERR(data->rst); - } - reset_control_deassert(data->rst); + if (IS_ERR(data->rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(data->rst), + "invalid or missing reset controller device tree entry"); + + ret = reset_control_deassert(data->rst); + if (ret) + return ret; ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert, data->rst); diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c index c8283279c477..c98863d612ad 100644 --- a/drivers/iio/adc/axp288_adc.c +++ b/drivers/iio/adc/axp288_adc.c @@ -207,6 +207,14 @@ static const struct dmi_system_id axp288_adc_ts_bias_override[] = { }, .driver_data = (void *)(uintptr_t)AXP288_ADC_TS_BIAS_80UA, }, + { + /* Haier HV103H */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Haier"), + DMI_MATCH(DMI_PRODUCT_NAME, "HV103H"), + }, + .driver_data = (void *)(uintptr_t)AXP288_ADC_TS_BIAS_80UA, + }, { } }; diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 9dd547e62b6c..aa6236630273 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -407,6 +407,14 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev, data = rxbuf[0]; } + + /* + * Differential channels are bipolar and the device returns the sample + * in two's complement, so sign-extend it from the resolution bit. + */ + if (chan->differential) + data = sign_extend32(data, st->chip_info->bits - 1); + *val = data; return 0; diff --git a/drivers/iio/adc/pac1934.c b/drivers/iio/adc/pac1934.c index edaff72e9d79..1cee9a149300 100644 --- a/drivers/iio/adc/pac1934.c +++ b/drivers/iio/adc/pac1934.c @@ -1108,6 +1108,10 @@ static int pac1934_acpi_parse_channel_config(struct i2c_client *client, devm_kmemdup(dev, rez->package.elements[i].string.pointer, (size_t)rez->package.elements[i].string.length + 1, GFP_KERNEL); + if (!info->labels[idx]) { + ACPI_FREE(rez); + return -ENOMEM; + } info->labels[idx][rez->package.elements[i].string.length] = '\0'; info->shunts[idx] = rez->package.elements[i + 1].integer.value * 1000; info->active_channels[idx] = (info->shunts[idx] != 0); diff --git a/drivers/iio/adc/rohm-bd79124.c b/drivers/iio/adc/rohm-bd79124.c index 06c55c8da93f..b8856cca69f4 100644 --- a/drivers/iio/adc/rohm-bd79124.c +++ b/drivers/iio/adc/rohm-bd79124.c @@ -222,7 +222,7 @@ static int bd79124gpo_set_multiple(struct gpio_chip *gc, unsigned long *mask, if (ret) return ret; - if (all_gpos ^ *mask) { + if (*mask & ~all_gpos) { dev_dbg(data->dev, "Invalid mux config. Can't set value.\n"); return -EINVAL; @@ -403,6 +403,9 @@ static int bd79124_start_measurement(struct bd79124_data *data, int chan) /* See if already started */ ret = regmap_read(data->map, BD79124_REG_AUTO_CHANNELS, &val); + if (ret) + return ret; + if (val & BIT(chan)) return 0; @@ -442,11 +445,16 @@ static int bd79124_stop_measurement(struct bd79124_data *data, int chan) /* See if already stopped */ ret = regmap_read(data->map, BD79124_REG_AUTO_CHANNELS, &enabled_chans); + if (ret) + return ret; + if (!(enabled_chans & BIT(chan))) return 0; ret = regmap_clear_bits(data->map, BD79124_REG_SEQ_CFG, BD79124_MSK_SEQ_START); + if (ret) + return ret; /* Clear the channel from the measured channels */ enabled_chans &= ~BIT(chan); @@ -546,7 +554,7 @@ static int bd79124_enable_event(struct bd79124_data *data, return ret; if (dir == IIO_EV_DIR_RISING) { - limit = &data->alarm_f_limit[channel]; + limit = &data->alarm_r_limit[channel]; reg = BD79124_GET_HIGH_LIMIT_REG(channel); } else { limit = &data->alarm_f_limit[channel]; @@ -941,13 +949,13 @@ static int bd79124_chan_init(struct bd79124_data *data, int channel) { int ret; - ret = regmap_write(data->map, BD79124_GET_HIGH_LIMIT_REG(channel), - BD79124_HIGH_LIMIT_MAX); + ret = bd79124_write_int_to_reg(data, BD79124_GET_HIGH_LIMIT_REG(channel), + BD79124_HIGH_LIMIT_MAX); if (ret) return ret; - return regmap_write(data->map, BD79124_GET_LOW_LIMIT_REG(channel), - BD79124_LOW_LIMIT_MIN); + return bd79124_write_int_to_reg(data, BD79124_GET_LOW_LIMIT_REG(channel), + BD79124_LOW_LIMIT_MIN); } static int bd79124_get_gpio_pins(const struct iio_chan_spec *cs, int num_channels) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 2d7f88459c7c..dae35ab929b6 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1609,11 +1609,16 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, ret = stm32_adc_single_conv(indio_dev, chan, val); else ret = -EINVAL; + iio_device_release_direct(indio_dev); + if (ret < 0) + return ret; - if (mask == IIO_CHAN_INFO_PROCESSED) + if (mask == IIO_CHAN_INFO_PROCESSED) { + if (*val == 0) + return -EINVAL; *val = STM32_ADC_VREFINT_VOLTAGE * adc->vrefint.vrefint_cal / *val; + } - iio_device_release_direct(indio_dev); return ret; case IIO_CHAN_INFO_SCALE: @@ -2264,33 +2269,37 @@ static int stm32_adc_populate_int_ch(struct iio_dev *indio_dev, const char *ch_n for (i = 0; i < STM32_ADC_INT_CH_NB; i++) { if (!strncmp(stm32_adc_ic[i].name, ch_name, STM32_ADC_CH_SZ)) { + bool na; + /* Check internal channel availability */ switch (i) { case STM32_ADC_INT_CH_VDDCORE: - if (!adc->cfg->regs->or_vddcore.reg) - dev_warn(&indio_dev->dev, - "%s channel not available\n", ch_name); + na = !adc->cfg->regs->or_vddcore.reg; break; case STM32_ADC_INT_CH_VDDCPU: - if (!adc->cfg->regs->or_vddcpu.reg) - dev_warn(&indio_dev->dev, - "%s channel not available\n", ch_name); + na = !adc->cfg->regs->or_vddcpu.reg; break; case STM32_ADC_INT_CH_VDDQ_DDR: - if (!adc->cfg->regs->or_vddq_ddr.reg) - dev_warn(&indio_dev->dev, - "%s channel not available\n", ch_name); + na = !adc->cfg->regs->or_vddq_ddr.reg; break; case STM32_ADC_INT_CH_VREFINT: - if (!adc->cfg->regs->ccr_vref.reg) - dev_warn(&indio_dev->dev, - "%s channel not available\n", ch_name); + na = !adc->cfg->regs->ccr_vref.reg; break; case STM32_ADC_INT_CH_VBAT: - if (!adc->cfg->regs->ccr_vbat.reg) - dev_warn(&indio_dev->dev, - "%s channel not available\n", ch_name); + na = !adc->cfg->regs->ccr_vbat.reg; break; + default: + return -EINVAL; + } + + if (na) { + /* + * Channel label matches an internal STM32 ADC channel. + * Warn about it, as there's normally no restriction on the + * name but that's not among available internal channels. + */ + dev_warn(&indio_dev->dev, "no %s internal channel\n", ch_name); + return 0; } if (stm32_adc_ic[i].idx != STM32_ADC_INT_CH_VREFINT) { diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 479115ea50bf..c0ab6b427be4 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -638,10 +638,10 @@ static int sun4i_gpadc_probe(struct platform_device *pdev) * thermal because no thermal DT node is found. */ if (IS_ERR(info->tzd) && PTR_ERR(info->tzd) != -ENODEV) { - dev_err(&pdev->dev, - "could not register thermal sensor: %ld\n", - PTR_ERR(info->tzd)); - return PTR_ERR(info->tzd); + ret = dev_err_probe(&pdev->dev, + PTR_ERR(info->tzd), + "could not register thermal sensor\n"); + goto err_map; } } @@ -657,7 +657,6 @@ static int sun4i_gpadc_probe(struct platform_device *pdev) if (!info->no_irq && IS_ENABLED(CONFIG_THERMAL_OF)) iio_map_array_unregister(indio_dev); - pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); return ret; @@ -668,7 +667,6 @@ static void sun4i_gpadc_remove(struct platform_device *pdev) struct iio_dev *indio_dev = platform_get_drvdata(pdev); struct sun4i_gpadc_iio *info = iio_priv(indio_dev); - pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); if (!IS_ENABLED(CONFIG_THERMAL_OF)) diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 3980dfacbcd7..b1142bd12140 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1402,13 +1402,14 @@ static int xadc_probe(struct platform_device *pdev) } if (irq > 0) { - ret = devm_request_irq(dev, irq, xadc->ops->interrupt_handler, - 0, dev_name(dev), indio_dev); + /* Clear out any work queued by the interrupt */ + ret = devm_add_action_or_reset(dev, xadc_cancel_delayed_work, + &xadc->zynq_unmask_work); if (ret) return ret; - ret = devm_add_action_or_reset(dev, xadc_cancel_delayed_work, - &xadc->zynq_unmask_work); + ret = devm_request_irq(dev, irq, xadc->ops->interrupt_handler, + 0, dev_name(dev), indio_dev); if (ret) return ret; } diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 27dd56334345..9af6171a96fb 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -82,10 +82,13 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, dma_dir = DMA_MEM_TO_DEV; if (block->sg_table) { - sgl = block->sg_table->sgl; - nents = sg_nents_for_len(sgl, block->bytes_used); - if (nents < 0) - return nents; + /* + * Only the first sgt->nents entries carry a valid + * sg_dma_address()/sg_dma_len() pair as mapping the table may + * have coalesced entries, in which case nents is smaller than + * orig_nents. + */ + nents = block->sg_table->nents; vecs = kmalloc_array(nents, sizeof(*vecs), GFP_ATOMIC); if (!vecs) @@ -93,7 +96,8 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, len_total = block->bytes_used; - for (i = 0; i < nents; i++) { + sgl = block->sg_table->sgl; + for (i = 0; i < nents && len_total; i++) { vecs[i].addr = sg_dma_address(sgl); vecs[i].len = min(sg_dma_len(sgl), len_total); len_total -= vecs[i].len; @@ -101,6 +105,8 @@ static int iio_dmaengine_buffer_submit_block(struct iio_dma_buffer_queue *queue, sgl = sg_next(sgl); } + nents = i; + desc = dmaengine_prep_peripheral_dma_vec(dmaengine_buffer->chan, vecs, nents, dma_dir, DMA_PREP_INTERRUPT); diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c index 427d32e398b3..6b3d3209cf85 100644 --- a/drivers/iio/cdc/ad7150.c +++ b/drivers/iio/cdc/ad7150.c @@ -637,11 +637,13 @@ static const struct i2c_device_id ad7150_id[] = { MODULE_DEVICE_TABLE(i2c, ad7150_id); static const struct of_device_id ad7150_of_match[] = { - { "adi,ad7150" }, - { "adi,ad7151" }, - { "adi,ad7156" }, + { .compatible = "adi,ad7150" }, + { .compatible = "adi,ad7151" }, + { .compatible = "adi,ad7156" }, { } }; +MODULE_DEVICE_TABLE(of, ad7150_of_match); + static struct i2c_driver ad7150_driver = { .driver = { .name = "ad7150", diff --git a/drivers/iio/dac/rohm-bd79703.c b/drivers/iio/dac/rohm-bd79703.c index e91090e4a66d..68e66e7286d8 100644 --- a/drivers/iio/dac/rohm-bd79703.c +++ b/drivers/iio/dac/rohm-bd79703.c @@ -73,6 +73,9 @@ static int bd79703_write_raw(struct iio_dev *idev, { struct bd79703_data *data = iio_priv(idev); + if (mask != IIO_CHAN_INFO_RAW) + return -EINVAL; + if (val < 0 || val >= 1 << BD79703_DAC_BITS) return -EINVAL; diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c index 5cea2c988790..a758c978c977 100644 --- a/drivers/iio/frequency/admv1013.c +++ b/drivers/iio/frequency/admv1013.c @@ -196,7 +196,7 @@ static int admv1013_read_raw(struct iio_dev *indio_dev, switch (info) { case IIO_CHAN_INFO_CALIBBIAS: - switch (chan->channel) { + switch (chan->channel2) { case IIO_MOD_I: addr = ADMV1013_REG_OFFSET_ADJUST_I; break; @@ -604,11 +604,14 @@ static int admv1013_probe(struct spi_device *spi) "failed to get the LO input clock\n"); st->nb.notifier_call = admv1013_freq_change; - ret = devm_clk_notifier_register(dev, st->clkin, &st->nb); + + ret = devm_mutex_init(dev, &st->lock); if (ret) return ret; - mutex_init(&st->lock); + ret = devm_clk_notifier_register(dev, st->clkin, &st->nb); + if (ret) + return ret; ret = admv1013_init(st, vcm_uv); if (ret) { diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index 369c7428e1ef..adcf54b67a28 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -145,7 +145,7 @@ static int adis16136_debugfs_init(struct iio_dev *indio_dev) struct adis16136 *adis16136 = iio_priv(indio_dev); struct dentry *d = iio_get_debugfs_dentry(indio_dev); - debugfs_create_file_unsafe("serial_number", 0400, + debugfs_create_file("serial_number", 0400, d, adis16136, &adis16136_serial_fops); debugfs_create_file_unsafe("product_id", 0400, d, adis16136, &adis16136_product_id_fops); diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index a48c0881a4c7..ddbeccd23088 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -291,9 +291,15 @@ static irqreturn_t max30102_interrupt_handler(int irq, void *private) { struct iio_dev *indio_dev = private; struct max30102_data *data = iio_priv(indio_dev); - unsigned int measurements = bitmap_weight(indio_dev->active_scan_mask, - iio_get_masklength(indio_dev)); - int ret, cnt = 0; + unsigned int measurements; + int ret, cnt; + + cnt = max30102_fifo_count(data); + if (cnt <= 0) + return IRQ_HANDLED; + + measurements = bitmap_weight(indio_dev->active_scan_mask, + iio_get_masklength(indio_dev)); mutex_lock(&data->lock); diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 36323ad149e0..7e85c1b8dc16 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -280,7 +280,7 @@ static void adis16400_debugfs_init(struct iio_dev *indio_dev) return; if (st->variant->flags & ADIS16400_HAS_SERIAL_NUMBER) - debugfs_create_file_unsafe("serial_number", 0400, + debugfs_create_file("serial_number", 0400, d, st, &adis16400_serial_number_fops); if (st->variant->flags & ADIS16400_HAS_PROD_ID) debugfs_create_file_unsafe("product_id", 0400, diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 543d5c4bfb11..d20455816e7d 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -310,9 +310,9 @@ static void adis16480_debugfs_init(struct iio_dev *indio_dev) if (!IS_ENABLED(CONFIG_DEBUG_FS)) return; - debugfs_create_file_unsafe("firmware_revision", 0400, + debugfs_create_file("firmware_revision", 0400, d, adis16480, &adis16480_firmware_revision_fops); - debugfs_create_file_unsafe("firmware_date", 0400, + debugfs_create_file("firmware_date", 0400, d, adis16480, &adis16480_firmware_date_fops); debugfs_create_file_unsafe("serial_number", 0400, d, adis16480, &adis16480_serial_number_fops); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 7d3a8f92d064..f38d9fdaf115 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -1355,6 +1355,10 @@ EXPORT_SYMBOL_GPL(iio_update_buffers); void iio_disable_all_buffers(struct iio_dev *indio_dev) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + + guard(mutex)(&iio_dev_opaque->mlock); + iio_disable_buffers(indio_dev); iio_buffer_deactivate_all(indio_dev); } @@ -2434,7 +2438,8 @@ int iio_push_to_buffers_with_ts_unaligned(struct iio_dev *indio_dev, bb = devm_krealloc(&indio_dev->dev, iio_dev_opaque->bounce_buffer, - indio_dev->scan_bytes, GFP_KERNEL); + indio_dev->scan_bytes, + GFP_KERNEL | __GFP_ZERO); if (!bb) return -ENOMEM; iio_dev_opaque->bounce_buffer = bb; diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 54416a384232..68e92eac2b77 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -509,6 +509,8 @@ static void iio_trig_release(struct device *device) struct iio_trigger *trig = to_iio_trigger(device); int i; + cancel_work_sync(&trig->reenable_work); + if (trig->subirq_base) { for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) { irq_modify_status(trig->subirq_base + i, diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index c7df4b258e2c..20d1aa9e99d7 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1560,6 +1560,7 @@ static int gp2ap020a00f_probe(struct i2c_client *client) iio_trigger_unregister(data->trig); error_free_irq: free_irq(client->irq, indio_dev); + irq_work_sync(&data->work); error_uninit_buffer: iio_triggered_buffer_cleanup(indio_dev); error_regulator_disable: @@ -1582,6 +1583,7 @@ static void gp2ap020a00f_remove(struct i2c_client *client) iio_device_unregister(indio_dev); iio_trigger_unregister(data->trig); free_irq(client->irq, indio_dev); + irq_work_sync(&data->work); iio_triggered_buffer_cleanup(indio_dev); regulator_disable(data->vled_reg); } diff --git a/drivers/iio/light/rohm-bu27034.c b/drivers/iio/light/rohm-bu27034.c index 28d111ac8c0a..92fca33387bb 100644 --- a/drivers/iio/light/rohm-bu27034.c +++ b/drivers/iio/light/rohm-bu27034.c @@ -137,6 +137,7 @@ static const struct iio_gain_sel_pair bu27034_gains[] = { #define BU27034_MEAS_MODE_200MS 2 #define BU27034_MEAS_MODE_400MS 4 +#define BU27034_INT_TIME_US_MIN (55 * USEC_PER_MSEC) static const struct iio_itime_sel_mul bu27034_itimes[] = { GAIN_SCALE_ITIME_US(400000, BU27034_MEAS_MODE_400MS, 8), GAIN_SCALE_ITIME_US(200000, BU27034_MEAS_MODE_200MS, 4), @@ -296,7 +297,7 @@ static int bu27034_get_gain(struct bu27034_data *data, int chan, int *gain) return 0; } -static int bu27034_get_int_time(struct bu27034_data *data) +static int bu27034_get_int_time(struct bu27034_data *data, int *itime) { int ret, sel; @@ -304,24 +305,30 @@ static int bu27034_get_int_time(struct bu27034_data *data) if (ret) return ret; - return iio_gts_find_int_time_by_sel(&data->gts, - sel & BU27034_MASK_MEAS_MODE); + ret = iio_gts_find_int_time_by_sel(&data->gts, + sel & BU27034_MASK_MEAS_MODE); + if (ret < 0) + return ret; + + *itime = ret; + + return 0; } static int _bu27034_get_scale(struct bu27034_data *data, int channel, int *val, int *val2) { - int gain, ret; + int gain, itime, ret; ret = bu27034_get_gain(data, channel, &gain); if (ret) return ret; - ret = bu27034_get_int_time(data); - if (ret < 0) + ret = bu27034_get_int_time(data, &itime); + if (ret) return ret; - return iio_gts_get_scale(&data->gts, gain, ret, val, val2); + return iio_gts_get_scale(&data->gts, gain, itime, val, val2); } static int bu27034_get_scale(struct bu27034_data *data, int channel, int *val, @@ -397,12 +404,10 @@ static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us) int ret, int_time_old, i; guard(mutex)(&data->mutex); - ret = bu27034_get_int_time(data); - if (ret < 0) + ret = bu27034_get_int_time(data, &int_time_old); + if (ret) return ret; - int_time_old = ret; - if (!iio_gts_valid_time(&data->gts, time_us)) { dev_err(data->dev, "Unsupported integration time %u\n", time_us); @@ -415,7 +420,7 @@ static int bu27034_try_set_int_time(struct bu27034_data *data, int time_us) for (i = 0; i < numg; i++) { ret = bu27034_get_gain(data, gains[i].chan, &gains[i].old_gain); if (ret) - return 0; + return ret; ret = iio_gts_find_new_gain_by_old_gain_time(&data->gts, gains[i].old_gain, @@ -841,7 +846,7 @@ static int bu27034_meas_set(struct bu27034_data *data, bool en) static int bu27034_get_single_result(struct bu27034_data *data, int chan, int *val) { - int ret; + int ret, itime; if (chan < BU27034_CHAN_DATA0 || chan > BU27034_CHAN_DATA1) return -EINVAL; @@ -850,11 +855,11 @@ static int bu27034_get_single_result(struct bu27034_data *data, int chan, if (ret) return ret; - ret = bu27034_get_int_time(data); - if (ret < 0) + ret = bu27034_get_int_time(data, &itime); + if (ret) return ret; - msleep(ret / 1000); + msleep(itime / 1000); return bu27034_read_result(data, chan, val); } @@ -904,12 +909,10 @@ static int bu27034_calc_mlux(struct bu27034_data *data, __le16 *res, int *val) if (ret) return ret; - ret = bu27034_get_int_time(data); - if (ret < 0) + ret = bu27034_get_int_time(data, &meastime); + if (ret) return ret; - meastime = ret; - d1_d0_ratio_scaled = (unsigned int)ch1 * (unsigned int)gain0 * 100; helper64 = (u64)ch1 * (u64)gain0 * 100LLU; @@ -970,9 +973,9 @@ static int bu27034_read_raw(struct iio_dev *idev, switch (mask) { case IIO_CHAN_INFO_INT_TIME: *val = 0; - *val2 = bu27034_get_int_time(data); - if (*val2 < 0) - return *val2; + ret = bu27034_get_int_time(data, val2); + if (ret) + return ret; return IIO_VAL_INT_PLUS_MICRO; @@ -1157,11 +1160,20 @@ static int bu27034_buffer_thread(void *arg) { struct iio_dev *idev = arg; struct bu27034_data *data; - int wait_ms; + int wait_ms, ret; data = iio_priv(idev); - wait_ms = bu27034_get_int_time(data); + /* + * If reading the integration time fails, default to the minimum so we + * don't lose samples. This may waste CPU cycles, but as a hardening + * against theoretical, once-in-a-blue-moon error, this should be Ok. + */ + wait_ms = BU27034_INT_TIME_US_MIN; + ret = bu27034_get_int_time(data, &wait_ms); + if (ret) + dev_warn(data->dev, "Failed to get integration time\n"); + wait_ms /= 1000; wait_ms -= BU27034_MEAS_WAIT_PREMATURE_MS; diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 0ebe0b682caa..c7b90df021d6 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -836,7 +836,7 @@ static int bmp280_write_sampling_frequency(struct bmp280_data *data, int val, int val2) { const int (*avail)[2] = data->chip_info->sampling_freq_avail; - const int n = data->chip_info->num_sampling_freq_avail; + const int n = data->chip_info->num_sampling_freq_avail / 2; int ret, prev; int i; diff --git a/drivers/iio/pressure/rohm-bm1390.c b/drivers/iio/pressure/rohm-bm1390.c index dac27fd359ad..3b48c1c86fd2 100644 --- a/drivers/iio/pressure/rohm-bm1390.c +++ b/drivers/iio/pressure/rohm-bm1390.c @@ -289,7 +289,7 @@ static int bm1390_read_data(struct bm1390_data *data, if (warn) dev_warn(data->dev, "Failed to stop measurement (%d)\n", warn); - return 0; + return ret; } static int bm1390_read_raw(struct iio_dev *idev, diff --git a/drivers/iio/proximity/aw96103.c b/drivers/iio/proximity/aw96103.c index 3472a2c36e44..b5c42e4743c6 100644 --- a/drivers/iio/proximity/aw96103.c +++ b/drivers/iio/proximity/aw96103.c @@ -24,6 +24,7 @@ #define AW96103_BIN_VALID_DATA_OFFSET 64 #define AW96103_BIN_DATA_LEN_OFFSET 16 #define AW96103_BIN_DATA_REG_NUM_SIZE 4 +#define AW96103_BIN_REG_SIZE 6 #define AW96103_BIN_CHIP_TYPE_SIZE 8 #define AW96103_BIN_CHIP_TYPE_OFFSET 24 @@ -229,14 +230,27 @@ static const struct aw_chip_info aw_chip_info_tbl[] = { }, }; -static void aw96103_parsing_bin_file(struct aw_bin *bin) +static int aw96103_parsing_bin_file(struct aw_bin *bin) { + u32 data_len; + + if (bin->len < AW96103_BIN_VALID_DATA_OFFSET) + return -EINVAL; + + data_len = get_unaligned_le32(bin->data + AW96103_BIN_DATA_LEN_OFFSET); + if (data_len < AW96103_BIN_DATA_REG_NUM_SIZE) + return -EINVAL; + + bin->valid_data_len = data_len - AW96103_BIN_DATA_REG_NUM_SIZE; + if (bin->valid_data_len > bin->len - AW96103_BIN_VALID_DATA_OFFSET || + bin->valid_data_len % AW96103_BIN_REG_SIZE) + return -EINVAL; + bin->valid_data_addr = AW96103_BIN_VALID_DATA_OFFSET; - bin->valid_data_len = - *(unsigned int *)(bin->data + AW96103_BIN_DATA_LEN_OFFSET) - - AW96103_BIN_DATA_REG_NUM_SIZE; memcpy(bin->chip_type, bin->data + AW96103_BIN_CHIP_TYPE_OFFSET, AW96103_BIN_CHIP_TYPE_SIZE); + + return 0; } static const struct regmap_config aw96103_regmap_confg = { @@ -500,7 +514,7 @@ static int aw96103_bin_valid_loaded(struct aw96103 *aw96103, int ret; for (i = 0; i < aw_bin_data_s->valid_data_len; - i += 6, start_addr += 6) { + i += AW96103_BIN_REG_SIZE, start_addr += AW96103_BIN_REG_SIZE) { reg_addr = get_unaligned_le16(aw_bin_data_s->data + start_addr); reg_data = get_unaligned_le32(aw_bin_data_s->data + start_addr + 2); @@ -550,6 +564,8 @@ static int aw96103_para_loaded(struct aw96103 *aw96103) static int aw96103_cfg_all_loaded(const struct firmware *cont, struct aw96103 *aw96103) { + int ret; + if (!cont) return -EINVAL; @@ -561,7 +577,9 @@ static int aw96103_cfg_all_loaded(const struct firmware *cont, aw_bin->len = cont->size; memcpy(aw_bin->data, cont->data, cont->size); release_firmware(cont); - aw96103_parsing_bin_file(aw_bin); + ret = aw96103_parsing_bin_file(aw_bin); + if (ret) + return ret; return aw96103_bin_valid_loaded(aw96103, aw_bin); } diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c index f69db6f2f380..ca6e0c2fb696 100644 --- a/drivers/iio/proximity/isl29501.c +++ b/drivers/iio/proximity/isl29501.c @@ -227,7 +227,7 @@ static int isl29501_register_read(struct isl29501_private *isl29501, return ret; } -static u32 isl29501_register_write(struct isl29501_private *isl29501, +static int isl29501_register_write(struct isl29501_private *isl29501, enum isl29501_register_name name, u32 value) { diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 21336b8f122a..993d3ad9bb08 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -295,12 +295,14 @@ static int lidar_probe(struct i2c_client *client) ret = pm_runtime_set_active(&client->dev); if (ret) - goto error_unreg_buffer; + goto error_unreg_dev; pm_runtime_enable(&client->dev); pm_runtime_idle(&client->dev); return 0; +error_unreg_dev: + iio_device_unregister(indio_dev); error_unreg_buffer: iio_triggered_buffer_cleanup(indio_dev); diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index c7b2d03c23bc..01aff1b584b7 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -223,7 +223,7 @@ static const struct iio_chan_spec_ext_info sx9324_channel_ext_info[] = { .scan_index = idx, \ .scan_type = { \ .sign = 's', \ - .realbits = 12, \ + .realbits = 16, \ .storagebits = 16, \ .endianness = IIO_BE, \ }, \ diff --git a/drivers/iio/proximity/vcnl3020.c b/drivers/iio/proximity/vcnl3020.c index 7f417372566a..d0b8f429999f 100644 --- a/drivers/iio/proximity/vcnl3020.c +++ b/drivers/iio/proximity/vcnl3020.c @@ -584,16 +584,26 @@ static irqreturn_t vcnl3020_handle_irq_thread(int irq, void *p) return IRQ_HANDLED; } - if (!(isr & VCNL_ICR_THRES_EN)) + if (!(isr & (VCNL_INT_TH_HI | VCNL_INT_TH_LOW))) return IRQ_NONE; - iio_push_event(indio_dev, - IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1, - IIO_EV_TYPE_THRESH, - IIO_EV_DIR_RISING), - iio_get_time_ns(indio_dev)); + if (isr & VCNL_INT_TH_HI) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(indio_dev)); + } + + if (isr & VCNL_INT_TH_LOW) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns(indio_dev)); + } - rc = regmap_write(data->regmap, VCNL_ISR, isr & VCNL_ICR_THRES_EN); + rc = regmap_write(data->regmap, VCNL_ISR, isr & (VCNL_INT_TH_HI | VCNL_INT_TH_LOW)); if (rc) dev_err(data->dev, "Error (%d) writing in reg (0x%x)\n", rc, VCNL_ISR); diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index 6c6e6dab045f..913ac191a187 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -221,7 +221,10 @@ static int vl53l0x_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: + if (!iio_device_claim_direct(indio_dev)) + return -EBUSY; ret = vl53l0x_read_proximity(data, chan, val); + iio_device_release_direct(indio_dev); if (ret < 0) return ret; diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 5facd6275c09..e4c80f185bf8 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -1967,6 +1967,14 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { }, .callback = atkbd_deactivate_fixup, }, + { + /* Lenovo IdeaPad Slim 3 15IWC11 (83RR) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83RR"), + }, + .callback = atkbd_deactivate_fixup, + }, { /* Xiaomi Book Pro 14 (TM2424) */ .matches = { diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 701377805dec..9e9bbdb16775 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -191,6 +191,7 @@ static const char * const smbus_pnp_ids[] = { "LEN2054", /* E480 */ "LEN2055", /* E580 */ "LEN2058", /* E490 */ + "LEN205b", /* T490 */ "LEN2068", /* T14 Gen 1 */ "SYN1221", /* TUXEDO InfinityBook Pro 14 v5 */ "SYN3003", /* HP EliteBook 850 G1 */ @@ -1838,8 +1839,10 @@ static int synaptics_setup_intertouch(struct psmouse *psmouse, return -ENXIO; } - /* Disable intertouch on known-broken board revisions */ - if (info->board_id == 2722) { + /* Disable intertouch on known-broken T440p board revisions */ + if (info->board_id == 2722 && + psmouse_matches_pnp_id(psmouse, + (const char * const []){"LEN0036", NULL})) { psmouse_info(psmouse, "Disabling intertouch for board id %u\n", info->board_id); diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h index ec364559d9e7..86cf413b0c49 100644 --- a/drivers/input/serio/i8042-acpipnpio.h +++ b/drivers/input/serio/i8042-acpipnpio.h @@ -670,6 +670,15 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { }, .driver_data = (void *)(SERIO_QUIRK_NOAUX) }, + { + /* Fujitsu LIFEBOOK U7410 */ + /* Mux mode also disturbs the EC keyboard, causing spurious ACKs */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU CLIENT COMPUTING LIMITED"), + DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U7410"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX) + }, { /* Gigabyte M912 */ .matches = { diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761.c index e1518a75a51b..8372a0de6c35 100644 --- a/drivers/input/touchscreen/s6sy761.c +++ b/drivers/input/touchscreen/s6sy761.c @@ -500,10 +500,22 @@ static int s6sy761_suspend(struct device *dev) static int s6sy761_resume(struct device *dev) { struct s6sy761_data *sdata = dev_get_drvdata(dev); + int err; + + err = s6sy761_power_on(sdata); + if (err) + return err; enable_irq(sdata->client->irq); - return s6sy761_power_on(sdata); + guard(mutex)(&sdata->input->mutex); + + if (!input_device_enabled(sdata->input)) + return 0; + + err = i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_ON); + + return err; } static const struct dev_pm_ops s6sy761_pm_ops = { diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index b06c8dd51562..a7e1de936d72 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -293,7 +293,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size, } size = bdev_nr_bytes(bdev); - if ((long)size % erase_size) { + if (!erase_size || (long)size % erase_size) { pr_err("erasesize must be a divisor of device size\n"); goto err_free_block2mtd; } diff --git a/drivers/mtd/devices/mtd_intel_dg.c b/drivers/mtd/devices/mtd_intel_dg.c index c9855d6f1f95..a28cf59c2886 100644 --- a/drivers/mtd/devices/mtd_intel_dg.c +++ b/drivers/mtd/devices/mtd_intel_dg.c @@ -387,7 +387,7 @@ idg_erase(struct intel_dg_nvm *nvm, u8 region, loff_t from, u64 len, u64 *fail_a void __iomem *base2 = nvm->base2; void __iomem *base = nvm->base; const u32 block = 0x10; - u32 iter = 0; + u32 iter; u32 reg; u64 i; @@ -396,6 +396,7 @@ idg_erase(struct intel_dg_nvm *nvm, u8 region, loff_t from, u64 len, u64 *fail_a iowrite32(region << 24 | block, base + NVM_ERASE_REG); if (nvm->non_posted_erase) { /* Wait for Erase Done */ + iter = 0; reg = ioread32(base2 + NVM_DEBUG_REG); while (!(reg & NVM_NON_POSTED_ERASE_DONE) && ++iter < NVM_NON_POSTED_ERASE_DONE_ITER) { diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 42cabd3c1efa..51c8ed489348 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1315,7 +1315,7 @@ int __get_mtd_device(struct mtd_info *mtd) int err; if (master->_get_device) { - err = master->_get_device(mtd); + err = master->_get_device(master); if (err) return err; } diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c index 54ed84dfc0be..5520f6f10898 100644 --- a/drivers/mtd/nand/raw/cadence-nand-controller.c +++ b/drivers/mtd/nand/raw/cadence-nand-controller.c @@ -2888,6 +2888,9 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl) goto free_buf_desc; } + spin_lock_init(&cdns_ctrl->irq_lock); + init_completion(&cdns_ctrl->complete); + if (devm_request_irq(cdns_ctrl->dev, cdns_ctrl->irq, cadence_nand_isr, IRQF_SHARED, "cadence-nand-controller", cdns_ctrl)) { @@ -2896,9 +2899,6 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl) goto free_buf; } - spin_lock_init(&cdns_ctrl->irq_lock); - init_completion(&cdns_ctrl->complete); - ret = cadence_nand_hw_init(cdns_ctrl); if (ret) goto disable_irq; diff --git a/drivers/mtd/nand/raw/vf610_nfc.c b/drivers/mtd/nand/raw/vf610_nfc.c index 4b5ba3187853..0f8f0337fde8 100644 --- a/drivers/mtd/nand/raw/vf610_nfc.c +++ b/drivers/mtd/nand/raw/vf610_nfc.c @@ -505,6 +505,11 @@ static int vf610_nfc_exec_op(struct nand_chip *chip, check_only); } +static unsigned int vf610_nfc_spare_size(struct mtd_info *mtd) +{ + return min_t(unsigned int, mtd->oobsize, 64); +} + static inline int vf610_nfc_correct_data(struct nand_chip *chip, uint8_t *dat, uint8_t *oob, int page) { @@ -514,6 +519,7 @@ static inline int vf610_nfc_correct_data(struct nand_chip *chip, uint8_t *dat, u8 ecc_status; u8 ecc_count; int flips_threshold = nfc->chip.ecc.strength / 2; + int ret; ecc_status = vf610_nfc_read(nfc, ecc_status_off) & 0xff; ecc_count = ecc_status & ECC_STATUS_ERR_COUNT; @@ -521,16 +527,22 @@ static inline int vf610_nfc_correct_data(struct nand_chip *chip, uint8_t *dat, if (!(ecc_status & ECC_STATUS_MASK)) return ecc_count; + /* The failed decode leaves a bogus correction in SRAM; re-read without ECC */ nfc->data_access = true; - nand_read_oob_op(&nfc->chip, page, 0, oob, mtd->oobsize); + ret = nand_read_page_op(&nfc->chip, page, 0, dat, mtd->writesize); + if (!ret) + ret = nand_read_oob_op(&nfc->chip, page, 0, oob, + vf610_nfc_spare_size(mtd)); nfc->data_access = false; + if (ret) + return ret; /* - * On an erased page, bit count (including OOB) should be zero or - * at least less then half of the ECC strength. + * Run the erased-page check with the driver's historic threshold + * of half the ECC strength. */ - return nand_check_erased_ecc_chunk(dat, nfc->chip.ecc.size, oob, - mtd->oobsize, NULL, 0, + return nand_check_erased_ecc_chunk(dat, mtd->writesize, oob, + vf610_nfc_spare_size(mtd), NULL, 0, flips_threshold); } @@ -551,7 +563,7 @@ static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf, { struct vf610_nfc *nfc = chip_to_nfc(chip); struct mtd_info *mtd = nand_to_mtd(chip); - int trfr_sz = mtd->writesize + mtd->oobsize; + int trfr_sz = mtd->writesize + vf610_nfc_spare_size(mtd); u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0; int stat; @@ -577,11 +589,16 @@ static int vf610_nfc_read_page(struct nand_chip *chip, uint8_t *buf, */ vf610_nfc_rd_from_sram(buf, nfc->regs + NFC_MAIN_AREA(0), mtd->writesize, false); - if (oob_required) + if (oob_required) { + unsigned int spare = vf610_nfc_spare_size(mtd); + vf610_nfc_rd_from_sram(chip->oob_poi, nfc->regs + NFC_MAIN_AREA(0) + mtd->writesize, - mtd->oobsize, false); + spare, false); + /* Not transferred, and never written: reads back erased */ + memset(chip->oob_poi + spare, 0xff, mtd->oobsize - spare); + } stat = vf610_nfc_correct_data(chip, buf, chip->oob_poi, page); @@ -599,7 +616,7 @@ static int vf610_nfc_write_page(struct nand_chip *chip, const uint8_t *buf, { struct vf610_nfc *nfc = chip_to_nfc(chip); struct mtd_info *mtd = nand_to_mtd(chip); - int trfr_sz = mtd->writesize + mtd->oobsize; + int trfr_sz = mtd->writesize + vf610_nfc_spare_size(mtd); u32 row = 0, cmd1 = 0, cmd2 = 0, code = 0; u8 status; int ret; @@ -740,6 +757,49 @@ static void vf610_nfc_init_controller(struct vf610_nfc *nfc) } } +/* + * With 64 byte OOB chips the core's large page layout matches what + * U-Boot uses, and on chips with more, U-Boot and older kernels clamped + * mtd->oobsize to 64. Modifying the OOB size is no longer possible, the + * actual chip geometry must be respected, so to avoid breaking those + * existing setups use our own layout: the core's large page one, + * computed over the first 64 spare bytes only. + */ +static int vf610_nfc_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + unsigned int total_ecc_bytes = nand->ecc.ctx.total; + + if (section || !total_ecc_bytes) + return -ERANGE; + + oobregion->length = total_ecc_bytes; + oobregion->offset = vf610_nfc_spare_size(mtd) - oobregion->length; + + return 0; +} + +static int vf610_nfc_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_device *nand = mtd_to_nanddev(mtd); + unsigned int total_ecc_bytes = nand->ecc.ctx.total; + + if (section) + return -ERANGE; + + oobregion->length = vf610_nfc_spare_size(mtd) - total_ecc_bytes - 2; + oobregion->offset = 2; + + return 0; +} + +static const struct mtd_ooblayout_ops vf610_nfc_ooblayout_ops = { + .ecc = vf610_nfc_ooblayout_ecc, + .free = vf610_nfc_ooblayout_free, +}; + static int vf610_nfc_attach_chip(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); @@ -770,12 +830,7 @@ static int vf610_nfc_attach_chip(struct nand_chip *chip) return -ENXIO; } - /* Only 64 byte ECC layouts known */ - if (mtd->oobsize > 64) - mtd->oobsize = 64; - - /* Use default large page ECC layout defined in NAND core */ - mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout()); + mtd_set_ooblayout(mtd, &vf610_nfc_ooblayout_ops); if (chip->ecc.strength == 32) { nfc->ecc_mode = ECC_60_BYTE; chip->ecc.bytes = 60; diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 2f656a5e4af8..d320f6a28bcc 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -180,8 +180,26 @@ static int spinand_init_cfg_cache(struct spinand_device *spinand) static int spinand_init_quad_enable(struct spinand_device *spinand, bool enable) { - return spinand_upd_cfg(spinand, CFG_QUAD_ENABLE, - enable ? CFG_QUAD_ENABLE : 0); + struct nand_device *nand = spinand_to_nand(spinand); + unsigned int target; + int ret; + + /* + * QE is a per-die setting on some devices. Program each target + * individually when enabling or disabling quad I/O mode. + */ + for (target = 0; target < nand->memorg.ntargets; target++) { + ret = spinand_select_target(spinand, target); + if (ret) + return ret; + + ret = spinand_upd_cfg(spinand, CFG_QUAD_ENABLE, + enable ? CFG_QUAD_ENABLE : 0); + if (ret) + return ret; + } + + return 0; } static int spinand_ecc_enable(struct spinand_device *spinand, @@ -1168,7 +1186,8 @@ static int spinand_create_dirmap(struct spinand_device *spinand, spinand->dirmaps[plane].rdesc = desc; - if (nand->ecc.engine->integration != NAND_ECC_ENGINE_INTEGRATION_PIPELINED) { + if (!nand->ecc.engine || + nand->ecc.engine->integration != NAND_ECC_ENGINE_INTEGRATION_PIPELINED) { spinand->dirmaps[plane].wdesc_ecc = spinand->dirmaps[plane].wdesc; spinand->dirmaps[plane].rdesc_ecc = spinand->dirmaps[plane].rdesc; @@ -1492,11 +1511,11 @@ static int spinand_configure_chip(struct spinand_device *spinand) spinand->ssdr_op_templates.write_cache->data.buswidth == 4 || spinand->ssdr_op_templates.update_cache->data.buswidth == 4) quad_enable = true; - } - ret = spinand_init_quad_enable(spinand, quad_enable); - if (ret) - return ret; + ret = spinand_init_quad_enable(spinand, quad_enable); + if (ret) + return ret; + } if (spinand->configure_chip) { ret = spinand->configure_chip(spinand, SSDR); @@ -1504,7 +1523,7 @@ static int spinand_configure_chip(struct spinand_device *spinand) return ret; } - return ret; + return 0; } static int spinand_init_flash(struct spinand_device *spinand) @@ -1645,12 +1664,17 @@ static int spinand_init(struct spinand_device *spinand) goto err_cleanup_ecc_engine; } - if (nand->ecc.engine) { - ret = mtd_ooblayout_count_freebytes(mtd); - if (ret < 0) - goto err_cleanup_ecc_engine; + if (!nand->ecc.engine) { + if (spinand->eccinfo.ooblayout) + mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout); + else + mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout); } + ret = mtd_ooblayout_count_freebytes(mtd); + if (ret < 0) + goto err_cleanup_ecc_engine; + mtd->oobavail = ret; /* Propagate ECC information to mtd_info */ diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 19dc13faf9fd..037407fc2e11 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1245,7 +1245,7 @@ static bool spi_nor_rww_start_exclusive(struct spi_nor *nor) { struct spi_nor_rww *rww = &nor->rww; - mutex_lock(&nor->lock); + guard(mutex)(&nor->lock); if (rww->ongoing_io || rww->ongoing_rd || rww->ongoing_pe) return false; diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index bc4e1f3b3752..ff2512b2fe7b 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -391,8 +391,10 @@ static void bcm_sysport_update_mib_counters(struct bcm_sysport_priv *priv) if (priv->is_lite) continue; - if (s->type != BCM_SYSPORT_STAT_MIB_RX) + if (s->type == BCM_SYSPORT_STAT_MIB_TX) offset = UMAC_MIB_STAT_OFFSET; + else if (s->type == BCM_SYSPORT_STAT_RUNT) + offset = 2 * UMAC_MIB_STAT_OFFSET; val = umac_readl(priv, UMAC_MIB_START + j + offset); break; case BCM_SYSPORT_STAT_RXCHK: @@ -482,10 +484,10 @@ static void bcm_sysport_get_stats(struct net_device *dev, s->type == BCM_SYSPORT_STAT_NETDEV64) { do { start = u64_stats_fetch_begin(syncp); - data[i] = *(u64 *)p; + data[j] = *(u64 *)p; } while (u64_stats_fetch_retry(syncp, start)); } else - data[i] = *(u32 *)p; + data[j] = *(u32 *)p; j++; } diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index a72e136fd9c3..5a891cf59f10 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -58,6 +58,9 @@ */ #define GENET_RSB_PAD (sizeof(struct status_64) + 2) +/* RX buffer plus the skb_shared_info napi_build_skb() places behind it */ +#define GENET_RX_BUF_SIZE SKB_HEAD_ALIGN(RX_BUF_LENGTH) + /* Tx/Rx DMA register offset, skip 256 descriptors */ #define WORDS_PER_BD(p) (p->hw_params->words_per_bd) #define DMA_DESC_SIZE (WORDS_PER_BD(priv) * sizeof(u32)) @@ -2250,11 +2253,12 @@ static int bcmgenet_rx_refill(struct bcmgenet_rx_ring *ring, struct enet_cb *cb) { struct bcmgenet_priv *priv = ring->priv; + unsigned int size = GENET_RX_BUF_SIZE; + unsigned int offset; dma_addr_t mapping; struct page *page; - page = page_pool_alloc_pages(ring->page_pool, - GFP_ATOMIC); + page = page_pool_dev_alloc(ring->page_pool, &offset, &size); if (!page) { priv->mib.alloc_rx_buff_failed++; netif_err(priv, rx_err, priv->dev, @@ -2263,9 +2267,13 @@ static int bcmgenet_rx_refill(struct bcmgenet_rx_ring *ring, } /* page_pool handles DMA mapping via PP_FLAG_DMA_MAP */ - mapping = page_pool_get_dma_addr(page); + mapping = page_pool_get_dma_addr(page) + offset; + dma_sync_single_for_device(&priv->pdev->dev, mapping, RX_BUF_LENGTH, + DMA_FROM_DEVICE); cb->rx_page = page; + cb->rx_offset = offset; + cb->rx_size = size; dmadesc_set_addr(priv, cb->bd_addr, mapping); return 0; @@ -2319,6 +2327,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, while ((rxpktprocessed < rxpkttoprocess) && (rxpktprocessed < budget)) { + unsigned int rx_offset, rx_size; struct status_64 *status; struct page *rx_page; void *hard_start; @@ -2328,6 +2337,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, /* Save the received page before refilling */ rx_page = cb->rx_page; + rx_offset = cb->rx_offset; + rx_size = cb->rx_size; if (bcmgenet_rx_refill(ring, cb)) { BCMGENET_STATS64_INC(stats, dropped); @@ -2337,10 +2348,10 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, /* Sync the full buffer; the HW may have written anywhere * up to RX_BUF_LENGTH. */ - page_pool_dma_sync_for_cpu(ring->page_pool, rx_page, 0, + page_pool_dma_sync_for_cpu(ring->page_pool, rx_page, rx_offset, RX_BUF_LENGTH); - hard_start = page_address(rx_page); + hard_start = page_address(rx_page) + rx_offset; status = (struct status_64 *)hard_start; dma_length_status = status->length_status; @@ -2406,7 +2417,7 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, /* Build SKB from the page - data starts at hard_start, * frame begins after RSB(64) + pad(2) = 66 bytes. */ - skb = napi_build_skb(hard_start, PAGE_SIZE); + skb = napi_build_skb(hard_start, rx_size); if (unlikely(!skb)) { BCMGENET_STATS64_INC(stats, dropped); page_pool_put_full_page(ring->page_pool, rx_page, @@ -2758,14 +2769,16 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, static int bcmgenet_rx_ring_create_pool(struct bcmgenet_priv *priv, struct bcmgenet_rx_ring *ring) { + /* Buffers share a page. bcmgenet_rx_refill() syncs each one for the + * device, PP_FLAG_DMA_SYNC_DEV would sync the whole page. + */ struct page_pool_params pp_params = { .order = 0, - .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, + .flags = PP_FLAG_DMA_MAP, .pool_size = ring->size, .nid = NUMA_NO_NODE, .dev = &priv->pdev->dev, .dma_dir = DMA_FROM_DEVICE, - .max_len = RX_BUF_LENGTH, }; int err; @@ -4143,8 +4156,11 @@ static int bcmgenet_probe(struct platform_device *pdev) netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1); /* Set default coalescing parameters */ - for (i = 0; i <= priv->hw_params->rx_queues; i++) + for (i = 0; i <= priv->hw_params->rx_queues; i++) { + priv->rx_rings[i].priv = priv; + priv->rx_rings[i].index = i; priv->rx_rings[i].rx_max_coalesced_frames = 1; + } /* Initialize u64 stats seq counter for 32bit machines */ for (i = 0; i <= GENET_MAX_MQ_CNT; i++) { diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 22a958ba9902..86f2aed20dbe 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -470,6 +470,8 @@ struct bcmgenet_rx_stats64 { struct enet_cb { struct sk_buff *skb; struct page *rx_page; + unsigned int rx_offset; + unsigned int rx_size; void __iomem *bd_addr; DEFINE_DMA_UNMAP_ADDR(dma_addr); DEFINE_DMA_UNMAP_LEN(dma_len); diff --git a/drivers/net/ethernet/google/gve/gve_tx_dqo.c b/drivers/net/ethernet/google/gve/gve_tx_dqo.c index b5565d0b197f..dad793c0a7c4 100644 --- a/drivers/net/ethernet/google/gve/gve_tx_dqo.c +++ b/drivers/net/ethernet/google/gve/gve_tx_dqo.c @@ -600,25 +600,25 @@ static int gve_prep_tso(struct sk_buff *skb) err = skb_cow_head(skb, 0); if (err < 0) return err; + shinfo = skb_shinfo(skb); l4_start = skb_transport_offset(skb); paylen = skb->len - l4_start; - switch (shinfo->gso_type) { - case SKB_GSO_TCPV4: - case SKB_GSO_TCPV6: + /* gso_type is a bitmask: SKB_GSO_DODGY, SKB_GSO_TCP_ECN and + * SKB_GSO_TCP_FIXEDID may be set alongside the protocol bit. + */ + if (shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { tcp = tcp_hdr(skb); csum_replace_by_diff(&tcp->check, (__force __wsum)htonl(paylen)); header_len = skb_tcp_all_headers(skb); - break; - case SKB_GSO_UDP_L4: + } else if (shinfo->gso_type & SKB_GSO_UDP_L4) { udp = udp_hdr(skb); csum_replace_by_diff(&udp->check, (__force __wsum)htonl(paylen)); header_len = sizeof(struct udphdr) + l4_start; - break; - default: + } else { return -EINVAL; } diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 2b66e238d61b..71ace291a8bf 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2340,7 +2340,7 @@ mvneta_swbm_rx_frame(struct mvneta_port *pp, /* Prefetch header */ prefetch(data); - xdp_buff_clear_frags_flag(xdp); + xdp_reinit_buff(xdp); xdp_prepare_buff(xdp, data, pp->rx_offset_correction + MVNETA_MH_SIZE, data_len, true); } diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mcs.c b/drivers/net/ethernet/marvell/octeontx2/af/mcs.c index 211c10aa5880..30c672d526a0 100644 --- a/drivers/net/ethernet/marvell/octeontx2/af/mcs.c +++ b/drivers/net/ethernet/marvell/octeontx2/af/mcs.c @@ -314,7 +314,7 @@ int mcs_clear_all_stats(struct mcs *mcs, u16 pcifunc, int dir) } /* Clear SC stats */ - for (id = 0; id < map->secy.max; id++) { + for (id = 0; id < map->sc.max; id++) { if (map->sc2pf_map[id] != pcifunc) continue; mcs_clear_stats(mcs, MCS_SC_STATS, id, dir); @@ -738,7 +738,7 @@ int mcs_free_all_rsrc(struct mcs *mcs, int dir, u16 pcifunc) } /* free sc entries */ - for (id = 0; id < map->secy.max; id++) { + for (id = 0; id < map->sc.max; id++) { if (map->sc2pf_map[id] != pcifunc) continue; mcs_free_rsrc(&map->sc, map->sc2pf_map, id, pcifunc); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index 83a51de89154..f27ec6d82e51 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -394,7 +394,7 @@ int otx2_rss_init(struct otx2_nic *pfvf) struct otx2_rss_info *rss = &pfvf->hw.rss_info; int idx, ret = 0; - rss->rss_size = sizeof(*rss->ind_tbl); + rss->rss_size = ARRAY_SIZE(rss->ind_tbl); /* Init RSS key if it is not setup already */ if (!rss->enable) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 3f43e487d887..162a17a87c7f 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -5337,6 +5337,22 @@ static int mtk_probe(struct platform_device *pdev) } } + /* we run 2 devices on the same DMA ring so we need a dummy device + * for NAPI to work. Allocate it before registering the netdevs so a + * concurrent ndo_open (e.g. netifd bringing the first netdev up the + * instant it is registered) never observes eth->dummy_dev == NULL in + * mtk_dma_init() -> mtk_rx_alloc() -> __xdp_rxq_info_reg() (net/core/xdp.c + * "Missing net_device from driver") and fails the first open. + */ + eth->dummy_dev = alloc_netdev_dummy(0); + if (!eth->dummy_dev) { + err = -ENOMEM; + dev_err(eth->dev, "failed to allocated dummy device\n"); + goto err_unreg_netdev; + } + netif_napi_add(eth->dummy_dev, ð->tx_napi, mtk_napi_tx); + netif_napi_add(eth->dummy_dev, ð->rx_napi, mtk_napi_rx); + for (i = 0; i < MTK_MAX_DEVS; i++) { if (!eth->netdev[i]) continue; @@ -5351,18 +5367,6 @@ static int mtk_probe(struct platform_device *pdev) eth->netdev[i]->base_addr, eth->irq[MTK_FE_IRQ_SHARED]); } - /* we run 2 devices on the same DMA ring so we need a dummy device - * for NAPI to work - */ - eth->dummy_dev = alloc_netdev_dummy(0); - if (!eth->dummy_dev) { - err = -ENOMEM; - dev_err(eth->dev, "failed to allocated dummy device\n"); - goto err_unreg_netdev; - } - netif_napi_add(eth->dummy_dev, ð->tx_napi, mtk_napi_tx); - netif_napi_add(eth->dummy_dev, ð->rx_napi, mtk_napi_rx); - platform_set_drvdata(pdev, eth); schedule_delayed_work(ð->reset.monitor_work, MTK_DMA_MONITOR_TIMEOUT); @@ -5372,6 +5376,16 @@ static int mtk_probe(struct platform_device *pdev) err_unreg_netdev: mtk_unreg_dev(eth); err_deinit_ppe: + /* A netdev opened while probe was still registering can have queued + * the frame-engine reset worker, which takes rtnl and drives the + * hardware; cancel it before anything below is torn down. + */ + cancel_work_sync(ð->pending_work); + if (eth->dummy_dev) { + netif_napi_del(ð->tx_napi); + netif_napi_del(ð->rx_napi); + free_netdev(eth->dummy_dev); + } mtk_ppe_deinit(eth); mtk_mdio_cleanup(eth); err_free_dev: diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c index 2f52e04b28de..bc21e27b8bf6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.c @@ -292,6 +292,9 @@ static u64 mlx5e_xsk_fill_timestamp(void *_priv) struct mlx5e_xsk_tx_complete *priv = _priv; u64 ts; + if (!priv->cqe) + return 0; + ts = get_cqe_ts(priv->cqe); if (mlx5_is_real_time_rq(priv->cq->mdev) || mlx5_is_real_time_sq(priv->cq->mdev)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index d20f9d3e30c7..353101dee4dc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -1333,9 +1333,11 @@ static int mlx5_handle_changeupper_event(struct mlx5_lag *ldev, } } if (i < MLX5_MAX_PORTS) { - slave = bond_slave_get_rcu(ndev_tmp); - if (slave) - has_inactive |= bond_is_slave_inactive(slave); + if (netif_is_bond_master(upper)) { + slave = bond_slave_get_rcu(ndev_tmp); + if (slave) + has_inactive |= bond_is_slave_inactive(slave); + } bond_status |= (1 << idx); } @@ -1419,7 +1421,7 @@ static int mlx5_handle_changeinfodata_event(struct mlx5_lag *ldev, bool has_inactive = 0; int idx; - if (!netif_is_lag_master(ndev)) + if (!netif_is_bond_master(ndev)) return 0; rcu_read_lock(); diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c index 049541eeaae0..d42c57bead89 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c @@ -1244,7 +1244,7 @@ const struct ethtool_ops sparx5_ethtool_ops = { .set_pauseparam = sparx5_set_pauseparam, }; -int sparx_stats_init(struct sparx5 *sparx5) +int sparx5_stats_init(struct sparx5 *sparx5) { const struct sparx5_consts *consts = sparx5->data->consts; char queue_name[32]; @@ -1278,3 +1278,10 @@ int sparx_stats_init(struct sparx5 *sparx5) return 0; } + +void sparx5_stats_deinit(struct sparx5 *sparx5) +{ + cancel_delayed_work_sync(&sparx5->stats_work); + destroy_workqueue(sparx5->stats_queue); + mutex_destroy(&sparx5->queue_stats_lock); +} diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c b/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c index f5584244612c..2bf9c5f64151 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_mactable.c @@ -419,7 +419,7 @@ static void sparx5_mact_handle_entry(struct sparx5 *sparx5, true); } -void sparx5_mact_pull_work(struct work_struct *work) +static void sparx5_mact_pull_work(struct work_struct *work) { struct delayed_work *del_work = to_delayed_work(work); struct sparx5 *sparx5 = container_of(del_work, struct sparx5, @@ -489,8 +489,10 @@ void sparx5_set_ageing(struct sparx5 *sparx5, int msecs) LRN_AUTOAGE_CFG(0)); } -void sparx5_mact_init(struct sparx5 *sparx5) +int sparx5_mact_init(struct sparx5 *sparx5) { + char queue_name[32]; + mutex_init(&sparx5->lock); /* Flush MAC table */ @@ -502,4 +504,32 @@ void sparx5_mact_init(struct sparx5 *sparx5) dev_warn(sparx5->dev, "MAC flush error\n"); sparx5_set_ageing(sparx5, BR_DEFAULT_AGEING_TIME / HZ * 1000); + + /* Add host mode BC address (points only to CPU) */ + sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU), + (unsigned char[]){0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + NULL_VID); + + mutex_init(&sparx5->mdb_lock); + INIT_LIST_HEAD(&sparx5->mdb_entries); + mutex_init(&sparx5->mact_lock); + INIT_LIST_HEAD(&sparx5->mact_entries); + snprintf(queue_name, sizeof(queue_name), "%s-mact", + dev_name(sparx5->dev)); + sparx5->mact_queue = create_singlethread_workqueue(queue_name); + if (!sparx5->mact_queue) + return -ENOMEM; + + INIT_DELAYED_WORK(&sparx5->mact_work, sparx5_mact_pull_work); + queue_delayed_work(sparx5->mact_queue, &sparx5->mact_work, + SPX5_MACT_PULL_DELAY); + + return 0; +} + +void sparx5_mact_deinit(struct sparx5 *sparx5) +{ + cancel_delayed_work_sync(&sparx5->mact_work); + destroy_workqueue(sparx5->mact_queue); + mutex_destroy(&sparx5->mact_lock); } diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c index 40b1bfc600a7..46837e7efbd0 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c @@ -683,10 +683,8 @@ static void sparx5_board_init(struct sparx5 *sparx5) static int sparx5_start(struct sparx5 *sparx5) { - u8 broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const struct sparx5_consts *consts = sparx5->data->consts; const struct sparx5_ops *ops = sparx5->data->ops; - char queue_name[32]; u32 idx; int err; @@ -726,19 +724,12 @@ static int sparx5_start(struct sparx5 *sparx5) ANA_CL_FILTER_CTRL_FORCE_FCS_UPDATE_ENA, sparx5, ANA_CL_FILTER_CTRL(idx)); - /* Init MAC table, ageing */ - sparx5_mact_init(sparx5); - /* Init PGID table arbitrator */ sparx5_pgid_init(sparx5); /* Setup VLANs */ sparx5_vlan_init(sparx5); - /* Add host mode BC address (points only to CPU) */ - sparx5_mact_learn(sparx5, sparx5_get_pgid(sparx5, PGID_CPU), broadcast, - NULL_VID); - /* Enable queue limitation watermarks */ sparx5_qlim_set(sparx5); @@ -750,41 +741,7 @@ static int sparx5_start(struct sparx5 *sparx5) if (err) return err; - /* Init stats */ - err = sparx_stats_init(sparx5); - if (err) - return err; - - /* Init mact_sw struct */ - mutex_init(&sparx5->mact_lock); - INIT_LIST_HEAD(&sparx5->mact_entries); - snprintf(queue_name, sizeof(queue_name), "%s-mact", - dev_name(sparx5->dev)); - sparx5->mact_queue = create_singlethread_workqueue(queue_name); - if (!sparx5->mact_queue) - return -ENOMEM; - - INIT_DELAYED_WORK(&sparx5->mact_work, sparx5_mact_pull_work); - queue_delayed_work(sparx5->mact_queue, &sparx5->mact_work, - SPX5_MACT_PULL_DELAY); - - mutex_init(&sparx5->mdb_lock); - INIT_LIST_HEAD(&sparx5->mdb_entries); - - err = sparx5_register_netdevs(sparx5); - if (err) - return err; - sparx5_board_init(sparx5); - err = sparx5_register_notifier_blocks(sparx5); - if (err) - return err; - - err = sparx5_vcap_init(sparx5); - if (err) { - sparx5_unregister_notifier_blocks(sparx5); - return err; - } /* Start Frame DMA with fallback to register based INJ/XTR */ err = -ENXIO; @@ -818,27 +775,9 @@ static int sparx5_start(struct sparx5 *sparx5) sparx5->xtr_irq = -ENXIO; } - if (sparx5->ptp_irq >= 0 && - sparx5_has_feature(sparx5, SPX5_FEATURE_PTP)) { - err = devm_request_threaded_irq(sparx5->dev, sparx5->ptp_irq, - NULL, ops->ptp_irq_handler, - IRQF_ONESHOT, "sparx5-ptp", - sparx5); - if (err) - sparx5->ptp_irq = -ENXIO; - - sparx5->ptp = 1; - } - return err; } -static void sparx5_cleanup_ports(struct sparx5 *sparx5) -{ - sparx5_unregister_netdevs(sparx5); - sparx5_destroy_netdevs(sparx5); -} - static int mchp_sparx5_probe(struct platform_device *pdev) { struct initial_port_config *configs, *config; @@ -957,6 +896,7 @@ static int mchp_sparx5_probe(struct platform_device *pdev) dev_info(sparx5->dev, "MAC addr was not set, use random MAC\n"); eth_random_addr(sparx5->base_mac); sparx5->base_mac[5] = 0; + sparx5->base_mac_assign_type = NET_ADDR_RANDOM; } sparx5->fdma_irq = platform_get_irq_byname(sparx5->pdev, "fdma"); @@ -1010,20 +950,58 @@ static int mchp_sparx5_probe(struct platform_device *pdev) goto cleanup_ports; } - err = sparx5_ptp_init(sparx5); + err = sparx5_vcap_init(sparx5); if (err) { - dev_err(sparx5->dev, "PTP failed\n"); + dev_err(sparx5->dev, "Failed to initialize VCAP\n"); goto cleanup_ports; } + err = sparx5_mact_init(sparx5); + if (err) { + dev_err(sparx5->dev, "Failed to initialize MAC table\n"); + goto cleanup_vcap; + } + + err = sparx5_stats_init(sparx5); + if (err) { + dev_err(sparx5->dev, "Failed to initialize stats\n"); + goto cleanup_mact; + } + INIT_LIST_HEAD(&sparx5->mall_entries); + err = sparx5_ptp_init(sparx5); + if (err) { + dev_err(sparx5->dev, "Failed to initialize PTP\n"); + goto cleanup_stats; + } + + err = sparx5_register_netdevs(sparx5); + if (err) { + dev_err(sparx5->dev, "Failed to register net devices\n"); + goto cleanup_ptp; + } + + err = sparx5_register_notifier_blocks(sparx5); + if (err) { + dev_err(sparx5->dev, "Failed to register notifier blocks\n"); + goto cleanup_netdevs; + } + goto cleanup_config; +cleanup_netdevs: + sparx5_unregister_netdevs(sparx5); +cleanup_ptp: + sparx5_ptp_deinit(sparx5); +cleanup_stats: + sparx5_stats_deinit(sparx5); +cleanup_mact: + sparx5_mact_deinit(sparx5); +cleanup_vcap: + sparx5_vcap_deinit(sparx5); cleanup_ports: - sparx5_cleanup_ports(sparx5); - if (sparx5->mact_queue) - destroy_workqueue(sparx5->mact_queue); + sparx5_destroy_netdevs(sparx5); cleanup_config: kfree(configs); cleanup_pnode: @@ -1045,13 +1023,14 @@ static void mchp_sparx5_remove(struct platform_device *pdev) disable_irq(sparx5->fdma_irq); sparx5->fdma_irq = -ENXIO; } + sparx5_unregister_notifier_blocks(sparx5); + sparx5_unregister_netdevs(sparx5); sparx5_ptp_deinit(sparx5); + sparx5_stats_deinit(sparx5); + sparx5_mact_deinit(sparx5); + sparx5_vcap_deinit(sparx5); ops->fdma_deinit(sparx5); - sparx5_cleanup_ports(sparx5); - sparx5_vcap_destroy(sparx5); - /* Unregister netdevs */ - sparx5_unregister_notifier_blocks(sparx5); - destroy_workqueue(sparx5->mact_queue); + sparx5_destroy_netdevs(sparx5); } static const struct sparx5_regs sparx5_regs = { diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h index fe7d8bcc0cd9..a5675f13a11e 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h @@ -392,6 +392,7 @@ struct sparx5 { struct notifier_block switchdev_blocking_nb; /* Switch state */ u8 base_mac[ETH_ALEN]; + u8 base_mac_assign_type; /* Associated bridge device (when bridged) */ struct net_device *hw_bridge_dev; /* Bridged interfaces */ @@ -470,7 +471,6 @@ void sparx5_fdma_reload(struct sparx5 *sparx5, struct fdma *fdma); void sparx5_fdma_injection_mode(struct sparx5 *sparx5); /* sparx5_mactable.c */ -void sparx5_mact_pull_work(struct work_struct *work); int sparx5_mact_learn(struct sparx5 *sparx5, int port, const unsigned char mac[ETH_ALEN], u16 vid); bool sparx5_mact_getnext(struct sparx5 *sparx5, @@ -489,7 +489,8 @@ int sparx5_del_mact_entry(struct sparx5 *sparx5, int sparx5_mc_sync(struct net_device *dev, const unsigned char *addr); int sparx5_mc_unsync(struct net_device *dev, const unsigned char *addr); void sparx5_set_ageing(struct sparx5 *sparx5, int msecs); -void sparx5_mact_init(struct sparx5 *sparx5); +int sparx5_mact_init(struct sparx5 *sparx5); +void sparx5_mact_deinit(struct sparx5 *sparx5); /* sparx5_vlan.c */ void sparx5_pgid_update_mask(struct sparx5_port *port, int pgid, bool enable); @@ -514,7 +515,8 @@ enum sparx5_cal_bw sparx5_get_port_cal_speed(struct sparx5 *sparx5, u32 portno); /* sparx5_ethtool.c */ void sparx5_get_stats64(struct net_device *ndev, struct rtnl_link_stats64 *stats); -int sparx_stats_init(struct sparx5 *sparx5); +int sparx5_stats_init(struct sparx5 *sparx5); +void sparx5_stats_deinit(struct sparx5 *sparx5); /* sparx5_dcb.c */ #ifdef CONFIG_SPARX5_DCB @@ -563,7 +565,7 @@ void sparx5_get_hwtimestamp(struct sparx5 *sparx5, /* sparx5_vcap_impl.c */ int sparx5_vcap_init(struct sparx5 *sparx5); -void sparx5_vcap_destroy(struct sparx5 *sparx5); +void sparx5_vcap_deinit(struct sparx5 *sparx5); /* sparx5_pgid.c */ enum sparx5_pgid_type { diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c index 1d34af78166a..ae84ab737882 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c @@ -289,6 +289,7 @@ struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno) ndev->ethtool_ops = &sparx5_ethtool_ops; eth_hw_addr_gen(ndev, sparx5->base_mac, portno + 1); + ndev->addr_assign_type = sparx5->base_mac_assign_type; return ndev; } diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c index 8b2e07821a95..5953e04ef14e 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c @@ -606,9 +606,22 @@ static int sparx5_ptp_phc_init(struct sparx5 *sparx5, int sparx5_ptp_init(struct sparx5 *sparx5) { u64 tod_adj = sparx5_ptp_get_nominal_value(sparx5); + const struct sparx5_ops *ops = sparx5->data->ops; struct sparx5_port *port; int err, i; + if (sparx5->ptp_irq >= 0 && + sparx5_has_feature(sparx5, SPX5_FEATURE_PTP)) { + err = devm_request_threaded_irq(sparx5->dev, sparx5->ptp_irq, + NULL, ops->ptp_irq_handler, + IRQF_ONESHOT, "sparx5-ptp", + sparx5); + if (err) + sparx5->ptp_irq = -ENXIO; + + sparx5->ptp = 1; + } + if (!sparx5->ptp) return 0; @@ -660,6 +673,14 @@ void sparx5_ptp_deinit(struct sparx5 *sparx5) struct sparx5_port *port; int i; + if (!sparx5->ptp) + return; + + if (sparx5->ptp_irq >= 0) { + disable_irq(sparx5->ptp_irq); + sparx5->ptp_irq = -ENXIO; + } + for (i = 0; i < sparx5->data->consts->n_ports; i++) { port = sparx5->ports[i]; if (!port) diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c index f426f37dd619..34e82758e992 100644 --- a/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c +++ b/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c @@ -2083,7 +2083,7 @@ int sparx5_vcap_init(struct sparx5 *sparx5) return err; } -void sparx5_vcap_destroy(struct sparx5 *sparx5) +void sparx5_vcap_deinit(struct sparx5 *sparx5) { struct vcap_control *ctrl = sparx5->vcap_ctrl; struct vcap_admin *admin, *admin_next; diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c index 49eef025d290..4c55ff842ed7 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -3524,8 +3524,8 @@ int vcap_filter_rule_keys(struct vcap_rule *rule, if (key == keylist[idx]) { list_del(&ckf->ctrl.list); kfree(ckf); - idx++; err = 0; + break; } } } diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index c5e13eb662f4..c3b32c3cbcc2 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -2042,12 +2042,16 @@ static void mana_rx_skb(void *buf_va, bool from_pool, } static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev, - dma_addr_t *da, bool *from_pool) + dma_addr_t *da, bool *from_pool, + struct page **pp_page, u32 *dma_sync_offset) { struct page *page; u32 offset; void *va; + *from_pool = false; + *pp_page = NULL; + *dma_sync_offset = 0; /* Don't use fragments for jumbo frames or XDP where it's 1 fragment * per page. @@ -2085,31 +2089,47 @@ static void *mana_get_rxfrag(struct mana_rxq *rxq, struct device *dev, va = page_to_virt(page) + offset; *da = page_pool_get_dma_addr(page) + offset + rxq->headroom; *from_pool = true; + *pp_page = page; + *dma_sync_offset = offset + rxq->headroom; return va; } /* Allocate frag for rx buffer, and save the old buf */ static void mana_refill_rx_oob(struct device *dev, struct mana_rxq *rxq, - struct mana_recv_buf_oob *rxoob, void **old_buf, - bool *old_fp) + struct mana_recv_buf_oob *rxoob, u32 pktlen, + void **old_buf, bool *old_fp) { + struct page *pp_page; + u32 dma_sync_offset; bool from_pool; dma_addr_t da; void *va; - va = mana_get_rxfrag(rxq, dev, &da, &from_pool); + va = mana_get_rxfrag(rxq, dev, &da, &from_pool, &pp_page, + &dma_sync_offset); if (!va) return; - if (!rxoob->from_pool || rxq->frag_count == 1) + if (!rxoob->from_pool || rxq->frag_count == 1) { dma_unmap_single(dev, rxoob->sgl[0].address, rxq->datasize, DMA_FROM_DEVICE); + } else { + /* The page pool maps the whole page and only syncs for device + * automatically (PP_FLAG_DMA_SYNC_DEV). Sync the received bytes + * for the CPU before they are read: this is required if DMA + * is incoherent or bounce buffers are used. + */ + page_pool_dma_sync_for_cpu(rxq->page_pool, rxoob->pp_page, + rxoob->dma_sync_offset, pktlen); + } *old_buf = rxoob->buf_va; *old_fp = rxoob->from_pool; rxoob->buf_va = va; rxoob->sgl[0].address = da; rxoob->from_pool = from_pool; + rxoob->pp_page = pp_page; + rxoob->dma_sync_offset = dma_sync_offset; } static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq, @@ -2179,7 +2199,8 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq, goto drop; } - mana_refill_rx_oob(dev, rxq, rxbuf_oob, &old_buf, &old_fp); + mana_refill_rx_oob(dev, rxq, rxbuf_oob, pktlen, + &old_buf, &old_fp); /* Unsuccessful refill will have old_buf == NULL. * In this case, mana_rx_skb() will drop the packet. @@ -2554,6 +2575,8 @@ static int mana_fill_rx_oob(struct mana_recv_buf_oob *rx_oob, u32 mem_key, struct mana_rxq *rxq, struct device *dev) { struct mana_port_context *mpc = netdev_priv(rxq->ndev); + struct page *pp_page = NULL; + u32 dma_sync_offset = 0; bool from_pool = false; dma_addr_t da; void *va; @@ -2561,13 +2584,16 @@ static int mana_fill_rx_oob(struct mana_recv_buf_oob *rx_oob, u32 mem_key, if (mpc->rxbufs_pre) va = mana_get_rxbuf_pre(rxq, &da); else - va = mana_get_rxfrag(rxq, dev, &da, &from_pool); + va = mana_get_rxfrag(rxq, dev, &da, &from_pool, &pp_page, + &dma_sync_offset); if (!va) return -ENOMEM; rx_oob->buf_va = va; rx_oob->from_pool = from_pool; + rx_oob->pp_page = pp_page; + rx_oob->dma_sync_offset = dma_sync_offset; rx_oob->sgl[0].address = da; rx_oob->sgl[0].size = rxq->datasize; @@ -2795,9 +2821,6 @@ static struct mana_rxq *mana_create_rxq(struct mana_port_context *apc, mana_destroy_rxq(apc, rxq, false); - if (cq) - mana_deinit_cq(apc, cq); - return NULL; } diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index d407b031cc2a..43a786ccf890 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5268,6 +5268,12 @@ static int r8169_mdio_register(struct rtl8169_private *tp) phy_disable_eee_mode(tp->phydev, ETHTOOL_LINK_MODE_2500baseT_Full_BIT); + /* Keep EEE off but the version stays EEE-capable so that link-up + * still clears the MAC TX-LPI bits. + */ + if (tp->mac_version == RTL_GIGA_MAC_VER_46) + phy_disable_eee(tp->phydev); + /* PHY will be woken up in rtl_open() */ phy_suspend(tp->phydev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 865531d6cd3b..21b473c8d2a9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -251,8 +251,8 @@ struct stmmac_priv { int hwts_tx_en; bool tx_path_in_lpi_mode; bool tso; - int sph; - int sph_cap; + bool sph_active; + bool sph_capable; u32 sarc_type; u32 rx_riwt[MTL_MAX_RX_QUEUES]; int hwts_rx_en; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index b9d4c2afc9a8..8fa378bd591d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1432,6 +1432,16 @@ static void stmmac_clear_descriptors(struct stmmac_priv *priv, stmmac_clear_tx_descriptors(priv, dma_conf, queue); } +static bool stmmac_rx_check_buf2_cap(struct stmmac_priv *priv) +{ + /* Only cores that can program an independent secondary RX buffer + * (used for scatter-gather overflow or split-header payload) back + * buffer2. Legacy cores have no set_sec_addr op, so buffer2 is + * never handed to the hardware there. + */ + return priv->hw->desc && priv->hw->desc->set_sec_addr; +} + /** * stmmac_init_rx_buffers - init the RX descriptor buffer. * @priv: driver private structure @@ -1462,16 +1472,13 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, buf->page_offset = stmmac_rx_offset(priv); } - if (priv->sph && !buf->sec_page) { + if (stmmac_rx_check_buf2_cap(priv) && !buf->sec_page) { buf->sec_page = page_pool_alloc_pages(rx_q->page_pool, gfp); if (!buf->sec_page) return -ENOMEM; buf->sec_addr = page_pool_get_dma_addr(buf->sec_page); stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, true); - } else { - buf->sec_page = NULL; - stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, false); } buf->addr = page_pool_get_dma_addr(buf->page) + buf->page_offset; @@ -2045,13 +2052,8 @@ static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv, pp_params.nid = dev_to_node(priv->device); pp_params.dev = priv->device; pp_params.dma_dir = xdp_prog ? DMA_BIDIRECTIONAL : DMA_FROM_DEVICE; - pp_params.offset = stmmac_rx_offset(priv); - pp_params.max_len = dma_conf->dma_buf_sz; - - if (priv->sph) { - pp_params.offset = 0; - pp_params.max_len += stmmac_rx_offset(priv); - } + pp_params.offset = 0; + pp_params.max_len = dma_conf->dma_buf_sz + stmmac_rx_offset(priv); rx_q->page_pool = page_pool_create(&pp_params); if (IS_ERR(rx_q->page_pool)) { @@ -3521,7 +3523,7 @@ static int stmmac_hw_setup(struct net_device *dev) } /* Enable Split Header */ - sph_en = (priv->hw->rx_csum > 0) && priv->sph; + sph_en = (priv->hw->rx_csum > 0) && priv->sph_active; for (chan = 0; chan < rx_cnt; chan++) stmmac_enable_sph(priv, priv->ioaddr, sph_en, chan); @@ -4846,7 +4848,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) break; } - if (priv->sph && !buf->sec_page) { + if (stmmac_rx_check_buf2_cap(priv) && !buf->sec_page) { buf->sec_page = page_pool_alloc_pages(rx_q->page_pool, gfp); if (!buf->sec_page) break; @@ -4857,10 +4859,8 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) buf->addr = page_pool_get_dma_addr(buf->page) + buf->page_offset; stmmac_set_desc_addr(priv, p, buf->addr); - if (priv->sph) - stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, true); - else - stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, false); + stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, + stmmac_rx_check_buf2_cap(priv)); stmmac_refill_desc3(priv, rx_q, p); rx_q->rx_count_frames++; @@ -4891,25 +4891,29 @@ static unsigned int stmmac_rx_buf1_len(struct stmmac_priv *priv, unsigned int plen = 0, hlen = 0; int coe = priv->hw->rx_csum; - /* Not first descriptor, buffer is always zero */ - if (priv->sph && len) + /* Not first descriptor, SPH enabled: buffer1 only carries the + * split header of the first descriptor, so it is zero here. + */ + if (priv->sph_active && len) return 0; /* First descriptor, get split header length */ stmmac_get_rx_header_len(priv, p, &hlen); - if (priv->sph && hlen) { + if (priv->sph_active && hlen) { priv->xstats.rx_split_hdr_pkt_n++; return hlen; } - /* First descriptor, not last descriptor and not split header */ + /* Not last descriptor and not split header: buffer1 is fully filled */ if (status & rx_not_ls) return priv->dma_conf.dma_buf_sz; plen = stmmac_get_rx_frame_len(priv, p, coe); - /* First descriptor and last descriptor and not split header */ - return min_t(unsigned int, priv->dma_conf.dma_buf_sz, plen); + /* Last descriptor and not split header: buffer1 holds the remaining + * bytes of the frame, up to dma_buf_sz + */ + return min_t(unsigned int, priv->dma_conf.dma_buf_sz, plen - len); } static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv, @@ -4919,8 +4923,7 @@ static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv, int coe = priv->hw->rx_csum; unsigned int plen = 0; - /* Not split header, buffer is not available */ - if (!priv->sph) + if (!stmmac_rx_check_buf2_cap(priv)) return 0; /* For GMAC4, when split header is enabled, in some rare cases, the @@ -4937,14 +4940,15 @@ static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv, * Thus 'plen - len' always gives the correct length of buf2. */ - /* Not GMAC4 and not last descriptor */ - if (priv->plat->core_type != DWMAC_CORE_GMAC4 && (status & rx_not_ls)) + /* Not GMAC4, or non-SPH and not last descriptor */ + if ((priv->plat->core_type != DWMAC_CORE_GMAC4 || !priv->sph_active) && + (status & rx_not_ls)) return priv->dma_conf.dma_buf_sz; /* GMAC4 or last descriptor */ plen = stmmac_get_rx_frame_len(priv, p, coe); - return plen - len; + return plen > len ? plen - len : 0; } static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, @@ -5491,6 +5495,7 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) unsigned int desc_size; struct sk_buff *skb = NULL; struct stmmac_xdp_buff ctx; + bool fcs_stripped = false; int xdp_status = 0; int bufsz; @@ -5592,24 +5597,25 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) len += buf2_len; /* ACS is disabled; strip manually. */ - if (likely(!(status & rx_not_ls))) { - if (buf2_len) { - buf2_len -= ETH_FCS_LEN; - len -= ETH_FCS_LEN; - } else if (buf1_len) { - buf1_len -= ETH_FCS_LEN; - len -= ETH_FCS_LEN; - } - } + if (likely(!(status & rx_not_ls))) + len -= ETH_FCS_LEN; if (!skb) { unsigned int pre_len, sync_len; + /* Each frame starts here: reset the FCS handling */ + fcs_stripped = false; + dma_sync_single_for_cpu(priv->device, buf->addr, buf1_len, dma_dir); net_prefetch(page_address(buf->page) + buf->page_offset); + if (stmmac_xdp_is_enabled(priv) && !buf2_len) { + buf1_len -= ETH_FCS_LEN; + fcs_stripped = true; + } + xdp_init_buff(&ctx.xdp, bufsz, &rx_q->xdp_rxq); xdp_prepare_buff(&ctx.xdp, page_address(buf->page), buf->page_offset, buf1_len, true); @@ -5710,6 +5716,15 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) /* Got entire packet into SKB. Finish it. */ + /* Remove FCS if needed */ + if (!fcs_stripped && pskb_trim(skb, len)) { + dev_kfree_skb_any(skb); + skb = NULL; + rx_dropped++; + count++; + continue; + } + stmmac_get_rx_hwtstamp(priv, p, np, skb); if (priv->hw->hw_vlan_en) @@ -6020,8 +6035,8 @@ static int stmmac_set_features(struct net_device *netdev, */ stmmac_rx_ipc(priv, priv->hw); - if (priv->sph_cap) { - bool sph_en = (priv->hw->rx_csum > 0) && priv->sph; + if (priv->sph_capable) { + bool sph_en = (priv->hw->rx_csum > 0) && priv->sph_active; u32 chan; for (chan = 0; chan < priv->plat->rx_queues_to_use; chan++) @@ -7002,7 +7017,7 @@ int stmmac_xdp_open(struct net_device *dev) } /* Adjust Split header */ - sph_en = (priv->hw->rx_csum > 0) && priv->sph; + sph_en = (priv->hw->rx_csum > 0) && priv->sph_active; /* DMA RX Channel Configuration */ for (chan = 0; chan < rx_cnt; chan++) { @@ -7621,8 +7636,8 @@ int stmmac_dvr_probe(struct device *device, if (priv->dma_cap.sphen && !(priv->plat->flags & STMMAC_FLAG_SPH_DISABLE)) { ndev->hw_features |= NETIF_F_GRO; - priv->sph_cap = true; - priv->sph = priv->sph_cap; + priv->sph_capable = true; + priv->sph_active = priv->sph_capable; dev_info(priv->device, "SPH feature enabled\n"); } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c index a2f99e2cb43b..d922e32fe4fb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c @@ -1807,7 +1807,7 @@ static int stmmac_test_sph(struct stmmac_priv *priv) struct stmmac_packet_attrs attr = { }; int ret; - if (!priv->sph) + if (!priv->sph_active) return -EOPNOTSUPP; /* Check for UDP first */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c index aa6f16d3df64..d7e4db7224b0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c @@ -129,7 +129,7 @@ int stmmac_xdp_set_prog(struct stmmac_priv *priv, struct bpf_prog *prog, bpf_prog_put(old_prog); /* Disable RX SPH for XDP operation */ - priv->sph = priv->sph_cap && !stmmac_xdp_is_enabled(priv); + priv->sph_active = priv->sph_capable && !stmmac_xdp_is_enabled(priv); if (if_running && need_update) stmmac_xdp_open(dev); diff --git a/drivers/net/pcs/pcs-rzn1-miic.c b/drivers/net/pcs/pcs-rzn1-miic.c index cea350745a7b..301cfde2e6dd 100644 --- a/drivers/net/pcs/pcs-rzn1-miic.c +++ b/drivers/net/pcs/pcs-rzn1-miic.c @@ -249,6 +249,9 @@ static struct miic_port *phylink_pcs_to_miic_port(struct phylink_pcs *pcs) static void miic_unlock_regs(struct miic *miic) { + /* Clear protection state */ + writel(0x0000, miic->base + MIIC_PRCMD); + /* Unprotect register writes */ writel(0x00A5, miic->base + MIIC_PRCMD); writel(0x0001, miic->base + MIIC_PRCMD); diff --git a/drivers/net/pfcp.c b/drivers/net/pfcp.c index a6aa30ae0af7..c1c8eaea63fc 100644 --- a/drivers/net/pfcp.c +++ b/drivers/net/pfcp.c @@ -104,6 +104,9 @@ static int pfcp_encap_recv(struct sock *sk, struct sk_buff *skb) static void pfcp_del_sock(struct pfcp_dev *pfcp) { + if (!pfcp->sock) + return; + udp_tunnel_sock_release(pfcp->sock); pfcp->sock = NULL; } diff --git a/drivers/net/phy/aquantia/aquantia_main.c b/drivers/net/phy/aquantia/aquantia_main.c index 41f3676c7f1e..ec69728f3349 100644 --- a/drivers/net/phy/aquantia/aquantia_main.c +++ b/drivers/net/phy/aquantia/aquantia_main.c @@ -544,7 +544,7 @@ static int aqr_gen1_read_status(struct phy_device *phydev) if (ret) return ret; - if (!phydev->link || phydev->autoneg == AUTONEG_DISABLE) + if (!phydev->link) return 0; /* The status register is not immediately correct on line side link up. @@ -594,6 +594,9 @@ static int aqr_gen1_read_status(struct phy_device *phydev) phydev->interface = aqr_translate_interface(phydev, interface); + if (phydev->autoneg == AUTONEG_DISABLE) + return 0; + /* Read rate from vendor register */ return aqr_gen1_read_rate(phydev); } diff --git a/drivers/net/phy/qcom/at803x.c b/drivers/net/phy/qcom/at803x.c index 023c1fe0cd14..22d862108eba 100644 --- a/drivers/net/phy/qcom/at803x.c +++ b/drivers/net/phy/qcom/at803x.c @@ -1064,11 +1064,15 @@ static int ipq5018_config_init(struct phy_device *phydev) if (priv->set_short_cable_dac) { /* setting MDAC (Multi-level Digital-to-Analog Converter) in MMD1 */ phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, IPQ5018_PHY_MMD1_MDAC, - IPQ5018_PHY_DAC_MASK, IPQ5018_PHY_MMD1_MDAC_VAL); + IPQ5018_PHY_DAC_MASK, + FIELD_PREP(IPQ5018_PHY_DAC_MASK, + IPQ5018_PHY_MMD1_MDAC_VAL)); /* setting EDAC (Error-detection and Correction) in debug register */ at803x_debug_reg_mask(phydev, IPQ5018_PHY_DEBUG_EDAC, - IPQ5018_PHY_DAC_MASK, IPQ5018_PHY_DEBUG_EDAC_VAL); + IPQ5018_PHY_DAC_MASK, + FIELD_PREP(IPQ5018_PHY_DAC_MASK, + IPQ5018_PHY_DEBUG_EDAC_VAL)); } return 0; diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 8178a8758cd3..aa66a30e56cd 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -1085,6 +1085,7 @@ static const struct usb_device_id products[] = { {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0122)}, /* Quectel RG650V */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ + {QMI_MATCH_FF_FF_FF(0x2c7c, 0x030b)}, /* Quectel EM060K/EG120K-EA */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */ {QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */ diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index c97c07a7ef0f..60ffecd52280 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -6402,6 +6402,7 @@ static int ath11k_mac_op_start(struct ieee80211_hw *hw) ar->num_started_vdevs = 0; ar->num_created_vdevs = 0; ar->num_peers = 0; + ar->num_stations = 0; ar->allocated_vdev_map = 0; /* Configure monitor status ring with default rx_filter to get rx status diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index c15219257499..bafa82da2441 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include #include #include "htc.h" @@ -328,11 +329,14 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev) tx_skb_cnt = min_t(u16, hif_dev->tx.tx_skb_cnt, MAX_TX_AGGR_NUM); for (i = 0; i < tx_skb_cnt; i++) { - nskb = __skb_dequeue(&hif_dev->tx.tx_skb_queue); + nskb = skb_peek(&hif_dev->tx.tx_skb_queue); + if (!nskb) + break; - /* Should never be NULL */ - BUG_ON(!nskb); + if (tx_buf->offset + nskb->len + 4 > MAX_TX_BUF_SIZE) + break; + nskb = __skb_dequeue(&hif_dev->tx.tx_skb_queue); hif_dev->tx.tx_skb_cnt--; buf = tx_buf->buf; @@ -342,13 +346,8 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev) *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG); buf += 4; memcpy(buf, nskb->data, nskb->len); - tx_buf->len = nskb->len + 4; - - if (i < (tx_skb_cnt - 1)) - tx_buf->offset += (((tx_buf->len - 1) / 4) + 1) * 4; - - if (i == (tx_skb_cnt - 1)) - tx_buf->len += tx_buf->offset; + tx_buf->len = tx_buf->offset + nskb->len + 4; + tx_buf->offset += round_up(nskb->len + 4, 4); __skb_queue_tail(&tx_buf->skb_queue, nskb); TX_STAT_INC(hif_dev, skb_queued); diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c index 805ad31edba2..610717fb83f5 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.c +++ b/drivers/net/wireless/ath/ath9k/wmi.c @@ -206,9 +206,16 @@ static void ath9k_wmi_rsp_callback(struct wmi *wmi, struct sk_buff *skb) { skb_pull(skb, sizeof(struct wmi_cmd_hdr)); - if (wmi->cmd_rsp_buf != NULL && wmi->cmd_rsp_len != 0) + if (wmi->cmd_rsp_buf && wmi->cmd_rsp_len) { + if (skb->len < wmi->cmd_rsp_len) { + wmi->cmd_rsp_status = -EMSGSIZE; + goto complete; + } memcpy(wmi->cmd_rsp_buf, skb->data, wmi->cmd_rsp_len); + } + wmi->cmd_rsp_status = 0; +complete: complete(&wmi->cmd_wait); } @@ -300,6 +307,7 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi, /* record the rsp buffer and length */ wmi->cmd_rsp_buf = rsp_buf; wmi->cmd_rsp_len = rsp_len; + wmi->cmd_rsp_status = 0; wmi->last_seq_id = wmi->tx_seq_id; spin_unlock_irqrestore(&wmi->wmi_lock, flags); @@ -356,9 +364,13 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id, return -ETIMEDOUT; } + spin_lock_irqsave(&wmi->wmi_lock, flags); + ret = wmi->cmd_rsp_status; + spin_unlock_irqrestore(&wmi->wmi_lock, flags); + mutex_unlock(&wmi->op_mutex); - return 0; + return ret; out: ath_dbg(common, WMI, "WMI failure for: %s\n", wmi_cmd_to_name(cmd_id)); diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h index 5c3b710b8f31..0bb9d31f1a1c 100644 --- a/drivers/net/wireless/ath/ath9k/wmi.h +++ b/drivers/net/wireless/ath/ath9k/wmi.h @@ -157,6 +157,7 @@ struct wmi { u16 tx_seq_id; u8 *cmd_rsp_buf; u32 cmd_rsp_len; + int cmd_rsp_status; bool stopped; struct list_head pending_tx_events; diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 54991f31c52c..6a8c070002fe 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -3806,6 +3806,7 @@ il3945_pci_remove(struct pci_dev *pdev) il_free_channel_map(il); il_free_geos(il); + il_eeprom_free(il); kfree(il->scan_cmd); dev_kfree_skb(il->beacon_skb); ieee80211_free_hw(il->hw); diff --git a/drivers/net/wireless/silabs/wfx/hif_tx.c b/drivers/net/wireless/silabs/wfx/hif_tx.c index 9f403d275cb1..9efb108bd877 100644 --- a/drivers/net/wireless/silabs/wfx/hif_tx.c +++ b/drivers/net/wireless/silabs/wfx/hif_tx.c @@ -207,9 +207,11 @@ int wfx_hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, si dev_warn(wdev->dev, "%s: confirmation mismatch request\n", __func__); ret = -EIO; } - if (ret == -ENOMEM) + if (!ret && le16_to_cpu(reply->length) > val_len) { dev_err(wdev->dev, "buffer is too small to receive %s (%zu < %d)\n", wfx_get_mib_name(mib_id), val_len, le16_to_cpu(reply->length)); + ret = -EIO; + } if (!ret) memcpy(val, &reply->mib_data, le16_to_cpu(reply->length)); else diff --git a/drivers/net/wireless/st/cw1200/bh.c b/drivers/net/wireless/st/cw1200/bh.c index 37232ee22037..91d4287f5e4a 100644 --- a/drivers/net/wireless/st/cw1200/bh.c +++ b/drivers/net/wireless/st/cw1200/bh.c @@ -343,6 +343,7 @@ static int cw1200_bh_tx_helper(struct cw1200_common *priv, int *tx_burst) { size_t tx_len; + size_t aligned_len; u8 *data; int ret; struct wsm_hdr *wsm; @@ -375,9 +376,14 @@ static int cw1200_bh_tx_helper(struct cw1200_common *priv, atomic_inc(&priv->bh_tx); - tx_len = priv->hwbus_ops->align_size( + aligned_len = priv->hwbus_ops->align_size( priv->hwbus_priv, tx_len); + /* Zero the bus alignment padding so no stale data is sent. */ + if (aligned_len > tx_len) + memset(data + tx_len, 0, aligned_len - tx_len); + tx_len = aligned_len; + /* Check if not exceeding CW1200 capabilities */ if (WARN_ON_ONCE(tx_len > EFFECTIVE_BUF_SIZE)) pr_debug("Write aligned len: %zu\n", tx_len); diff --git a/drivers/net/wireless/st/cw1200/txrx.c b/drivers/net/wireless/st/cw1200/txrx.c index 084d52b11f5b..e13695667a00 100644 --- a/drivers/net/wireless/st/cw1200/txrx.c +++ b/drivers/net/wireless/st/cw1200/txrx.c @@ -14,6 +14,7 @@ #include "wsm.h" #include "bh.h" #include "sta.h" +#include "hwbus.h" #include "debug.h" #define CW1200_INVALID_RATE_ID (0xFF) @@ -716,6 +717,7 @@ void cw1200_tx(struct ieee80211_hw *dev, struct ieee80211_sta *sta; struct wsm_tx *wsm; bool tid_update = false; + size_t pad_len; u8 flags = 0; int ret; @@ -764,6 +766,18 @@ void cw1200_tx(struct ieee80211_hw *dev, sta = t.sta; + /* + * The bus transfer is padded up to the bus alignment and the + * padding is transferred from the frame buffer. Make sure the + * buffer has room for the padding so the device never receives + * data past the end of the frame. + */ + pad_len = priv->hwbus_ops->align_size(priv->hwbus_priv, skb->len) - + skb->len; + if (skb_tailroom(skb) < pad_len && + pskb_expand_head(skb, 0, pad_len, GFP_ATOMIC)) + goto drop; + spin_lock_bh(&priv->ps_state_lock); { tid_update = cw1200_tx_h_pm_state(priv, &t); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index fe7c2e70d168..250aa814b392 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -6835,8 +6835,10 @@ void wlcore_remove(struct platform_device *pdev) if (pdev_data->family && pdev_data->family->nvs_name) wait_for_completion(&wl->nvs_loading_complete); - if (!wl->initialized) + if (!wl->initialized) { + pm_runtime_put_noidle(wl->dev); return; + } if (wl->wakeirq >= 0) { dev_pm_clear_wake_irq(wl->dev); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index a11a0e949400..ce3b2d98f6b4 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1234,8 +1234,16 @@ static int handle_incoming_queue(struct netfront_queue *queue, while ((skb = __skb_dequeue(rxq)) != NULL) { int pull_to = NETFRONT_SKB_CB(skb)->pull_to; - if (pull_to > skb_headlen(skb)) - __pskb_pull_tail(skb, pull_to - skb_headlen(skb)); + /* pull_to comes from the first slot's length, which the + * backend controls. Make sure the head holds at least an + * Ethernet header for eth_type_trans(). + */ + if (!pskb_may_pull(skb, max(pull_to, ETH_HLEN))) { + kfree_skb(skb); + packets_dropped++; + queue->info->netdev->stats.rx_errors++; + continue; + } /* Ethernet work: Delayed to here as it peeks the header. */ skb->protocol = eth_type_trans(skb, queue->info->netdev); diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index 616d1ce6b8e5..c2ab518e4470 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -754,8 +754,6 @@ int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl, struct nvme_ns_head *head) lim.dma_alignment = 3; lim.features |= BLK_FEAT_IO_STAT | BLK_FEAT_NOWAIT | BLK_FEAT_POLL | BLK_FEAT_ATOMIC_WRITES; - if (head->ids.csi == NVME_CSI_ZNS) - lim.features |= BLK_FEAT_ZONED; head->disk = blk_alloc_disk(&lim, ctrl->numa_node); if (IS_ERR(head->disk)) @@ -834,7 +832,8 @@ static int nvme_parse_ana_log(struct nvme_ctrl *ctrl, void *data, u32 nr_nsids; size_t nsid_buf_size; - if (WARN_ON_ONCE(offset > ctrl->ana_log_size - sizeof(*desc))) + if (WARN_ON_ONCE(offset > ctrl->ana_log_size || + sizeof(*desc) > ctrl->ana_log_size - offset)) return -EINVAL; nr_nsids = le32_to_cpu(desc->nnsids); @@ -850,7 +849,7 @@ static int nvme_parse_ana_log(struct nvme_ctrl *ctrl, void *data, return -EINVAL; offset += sizeof(*desc); - if (WARN_ON_ONCE(offset > ctrl->ana_log_size - nsid_buf_size)) + if (WARN_ON_ONCE(nsid_buf_size > ctrl->ana_log_size - offset)) return -EINVAL; error = cb(ctrl, desc, data); diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index e414ba56a6be..f424cfba833e 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -3917,6 +3917,8 @@ static const struct pci_device_id nvme_id_table[] = { .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN }, { PCI_DEVICE(0x1344, 0x6001), /* Micron Nitro NVMe */ .driver_data = NVME_QUIRK_BOGUS_NID, }, + { PCI_DEVICE(0x1344, 0x6004), /* Micron 4100AT */ + .driver_data = NVME_QUIRK_DMAPOOL_ALIGN_512, }, { PCI_DEVICE(0x1c5c, 0x1504), /* SK Hynix PC400 */ .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, }, { PCI_DEVICE(0x1c5c, 0x174a), /* SK Hynix P31 SSD */ diff --git a/drivers/nvme/target/auth.c b/drivers/nvme/target/auth.c index 95e14f3f03d7..8230a0563616 100644 --- a/drivers/nvme/target/auth.c +++ b/drivers/nvme/target/auth.c @@ -140,7 +140,7 @@ int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, u8 dhgroup_id) return ret; } -u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq) +u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, bool reset) { int ret = 0; struct nvmet_host_link *p; @@ -166,7 +166,7 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq) goto out_unlock; } - if (nvmet_queue_tls_keyid(sq)) { + if (!reset && nvmet_queue_tls_keyid(sq)) { pr_debug("host %s tls enabled\n", ctrl->hostnqn); goto out_unlock; } diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index e44ef69dffc2..f6ac42eaac0e 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -507,6 +507,7 @@ static ssize_t nvmet_ns_device_path_store(struct config_item *item, struct nvmet_subsys *subsys = ns->subsys; size_t len; int ret; + char *new_path = NULL; mutex_lock(&subsys->lock); ret = -EBUSY; @@ -518,12 +519,14 @@ static ssize_t nvmet_ns_device_path_store(struct config_item *item, if (!len) goto out_unlock; - kfree(ns->device_path); ret = -ENOMEM; - ns->device_path = kmemdup_nul(page, len, GFP_KERNEL); - if (!ns->device_path) + new_path = kmemdup_nul(page, len, GFP_KERNEL); + if (!new_path) goto out_unlock; + kfree(ns->device_path); + ns->device_path = new_path; + mutex_unlock(&subsys->lock); return count; diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 1f145b88120b..3310d0b44ccf 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -1633,6 +1633,8 @@ struct nvmet_ctrl *nvmet_alloc_ctrl(struct nvmet_alloc_ctrl_args *args) memcpy(ctrl->subsysnqn, args->subsysnqn, NVMF_NQN_SIZE); memcpy(ctrl->hostnqn, args->hostnqn, NVMF_NQN_SIZE); + if (args->hostid) + uuid_copy(&ctrl->hostid, args->hostid); kref_init(&ctrl->ref); ctrl->subsys = subsys; @@ -1689,10 +1691,7 @@ struct nvmet_ctrl *nvmet_alloc_ctrl(struct nvmet_alloc_ctrl_args *args) nvmet_debugfs_ctrl_setup(ctrl); mutex_unlock(&subsys->lock); - if (args->hostid) - uuid_copy(&ctrl->hostid, args->hostid); - - dhchap_status = nvmet_setup_auth(ctrl, args->sq); + dhchap_status = nvmet_setup_auth(ctrl, args->sq, false); if (dhchap_status) { pr_err("Failed to setup authentication, dhchap status %u\n", dhchap_status); diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c index 9642f1360165..35bf1a2357d4 100644 --- a/drivers/nvme/target/fabrics-cmd-auth.c +++ b/drivers/nvme/target/fabrics-cmd-auth.c @@ -310,7 +310,8 @@ void nvmet_execute_auth_send(struct nvmet_req *req) pr_debug("%s: ctrl %d qid %d reset negotiation\n", __func__, ctrl->cntlid, req->sq->qid); if (!req->sq->qid) { - dhchap_status = nvmet_setup_auth(ctrl, req->sq); + dhchap_status = nvmet_setup_auth(ctrl, req->sq, + true); if (dhchap_status) { pr_err("ctrl %d qid 0 failed to setup re-authentication\n", ctrl->cntlid); @@ -427,7 +428,7 @@ static int nvmet_auth_challenge(struct nvmet_req *req, void *d, int al) struct nvmet_ctrl *ctrl = req->sq->ctrl; int ret = 0; int hash_len = nvme_auth_hmac_hash_len(ctrl->shash_id); - int data_size = sizeof(*d) + hash_len; + int data_size = sizeof(*data) + hash_len; if (ctrl->dh_tfm) data_size += ctrl->dh_keysize; diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index f2ea7993eabc..3e8a43df57a6 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -897,7 +897,7 @@ void nvmet_execute_auth_receive(struct nvmet_req *req); int nvmet_auth_set_key(struct nvmet_host *host, const char *secret, bool set_ctrl); int nvmet_auth_set_host_hash(struct nvmet_host *host, const char *hash); -u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq); +u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, bool reset); void nvmet_auth_sq_init(struct nvmet_sq *sq); void nvmet_destroy_auth(struct nvmet_ctrl *ctrl); void nvmet_auth_sq_free(struct nvmet_sq *sq); @@ -919,7 +919,7 @@ int nvmet_auth_ctrl_sesskey(struct nvmet_req *req, void nvmet_auth_insert_psk(struct nvmet_sq *sq); #else static inline u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, - struct nvmet_sq *sq) + struct nvmet_sq *sq, bool reset) { return 0; } diff --git a/drivers/nvme/target/pci-epf.c b/drivers/nvme/target/pci-epf.c index 9b1df0ad07a2..1afda3686311 100644 --- a/drivers/nvme/target/pci-epf.c +++ b/drivers/nvme/target/pci-epf.c @@ -1000,6 +1000,9 @@ nvmet_pci_epf_get_sgl_segment(struct nvmet_pci_epf_ctrl *ctrl, int nr_descs, ret; void *buf; + if (length < sizeof(struct nvme_sgl_desc)) + return NULL; + buf = kmalloc(length, GFP_KERNEL); if (!buf) return NULL; diff --git a/drivers/of/base.c b/drivers/of/base.c index ffd1d51dff38..1fed97aeafed 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -95,9 +95,17 @@ static bool __of_node_is_type(const struct device_node *np, const char *type) return !strcmp(match, type); } +static bool of_coreboot_present(void) +{ + struct device_node *np __free(device_node) = + of_find_compatible_node(NULL, NULL, "coreboot"); + + return np; +} + #define EXCLUDED_DEFAULT_CELLS_PLATFORMS ( \ IS_ENABLED(CONFIG_SPARC) || \ - of_find_compatible_node(NULL, NULL, "coreboot") \ + of_coreboot_present() \ ) int of_bus_n_addr_cells(struct device_node *np) diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 1cd93549d093..14ca310c375a 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -660,6 +660,8 @@ void __init of_irq_init(const struct of_device_id *matches) list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) { list_del(&desc->list); + of_node_put(desc->interrupt_parent); + of_node_put(desc->dev); kfree(desc); } err: diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index 1528d8ad9f26..f987b0db24b3 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -256,6 +256,9 @@ static struct property *dup_and_fixup_symbol_prop( if (!target_path) return NULL; target_path_len = strlen(target_path); + /* a root target renders as "/"; drop it to avoid "//" results */ + if (target_path_len == 1 && target_path[0] == '/' && path_tail_len) + target_path_len = 0; new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); if (!new_prop) @@ -358,12 +361,13 @@ static int add_changeset_property(struct overlay_changeset *ovcs, return -ENOMEM; if (!prop) { - if (!target->in_livetree) { + ret = of_changeset_add_property(&ovcs->cset, target->np, + new_prop); + /* the detached node owns the property until the apply */ + if (!ret && !target->in_livetree) { new_prop->next = target->np->deadprops; target->np->deadprops = new_prop; } - ret = of_changeset_add_property(&ovcs->cset, target->np, - new_prop); } else { ret = of_changeset_update_property(&ovcs->cset, target->np, new_prop); @@ -853,6 +857,10 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs, err_out: pr_err("%s() failed, ret = %d\n", __func__, ret); + /* let free_overlay_changeset() put the fragments set up so far */ + if (ovcs->fragments) + ovcs->count = cnt; + return ret; } @@ -863,7 +871,8 @@ static void free_overlay_changeset(struct overlay_changeset *ovcs) if (ovcs->cset.entries.next) of_changeset_destroy(&ovcs->cset); - if (ovcs->id) { + /* a failed idr_alloc() leaves its negative error in ovcs->id */ + if (ovcs->id > 0) { idr_remove(&ovcs_idr, ovcs->id); list_del(&ovcs->ovcs_list); ovcs->id = 0; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6aa41fbf251c..264213aa7630 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3721,8 +3721,21 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) } root = pcie_find_root_port(dev); - if (!root) + if (!root) { + + /* + * A hypervisor may expose a topology with the root port + * not visible to the guest. If the hypervisor has already + * set AtomicOp Requester Enable in the endpoint, we assume + * it has verified support in the root port, so it is safe + * for the driver to use AtomicOps. + */ + pcie_capability_read_dword(dev, PCI_EXP_DEVCTL2, &ctl2); + if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_REQ) + return 0; + return -EINVAL; + } pcie_capability_read_dword(root, PCI_EXP_DEVCAP2, &cap); if ((cap & cap_mask) != cap_mask) diff --git a/drivers/rtc/dev.c b/drivers/rtc/dev.c index baf1a8ca8b2b..f699de159b14 100644 --- a/drivers/rtc/dev.c +++ b/drivers/rtc/dev.c @@ -207,7 +207,7 @@ static long rtc_dev_ioctl(struct file *file, struct rtc_device *rtc = file->private_data; const struct rtc_class_ops *ops = rtc->ops; struct rtc_time tm; - struct rtc_wkalrm alarm; + struct rtc_wkalrm alarm = { 0 }; struct rtc_param param; void __user *uarg = (void __user *)arg; diff --git a/drivers/rtc/rtc-ac100.c b/drivers/rtc/rtc-ac100.c index 33626311fa78..ef6a9368c63f 100644 --- a/drivers/rtc/rtc-ac100.c +++ b/drivers/rtc/rtc-ac100.c @@ -316,10 +316,12 @@ static int ac100_rtc_register_clks(struct ac100_rtc_dev *chip) if (!chip->clk_data) return -ENOMEM; - chip->rtc_32k_clk = clk_hw_register_fixed_rate(chip->dev, - AC100_RTC_32K_NAME, - NULL, 0, - AC100_RTC_32K_RATE); + chip->clk_data->num = AC100_CLKOUT_NUM; + + chip->rtc_32k_clk = devm_clk_hw_register_fixed_rate(chip->dev, + AC100_RTC_32K_NAME, + NULL, 0, + AC100_RTC_32K_RATE); if (IS_ERR(chip->rtc_32k_clk)) { ret = PTR_ERR(chip->rtc_32k_clk); dev_err(chip->dev, "Failed to register RTC-32k clock: %d\n", @@ -353,29 +355,14 @@ static int ac100_rtc_register_clks(struct ac100_rtc_dev *chip) if (ret) { dev_err(chip->dev, "Failed to register clk '%s': %d\n", init.name, ret); - goto err_unregister_rtc_32k; + return ret; } chip->clk_data->hws[i] = &clk->hw; } - chip->clk_data->num = i; - ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, chip->clk_data); - if (ret) - goto err_unregister_rtc_32k; - - return 0; - -err_unregister_rtc_32k: - clk_unregister_fixed_rate(chip->rtc_32k_clk->clk); - - return ret; -} - -static void ac100_rtc_unregister_clks(struct ac100_rtc_dev *chip) -{ - of_clk_del_provider(chip->dev->of_node); - clk_unregister_fixed_rate(chip->rtc_32k_clk->clk); + return devm_of_clk_add_hw_provider(chip->dev, of_clk_hw_onecell_get, + chip->clk_data); } /* @@ -613,13 +600,6 @@ static int ac100_rtc_probe(struct platform_device *pdev) return devm_rtc_register_device(chip->rtc); } -static void ac100_rtc_remove(struct platform_device *pdev) -{ - struct ac100_rtc_dev *chip = platform_get_drvdata(pdev); - - ac100_rtc_unregister_clks(chip); -} - static const struct of_device_id ac100_rtc_match[] = { { .compatible = "x-powers,ac100-rtc" }, { }, @@ -628,7 +608,6 @@ MODULE_DEVICE_TABLE(of, ac100_rtc_match); static struct platform_driver ac100_rtc_driver = { .probe = ac100_rtc_probe, - .remove = ac100_rtc_remove, .driver = { .name = "ac100-rtc", .of_match_table = of_match_ptr(ac100_rtc_match), diff --git a/drivers/rtc/rtc-mpfs.c b/drivers/rtc/rtc-mpfs.c index ece6de4a6adb..60596b0ea9d8 100644 --- a/drivers/rtc/rtc-mpfs.c +++ b/drivers/rtc/rtc-mpfs.c @@ -256,8 +256,12 @@ static int mpfs_rtc_probe(struct platform_device *pdev) return ret; } + clk = devm_clk_get(&pdev->dev, "rtcref"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + /* prescaler hardware adds 1 to reg value */ - prescaler = clk_get_rate(devm_clk_get(&pdev->dev, "rtcref")) - 1; + prescaler = clk_get_rate(clk) - 1; if (prescaler > MAX_PRESCALER_COUNT) { dev_dbg(&pdev->dev, "invalid prescaler %lu\n", prescaler); return -EINVAL; diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index 959acff8faff..d12bccb3cf5e 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -363,6 +363,12 @@ static int spear_rtc_probe(struct platform_device *pdev) if (irq < 0) return irq; + config->ioaddr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(config->ioaddr)) + return PTR_ERR(config->ioaddr); + + spin_lock_init(&config->lock); + status = devm_request_irq(&pdev->dev, irq, spear_rtc_irq, 0, pdev->name, config); if (status) { @@ -371,10 +377,6 @@ static int spear_rtc_probe(struct platform_device *pdev) return status; } - config->ioaddr = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(config->ioaddr)) - return PTR_ERR(config->ioaddr); - config->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(config->clk)) return PTR_ERR(config->clk); @@ -383,7 +385,6 @@ static int spear_rtc_probe(struct platform_device *pdev) if (status < 0) return status; - spin_lock_init(&config->lock); platform_set_drvdata(pdev, config); config->rtc->ops = &spear_rtc_ops; diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c index 14307dd800b7..4d153f58f246 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -230,12 +231,108 @@ static size_t cs42l43_spi_max_length(struct spi_device *spi) return CS42L43_SPI_MAX_LENGTH; } +/* + * Workaround needed for two speaker ID pins in one ACPI GpioIo() but + * the Linux-specific _DSD property only contains one pin. + * Create a temporary acpi_gpio_mapping pointing at both pins. + */ +static const struct acpi_gpio_params cs42l43_2bit_speaker_id_from_one_gpioio_params[] = { + [0] = { + .crs_entry_index = 0, + .line_index = 0, + }, + [1] = { + .crs_entry_index = 0, + .line_index = 1, + }, +}; + +static const struct acpi_gpio_mapping cs42l43_2bit_speaker_id_from_one_gpioio_mapping[] = { + { + .name = "spk-id-quirk-gpios", + .data = cs42l43_2bit_speaker_id_from_one_gpioio_params, + .size = ARRAY_SIZE(cs42l43_2bit_speaker_id_from_one_gpioio_params), + }, + { } +}; + +static int cs42l43_get_2bit_speaker_id_from_one_gpioio(struct cs42l43_spi *priv, int *result) +{ + struct fwnode_reference_args args; + struct acpi_device *adev; + struct gpio_desc *desc; + u32 spkid = 0; + int i, ret; + + /* Use the _DSD property to get the node containing the GpioIo() */ + ret = fwnode_property_get_reference_args(dev_fwnode(priv->dev), "spk-id-gpios", + NULL, 3, 0, &args); + if (ret) + return ret; + + struct fwnode_handle *fwnode __free(fwnode_handle) = args.fwnode; + + /* An acpi_gpio_mapping must be added to the node that contains the GpioIo() */ + adev = to_acpi_device_node(fwnode); + if (!adev) + return -EINVAL; + + ret = acpi_dev_add_driver_gpios(adev, cs42l43_2bit_speaker_id_from_one_gpioio_mapping); + if (ret) + return ret; + + /* gpiod_get_array() can't read from a mapping in a child node */ + for (i = 0; i < ARRAY_SIZE(cs42l43_2bit_speaker_id_from_one_gpioio_params); i++) { + desc = fwnode_gpiod_get_index(fwnode, "spk-id-quirk", i, GPIOD_IN, + dev_name(priv->dev)); + if (IS_ERR(desc)) { + ret = PTR_ERR(desc); + goto out; + } + + ret = gpiod_get_value_cansleep(desc); + gpiod_put(desc); + if (ret < 0) + goto out; + + spkid |= (u32)ret << i; + } + + dev_dbg(priv->dev, "spk-id-gpios = %u\n", spkid); + *result = spkid; + ret = 0; +out: + acpi_dev_remove_driver_gpios(adev); + + return ret; +} + +static const struct dmi_system_id cs42l43_spk_id_quirks[] = { + { + .ident = "Dell XPS 13 DX13260", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0E53"), + }, + .driver_data = cs42l43_get_2bit_speaker_id_from_one_gpioio, + }, + { } +}; + static int cs42l43_get_speaker_id_gpios(struct cs42l43_spi *priv, int *result) { + const struct dmi_system_id *dmi_id; struct gpio_descs *descs; u32 spkid; int i, ret; + dmi_id = dmi_first_match(cs42l43_spk_id_quirks); + if (dmi_id) { + int (*get_speaker_id)(struct cs42l43_spi *priv, int *result) = dmi_id->driver_data; + + return get_speaker_id(priv, result); + } + descs = gpiod_get_array_optional(priv->dev, "spk-id", GPIOD_IN); if (!descs) return 0; diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c index 10df5c37c83e..78bf8c4031e9 100644 --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -944,7 +944,8 @@ static int gb_tty_init(void) int retval = 0; gb_tty_driver = tty_alloc_driver(GB_NUM_MINORS, TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV); + TTY_DRIVER_DYNAMIC_DEV | + TTY_DRIVER_RESET_SAVED_TERMIOS); if (IS_ERR(gb_tty_driver)) { pr_err("Can not allocate tty driver\n"); retval = -ENOMEM; diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index f92175ee3841..6058c8b6c2b7 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -73,7 +73,6 @@ struct tb_ctl { #define tb_ctl_dbg_once(ctl, format, arg...) \ dev_dbg_once(&(ctl)->nhi->pdev->dev, format, ## arg) -static DECLARE_WAIT_QUEUE_HEAD(tb_cfg_request_cancel_queue); /* Serializes access to request kref_get/put */ static DEFINE_MUTEX(tb_cfg_request_lock); @@ -133,41 +132,42 @@ void tb_cfg_request_put(struct tb_cfg_request *req) static int tb_cfg_request_enqueue(struct tb_ctl *ctl, struct tb_cfg_request *req) { + tb_cfg_request_get(req); + WARN_ON(test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags)); WARN_ON(req->ctl); - mutex_lock(&ctl->request_queue_lock); + guard(mutex)(&ctl->request_queue_lock); if (!ctl->running) { - mutex_unlock(&ctl->request_queue_lock); + tb_cfg_request_put(req); return -ENOTCONN; } req->ctl = ctl; list_add_tail(&req->list, &ctl->request_queue); set_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); - mutex_unlock(&ctl->request_queue_lock); return 0; } -static void tb_cfg_request_dequeue(struct tb_cfg_request *req) +static bool tb_cfg_request_is_active(struct tb_cfg_request *req) { - struct tb_ctl *ctl = req->ctl; - - mutex_lock(&ctl->request_queue_lock); - if (!test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags)) { - mutex_unlock(&ctl->request_queue_lock); - return; - } + return test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); +} - list_del(&req->list); - clear_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); - if (test_bit(TB_CFG_REQUEST_CANCELED, &req->flags)) - wake_up(&tb_cfg_request_cancel_queue); - mutex_unlock(&ctl->request_queue_lock); +static bool tb_cfg_request_is_canceled(struct tb_cfg_request *req) +{ + return test_bit(TB_CFG_REQUEST_CANCELED, &req->flags); } -static bool tb_cfg_request_is_active(struct tb_cfg_request *req) +static void tb_cfg_request_dequeue(struct tb_cfg_request *req) { - return test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); + struct tb_ctl *ctl = req->ctl; + + guard(mutex)(&ctl->request_queue_lock); + if (tb_cfg_request_is_active(req)) { + list_del(&req->list); + clear_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); + tb_cfg_request_put(req); + } } static struct tb_cfg_request * @@ -178,7 +178,7 @@ tb_cfg_request_find(struct tb_ctl *ctl, struct ctl_pkg *pkg) mutex_lock(&pkg->ctl->request_queue_lock); list_for_each_entry(iter, &pkg->ctl->request_queue, list) { tb_cfg_request_get(iter); - if (iter->match(iter, pkg)) { + if (!tb_cfg_request_is_canceled(iter) && iter->match(iter, pkg)) { req = iter; break; } @@ -512,8 +512,11 @@ static void tb_ctl_rx_callback(struct tb_ring *ring, struct ring_frame *frame, trace_tb_rx(pkg->ctl->index, frame->eof, pkg->buffer, frame->size, !req); if (req) { - if (req->copy(req, pkg)) - schedule_work(&req->work); + scoped_guard(mutex, &pkg->ctl->request_queue_lock) { + if (!tb_cfg_request_is_canceled(req) && + req->copy(req, pkg)) + schedule_work(&req->work); + } tb_cfg_request_put(req); } @@ -525,11 +528,10 @@ static void tb_cfg_request_work(struct work_struct *work) { struct tb_cfg_request *req = container_of(work, typeof(*req), work); - if (!test_bit(TB_CFG_REQUEST_CANCELED, &req->flags)) + if (!tb_cfg_request_is_canceled(req)) req->callback(req->callback_data); tb_cfg_request_dequeue(req); - tb_cfg_request_put(req); } /** @@ -555,10 +557,9 @@ int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req, INIT_WORK(&req->work, tb_cfg_request_work); INIT_LIST_HEAD(&req->list); - tb_cfg_request_get(req); ret = tb_cfg_request_enqueue(ctl, req); if (ret) - goto err_put; + return ret; ret = tb_ctl_tx(ctl, req->request, req->request_size, req->request_type); @@ -572,9 +573,6 @@ int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req, err_dequeue: tb_cfg_request_dequeue(req); -err_put: - tb_cfg_request_put(req); - return ret; } @@ -588,9 +586,10 @@ int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req, */ void tb_cfg_request_cancel(struct tb_cfg_request *req, int err) { - set_bit(TB_CFG_REQUEST_CANCELED, &req->flags); - schedule_work(&req->work); - wait_event(tb_cfg_request_cancel_queue, !tb_cfg_request_is_active(req)); + scoped_guard(mutex, &req->ctl->request_queue_lock) + set_bit(TB_CFG_REQUEST_CANCELED, &req->flags); + cancel_work_sync(&req->work); + tb_cfg_request_dequeue(req); req->result.err = err; } diff --git a/drivers/thunderbolt/quirks.c b/drivers/thunderbolt/quirks.c index e81de9c30eac..520afebebd42 100644 --- a/drivers/thunderbolt/quirks.c +++ b/drivers/thunderbolt/quirks.c @@ -92,6 +92,9 @@ static const struct tb_quirk tb_quirks[] = { quirk_usb3_maximum_bandwidth }, { 0x8087, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HUB_40G_BRIDGE, 0x0000, 0x0000, quirk_usb3_maximum_bandwidth }, + /* CLx is unstable on the Anker Prime TB5 dock (DROM 01ea:83b5) */ + { 0x8087, PCI_DEVICE_ID_INTEL_BARLOW_RIDGE_HUB_80G_BRIDGE, 0x01ea, 0x83b5, + quirk_clx_disable }, /* * Block Runtime PM in DP redrive mode for Intel Barlow Ridge host * controllers. diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index a99d2db22080..1cd37b5c21f2 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -768,6 +768,7 @@ static int tb_port_alloc_hopid(struct tb_port *port, bool in, int min_hopid, { int port_max_hopid; struct ida *ida; + int ret; if (in) { port_max_hopid = port->config.max_in_hop_id; @@ -787,7 +788,11 @@ static int tb_port_alloc_hopid(struct tb_port *port, bool in, int min_hopid, if (max_hopid < 0 || max_hopid > port_max_hopid) max_hopid = port_max_hopid; - return ida_alloc_range(ida, min_hopid, max_hopid, GFP_KERNEL); + ret = ida_alloc_range(ida, min_hopid, max_hopid, GFP_KERNEL); + if (ret >= 0) + tb_switch_get(port->sw); + + return ret; } /** @@ -826,6 +831,7 @@ int tb_port_alloc_out_hopid(struct tb_port *port, int min_hopid, int max_hopid) void tb_port_release_in_hopid(struct tb_port *port, int hopid) { ida_free(&port->in_hopids, hopid); + tb_switch_put(port->sw); } /** @@ -836,6 +842,7 @@ void tb_port_release_in_hopid(struct tb_port *port, int hopid) void tb_port_release_out_hopid(struct tb_port *port, int hopid) { ida_free(&port->out_hopids, hopid); + tb_switch_put(port->sw); } static inline bool tb_switch_is_reachable(const struct tb_switch *parent, diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 205985eb197e..51b56a304ae8 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -1910,6 +1910,18 @@ static void tb_dp_tunnel_active(struct tb_tunnel *tunnel, void *data) struct tb *tb = data; mutex_lock(&tb->lock); + + /* + * If the DPRX read was canceled the tunnel is already being torn + * down by whoever canceled it. Do not touch the adapters here + * because the routers may be gone by now. + */ + if (tunnel->dprx_canceled) { + tb_tunnel_dbg(tunnel, "DPRX read canceled, not activating\n"); + mutex_unlock(&tb->lock); + return; + } + if (tb_tunnel_is_active(tunnel)) { int consumed_up, consumed_down, ret; @@ -1964,8 +1976,6 @@ static void tb_dp_tunnel_active(struct tb_tunnel *tunnel, void *data) tb_dp_resource_unavailable(tb, in, "DPRX negotiation failed"); } mutex_unlock(&tb->lock); - - tb_domain_put(tb); } static void tb_tunnel_one_dp(struct tb *tb, struct tb_port *in, @@ -2026,8 +2036,7 @@ static void tb_tunnel_one_dp(struct tb *tb, struct tb_port *in, available_up, available_down); tunnel = tb_tunnel_alloc_dp(tb, in, out, link_nr, available_up, - available_down, tb_dp_tunnel_active, - tb_domain_get(tb)); + available_down, tb_dp_tunnel_active, tb); if (!tunnel) { tb_port_dbg(out, "could not allocate DP tunnel\n"); goto err_reclaim_usb; @@ -2048,7 +2057,6 @@ static void tb_tunnel_one_dp(struct tb *tb, struct tb_port *in, tb_tunnel_put(tunnel); err_reclaim_usb: tb_reclaim_usb3_bandwidth(tb, in, out); - tb_domain_put(tb); err_detach_group: tb_detach_bandwidth_group(in); err_dealloc_dp: @@ -2946,11 +2954,12 @@ static void tb_stop(struct tb *tb) /* tunnels are only present after everything has been initialized */ list_for_each_entry_safe(tunnel, n, &tcm->tunnel_list, list) { /* - * DMA tunnels require the driver to be functional so we - * tear them down. Other protocol tunnels can be left - * intact. + * DMA tunnels and DP tunnels which are not yet active require + * the driver to be functional so we tear them down. + * Other protocol tunnels can be left intact. */ - if (tb_tunnel_is_dma(tunnel)) + if (tb_tunnel_is_dma(tunnel) || + (tb_tunnel_is_dp(tunnel) && !tb_tunnel_is_active(tunnel))) tb_tunnel_deactivate(tunnel); tb_tunnel_put(tunnel); } diff --git a/drivers/thunderbolt/test.c b/drivers/thunderbolt/test.c index 1f4318249c22..fb769005f7cd 100644 --- a/drivers/thunderbolt/test.c +++ b/drivers/thunderbolt/test.c @@ -33,6 +33,18 @@ static void kunit_ida_init(struct kunit *test, struct ida *ida) kunit_alloc_resource(test, __ida_init, __ida_destroy, GFP_KERNEL, ida); } +static void tb_test_switch_release(struct device *dev) +{ + /* The memory is owned by KUnit, nothing to do here */ +} + +static void tb_test_switch_put(void *data) +{ + struct tb_switch *sw = data; + + put_device(&sw->dev); +} + static struct tb_switch *alloc_switch(struct kunit *test, u64 route, u8 upstream_port, u8 max_port_number) { @@ -44,6 +56,15 @@ static struct tb_switch *alloc_switch(struct kunit *test, u64 route, if (!sw) return NULL; + /* + * HopID allocations take a reference to their routers and those devices + * have to be initialized for that to work. + */ + sw->dev.release = tb_test_switch_release; + device_initialize(&sw->dev); + if (kunit_add_action_or_reset(test, tb_test_switch_put, sw)) + return NULL; + sw->config.upstream_port_number = upstream_port; sw->config.depth = tb_route_length(route); sw->config.route_hi = upper_32_bits(route); diff --git a/drivers/thunderbolt/tunnel.c b/drivers/thunderbolt/tunnel.c index 6066355388b7..466e9da02935 100644 --- a/drivers/thunderbolt/tunnel.c +++ b/drivers/thunderbolt/tunnel.c @@ -513,6 +513,7 @@ struct tb_tunnel *tb_tunnel_discover_pci(struct tb *tb, struct tb_port *down, goto err_deactivate; } + tb_tunnel_set_active(tunnel, true); tb_tunnel_dbg(tunnel, "discovered\n"); return tunnel; @@ -1096,8 +1097,14 @@ static void tb_dp_dprx_work(struct work_struct *work) struct tb_tunnel *tunnel = container_of(work, typeof(*tunnel), dprx_work.work); struct tb *tb = tunnel->tb; + /* + * The DPRX read can be canceled while this work is waiting for + * tb->lock. Check the flag only once it is held: while the lock is + * held the tunnel cannot be torn down under us and the adapters are + * safe to access. + */ + mutex_lock(&tb->lock); if (!tunnel->dprx_canceled) { - mutex_lock(&tb->lock); if (tb_dp_is_usb4(tunnel->src_port->sw) && tb_dp_wait_dprx(tunnel, TB_DPRX_WAIT_TIMEOUT)) { if (ktime_before(ktime_get(), tunnel->dprx_timeout)) { @@ -1109,23 +1116,26 @@ static void tb_dp_dprx_work(struct work_struct *work) } else { tb_tunnel_set_active(tunnel, true); } - mutex_unlock(&tb->lock); } + mutex_unlock(&tb->lock); if (tunnel->callback) tunnel->callback(tunnel, tunnel->callback_data); tb_tunnel_put(tunnel); + tb_domain_put(tb); } static int tb_dp_dprx_start(struct tb_tunnel *tunnel) { /* - * Bump up the reference to keep the tunnel around. It will be - * dropped in tb_dp_dprx_stop() once the tunnel is deactivated. + * Bump up the references to keep the tunnel and the domain around + * until the work has run or has been canceled. */ tb_tunnel_get(tunnel); + tb_domain_get(tunnel->tb); tunnel->dprx_started = true; + tunnel->dprx_canceled = false; if (tunnel->callback) { tunnel->dprx_timeout = dprx_timeout_to_ktime(dprx_timeout); @@ -1139,11 +1149,15 @@ static int tb_dp_dprx_start(struct tb_tunnel *tunnel) static void tb_dp_dprx_stop(struct tb_tunnel *tunnel) { + struct tb *tb = tunnel->tb; + if (tunnel->dprx_started) { tunnel->dprx_started = false; tunnel->dprx_canceled = true; - if (cancel_delayed_work(&tunnel->dprx_work)) + if (cancel_delayed_work(&tunnel->dprx_work)) { tb_tunnel_put(tunnel); + tb_domain_put(tb); + } } } @@ -1659,6 +1673,7 @@ struct tb_tunnel *tb_tunnel_discover_dp(struct tb *tb, struct tb_port *in, tb_dp_dump(tunnel); + tb_tunnel_set_active(tunnel, true); tb_tunnel_dbg(tunnel, "discovered\n"); return tunnel; @@ -2287,6 +2302,7 @@ struct tb_tunnel *tb_tunnel_discover_usb3(struct tb *tb, struct tb_port *down, tb_usb3_reclaim_available_bandwidth; } + tb_tunnel_set_active(tunnel, true); tb_tunnel_dbg(tunnel, "discovered\n"); return tunnel; diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c index e2c46366c816..d9c2686b5fe4 100644 --- a/drivers/thunderbolt/xdomain.c +++ b/drivers/thunderbolt/xdomain.c @@ -377,6 +377,10 @@ static int tb_xdp_properties_request(struct tb_ctl *ctl, u64 route, len += sizeof(res->hdr.xd_hdr) / 4; len -= sizeof(*res) / 4; + if (len > TB_XDP_PROPERTIES_MAX_DATA_LENGTH) { + ret = -EINVAL; + goto err; + } if (res->offset != req.offset) { ret = -EINVAL; diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index 5af46442a792..4519d43a9857 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -1138,11 +1138,6 @@ static int rs_ioctl(struct tty_struct *tty, local_irq_save(flags); cnow = info->icount; /* atomic copy */ local_irq_restore(flags); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { - ret = -EIO; /* no change => error */ - break; - } if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || @@ -1150,6 +1145,10 @@ static int rs_ioctl(struct tty_struct *tty, ret = 0; break; } + if (tty_io_error(tty)) { + ret = -EIO; + break; + } schedule(); /* see if a signal did it */ if (signal_pending(current)) { diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 553d8c70352b..0749f50cff90 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -454,14 +454,13 @@ static const u8 gsm_fcs8[256] = { static void gsm_dlci_close(struct gsm_dlci *dlci); static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len); -static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk); +static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk, bool wait); static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len, u8 ctrl); static int gsm_send_packet(struct gsm_mux *gsm, struct gsm_msg *msg); static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr); static void gsmld_write_trigger(struct gsm_mux *gsm); static void gsmld_write_task(struct work_struct *work); -static int gsm_modem_send_initial_msc(struct gsm_dlci *dlci); /** * gsm_fcs_add - update FCS @@ -2175,7 +2174,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) pr_debug("DLCI %d goes open.\n", dlci->addr); /* Send current modem state */ if (dlci->addr) { - gsm_modem_send_initial_msc(dlci); + gsm_modem_update(dlci, 0, false); } else { /* Start keep-alive control */ gsm->ka_num = 0; @@ -4137,9 +4136,10 @@ static void gsm_modem_upd_via_data(struct gsm_dlci *dlci, u8 brk) * gsm_modem_upd_via_msc - send modem bits via control frame * @dlci: channel * @brk: break signal + * @wait: wait for the MSC command */ -static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk) +static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk, bool wait) { u8 modembits[3]; struct gsm_control *ctrl; @@ -4156,41 +4156,22 @@ static int gsm_modem_upd_via_msc(struct gsm_dlci *dlci, u8 brk) modembits[2] = (brk << 4) | 2 | EA; /* Length, Break, EA */ len++; } + if (!wait) + return gsm_control_command(dlci->gsm, CMD_MSC, modembits, len); ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len); if (ctrl == NULL) return -ENOMEM; return gsm_control_wait(dlci->gsm, ctrl); } -/** - * gsm_modem_send_initial_msc - Send initial modem status message - * - * @dlci channel - * - * Send an initial MSC message after DLCI open to set the initial - * modem status lines. This is only done for basic mode. - * Does not wait for a response as we cannot block the input queue - * processing. - */ -static int gsm_modem_send_initial_msc(struct gsm_dlci *dlci) -{ - u8 modembits[2]; - - if (dlci->adaption != 1 || dlci->gsm->encoding != GSM_BASIC_OPT) - return 0; - - modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */ - modembits[1] = (gsm_encode_modem(dlci) << 1) | EA; - return gsm_control_command(dlci->gsm, CMD_MSC, (const u8 *)&modembits, 2); -} - /** * gsm_modem_update - send modem status line state * @dlci: channel * @brk: break signal + * @wait: wait for the MSC command */ -static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk) +static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk, bool wait) { if (dlci->gsm->dead) return -EL2HLT; @@ -4200,7 +4181,7 @@ static int gsm_modem_update(struct gsm_dlci *dlci, u8 brk) return 0; } else if (dlci->gsm->encoding == GSM_BASIC_OPT) { /* Send as MSC control message. */ - return gsm_modem_upd_via_msc(dlci, brk); + return gsm_modem_upd_via_msc(dlci, brk, wait); } /* Modem status lines are not supported. */ @@ -4266,7 +4247,7 @@ static void gsm_dtr_rts(struct tty_port *port, bool active) modem_tx &= ~(TIOCM_DTR | TIOCM_RTS); if (modem_tx != dlci->modem_tx) { dlci->modem_tx = modem_tx; - gsm_modem_update(dlci, 0); + gsm_modem_update(dlci, 0, true); } } @@ -4472,7 +4453,7 @@ static int gsmtty_tiocmset(struct tty_struct *tty, if (modem_tx != dlci->modem_tx) { dlci->modem_tx = modem_tx; - return gsm_modem_update(dlci, 0); + return gsm_modem_update(dlci, 0, true); } return 0; } @@ -4554,7 +4535,7 @@ static void gsmtty_throttle(struct tty_struct *tty) dlci->modem_tx &= ~TIOCM_RTS; dlci->throttled = true; /* Send an MSC with RTS cleared */ - gsm_modem_update(dlci, 0); + gsm_modem_update(dlci, 0, true); } static void gsmtty_unthrottle(struct tty_struct *tty) @@ -4566,7 +4547,7 @@ static void gsmtty_unthrottle(struct tty_struct *tty) dlci->modem_tx |= TIOCM_RTS; dlci->throttled = false; /* Send an MSC with RTS set */ - gsm_modem_update(dlci, 0); + gsm_modem_update(dlci, 0, true); } static int gsmtty_break_ctl(struct tty_struct *tty, int state) @@ -4584,7 +4565,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state) if (encode > 0x0F) encode = 0x0F; /* Best effort */ } - return gsm_modem_update(dlci, encode); + return gsm_modem_update(dlci, encode, true); } static void gsmtty_cleanup(struct tty_struct *tty) diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c index 742004d63c6f..60c7d5c9100c 100644 --- a/drivers/tty/serial/8250/8250_bcm7271.c +++ b/drivers/tty/serial/8250/8250_bcm7271.c @@ -1123,8 +1123,8 @@ static void brcmuart_remove(struct platform_device *pdev) struct brcmuart_priv *priv = platform_get_drvdata(pdev); debugfs_remove_recursive(priv->debugfs_dir); - hrtimer_cancel(&priv->hrt); serial8250_unregister_port(priv->line); + hrtimer_cancel(&priv->hrt); brcmuart_free_bufs(&pdev->dev, priv); if (priv->dma_enabled) brcmuart_arbitration(priv, 0); diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 454a5e0f40c4..c0ffee251614 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -727,12 +727,6 @@ static int omap_8250_startup(struct uart_port *port) struct uart_8250_dma *dma = &priv->omap8250_dma; int ret; - if (priv->wakeirq) { - ret = dev_pm_set_dedicated_wake_irq(port->dev, priv->wakeirq); - if (ret) - return ret; - } - #ifdef CONFIG_PM up->capabilities |= UART_CAP_RPM; #endif @@ -803,7 +797,6 @@ static void omap_8250_shutdown(struct uart_port *port) } disable_irq_nosync(port->irq); - dev_pm_clear_wake_irq(port->dev); serial8250_release_dma(up); up->dma = NULL; @@ -1602,6 +1595,12 @@ static int omap8250_probe(struct platform_device *pdev) priv->wakeirq = irq_of_parse_and_map(np, 1); + if (priv->wakeirq) { + ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, priv->wakeirq); + if (ret) + goto err; + } + ret = serial8250_register_8250_port(&up); if (ret < 0) { dev_err(&pdev->dev, "unable to register 8250 port\n"); @@ -1617,6 +1616,7 @@ static int omap8250_probe(struct platform_device *pdev) return 0; err: + dev_pm_clear_wake_irq(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); flush_work(&priv->qos_work); @@ -1639,6 +1639,7 @@ static void omap8250_remove(struct platform_device *pdev) omap_8250_shutdown(&up->port); serial8250_unregister_port(priv->line); priv->line = -ENODEV; + dev_pm_clear_wake_irq(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); flush_work(&priv->qos_work); diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 85f6c5a76e0f..a3776194f3c2 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -188,6 +188,11 @@ static void cleanup_kgdboc(void) kgdboc_unregister_kbd(); kgdb_unregister_io_module(&kgdboc_io_ops); + + if (kgdb_tty_driver) { + tty_driver_kref_put(kgdb_tty_driver); + kgdb_tty_driver = NULL; + } } static int configure_kgdboc(void) @@ -254,6 +259,10 @@ static int configure_kgdboc(void) noconfig: kgdboc_unregister_kbd(); + if (kgdb_tty_driver) { + tty_driver_kref_put(kgdb_tty_driver); + kgdb_tty_driver = NULL; + } configured = 0; return err; diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c index 920fe7ff5083..0809655f4395 100644 --- a/drivers/tty/serial/ma35d1_serial.c +++ b/drivers/tty/serial/ma35d1_serial.c @@ -728,7 +728,7 @@ static int ma35d1serial_probe(struct platform_device *pdev) ret = clk_prepare_enable(up->clk); if (ret) - goto err_iounmap; + goto err_put_clk; if (up->port.line != 0) up->port.uartclk = clk_get_rate(up->clk); @@ -755,6 +755,9 @@ static int ma35d1serial_probe(struct platform_device *pdev) err_clk_disable: clk_disable_unprepare(up->clk); +err_put_clk: + clk_put(up->clk); + err_iounmap: iounmap(up->port.membase); return ret; @@ -770,6 +773,7 @@ static void ma35d1serial_remove(struct platform_device *dev) uart_remove_one_port(&ma35d1serial_reg, port); clk_disable_unprepare(up->clk); + clk_put(up->clk); } static int ma35d1serial_suspend(struct platform_device *dev, pm_message_t state) diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 3faa1b6aa3ee..319453b5f4e8 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -536,11 +536,11 @@ static void max3100_shutdown(struct uart_port *port) timer_delete_sync(&s->timer); if (s->workqueue) { + free_irq(port->irq, s); + cancel_work_sync(&s->work); destroy_workqueue(s->workqueue); s->workqueue = NULL; } - if (port->irq) - free_irq(port->irq, s); /* set shutdown mode to save power */ max3100_sr(s, MAX3100_WC | MAX3100_SHDN, &rx); @@ -753,6 +753,15 @@ static void max3100_remove(struct spi_device *spi) if (max3100s[i] == s) { dev_dbg(&spi->dev, "%s: removing port %d\n", __func__, i); uart_remove_one_port(&max3100_uart_driver, &max3100s[i]->port); + + s->force_end_work = 1; + timer_shutdown_sync(&s->timer); + if (s->workqueue) { + free_irq(s->port.irq, s); + cancel_work_sync(&s->work); + destroy_workqueue(s->workqueue); + s->workqueue = NULL; + } kfree(max3100s[i]); max3100s[i] = NULL; break; diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 953b73735710..5d59a2cfab3e 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1303,9 +1303,8 @@ static int geni_serial_set_rate(struct uart_port *uport, unsigned int baud) * Bump up BW vote on CPU and CORE path as driver supports FIFO mode * only. */ - avg_bw_core = (baud > 115200) ? Bps_to_icc(CORE_2X_50_MHZ) - : GENI_DEFAULT_BW; - port->se.icc_paths[GENI_TO_CORE].avg_bw = avg_bw_core; + avg_bw_core = baud > 115200 ? CORE_2X_50_MHZ : CORE_2X_19_2_MHZ; + port->se.icc_paths[GENI_TO_CORE].avg_bw = Bps_to_icc(avg_bw_core); port->se.icc_paths[CPU_TO_GENI].avg_bw = Bps_to_icc(baud); geni_icc_set_bw(&port->se); diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 5592f797e3b0..42ad926f1fe6 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -246,6 +246,8 @@ #define SC16IS7XX_TLR_TX_TRIGGER(words) ((((words) / 4) & 0x0f) << 0) #define SC16IS7XX_TLR_RX_TRIGGER(words) ((((words) / 4) & 0x0f) << 4) +#define SC16IS7XX_TX_TRIGGER_LEVEL 8 + /* IOControl register bits (Only 75x/76x) */ #define SC16IS7XX_IOCONTROL_LATCH_BIT BIT(0) /* Enable input latching */ #define SC16IS7XX_IOCONTROL_MODEM_A_BIT BIT(1) /* Enable GPIO[7:4] as modem A pins */ @@ -694,12 +696,26 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, tty_flip_buffer_push(&port->state->port); } +static unsigned int sc16is7xx_txlvl(struct uart_port *port) +{ + unsigned int txlvl; + + txlvl = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); + if (txlvl > SC16IS7XX_FIFO_SIZE) { + dev_err_ratelimited(port->dev, + "chip reports %u free bytes in TX FIFO, but it only has %u\n", + txlvl, SC16IS7XX_FIFO_SIZE); + return 0; + } + + return txlvl; +} + static void sc16is7xx_handle_tx(struct uart_port *port) { struct tty_port *tport = &port->state->port; unsigned long flags; unsigned int txlen; - unsigned char *tail; if (unlikely(port->x_char)) { sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char); @@ -716,17 +732,28 @@ static void sc16is7xx_handle_tx(struct uart_port *port) } /* Limit to space available in TX FIFO */ - txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); - if (txlen > SC16IS7XX_FIFO_SIZE) { - dev_err_ratelimited(port->dev, - "chip reports %d free bytes in TX fifo, but it only has %d", - txlen, SC16IS7XX_FIFO_SIZE); - txlen = 0; - } + txlen = sc16is7xx_txlvl(port); + + /* Handle circular buffer wrap-around by sending multiple segments */ + while (txlen > 0 && !kfifo_is_empty(&tport->xmit_fifo)) { + unsigned char *tail; + unsigned int to_send; + + to_send = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, txlen); + if (!to_send) + break; - txlen = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, txlen); - sc16is7xx_fifo_write(port, tail, txlen); - uart_xmit_advance(port, txlen); + sc16is7xx_fifo_write(port, tail, to_send); + uart_xmit_advance(port, to_send); + + if (kfifo_is_empty(&tport->xmit_fifo)) + break; + + /* Refill below the trigger to enable the next THRI crossing. */ + txlen = sc16is7xx_txlvl(port); + if (txlen < SC16IS7XX_TX_TRIGGER_LEVEL) + break; + } uart_port_lock_irqsave(port, &flags); if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) @@ -1177,6 +1204,10 @@ static int sc16is7xx_startup(struct uart_port *port) SC16IS7XX_TCR_RX_RESUME(24) | SC16IS7XX_TCR_RX_HALT(48)); + /* Sync hardware and software TX trigger levels */ + sc16is7xx_port_write(port, SC16IS7XX_TLR_REG, + SC16IS7XX_TLR_TX_TRIGGER(SC16IS7XX_TX_TRIGGER_LEVEL)); + /* Disable TCR/TLR access */ sc16is7xx_port_update(port, SC16IS7XX_MCR_REG, SC16IS7XX_MCR_TCRTLR_BIT, 0); diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index 8004fc00fb9c..b0fc4ae3686f 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -306,11 +306,19 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits) { unsigned long fcr = tup->fcr_shadow; unsigned int lsr, tmout = 10000; + bool clear_tx = !!(fcr_bits & UART_FCR_CLEAR_XMIT); if (tup->rts_active) set_rts(tup, false); - if (tup->cdata->allow_txfifo_reset_fifo_mode) { + /* + * Leaving FIFO mode below is a workaround for a Tegra30 + * restriction on clearing the Tx FIFO while FIFO mode is + * enabled. It empties both FIFOs, so applying it to an + * Rx-only reset would destroy an in-flight transmission. + * Only take that path when the caller asked for CLEAR_XMIT. + */ + if (tup->cdata->allow_txfifo_reset_fifo_mode || !clear_tx) { fcr |= fcr_bits & (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); tegra_uart_write(tup, fcr, UART_FCR); } else { @@ -335,9 +343,15 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits) */ tegra_uart_wait_cycle_time(tup, 32); + /* + * Only wait for the transmitter to drain when the Tx FIFO was + * part of the reset. For an Rx-only reset it is left intact, + * and waiting for TEMT here would spin for a full frame time. + */ do { lsr = tegra_uart_read(tup, UART_LSR); - if ((lsr & UART_LSR_TEMT) && !(lsr & UART_LSR_DR)) + if ((!clear_tx || (lsr & UART_LSR_TEMT)) && + !(lsr & UART_LSR_DR)) break; udelay(1); } while (--tmout); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 96599dee967b..32cdfc59a9ad 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1220,18 +1220,19 @@ static int uart_wait_modem_status(struct uart_state *state, unsigned long arg) uport = uart_port_ref(state); if (!uport) return -EIO; - scoped_guard(uart_port_lock_irq, uport) { - memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); - uart_enable_ms(uport); - } + uart_port_lock_irq(uport); + memcpy(&cprev, &uport->icount, sizeof(struct uart_icount)); + uart_enable_ms(uport); + uart_port_unlock_irq(uport); add_wait_queue(&port->delta_msr_wait, &wait); for (;;) { - scoped_guard(uart_port_lock_irq, uport) - memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); - set_current_state(TASK_INTERRUPTIBLE); + uart_port_lock_irq(uport); + memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); + uart_port_unlock_irq(uport); + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || diff --git a/drivers/tty/serial/vt8500_serial.c b/drivers/tty/serial/vt8500_serial.c index 78a1c1eea11b..fc6fdc751b16 100644 --- a/drivers/tty/serial/vt8500_serial.c +++ b/drivers/tty/serial/vt8500_serial.c @@ -656,6 +656,7 @@ static int vt8500_serial_probe(struct platform_device *pdev) ret = clk_prepare_enable(vt8500_port->clk); if (ret) { dev_err(&pdev->dev, "failed to enable clock\n"); + clk_put(vt8500_port->clk); return ret; } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index f779f8fb138e..dd7231d9cab9 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -620,6 +620,8 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) tty_ldisc_hangup(tty, cons_filp != NULL); + wake_up_interruptible(&tty->break_wait); + spin_lock_irq(&tty->ctrl.lock); clear_bit(TTY_THROTTLED, &tty->flags); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); @@ -2458,6 +2460,7 @@ static int tiocgetd(struct tty_struct *tty, int __user *p) * send_break - performed time break * @tty: device to break on * @duration: timeout in mS + * @file: file object * * Perform a timed break on hardware that lacks its own driver level timed * break functionality. @@ -2465,8 +2468,9 @@ static int tiocgetd(struct tty_struct *tty, int __user *p) * Locking: * @tty->atomic_write_lock serializes */ -static int send_break(struct tty_struct *tty, unsigned int duration) +static int send_break(struct file *file, struct tty_struct *tty, unsigned int duration) { + long timeout; int retval; if (tty->ops->break_ctl == NULL) @@ -2480,13 +2484,26 @@ static int send_break(struct tty_struct *tty, unsigned int duration) return -EINTR; retval = tty->ops->break_ctl(tty, -1); - if (!retval) { - msleep_interruptible(duration); - retval = tty->ops->break_ctl(tty, 0); - } else if (retval == -EOPNOTSUPP) { - /* some drivers can tell only dynamically */ - retval = 0; + if (retval) { + if (retval == -EOPNOTSUPP) { + /* some drivers can tell only dynamically */ + retval = 0; + } + goto out_unlock; + } + + timeout = msecs_to_jiffies(duration); + timeout = wait_event_interruptible_timeout(tty->break_wait, + tty_hung_up_p(file), + timeout); + /* return early on hangup only */ + if (timeout > 0) { + retval = -EIO; + goto out_unlock; } + + retval = tty->ops->break_ctl(tty, 0); +out_unlock: tty_write_unlock(tty); if (signal_pending(current)) @@ -2754,10 +2771,10 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) * This is used by the tcdrain() termios function. */ if (!arg) - return send_break(tty, 250); + return send_break(file, tty, 250); return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ - return send_break(tty, arg ? arg*100 : 250); + return send_break(file, tty, arg ? arg * 100 : 250); case TIOCMGET: return tty_tiocmget(tty, p); @@ -3117,6 +3134,7 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) init_ldsem(&tty->ldisc_sem); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); + init_waitqueue_head(&tty->break_wait); INIT_WORK(&tty->hangup_work, do_tty_hangup); mutex_init(&tty->atomic_write_lock); spin_lock_init(&tty->ctrl.lock); @@ -3265,14 +3283,16 @@ struct device *tty_register_device_attr(struct tty_driver *driver, goto err_put; if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { - /* - * Free any saved termios data so that the termios state is - * reset when reusing a minor number. - */ - tp = driver->termios[index]; - if (tp) { - driver->termios[index] = NULL; - kfree(tp); + if (driver->flags & TTY_DRIVER_RESET_SAVED_TERMIOS) { + /* + * Free any saved termios data so that the termios + * state is reset when reusing a minor number. + */ + tp = driver->termios[index]; + if (tp) { + driver->termios[index] = NULL; + kfree(tp); + } } retval = tty_cdev_add(driver, devt, index, 1); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index fe67c5cb0a3f..6c3055e179ee 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -319,19 +319,9 @@ void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) } EXPORT_SYMBOL(tty_port_tty_set); -/** - * tty_port_shutdown - internal helper to shutdown the device - * @port: tty port to be shut down - * @tty: the associated tty - * - * It is used by tty_port_hangup() and tty_port_close(). Its task is to - * shutdown the device if it was initialized (note consoles remain - * functioning). It lowers DTR/RTS (if @tty has HUPCL set) and invokes - * @port->ops->shutdown(). - */ -static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty) +static void tty_port_shutdown_locked(struct tty_port *port, struct tty_struct *tty) { - guard(mutex)(&port->mutex); + lockdep_assert_held(&port->mutex); if (port->console) return; @@ -351,6 +341,23 @@ static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty) port->ops->shutdown(port); } +/** + * tty_port_shutdown - internal helper to shutdown the device + * @port: tty port to be shut down + * @tty: the associated tty + * + * It is used by tty_port_hangup() and tty_port_close(). Its task is to + * shutdown the device if it was initialized (note consoles remain + * functioning). It lowers DTR/RTS (if @tty has HUPCL set) and invokes + * @port->ops->shutdown(). + */ +static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty) +{ + guard(mutex)(&port->mutex); + + tty_port_shutdown_locked(port, tty); +} + /** * tty_port_hangup - hangup helper * @port: tty port @@ -364,36 +371,58 @@ void tty_port_hangup(struct tty_port *port) { struct tty_struct *tty; - scoped_guard(spinlock_irqsave, &port->lock) { - port->count = 0; - tty = port->tty; - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); - port->tty = NULL; - } + scoped_guard(mutex, &port->mutex) { + scoped_guard(spinlock_irqsave, &port->lock) { + port->count = 0; + tty = port->tty; + if (tty) + set_bit(TTY_IO_ERROR, &tty->flags); + port->tty = NULL; + } - tty_port_set_active(port, false); - tty_port_shutdown(port, tty); + tty_port_set_active(port, false); + tty_port_shutdown_locked(port, tty); + } tty_kref_put(tty); wake_up_interruptible(&port->open_wait); wake_up_interruptible(&port->delta_msr_wait); } EXPORT_SYMBOL(tty_port_hangup); -void __tty_port_tty_hangup(struct tty_port *port, bool check_clocal, bool async) +/** + * tty_port_tty_hangup - helper to hang up a tty asynchronously + * @port: tty port + * @check_clocal: hang only ttys with %CLOCAL unset? + */ +void tty_port_tty_hangup(struct tty_port *port, bool check_clocal) { scoped_guard(tty_port_tty, port) { struct tty_struct *tty = scoped_tty(); - if (!check_clocal || !C_CLOCAL(tty)) { - if (async) - tty_hangup(tty); - else - tty_vhangup(tty); - } + if (!check_clocal || !C_CLOCAL(tty)) + tty_hangup(tty); + } +} +EXPORT_SYMBOL_GPL(tty_port_tty_hangup); + +/** + * tty_port_tty_vhangup - helper to hang up a tty synchronously + * @port: tty port + */ +void tty_port_tty_vhangup(struct tty_port *port) +{ + struct tty_struct *tty; + + mutex_lock(&port->mutex); + tty = tty_port_tty_get(port); + mutex_unlock(&port->mutex); + + if (tty) { + tty_vhangup(tty); + tty_kref_put(tty); } } -EXPORT_SYMBOL_GPL(__tty_port_tty_hangup); +EXPORT_SYMBOL_GPL(tty_port_tty_vhangup); /** * tty_port_tty_wakeup - helper to wake up a tty @@ -745,8 +774,10 @@ int tty_port_open(struct tty_port *port, struct tty_struct *tty, clear_bit(TTY_IO_ERROR, &tty->flags); if (port->ops->activate) { int retval = port->ops->activate(port, tty); - if (retval) + if (retval) { + set_bit(TTY_IO_ERROR, &tty->flags); return retval; + } } tty_port_set_initialized(port, true); } diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c index 2960031ace72..e1b67d0dbbef 100644 --- a/drivers/tty/vcc.c +++ b/drivers/tty/vcc.c @@ -492,7 +492,7 @@ static ssize_t domain_show(struct device *dev, static int vcc_send_ctl(struct vcc_port *port, int ctl) { - struct vio_vcc pkt; + struct vio_vcc pkt = {}; int rv; pkt.tag.type = VIO_TYPE_CTRL; @@ -986,7 +986,8 @@ static void vcc_cleanup(struct tty_struct *tty) port = vcc_get(tty->index, true); if (port) { - port->tty = NULL; + scoped_guard(spinlock_irqsave, &port->lock) + port->tty = NULL; if (port->removed) { vcc_table_remove(tty->index); diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 07d3b93975d3..12398a7f8f40 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -433,8 +433,8 @@ int paste_selection(struct tty_struct *tty) bps = NULL; } - count = vc_sel.buf_len - pasted; - if (count) { + if (vc_sel.buf_len > pasted) { + count = vc_sel.buf_len - pasted; pasted += tty_ldisc_receive_buf(ld, vc_sel.buffer + pasted, NULL, count); if (vc_sel.buf_len > pasted) diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 60b12d40724c..e9d1ca6d02d4 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -633,6 +633,18 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) ret = copy_from_user(con_buf, buf, this_round); console_lock(); + /* The vc might have been freed or vcs_size might have changed + * while we slept to grab the user buffer; recheck here, before + * if (ret), so every break path below passes a fresh vc to the + * post-loop vcs_scr_updated(). Return data written so far. + */ + vc = vcs_vc(inode, &viewed); + if (!vc) { + if (written) + break; + return -ENXIO; + } + if (ret) { this_round -= ret; if (!this_round) { @@ -644,17 +656,6 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) return -EFAULT; } } - - /* The vc might have been freed or vcs_size might have changed - * while we slept to grab the user buffer, so recheck. - * Return data written up to now on failure. - */ - vc = vcs_vc(inode, &viewed); - if (!vc) { - if (written) - break; - return -ENXIO; - } size = vcs_size(vc, attr, false); if (size < 0) { if (written) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index a1117196cbb3..8306744bee4d 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1106,6 +1106,8 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ return 0; err_free: visual_deinit(vc); + if (*vc->uni_pagedict_loc) + con_free_unimap(vc); kfree(vc); vc_cons[currcons].d = NULL; return err; @@ -2790,7 +2792,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, u8 c) csi_J(vc, CSI_J_VISIBLE); vc->vc_video_erase_char = (vc->vc_video_erase_char & 0xff00) | ' '; - do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); + if (con_should_update(vc)) + do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); } return; case ESsetG0: /* ESC ( */ diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index bc1157a4df00..331f10cc3fca 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -3270,6 +3270,10 @@ static void cdns3_gadget_exit(struct cdns *cdns) usb_del_gadget(&priv_dev->gadget); devm_free_irq(cdns->dev, cdns->dev_irq, priv_dev); + /* The works can still be queued until the IRQ is freed. */ + cancel_work_sync(&priv_dev->pending_status_wq); + cancel_work_sync(&priv_dev->aligned_buf_wq); + cdns3_free_all_eps(priv_dev); while (!list_empty(&priv_dev->aligned_buf_list)) { diff --git a/drivers/usb/cdns3/cdns3-pci-wrap.c b/drivers/usb/cdns3/cdns3-pci-wrap.c index 57f57c24c663..37390cf769cd 100644 --- a/drivers/usb/cdns3/cdns3-pci-wrap.c +++ b/drivers/usb/cdns3/cdns3-pci-wrap.c @@ -96,6 +96,11 @@ static int cdns3_pci_probe(struct pci_dev *pdev, if (pci_is_enabled(func)) { wrap = pci_get_drvdata(func); + if (!wrap) { + dev_err(&pdev->dev, + "second function not initialized, retrying\n"); + return -EPROBE_DEFER; + } } else { wrap = kzalloc(sizeof(*wrap), GFP_KERNEL); if (!wrap) diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c index 372788f0f970..26225b034d3b 100644 --- a/drivers/usb/chipidea/ci_hdrc_tegra.c +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -306,8 +306,10 @@ static int tegra_usb_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); err = pm_runtime_resume_and_get(&pdev->dev); - if (err) + if (err) { + pm_runtime_disable(&pdev->dev); return err; + } if (device_property_present(&pdev->dev, "nvidia,needs-double-reset")) usb->needs_double_reset = true; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index d6a2f1591460..b980cb08d675 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -331,7 +331,6 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) spin_lock_irqsave(&acm->read_lock, flags); acm->ctrlin = newctrl; - acm->oldcount = acm->iocount; if (difference & USB_CDC_SERIAL_STATE_DSR) acm->iocount.dsr++; @@ -788,6 +787,9 @@ static void acm_port_shutdown(struct tty_port *port) usb_autopm_put_interface_async(acm->control); } + if (acm->disconnected) + return; + acm_unpoison_urbs(acm); if (acm->quirks & ALWAYS_POLL_CTRL) { @@ -1027,11 +1029,16 @@ static int wait_serial_change(struct acm *acm, unsigned long arg) DECLARE_WAITQUEUE(wait, current); struct async_icount old, new; - do { + spin_lock_irq(&acm->read_lock); + old = acm->iocount; + spin_unlock_irq(&acm->read_lock); + + add_wait_queue(&acm->wioctl, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + spin_lock_irq(&acm->read_lock); - old = acm->oldcount; new = acm->iocount; - acm->oldcount = new; spin_unlock_irq(&acm->read_lock); if ((arg & TIOCM_DSR) && @@ -1044,22 +1051,20 @@ static int wait_serial_change(struct acm *acm, unsigned long arg) old.rng != new.rng) break; - add_wait_queue(&acm->wioctl, &wait); - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - remove_wait_queue(&acm->wioctl, &wait); if (acm->disconnected) { - if (arg & TIOCM_CD) - break; - else - rv = -ENODEV; - } else { - if (signal_pending(current)) - rv = -ERESTARTSYS; + rv = -ENODEV; + break; } - } while (!rv); - + schedule(); + + if (signal_pending(current)) { + rv = -ERESTARTSYS; + break; + } + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(&acm->wioctl, &wait); return rv; } @@ -2140,7 +2145,7 @@ static int __init acm_init(void) { int retval; acm_tty_driver = tty_alloc_driver(ACM_TTY_MINORS, TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV); + TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_RESET_SAVED_TERMIOS); if (IS_ERR(acm_tty_driver)) return PTR_ERR(acm_tty_driver); acm_tty_driver->driver_name = "acm", diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 01f448a783c0..d245e60eb9f5 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -90,7 +90,6 @@ struct acm { unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ unsigned int ctrlout; /* output control lines (DTR, RTS) */ struct async_icount iocount; /* counters for control line changes */ - struct async_icount oldcount; /* for comparison of counter */ wait_queue_head_t wioctl; /* for ioctl */ unsigned int writesize; /* max packet size for the output bulk endpoint */ unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8097a1476a0f..eedbe84a4812 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -71,8 +71,11 @@ /* * Give SS hubs 200ms time after wake to train downstream links before * assuming no port activity and allowing hub to runtime suspend back. + * Root hubs have no upstream hub whose wake propagation needs to be + * accounted for, so they need less time, use 120ms for them. */ #define USB_SS_PORT_U0_WAKE_TIME 200 /* ms */ +#define USB_SS_RH_PORT_U0_WAKE_TIME 120 /* ms */ /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can @@ -1362,7 +1365,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) queue_delayed_work(system_power_efficient_wq, &hub->post_resume_work, - msecs_to_jiffies(USB_SS_PORT_U0_WAKE_TIME)); + msecs_to_jiffies(hdev->parent ? + USB_SS_PORT_U0_WAKE_TIME : + USB_SS_RH_PORT_U0_WAKE_TIME)); return; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 43522f1d6b2b..e291cec42c99 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1335,7 +1335,8 @@ static void remove_intf_ep_devs(struct usb_interface *intf) * * Disables the endpoint for URB submission and nukes all pending URBs. * If @reset_hardware is set then also deallocates hcd/hardware state - * for the endpoint. + * for the endpoint (clearing both ep_in and ep_out pointers for + * bidirectional non-ep0 control endpoints). */ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr, bool reset_hardware) @@ -1356,6 +1357,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr, dev->ep_in[epnum] = NULL; } if (ep) { + if (reset_hardware && epnum != 0 && + usb_endpoint_xfer_control(&ep->desc)) { + dev->ep_out[epnum] = NULL; + dev->ep_in[epnum] = NULL; + } ep->enabled = 0; usb_hcd_flush_endpoint(dev, ep); if (reset_hardware) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index e34aaa59a3d8..dc45757c39e8 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -5082,14 +5082,13 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg) } cancel_work_sync(&hsotg->phy_reset_work); - - timer_delete(&hsotg->wkp_timer); } static void dwc2_hcd_release(struct dwc2_hsotg *hsotg) { /* Turn off all host-specific interrupts */ dwc2_disable_host_interrupts(hsotg); + timer_shutdown_sync(&hsotg->wkp_timer); dwc2_hcd_free(hsotg); } diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index a39bf284c763..7d310c56fe08 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -49,6 +49,7 @@ #define DWC3_ENDPOINTS_NUM 32 #define DWC3_XHCI_RESOURCES_NUM 2 #define DWC3_ISOC_MAX_RETRIES 5 +#define DWC3_ERR_RECOVERY_MAX 3 #define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */ #define DWC3_EVENT_BUFFERS_SIZE 4096 @@ -842,6 +843,12 @@ enum dwc3_link_state { DWC3_LINK_STATE_MASK = 0x0f, }; +enum dwc3_err_state { + DWC3_ERR_NONE = 0, + DWC3_ERR_RECOVERY, + DWC3_ERR_UNRECOVERABLE, +}; + /* TRB Length, PCM and Status */ #define DWC3_TRB_SIZE_MASK (0x00ffffff) #define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK) @@ -1005,6 +1012,7 @@ struct dwc3_glue_ops { /** * struct dwc3 - representation of our controller * @drd_work: workqueue used for role swapping + * @err_recovery_work: workqueue used for controller error recovery * @ep0_trb: trb which is used for the ctrl_req * @bounce: address of bounce buffer * @setup_buf: used while precessing STD USB requests @@ -1014,6 +1022,7 @@ struct dwc3_glue_ops { * @ep0_in_setup: one control transfer is completed and enter setup phase * @lock: for synchronizing * @mutex: for mode switching + * @connect_mutex: for the pull-up and err_recovery_work * @dev: pointer to our struct device * @sysdev: pointer to the DMA-capable device * @xhci: pointer to our xHCI child @@ -1078,6 +1087,9 @@ struct dwc3_glue_ops { * @ep0_next_event: hold the next expected event * @ep0state: state of endpoint zero * @link_state: link state + * @err_state: current error recovery state. + * @err_recovery_count: number of consecutive error recovery attempts until + * confirmed healthy and reset to 0 on reset event. * @speed: device speed (super, high, full, low) * @hwparams: copy of hwparams registers * @regset: debugfs pointer to regdump file @@ -1186,6 +1198,7 @@ struct dwc3_glue_ops { */ struct dwc3 { struct work_struct drd_work; + struct work_struct err_recovery_work; struct dwc3_trb *ep0_trb; void *bounce; u8 *setup_buf; @@ -1200,6 +1213,9 @@ struct dwc3 { /* mode switching lock */ struct mutex mutex; + /* serializes pull-up run/stop vs error recovery */ + struct mutex connect_mutex; + struct device *dev; struct device *sysdev; @@ -1325,6 +1341,9 @@ struct dwc3 { enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_state ep0state; enum dwc3_link_state link_state; + enum dwc3_err_state err_state; + + u32 err_recovery_count; u16 u2sel; u16 u2pel; diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c index 9db8f3ca493d..e87d335d5d2f 100644 --- a/drivers/usb/dwc3/dwc3-am62.c +++ b/drivers/usb/dwc3/dwc3-am62.c @@ -298,6 +298,7 @@ static int dwc3_ti_probe(struct platform_device *pdev) err_pm_disable: clk_disable_unprepare(am62->usb2_refclk); + pm_runtime_put_noidle(dev); pm_runtime_disable(dev); pm_runtime_set_suspended(dev); return ret; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index fe479bba10c3..5000de8446dc 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -200,6 +200,11 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int ret; spin_lock_irqsave(&dwc->lock, flags); + if (dwc->err_state != DWC3_ERR_NONE) { + ret = -ESHUTDOWN; + goto out; + } + if (!dep->endpoint.desc || !dwc->pullups_connected || !dwc->connected) { dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n", dep->name); @@ -271,6 +276,10 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value) int ret; spin_lock_irqsave(&dwc->lock, flags); + if (dwc->err_state != DWC3_ERR_NONE) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -ESHUTDOWN; + } ret = __dwc3_gadget_ep0_set_halt(ep, value); spin_unlock_irqrestore(&dwc->lock, flags); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 050ea2b463bf..ed9f759c9575 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1149,6 +1149,10 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep, return 0; spin_lock_irqsave(&dwc->lock, flags); + if (dwc->err_state != DWC3_ERR_NONE) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -ESHUTDOWN; + } ret = __dwc3_gadget_ep_enable(dep, DWC3_DEPCFG_ACTION_INIT); spin_unlock_irqrestore(&dwc->lock, flags); @@ -2060,6 +2064,10 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, int ret; spin_lock_irqsave(&dwc->lock, flags); + if (dwc->err_state != DWC3_ERR_NONE) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -ESHUTDOWN; + } ret = __dwc3_gadget_ep_queue(dep, req); spin_unlock_irqrestore(&dwc->lock, flags); @@ -2292,6 +2300,10 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value) int ret; spin_lock_irqsave(&dwc->lock, flags); + if (dwc->err_state != DWC3_ERR_NONE) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -ESHUTDOWN; + } ret = __dwc3_gadget_ep_set_halt(dep, value, false); spin_unlock_irqrestore(&dwc->lock, flags); @@ -2306,6 +2318,10 @@ static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep) int ret; spin_lock_irqsave(&dwc->lock, flags); + if (dwc->err_state != DWC3_ERR_NONE) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -ESHUTDOWN; + } dep->flags |= DWC3_EP_WEDGE; if (dep->number == 0 || dep->number == 1) @@ -2437,6 +2453,10 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) } spin_lock_irqsave(&dwc->lock, flags); + if (dwc->err_state != DWC3_ERR_NONE) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -ESHUTDOWN; + } if (!dwc->gadget->wakeup_armed) { dev_err(dwc->dev, "not armed for remote wakeup\n"); spin_unlock_irqrestore(&dwc->lock, flags); @@ -2464,6 +2484,10 @@ static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id) } spin_lock_irqsave(&dwc->lock, flags); + if (dwc->err_state != DWC3_ERR_NONE) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -ESHUTDOWN; + } /* * If the link is in U3, signal for remote wakeup and wait for the * link to transition to U0 before sending device notification. @@ -2833,10 +2857,13 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) synchronize_irq(dwc->irq_gadget); + /* Serialize against dwc3_err_recovery_work() */ + mutex_lock(&dwc->connect_mutex); if (!is_on) ret = dwc3_gadget_soft_disconnect(dwc); else ret = dwc3_gadget_soft_connect(dwc); + mutex_unlock(&dwc->connect_mutex); pm_runtime_put(dwc->dev); @@ -4142,6 +4169,10 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) dwc->suspended = false; + /* The controller is recovered. */ + if (dwc->err_state == DWC3_ERR_NONE) + dwc->err_recovery_count = 0; + /* * Ideally, dwc3_reset_gadget() would trigger the function * drivers to stop any active transfers through ep disable. @@ -4629,6 +4660,12 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt) return ret; } +static void dwc3_schedule_err_recovery(struct dwc3 *dwc) +{ + dwc->err_state = DWC3_ERR_RECOVERY; + schedule_work(&dwc->err_recovery_work); +} + static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) { struct dwc3 *dwc = evt->dwc; @@ -4662,9 +4699,21 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) return IRQ_NONE; if (count > evt->length) { - dev_err_ratelimited(dwc->dev, "invalid count(%u) > evt->length(%u)\n", + dev_err(dwc->dev, "invalid count(%u) > evt->length(%u)\n", count, evt->length); - return IRQ_NONE; + /* + * This is a fatal error - the driver and controller are out of + * sync on which event has been consumed. Reinitializing the + * controller is required to recover. Write the bogus count back + * to GEVNTCOUNT to clear the IRQ source, consistent with the + * stale event clearing in dwc3_event_buffers_setup(), then + * schedule error recovery. + */ + spin_lock(&dwc->lock); + dwc3_schedule_err_recovery(dwc); + spin_unlock(&dwc->lock); + dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), count); + return IRQ_HANDLED; } evt->count = count; @@ -4724,6 +4773,57 @@ static void dwc_gadget_release(struct device *dev) kfree(gadget); } +static void dwc3_err_recovery_work(struct work_struct *work) +{ + struct dwc3 *dwc = container_of(work, struct dwc3, err_recovery_work); + unsigned long flags; + int ret; + + /* serializes against dwc3_gadget_pullup() */ + mutex_lock(&dwc->connect_mutex); + + ret = dwc3_gadget_soft_disconnect(dwc); + + dwc3_disconnect_gadget_sleepable(dwc); + + if (ret) + goto err_unrecoverable; + + if (dwc->softconnect) { + u32 count; + /* + * Wait irq to finish before soft_connect resets evt->lpos and + * the event buffer registers to avoid racing with + * dwc3_process_event_buf(). + */ + synchronize_irq(dwc->irq_gadget); + + spin_lock_irqsave(&dwc->lock, flags); + count = ++dwc->err_recovery_count; + spin_unlock_irqrestore(&dwc->lock, flags); + + if (count > DWC3_ERR_RECOVERY_MAX) + goto err_unrecoverable; + + ret = dwc3_gadget_soft_connect(dwc); + if (ret) + goto err_unrecoverable; + } + mutex_unlock(&dwc->connect_mutex); + + spin_lock_irqsave(&dwc->lock, flags); + dwc->err_state = DWC3_ERR_NONE; + spin_unlock_irqrestore(&dwc->lock, flags); + return; + +err_unrecoverable: + dev_err(dwc->dev, "Unable to recover the controller\n"); + mutex_unlock(&dwc->connect_mutex); + spin_lock_irqsave(&dwc->lock, flags); + dwc->err_state = DWC3_ERR_UNRECOVERABLE; + spin_unlock_irqrestore(&dwc->lock, flags); +} + /** * dwc3_gadget_init - initializes gadget related registers * @dwc: pointer to our controller context structure @@ -4767,6 +4867,8 @@ int dwc3_gadget_init(struct dwc3 *dwc) } init_completion(&dwc->ep0_in_setup); + INIT_WORK(&dwc->err_recovery_work, dwc3_err_recovery_work); + mutex_init(&dwc->connect_mutex); dwc->gadget = kzalloc(sizeof(struct usb_gadget), GFP_KERNEL); if (!dwc->gadget) { ret = -ENOMEM; @@ -4862,6 +4964,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc) if (!dwc->gadget) return; + cancel_work_sync(&dwc->err_recovery_work); + mutex_destroy(&dwc->connect_mutex); dwc3_enable_susphy(dwc, true); usb_del_gadget(dwc->gadget); dwc3_gadget_free_endpoints(dwc); diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index d73b082d5d83..fb485cbaa495 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1822,8 +1822,9 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, break; case FUNCTIONFS_ENDPOINT_DESC: { + const struct usb_endpoint_descriptor *desc; + struct usb_endpoint_descriptor desc1; int desc_idx; - struct usb_endpoint_descriptor desc1, *desc; switch (epfile->ffs->gadget->speed) { case USB_SPEED_SUPER: @@ -1837,7 +1838,17 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, desc_idx = 0; } - desc = epfile->ep->descs[desc_idx]; + do { + desc = epfile->ep->descs[desc_idx]; + } while (!desc && --desc_idx >= 0); + + if (!desc) + desc = epfile->ep->ep->desc; + if (!desc) { + ret = -EINVAL; + break; + } + memcpy(&desc1, desc, desc->bLength); spin_unlock_irq(&epfile->ffs->eps_lock); diff --git a/drivers/usb/gadget/function/f_midi2.c b/drivers/usb/gadget/function/f_midi2.c index 076d0aca647f..c38c305ec863 100644 --- a/drivers/usb/gadget/function/f_midi2.c +++ b/drivers/usb/gadget/function/f_midi2.c @@ -1634,8 +1634,8 @@ struct f_midi2_usb_config { /* MIDI 1.0 jacks */ unsigned char jack_in, jack_out, jack_id; - struct usb_midi_in_jack_descriptor jack_ins[MAX_CABLES]; - struct usb_midi_out_jack_descriptor_1 jack_outs[MAX_CABLES]; + struct usb_midi_in_jack_descriptor jack_ins[MAX_CABLES * 2]; + struct usb_midi_out_jack_descriptor_1 jack_outs[MAX_CABLES * 2]; }; static int append_config(struct f_midi2_usb_config *config, void *d) diff --git a/drivers/usb/gadget/function/f_uac1_legacy.c b/drivers/usb/gadget/function/f_uac1_legacy.c index c234f9fea27c..f62ab9932d69 100644 --- a/drivers/usb/gadget/function/f_uac1_legacy.c +++ b/drivers/usb/gadget/function/f_uac1_legacy.c @@ -797,6 +797,9 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value) { + if (cmd >= ARRAY_SIZE(con->data)) + return -EINVAL; + con->data[cmd] = value; return 0; @@ -804,6 +807,9 @@ static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value) static int generic_get_cmd(struct usb_audio_control *con, u8 cmd) { + if (cmd >= ARRAY_SIZE(con->data)) + return -EINVAL; + return con->data[cmd]; } diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c index f2685f89b3e5..62d282bab525 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/core.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c @@ -266,6 +266,9 @@ static void ast_vhub_remove(struct platform_device *pdev) for (i = 0; i < vhub->max_ports; i++) ast_vhub_del_dev(&vhub->ports[i].dev); + /* Final drain; the worker takes vhub->lock, so stay outside of it */ + cancel_work_sync(&vhub->wake_work); + spin_lock_irqsave(&vhub->lock, flags); /* Mask & ack all interrupts */ @@ -324,6 +327,7 @@ static int ast_vhub_probe(struct platform_device *pdev) return -ENOMEM; spin_lock_init(&vhub->lock); + INIT_WORK(&vhub->wake_work, ast_vhub_wake_work); vhub->pdev = pdev; vhub->port_irq_mask = GENMASK(VHUB_IRQ_DEV1_BIT + vhub->max_ports - 1, VHUB_IRQ_DEV1_BIT); diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index a09f72772e6e..477d0ae789c2 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -280,7 +280,7 @@ static int ast_vhub_udc_wakeup(struct usb_gadget* gadget) int rc = -EINVAL; spin_lock_irqsave(&d->vhub->lock, flags); - if (!d->wakeup_en) + if (!d->wakeup_en || !d->registered) goto err; DDBG(d, "Device initiated wakeup\n"); diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index 02fe1a08d575..d0345f31037a 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -558,7 +558,7 @@ void ast_vhub_device_connect(struct ast_vhub *vhub, ast_vhub_send_host_wakeup(vhub); } -static void ast_vhub_wake_work(struct work_struct *work) +void ast_vhub_wake_work(struct work_struct *work) { struct ast_vhub *vhub = container_of(work, struct ast_vhub, @@ -588,6 +588,8 @@ static void ast_vhub_wake_work(struct work_struct *work) void ast_vhub_hub_wake_all(struct ast_vhub *vhub) { + lockdep_assert_held(&vhub->lock); + /* * A device is trying to wake the world, because this * can recurse into the device, we break the call chain @@ -1076,7 +1078,6 @@ static int ast_vhub_init_desc(struct ast_vhub *vhub) int ast_vhub_init_hub(struct ast_vhub *vhub) { vhub->speed = USB_SPEED_UNKNOWN; - INIT_WORK(&vhub->wake_work, ast_vhub_wake_work); return ast_vhub_init_desc(vhub); } diff --git a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h index 6b9dfa6e10eb..0ca168b39d96 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/vhub.h +++ b/drivers/usb/gadget/udc/aspeed-vhub/vhub.h @@ -546,6 +546,7 @@ void ast_vhub_hub_suspend(struct ast_vhub *vhub); void ast_vhub_hub_resume(struct ast_vhub *vhub); void ast_vhub_hub_reset(struct ast_vhub *vhub); void ast_vhub_hub_wake_all(struct ast_vhub *vhub); +void ast_vhub_wake_work(struct work_struct *work); /* dev.c */ int ast_vhub_init_dev(struct ast_vhub *vhub, unsigned int idx); diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 5e3cbe0338bf..1d4df43f0f8c 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -343,9 +343,11 @@ static void dummy_giveback(struct dummy *dum, struct usb_ep *_ep, { bool fifo = req == &dum->fifo_req; + ++dum->callback_usage; spin_unlock(&dum->lock); usb_gadget_giveback_request(_ep, &req->req); spin_lock(&dum->lock); + --dum->callback_usage; if (fifo) dum->fifo_req_busy = 0; } @@ -759,11 +761,13 @@ static int dummy_queue(struct usb_ep *_ep, struct usb_request *_req, req->req.complete = fifo_complete; list_add_tail(&req->queue, &ep->queue); + ++dum->callback_usage; spin_unlock(&dum->lock); _req->actual = _req->length; _req->status = 0; usb_gadget_giveback_request(_ep, _req); spin_lock(&dum->lock); + --dum->callback_usage; } else list_add_tail(&req->queue, &ep->queue); spin_unlock_irqrestore(&dum->lock, flags); diff --git a/drivers/usb/host/octeon-hcd.c b/drivers/usb/host/octeon-hcd.c index 361d33b0c4d2..cbf55c409649 100644 --- a/drivers/usb/host/octeon-hcd.c +++ b/drivers/usb/host/octeon-hcd.c @@ -578,7 +578,7 @@ static int cvmx_wait_tx_rx(struct octeon_hcd *usb, int fflsh_type) int result; u64 address = CVMX_USBCX_GRSTCTL(usb->index); u64 done = cvmx_get_cycle() + 100 * - (u64)octeon_get_clock_rate / 1000000; + (u64)octeon_get_clock_rate() / 1000000; union cvmx_usbcx_grstctl c; while (1) { diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 3c5ca2d7c92e..6a5afff5e2ca 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -464,6 +464,7 @@ static int ohci_da8xx_probe(struct platform_device *pdev) err_remove_hcd: usb_remove_hcd(hcd); + device_wakeup_disable(hcd->self.controller); err: usb_put_hcd(hcd); return error; @@ -474,6 +475,7 @@ static void ohci_da8xx_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); usb_remove_hcd(hcd); + device_wakeup_disable(hcd->self.controller); usb_put_hcd(hcd); } diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index e623e24d3f8e..7c0e35be58f1 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -335,6 +335,7 @@ ohci_hcd_s3c2410_remove(struct platform_device *dev) struct usb_hcd *hcd = platform_get_drvdata(dev); usb_remove_hcd(hcd); + device_wakeup_disable(hcd->self.controller); s3c2410_stop_hc(dev); usb_put_hcd(hcd); } diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index 6843d7cb3f9f..5aeabb051265 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -103,6 +103,7 @@ static void spear_ohci_hcd_drv_remove(struct platform_device *pdev) struct spear_ohci *sohci_p = to_spear_ohci(hcd); usb_remove_hcd(hcd); + device_wakeup_disable(hcd->self.controller); clk_disable_unprepare(sohci_p->clk); usb_put_hcd(hcd); diff --git a/drivers/usb/host/ohci-st.c b/drivers/usb/host/ohci-st.c index d1656fce5400..53010a277b67 100644 --- a/drivers/usb/host/ohci-st.c +++ b/drivers/usb/host/ohci-st.c @@ -235,6 +235,7 @@ static void st_ohci_platform_remove(struct platform_device *dev) int clk; usb_remove_hcd(hcd); + device_wakeup_disable(hcd->self.controller); if (pdata->power_off) pdata->power_off(dev); diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 9e2a18c0b218..ea1fe5d1e449 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -165,7 +165,11 @@ int usb_serial_bus_register(struct usb_serial_driver *driver) void usb_serial_bus_deregister(struct usb_serial_driver *driver) { - free_dynids(driver); driver_unregister(&driver->driver); + free_dynids(driver); } +void usb_serial_bus_remove_new_id(struct usb_serial_driver *driver) +{ + driver_remove_file(&driver->driver, &driver_attr_new_id); +} diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 36b25418b214..9f16be82e70b 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -223,6 +223,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ + { USB_DEVICE(0x1B1C, 0x1C02) }, /* Corsair AX1500i Power Supply */ { USB_DEVICE(0x1B93, 0x1013) }, /* Phoenix Contact UPS Device */ { USB_DEVICE(0x1BA4, 0x0002) }, /* Silicon Labs 358x factory default */ { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 757f0a586ddb..4c2b6f17ecf1 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -267,6 +267,7 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_chars_in_buffer); void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout) { struct usb_serial_port *port = tty->driver_data; + struct tty_port *tport = &port->port; unsigned int bps; unsigned long period; unsigned long expire; @@ -286,7 +287,14 @@ void usb_serial_generic_wait_until_sent(struct tty_struct *tty, long timeout) __func__, jiffies_to_msecs(timeout), jiffies_to_msecs(period)); expire = jiffies + timeout; - while (!port->serial->type->tx_empty(port)) { + for (;;) { + mutex_lock(&tport->mutex); + if (tty_io_error(tty) || port->serial->type->tx_empty(port)) { + mutex_unlock(&tport->mutex); + break; + } + mutex_unlock(&tport->mutex); + schedule_timeout_interruptible(period); if (signal_pending(current)) break; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5652155fc680..0f9a7a4c1f66 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -261,6 +261,7 @@ static void option_instat_callback(struct urb *urb); #define QUECTEL_PRODUCT_EM060K_12a 0x012a #define QUECTEL_PRODUCT_EM060K_12b 0x012b #define QUECTEL_PRODUCT_EM060K_12c 0x012c +#define QUECTEL_PRODUCT_RG660QB 0x013d #define QUECTEL_PRODUCT_EG91 0x0191 #define QUECTEL_PRODUCT_EG95 0x0195 #define QUECTEL_PRODUCT_BG96 0x0296 @@ -281,6 +282,7 @@ static void option_instat_callback(struct urb *urb); #define QUECTEL_PRODUCT_EC200U 0x0901 #define QUECTEL_PRODUCT_EG912Y 0x6001 #define QUECTEL_PRODUCT_EC200S_CN 0x6002 +#define QUECTEL_PRODUCT_EG060W 0x6004 #define QUECTEL_PRODUCT_EC200A 0x6005 #define QUECTEL_PRODUCT_EG916Q 0x6007 #define QUECTEL_PRODUCT_EM061K_LWW 0x6008 @@ -1269,12 +1271,15 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200A, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200U, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200S_CN, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG060W, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EC200T, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG912Y, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG916Q, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RM500K, 0xff, 0x00, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG650V, 0xff, 0, 0) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG660QB, 0xff, 0xff, 0x30) }, + { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG660QB, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x30) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0, 0) }, { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_RG255C, 0xff, 0xff, 0x40) }, @@ -2169,6 +2174,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9003, 0xff) }, /* Simcom SIM7500/SIM7600 MBIM mode */ { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9011, 0xff), /* Simcom SIM7500/SIM7600 RNDIS mode */ .driver_info = RSVD(7) }, + { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x902b, 0xff), + .driver_info = RSVD(4) }, { USB_DEVICE(0x1e0e, 0x9071), /* Simcom SIM8230 RMNET mode */ .driver_info = RSVD(3) | RSVD(4) }, { USB_DEVICE_INTERFACE_CLASS(0x1e0e, 0x9078, 0xff), /* Simcom SIM8230 ECM mode */ @@ -2430,6 +2437,13 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(5) }, { USB_DEVICE_INTERFACE_CLASS(0x0489, 0xe167, 0xff), /* Foxconn T99W640 MBIM */ .driver_info = RSVD(3) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x01) }, /* Compal EXC-T1 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x02) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x03) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x4d22, 0xff, 0x10, 0x04) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x30) }, /* Compal EXM-G1x */ + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x40) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x04b7, 0x8217, 0xff, 0xff, 0x60) }, { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 (IOT version) */ .driver_info = RSVD(4) | RSVD(5) | RSVD(6) }, { USB_DEVICE(0x1782, 0x4d10) }, /* Fibocom L610 (AT mode) */ diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 72fe83a6c978..a4f893af3fb8 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -54,6 +54,7 @@ #define QT2_XMIT_FLUSH 0x05 /* no following info */ #define QT2_CONTROL_ESCAPE 0xff /* pass through previous 2 control bytes */ +#define MIN_BAUD_RATE 50 #define MAX_BAUD_RATE 921600 #define DEFAULT_BAUD_RATE 9600 @@ -158,7 +159,7 @@ static inline int calc_baud_divisor(int baudrate) static inline int qt2_set_port_config(struct usb_device *dev, unsigned char port_number, - u16 baudrate, u16 lcr) + speed_t baudrate, u16 lcr) { int divisor = calc_baud_divisor(baudrate); u16 index = ((u16) (lcr << 8) | (u16) (port_number)); @@ -259,9 +260,9 @@ static void qt2_set_termios(struct tty_struct *tty, struct usb_device *dev = port->serial->dev; struct qt2_port_private *port_priv; struct ktermios *termios = &tty->termios; - u16 baud; unsigned int cflag = termios->c_cflag; u16 new_lcr = 0; + speed_t baud; int status; port_priv = usb_get_serial_port_data(port); @@ -279,6 +280,18 @@ static void qt2_set_termios(struct tty_struct *tty, if (!baud) baud = 9600; + if (baud < MIN_BAUD_RATE || baud > MAX_BAUD_RATE) { + if (old_termios) + baud = tty_termios_baud_rate(old_termios); + else + baud = clamp(baud, MIN_BAUD_RATE, MAX_BAUD_RATE); + + tty_encode_baud_rate(tty, baud, baud); + + if (!baud) + baud = 9600; + } + status = qt2_set_port_config(dev, port_priv->device_port, baud, new_lcr); if (status < 0) @@ -375,7 +388,7 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) port_priv->device_port = (u8) device_port; if (tty) - qt2_set_termios(tty, port, &tty->termios); + qt2_set_termios(tty, port, NULL); return 0; diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index df21009bdf42..5d8ff1c6af1e 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -34,6 +34,7 @@ #define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) +#define MIN_BAUD_RATE 50 #define MAX_BAUD_RATE 460800 #define ATC_DISABLED 0x00 @@ -219,9 +220,10 @@ static void ssu100_set_termios(struct tty_struct *tty, { struct usb_device *dev = port->serial->dev; struct ktermios *termios = &tty->termios; - u16 baud, divisor, remainder; + speed_t baud, remainder; unsigned int cflag = termios->c_cflag; u16 urb_value = 0; /* will hold the new flags */ + u16 divisor; int result; if (cflag & PARENB) { @@ -237,6 +239,18 @@ static void ssu100_set_termios(struct tty_struct *tty, if (!baud) baud = 9600; + if (baud < MIN_BAUD_RATE || baud > MAX_BAUD_RATE) { + if (old_termios) + baud = tty_termios_baud_rate(old_termios); + else + baud = clamp(baud, MIN_BAUD_RATE, MAX_BAUD_RATE); + + tty_encode_baud_rate(tty, baud, baud); + + if (!baud) + baud = 9600; + } + dev_dbg(&port->dev, "%s - got baud = %d\n", __func__, baud); @@ -312,7 +326,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) dev_dbg(&port->dev, "%s - set uart failed\n", __func__); if (tty) - ssu100_set_termios(tty, port, &tty->termios); + ssu100_set_termios(tty, port, NULL); return usb_serial_generic_open(tty, port); } diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index c78ff40b1e5f..3cccddaabb51 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -403,17 +403,13 @@ static unsigned int serial_chars_in_buffer(struct tty_struct *tty) static void serial_wait_until_sent(struct tty_struct *tty, int timeout) { struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; dev_dbg(&port->dev, "%s\n", __func__); if (!port->serial->type->wait_until_sent) return; - mutex_lock(&serial->disc_mutex); - if (!serial->disconnected) - port->serial->type->wait_until_sent(tty, timeout); - mutex_unlock(&serial->disc_mutex); + port->serial->type->wait_until_sent(tty, timeout); } static void serial_throttle(struct tty_struct *tty) @@ -441,8 +437,13 @@ static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss) struct usb_serial_port *port = tty->driver_data; struct tty_port *tport = &port->port; unsigned int close_delay, closing_wait; + int ret = 0; mutex_lock(&tport->mutex); + if (tty_io_error(tty)) { + ret = -EIO; + goto out_unlock; + } close_delay = jiffies_to_msecs(tport->close_delay) / 10; closing_wait = tport->closing_wait; @@ -455,10 +456,10 @@ static int serial_get_serial(struct tty_struct *tty, struct serial_struct *ss) if (port->serial->type->get_serial) port->serial->type->get_serial(tty, ss); - +out_unlock: mutex_unlock(&tport->mutex); - return 0; + return ret; } static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss) @@ -474,6 +475,10 @@ static int serial_set_serial(struct tty_struct *tty, struct serial_struct *ss) closing_wait = msecs_to_jiffies(closing_wait * 10); mutex_lock(&tport->mutex); + if (tty_io_error(tty)) { + ret = -EIO; + goto out_unlock; + } if (!capable(CAP_SYS_ADMIN)) { if (close_delay != tport->close_delay || @@ -501,6 +506,7 @@ static int serial_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; + struct tty_port *tport = &port->port; int retval = -ENOIOCTLCMD; dev_dbg(&port->dev, "%s - cmd 0x%04x\n", __func__, cmd); @@ -511,8 +517,21 @@ static int serial_ioctl(struct tty_struct *tty, retval = port->serial->type->tiocmiwait(tty, arg); break; default: - if (port->serial->type->ioctl) + if (!port->serial->type->ioctl) + break; + + if (cmd == TIOCSRS485) + down_write(&tty->termios_rwsem); + + mutex_lock(&tport->mutex); + if (tty_io_error(tty)) + retval = -EIO; + else retval = port->serial->type->ioctl(tty, cmd, arg); + mutex_unlock(&tport->mutex); + + if (cmd == TIOCSRS485) + up_write(&tty->termios_rwsem); } return retval; @@ -522,25 +541,40 @@ static void serial_set_termios(struct tty_struct *tty, const struct ktermios *old) { struct usb_serial_port *port = tty->driver_data; + struct tty_port *tport = &port->port; dev_dbg(&port->dev, "%s\n", __func__); - if (port->serial->type->set_termios) - port->serial->type->set_termios(tty, port, old); - else + if (!port->serial->type->set_termios) { tty_termios_copy_hw(&tty->termios, old); + return; + } + + mutex_lock(&tport->mutex); + if (!tty_io_error(tty)) + port->serial->type->set_termios(tty, port, old); + mutex_unlock(&tport->mutex); } static int serial_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; + struct tty_port *tport = &port->port; + int ret; dev_dbg(&port->dev, "%s\n", __func__); - if (port->serial->type->break_ctl) - return port->serial->type->break_ctl(tty, break_state); + if (!port->serial->type->break_ctl) + return -ENOTTY; - return -ENOTTY; + mutex_lock(&tport->mutex); + if (tty_io_error(tty)) + ret = -EIO; + else + ret = port->serial->type->break_ctl(tty, break_state); + mutex_unlock(&tport->mutex); + + return ret; } static int serial_proc_show(struct seq_file *m, void *v) @@ -581,24 +615,44 @@ static int serial_proc_show(struct seq_file *m, void *v) static int serial_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; + struct tty_port *tport = &port->port; + int ret; dev_dbg(&port->dev, "%s\n", __func__); - if (port->serial->type->tiocmget) - return port->serial->type->tiocmget(tty); - return -ENOTTY; + if (!port->serial->type->tiocmget) + return -ENOTTY; + + mutex_lock(&tport->mutex); + if (tty_io_error(tty)) + ret = -EIO; + else + ret = port->serial->type->tiocmget(tty); + mutex_unlock(&tport->mutex); + + return ret; } static int serial_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; + struct tty_port *tport = &port->port; + int ret; dev_dbg(&port->dev, "%s\n", __func__); - if (port->serial->type->tiocmset) - return port->serial->type->tiocmset(tty, set, clear); - return -ENOTTY; + if (!port->serial->type->tiocmset) + return -ENOTTY; + + mutex_lock(&tport->mutex); + if (tty_io_error(tty)) + ret = -EIO; + else + ret = port->serial->type->tiocmset(tty, set, clear); + mutex_unlock(&tport->mutex); + + return ret; } static int serial_get_icount(struct tty_struct *tty, @@ -1194,12 +1248,17 @@ static void usb_serial_disconnect(struct usb_interface *interface) usb_serial_port_poison_urbs(port); wake_up_interruptible(&port->port.delta_msr_wait); cancel_work_sync(&port->work); - if (device_is_registered(&port->dev)) - device_del(&port->dev); } + if (serial->type->disconnect) serial->type->disconnect(serial); + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + if (device_is_registered(&port->dev)) + device_del(&port->dev); + } + release_sibling(serial, interface); /* let the last holder of this object cause it to be cleaned up */ @@ -1316,7 +1375,8 @@ static int __init usb_serial_init(void) int result; usb_serial_tty_driver = tty_alloc_driver(USB_SERIAL_TTY_MINORS, - TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); + TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | + TTY_DRIVER_RESET_SAVED_TERMIOS); if (IS_ERR(usb_serial_tty_driver)) return PTR_ERR(usb_serial_tty_driver); @@ -1467,7 +1527,7 @@ int __usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers { int rc; struct usb_driver *udriver; - struct usb_serial_driver * const *sd; + struct usb_serial_driver * const *sd, * const *s; /* * udriver must be registered before any of the serial drivers, @@ -1520,9 +1580,11 @@ int __usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers return 0; err_deregister_drivers: + for (s = serial_drivers; s < sd; ++s) + usb_serial_bus_remove_new_id(*s); + usb_deregister(udriver); while (sd-- > serial_drivers) usb_serial_deregister(*sd); - usb_deregister(udriver); err_free_driver: kfree(udriver); return rc; @@ -1540,10 +1602,23 @@ EXPORT_SYMBOL_GPL(__usb_serial_register_drivers); void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[]) { struct usb_driver *udriver = (*serial_drivers)->usb_driver; + struct usb_serial_driver * const *sd; + + /* + * udriver must be deregistered before the serial drivers so that + * I/O is stopped before unbinding the ports. + * + * Remove the new_id attributes to prevent ids from being added and + * triggering a probe of udriver after it has been deregistered. + */ + for (sd = serial_drivers; *sd; ++sd) + usb_serial_bus_remove_new_id(*sd); + + usb_deregister(udriver); for (; *serial_drivers; ++serial_drivers) usb_serial_deregister(*serial_drivers); - usb_deregister(udriver); + kfree(udriver); } EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers); diff --git a/drivers/usb/serial/xr_serial.c b/drivers/usb/serial/xr_serial.c index 4186e791b384..eb9424bad4f7 100644 --- a/drivers/usb/serial/xr_serial.c +++ b/drivers/usb/serial/xr_serial.c @@ -849,12 +849,9 @@ static int xr_get_rs485_config(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct xr_data *data = usb_get_serial_port_data(port); - down_read(&tty->termios_rwsem); - if (copy_to_user(argp, &data->rs485, sizeof(data->rs485))) { - up_read(&tty->termios_rwsem); + /* core holds port mutex */ + if (copy_to_user(argp, &data->rs485, sizeof(data->rs485))) return -EFAULT; - } - up_read(&tty->termios_rwsem); return 0; } @@ -870,10 +867,9 @@ static int xr_set_rs485_config(struct tty_struct *tty, return -EFAULT; xr_sanitize_serial_rs485(&rs485); - down_write(&tty->termios_rwsem); + /* core holds termios rwsem and port mutex */ data->rs485 = rs485; xr_set_flow_mode(tty, port, NULL); - up_write(&tty->termios_rwsem); if (copy_to_user(argp, &rs485, sizeof(rs485))) return -EFAULT; diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index 177fa6cd143a..d8fe9561b2b5 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c @@ -77,6 +77,13 @@ static int sierra_get_swoc_info(struct usb_device *udev, sizeof(struct swoc_info), /* __u16 size */ USB_CTRL_SET_TIMEOUT); /* int timeout */ + /* + * A short IN transfer leaves the tail of swocInfo uninitialized; + * only a full transfer is valid. + */ + if (result != sizeof(struct swoc_info)) + return -EIO; + swocInfo->LinuxSKU = le16_to_cpu(swocInfo->LinuxSKU); swocInfo->LinuxVer = le16_to_cpu(swocInfo->LinuxVer); return result; diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index 6b4cbc3bfa37..261b4bb284f2 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -1567,8 +1567,11 @@ static void anx7411_i2c_remove(struct i2c_client *client) anx7411_partner_unregister_altmode(plat); anx7411_unregister_partner(plat); - if (plat->workqueue) + if (plat->workqueue) { + disable_irq(plat->intp_irq); + cancel_work_sync(&plat->work); destroy_workqueue(plat->workqueue); + } i2c_unregister_device(plat->spi_client); diff --git a/drivers/usb/typec/port-mapper.c b/drivers/usb/typec/port-mapper.c index cdbb7c11d714..3a97b084c3bd 100644 --- a/drivers/usb/typec/port-mapper.c +++ b/drivers/usb/typec/port-mapper.c @@ -42,6 +42,23 @@ static int usb4_port_compare(struct device *dev, void *fwnode) return usb4_usb3_port_match(dev, fwnode); } +static bool typec_has_usb4_host_interface(const struct fwnode_handle *fwnode) +{ + if (!IS_REACHABLE(CONFIG_USB4)) + return false; + + struct fwnode_handle *nhi_fwnode __free(fwnode_handle) = + fwnode_find_reference(fwnode, "usb4-host-interface", 0); + + /* + * The USB4 port can only appear if the host interface is enabled in + * the firmware and has been enumerated as a device. The latter is + * the same check as in usb_acpi_add_usb4_devlink(). + */ + return !IS_ERR(nhi_fwnode) && fwnode_device_is_available(nhi_fwnode) && + nhi_fwnode->dev; +} + static int typec_port_compare(struct device *dev, void *fwnode) { return device_match_fwnode(dev, fwnode); @@ -64,11 +81,11 @@ static int typec_port_match(struct device *dev, void *data) adev_fwnode); /* - * If dev is USB 3.x port, it may have reference to the + * If dev is USB 3.x port, it may have reference to an available * USB4 host interface in which case we can also link the * Type-C port with the USB4 port. */ - if (fwnode_property_present(adev_fwnode, "usb4-host-interface")) + if (typec_has_usb4_host_interface(adev_fwnode)) component_match_add(&arg->port->dev, &arg->match, usb4_port_compare, adev_fwnode); } diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 30cea27ff932..d568f01d04f2 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -6503,7 +6503,7 @@ static void tcpm_pd_event_handler(struct kthread_work *work) port->upcoming_state = FR_SWAP_SEND; ret = tcpm_ams_start(port, FAST_ROLE_SWAP); if (ret == -EAGAIN) - port->upcoming_state = INVALID_STATE; + tcpm_set_state(port, ERROR_RECOVERY, 0); } else { tcpm_log(port, "Discarding FRS_SIGNAL! Not in sink ready"); } diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index d6fbe515e644..e4bc3e79046b 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -340,7 +340,7 @@ static void tps6598x_set_data_role(struct tps6598x *tps, static int tps6598x_connect(struct tps6598x *tps, u32 status) { - struct typec_partner_desc desc; + struct typec_partner_desc desc = { }; enum typec_pwr_opmode mode; int ret; @@ -351,7 +351,6 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status) desc.usb_pd = mode == TYPEC_PWR_MODE_PD; desc.accessory = TYPEC_ACCESSORY_NONE; /* XXX: handle accessories */ - desc.identity = NULL; if (desc.usb_pd) { ret = tps6598x_read_partner_identity(tps); @@ -813,11 +812,10 @@ static void cd321x_update_work(struct work_struct *work) /* Set up partner if we were previously disconnected (or changed). */ if (!tps->partner) { - struct typec_partner_desc desc; + struct typec_partner_desc desc = { }; desc.usb_pd = is_pd; desc.accessory = TYPEC_ACCESSORY_NONE; /* XXX: handle accessories */ - desc.identity = NULL; if (desc.usb_pd) desc.identity = &st.partner_identity; @@ -1745,6 +1743,7 @@ static int tps6598x_probe(struct i2c_client *client) const struct tipd_data *data; struct tps6598x *tps; struct fwnode_handle *fwnode; + bool patch_loaded = false; u32 status; u32 vid; int ret; @@ -1797,6 +1796,7 @@ static int tps6598x_probe(struct i2c_client *client) return ret; if (ret == TPS_MODE_PTCH) { + patch_loaded = true; ret = tps->data->init(tps); if (ret) return ret; @@ -1885,7 +1885,8 @@ static int tps6598x_probe(struct i2c_client *client) tps6598x_write64(tps, TPS_REG_INT_MASK1, 0); err_reset_controller: /* Reset PD controller to remove any applied patch */ - tps->data->reset(tps); + if (patch_loaded) + tps->data->reset(tps); return ret; } diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c index 8d2032d0762c..572da7bbd29c 100644 --- a/drivers/usb/typec/ucsi/displayport.c +++ b/drivers/usb/typec/ucsi/displayport.c @@ -71,11 +71,14 @@ static int ucsi_displayport_enter(struct typec_altmode *alt, u32 *vdo) if (ret < 0) { if (ucsi->version > 0x0100) goto err_unlock; - cur = 0xff; } - if (cur < UCSI_MAX_ALTMODES) { - ret = dp->con->port_altmode[cur] == alt ? 0 : -EBUSY; + if (cur != 0xff) { + if (cur < UCSI_MAX_ALTMODES) + ret = dp->con->port_altmode[cur] == alt ? 0 : -EBUSY; + else + ret = -EINVAL; + goto err_unlock; } diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 2acd48a0a6a2..4c8f23826d45 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -1714,10 +1714,21 @@ static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con) { struct fwnode_handle *fwnode; int i = 1; + int ret; + u32 port; - device_for_each_child_node(con->ucsi->dev, fwnode) - if (i++ == con->num) - return fwnode; + device_for_each_child_node(con->ucsi->dev, fwnode) { + ret = fwnode_property_read_u32(fwnode, "reg", &port); + if (ret < 0) { + if (i == con->num) + return fwnode; + } else { + if (port == con->num - 1) + return fwnode; + } + + i++; + } return NULL; } diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 94b52ccf6f42..c3f6856032c2 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -105,6 +105,32 @@ static const struct ucsi_operations ucsi_acpi_ops = { .async_control = ucsi_acpi_async_control }; +static int ucsi_acer_read_version(struct ucsi *ucsi, u16 *version) +{ + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); + int ret; + + ret = ucsi_acpi_read_version(ucsi, version); + if (ret) + return ret; + + if (!*version) { + dev_warn(ua->dev, "UCSI version is zero, assuming 1.2\n"); + *version = UCSI_VERSION_1_2; + } + + return 0; +} + +static const struct ucsi_operations ucsi_acer_ops = { + .read_version = ucsi_acer_read_version, + .read_cci = ucsi_acpi_read_cci, + .poll_cci = ucsi_acpi_poll_cci, + .read_message_in = ucsi_acpi_read_message_in, + .sync_control = ucsi_sync_control_common, + .async_control = ucsi_acpi_async_control +}; + static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci, void *val, size_t len) { @@ -144,6 +170,13 @@ static const struct ucsi_operations ucsi_gram_ops = { }; static const struct dmi_system_id ucsi_acpi_quirks[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Nitro ANV15-41"), + }, + .driver_data = (void *)&ucsi_acer_ops, + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c index 8af79101a2fc..f93d6ef69357 100644 --- a/drivers/usb/typec/ucsi/ucsi_glink.c +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -302,6 +302,10 @@ static void pmic_glink_ucsi_destroy(void *data) { struct pmic_glink_ucsi *ucsi = data; + /* Drain the work items before ucsi_destroy() frees the ucsi instance */ + cancel_work_sync(&ucsi->notify_work); + cancel_work_sync(&ucsi->register_work); + /* Protect to make sure we're not in a middle of a transaction from a glink callback */ mutex_lock(&ucsi->lock); ucsi_destroy(ucsi->ucsi); @@ -403,8 +407,15 @@ static void pmic_glink_ucsi_remove(struct auxiliary_device *adev) { struct pmic_glink_ucsi *ucsi = dev_get_drvdata(&adev->dev); - /* Unregister first to stop having read & writes */ - ucsi_unregister(ucsi->ucsi); + /* Callbacks can queue work until devres releases the client */ + disable_work_sync(&ucsi->notify_work); + disable_work_sync(&ucsi->register_work); + + /* register_work may have unregistered the instance already */ + if (ucsi->ucsi_registered) { + ucsi->ucsi_registered = false; + ucsi_unregister(ucsi->ucsi); + } } static const struct auxiliary_device_id pmic_glink_ucsi_id_table[] = { diff --git a/drivers/virt/nitro_enclaves/ne_misc_dev.c b/drivers/virt/nitro_enclaves/ne_misc_dev.c index 241b94f62e56..2cd7cd177795 100644 --- a/drivers/virt/nitro_enclaves/ne_misc_dev.c +++ b/drivers/virt/nitro_enclaves/ne_misc_dev.c @@ -1710,6 +1710,7 @@ static int ne_create_vm_ioctl(struct ne_pci_dev *ne_pci_dev, u64 __user *slot_ui return enclave_fd; put_file: + enclave_file->private_data = NULL; fput(enclave_file); put_fd: put_unused_fd(enclave_fd); diff --git a/drivers/virt/vmgenid.c b/drivers/virt/vmgenid.c index 66135eac3abf..0d269edf283d 100644 --- a/drivers/virt/vmgenid.c +++ b/drivers/virt/vmgenid.c @@ -75,13 +75,16 @@ static int vmgenid_add_acpi(struct device *dev, struct vmgenid_state *state) phys_addr = (obj->package.elements[0].integer.value << 0) | (obj->package.elements[1].integer.value << 32); - virt_addr = devm_memremap(&device->dev, phys_addr, VMGENID_SIZE, MEMREMAP_WB); + virt_addr = devm_memremap(&device->dev, phys_addr, VMGENID_SIZE, + MEMREMAP_WB | MEMREMAP_DEC); if (IS_ERR(virt_addr)) { ret = PTR_ERR(virt_addr); goto out; } setup_vmgenid_state(state, virt_addr); + dev->driver_data = state; + status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, vmgenid_acpi_handler, dev); if (ACPI_FAILURE(status)) { @@ -89,7 +92,6 @@ static int vmgenid_add_acpi(struct device *dev, struct vmgenid_state *state) goto out; } - dev->driver_data = state; out: ACPI_FREE(parsed.pointer); return ret; @@ -123,12 +125,13 @@ static int vmgenid_add_of(struct platform_device *pdev, if (ret < 0) return ret; + pdev->dev.driver_data = state; + ret = devm_request_irq(&pdev->dev, ret, vmgenid_of_irq_handler, IRQF_SHARED, "vmgenid", &pdev->dev); if (ret < 0) return ret; - pdev->dev.driver_data = state; return 0; } diff --git a/fs/attr.c b/fs/attr.c index 795f231d00e8..3f2cce4e4ad1 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -169,7 +169,17 @@ int setattr_prepare(struct mnt_idmap *idmap, struct dentry *dentry, * ATTR_FORCE. */ if (ia_valid & ATTR_SIZE) { - int error = inode_newsize_ok(inode, attr->ia_size); + int error; + + /* + * Verity files are immutable, so deny truncates. This isn't + * covered by the open-time check because sys_truncate() takes a + * path, not an open file. + */ + if (IS_VERITY(inode)) + return -EPERM; + + error = inode_newsize_ok(inode, attr->ia_size); if (error) return error; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6ab593b89319..c63b2f5edae9 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4040,10 +4040,11 @@ static int btrfs_read_locked_inode(struct btrfs_inode *inode, struct btrfs_path btrfs_inode_split_flags(btrfs_inode_flags(leaf, inode_item), &inode->flags, &inode->ro_flags); + +cache_index: btrfs_update_inode_mapping_flags(inode); btrfs_set_inode_mapping_order(inode); -cache_index: /* * If we were modified in the current generation and evicted from memory * and then re-read we need to do a full sync since we don't have any diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 3b2891f18540..d2977c560c96 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -5898,10 +5898,6 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry, if (error) return error; - error = fsverity_prepare_setattr(dentry, attr); - if (error) - return error; - if (is_quota_modification(idmap, inode, attr)) { error = dquot_initialize(inode); if (error) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 222b2a8bbc94..791f1cf198c1 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1123,10 +1123,6 @@ int f2fs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, if (err) return err; - err = fsverity_prepare_setattr(dentry, attr); - if (err) - return err; - if (unlikely(IS_IMMUTABLE(inode))) return -EPERM; diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c index cccc860893f0..29868dcd1ec3 100644 --- a/fs/netfs/buffered_read.c +++ b/fs/netfs/buffered_read.c @@ -460,6 +460,13 @@ static int netfs_read_gaps(struct file *file, struct folio *folio) ret = netfs_wait_for_read(rreq); if (ret >= 0) { + if (ret < flen) { + struct iov_iter iter; + + iov_iter_bvec(&iter, ITER_DEST, bvec, i, flen); + iov_iter_advance(&iter, ret); + iov_iter_zero(flen - ret, &iter); + } if (group) folio_change_private(folio, group); else diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c index 0f61746bee2a..7da07737ced8 100644 --- a/fs/netfs/buffered_write.c +++ b/fs/netfs/buffered_write.c @@ -470,6 +470,7 @@ ssize_t netfs_buffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *fr struct netfs_group *netfs_group) { struct file *file = iocb->ki_filp; + struct inode *inode = file_inode(file); ssize_t ret; trace_netfs_write_iter(iocb, from); @@ -482,6 +483,14 @@ ssize_t netfs_buffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *fr if (ret) return ret; + if (iocb->ki_pos > i_size_read(inode)) { + ret = netfs_clear_stale_pre_isize(inode, i_size_read(inode), + iocb->ki_pos, + iocb->ki_flags & IOCB_NOWAIT); + if (ret) + return ret; + } + return netfs_perform_write(iocb, from, netfs_group); } EXPORT_SYMBOL(netfs_buffered_write_iter_locked); diff --git a/fs/netfs/direct_write.c b/fs/netfs/direct_write.c index e05f69eb56a6..ba0cc6172a67 100644 --- a/fs/netfs/direct_write.c +++ b/fs/netfs/direct_write.c @@ -363,6 +363,15 @@ ssize_t netfs_unbuffered_write_iter(struct kiocb *iocb, struct iov_iter *from) ret = file_update_time(file); if (ret < 0) goto out; + + if (iocb->ki_pos > i_size_read(inode)) { + ret = netfs_clear_stale_pre_isize(inode, i_size_read(inode), + iocb->ki_pos, + iocb->ki_flags & IOCB_NOWAIT); + if (ret < 0) + goto out; + } + if (iocb->ki_flags & IOCB_NOWAIT) { /* We could block if there are any pages in the range. */ ret = -EAGAIN; diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h index d889caa401dc..a4a5cec256b0 100644 --- a/fs/netfs/internal.h +++ b/fs/netfs/internal.h @@ -78,6 +78,8 @@ ssize_t netfs_wait_for_read(struct netfs_io_request *rreq); ssize_t netfs_wait_for_write(struct netfs_io_request *rreq); void netfs_wait_for_paused_read(struct netfs_io_request *rreq); void netfs_wait_for_paused_write(struct netfs_io_request *rreq); +int netfs_clear_stale_pre_isize(struct inode *inode, unsigned long long from, + unsigned long long to, bool nowait); /* * objects.c diff --git a/fs/netfs/misc.c b/fs/netfs/misc.c index 1109ac379128..628c45f53d83 100644 --- a/fs/netfs/misc.c +++ b/fs/netfs/misc.c @@ -6,6 +6,7 @@ */ #include +#include #include "internal.h" /** @@ -548,3 +549,101 @@ void netfs_wait_for_paused_write(struct netfs_io_request *rreq) { return netfs_wait_for_pause(rreq, netfs_write_collection); } + +/** + * netfs_clear_stale_isize - Clear stale pagecache in a to-be-created hole + * @inode: The inode to act upon. + * @from: The base of the hole to be made. + * @to: The top of the hole to be made. + * @nowait: True to return -EAGAIN rather than block. + * @exclusive: True if the caller holds i_rwsem exclusively for the resize. + * + * Zero any data left in the pagecache within the [@from, @to) hole by a + * write through an mmap so that it isn't exposed as file content once the + * file is extended. Only the uptodate folio straddling @from can hold such + * data as pages wholly beyond the EOF can't be faulted in, so the zeroing + * is limited to that folio. The folio is zeroed rather than dropped so + * that a concurrent extending write can't lose data. + * + * If @exclusive is false, @from is re-read from i_size and used to clamp + * the zeroed range, for callers that may race with another writer also + * extending the file (eg. multiple buffered writes extending the same file + * under a shared i_rwsem). If @exclusive is true, for callers that hold + * i_rwsem exclusively across the whole resize and have already updated + * i_size to @to, staleness is decided from the folio's dirty state instead: + * since no genuine concurrent buffered writer can be racing, a lockless + * stat() adopting a server-confirmed size mid-resize has no data behind it + * and never dirties the folio, so it can't fool this check into skipping + * the zeroing the way it could fool the @exclusive false clamp. + * + * pagecache_isize_extended() can't be reused here: it is keyed on a + * sub-page block size (a no-op when the block size is >= PAGE_SIZE, as on + * network filesystems), runs after i_size is updated, can't honour + * @nowait, and doesn't wait for writeback. Keep the two in sync if either + * is changed. + * + * Return: 0 on success, or -EAGAIN if @nowait is set and the folio is + * mapped or under writeback and so can't be cleaned without blocking. + */ +static int netfs_clear_stale_isize(struct inode *inode, unsigned long long from, + unsigned long long to, bool nowait, bool exclusive) +{ + struct address_space *mapping = inode->i_mapping; + fgf_t fgp = FGP_LOCK; + struct folio *folio; + int ret; + + if (from >= to) + return 0; + + if (nowait) + fgp |= FGP_NOWAIT; + + folio = __filemap_get_folio(mapping, from >> PAGE_SHIFT, fgp, 0); + if (IS_ERR(folio)) + return PTR_ERR(folio) == -EAGAIN ? -EAGAIN : 0; + + ret = 0; + if (nowait && (folio_mapped(folio) || folio_test_writeback(folio))) { + ret = -EAGAIN; + goto out; + } + + folio_wait_writeback(folio); + + if (folio_mkclean(folio)) + folio_mark_dirty(folio); + + if (folio_test_uptodate(folio) && + (!exclusive || folio_test_dirty(folio))) { + unsigned long long fpos = folio_pos(folio); + + if (!exclusive) + from = umax(from, i_size_read(inode)); + if (from < to && from < fpos + folio_size(folio)) { + size_t end = umin(to - fpos, folio_size(folio)); + size_t offset = from - fpos; + + folio_zero_segment(folio, offset, end); + } + } +out: + folio_unlock(folio); + folio_put(folio); + return ret; +} + +/* Clear stale pagecache before an extending buffered/DIO write. */ +int netfs_clear_stale_pre_isize(struct inode *inode, unsigned long long from, + unsigned long long to, bool nowait) +{ + return netfs_clear_stale_isize(inode, from, to, nowait, false); +} + +/* Clear stale pagecache when extending a file under an exclusive resize. */ +void netfs_clear_stale_post_isize(struct inode *inode, unsigned long long from, + unsigned long long to) +{ + netfs_clear_stale_isize(inode, from, to, false, true); +} +EXPORT_SYMBOL(netfs_clear_stale_post_isize); diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c index 1bd15cc8194c..0c8c0e69e1ea 100644 --- a/fs/smb/client/cached_dir.c +++ b/fs/smb/client/cached_dir.c @@ -155,7 +155,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, struct cached_fid *cfid; struct cached_fids *cfids; const char *npath; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; __le32 lease_flags = 0; if (cifs_sb->root == NULL) @@ -313,6 +313,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon, smb2_set_related(&rqst[1]); if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); + smb2_set_replay(server, &rqst[0]); smb2_set_replay(server, &rqst[1]); } diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 6d35f3872266..30daa09ab1b6 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -1539,8 +1539,13 @@ ssize_t cifs_file_copychunk_range(unsigned int xid, /* Flush and invalidate all the folios in the destination region. If * the copy was successful, then some of the flush is extra overhead, * but we need to allow for the copy failing in some way (eg. ENOSPC). + * + * Start at the old EOF when extending so the folio straddling it, which + * may hold data written past EOF through an mmap, is dropped too. */ - rc = filemap_invalidate_inode(target_inode, true, destoff, destoff + len - 1); + rc = filemap_invalidate_inode(target_inode, true, + min(destoff, i_size_read(target_inode)), + destoff + len - 1); if (rc) goto unlock; diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 1837f4820bd6..562967d44bf3 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1457,11 +1457,11 @@ struct cifsFileInfo { struct dentry *dentry; struct tcon_link *tlink; unsigned int f_flags; - bool invalidHandle:1; /* file closed via session abend */ - bool swapfile:1; - bool oplock_break_cancelled:1; - bool status_file_deleted:1; /* file has been deleted */ - bool offload:1; /* offload final part of _put to a wq */ + bool invalidHandle; /* file closed via session abend */ + bool swapfile; + bool oplock_break_cancelled; + bool status_file_deleted; /* file has been deleted */ + bool offload; /* offload final part of _put to a wq */ __u16 oplock_epoch; /* epoch from the lease break */ __u32 oplock_level; /* oplock/lease level from the lease break */ int count; diff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c index 30368ddd0a1e..8675edf73693 100644 --- a/fs/smb/client/dir.c +++ b/fs/smb/client/dir.c @@ -177,7 +177,8 @@ check_name(struct dentry *direntry, struct cifs_tcon *tcon) static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, struct tcon_link *tlink, unsigned int oflags, umode_t mode, __u32 *oplock, - struct cifs_fid *fid, struct cifs_open_info_data *buf) + struct cifs_fid *fid, struct cifs_open_info_data *buf, + bool *opened) { int rc = -ENOENT; int create_options = CREATE_NOT_DIR; @@ -194,6 +195,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int rdwr_for_fscache = 0; __le32 lease_flags = 0; + *opened = false; *oplock = 0; if (tcon->ses->server->oplocks) *oplock = REQ_OPLOCK; @@ -216,6 +218,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned oflags, oplock, &fid->netfid, xid); switch (rc) { case 0: + *opened = true; if (newinode == NULL) { /* query inode info */ goto cifs_create_get_file_info; @@ -232,11 +235,9 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned /* * The server may allow us to open things like * FIFOs, but the client isn't set up to deal - * with that. If it's not a regular file, just - * close it and proceed as if it were a normal - * lookup. + * with that. Keep the handle until the caller + * can finish the lookup. */ - CIFSSMBClose(xid, tcon, fid->netfid); goto cifs_create_get_file_info; } /* success, no need to query */ @@ -359,6 +360,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned } goto out; } + *opened = true; if (rdwr_for_fscache == 2) cifs_invalidate_cache(inode, FSCACHE_INVAL_DIO_WRITE); @@ -449,7 +451,7 @@ static int cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned return rc; out_err: - if (server->ops->close) + if (*opened && server->ops->close) server->ops->close(xid, tcon, fid); if (newinode) iput(newinode); @@ -468,6 +470,8 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, struct cifs_fid fid = {}; struct cifs_pending_open open; __u32 oplock; + bool is_regular; + bool opened; struct cifsFileInfo *file_info; struct cifs_open_info_data buf = {}; @@ -521,15 +525,28 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, cifs_add_pending_open(&fid, tlink, &open); rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, - &oplock, &fid, &buf); + &oplock, &fid, &buf, &opened); if (rc) { cifs_del_pending_open(&open); goto out; } - if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + is_regular = d_is_reg(direntry); + if (!is_regular || !opened) { + if (opened && server->ops->close) + server->ops->close(xid, tcon, &fid); + cifs_del_pending_open(&open); + } + + if (is_regular && opened && + (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) file->f_mode |= FMODE_CREATED; + if (!is_regular || !opened) { + rc = finish_no_open(file, NULL); + goto out; + } + rc = finish_open(file, direntry, generic_file_open); if (rc) { if (server->ops->close) @@ -584,6 +601,7 @@ int cifs_create(struct mnt_idmap *idmap, struct inode *inode, struct TCP_Server_Info *server; struct cifs_fid fid; __u32 oplock; + bool opened; struct cifs_open_info_data buf = {}; cifs_dbg(FYI, "cifs_create parent inode = 0x%p name is: %pd and dentry = 0x%p\n", @@ -605,8 +623,9 @@ int cifs_create(struct mnt_idmap *idmap, struct inode *inode, if (server->ops->new_lease_key) server->ops->new_lease_key(&fid); - rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, &oplock, &fid, &buf); - if (!rc && server->ops->close) + rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, + &oplock, &fid, &buf, &opened); + if (!rc && opened && server->ops->close) server->ops->close(xid, tcon, &fid); cifs_free_open_info(&buf); diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c index ac31564ce926..9a6a23e038b6 100644 --- a/fs/smb/client/link.c +++ b/fs/smb/client/link.c @@ -320,7 +320,7 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, int buf_type = CIFS_NO_BUFFER; __le16 *utf16_path; __u8 oplock = SMB2_OPLOCK_LEVEL_NONE; - struct smb2_file_all_info *pfile_info = NULL; + struct cifs_open_info_data data = {}; oparms = (struct cifs_open_parms) { .tcon = tcon, @@ -336,20 +336,12 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, if (utf16_path == NULL) return -ENOMEM; - pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2, - GFP_KERNEL); - - if (pfile_info == NULL) { - kfree(utf16_path); - return -ENOMEM; - } - - rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL, + rc = SMB2_open(xid, &oparms, utf16_path, &oplock, &data, NULL, NULL, NULL); if (rc) goto qmf_out_open_fail; - if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { + if (data.fi.EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) { /* it's not a symlink */ rc = -ENOENT; /* Is there a better rc to return? */ goto qmf_out; @@ -367,7 +359,6 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); qmf_out_open_fail: kfree(utf16_path); - kfree(pfile_info); return rc; } diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c index 36efebef82e4..865bfd0b07a2 100644 --- a/fs/smb/client/smb2file.c +++ b/fs/smb/client/smb2file.c @@ -170,8 +170,6 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *smb2_path; __u8 smb2_oplock; struct cifs_open_info_data *data = buf; - struct smb2_file_all_info file_info = {}; - struct smb2_file_all_info *smb2_data = data ? &file_info : NULL; struct kvec err_iov = {}; int err_buftype = CIFS_NO_BUFFER; struct cifs_fid *fid = oparms->fid; @@ -198,14 +196,14 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, } smb2_oplock = SMB2_OPLOCK_LEVEL_BATCH; - rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, + rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, data, NULL, &err_iov, &err_buftype); if (rc == -EACCES && retry_without_read_attributes) { free_rsp_buf(err_buftype, err_iov.iov_base); memset(&err_iov, 0, sizeof(err_iov)); err_buftype = CIFS_NO_BUFFER; oparms->desired_access &= ~FILE_READ_ATTRIBUTES; - rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, NULL, &err_iov, + rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, data, NULL, &err_iov, &err_buftype); } if (rc && data) { @@ -226,9 +224,9 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, if (rc == -ENODATA) rc = -EIO; if (!rc) { - memset(smb2_data, 0, sizeof(*smb2_data)); + memset(&data->fi, 0, sizeof(data->fi)); oparms->create_options |= OPEN_REPARSE_POINT; - rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, smb2_data, + rc = SMB2_open(xid, oparms, smb2_path, &smb2_oplock, data, NULL, NULL, NULL); oparms->create_options &= ~OPEN_REPARSE_POINT; } @@ -262,23 +260,22 @@ int smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, rc = 0; } - if (smb2_data) { + if (data) { /* if open response does not have IndexNumber field - get it */ - if (smb2_data->IndexNumber == 0) { + if (data->fi.IndexNumber == 0) { rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid, fid->volatile_fid, - &smb2_data->IndexNumber); + &data->fi.IndexNumber); if (rc) { /* * let get_inode_info disable server inode * numbers */ - smb2_data->IndexNumber = 0; + data->fi.IndexNumber = 0; rc = 0; } } - memcpy(&data->fi, smb2_data, sizeof(data->fi)); } *oplock = smb2_oplock; diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index e419b303ce9c..37a00586f2e7 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -199,7 +199,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, struct reparse_data_buffer *rbuf; struct TCP_Server_Info *server; int resp_buftype[MAX_COMPOUND]; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; __u8 delete_pending[8] = {1,}; struct kvec *rsp_iov, *iov; struct inode *inode = NULL; @@ -649,18 +649,26 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, num_rqst++; if (cfile) { - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); for (i = 1; i < num_rqst - 2; i++) smb2_set_replay(server, &rqst[i]); + } rc = compound_send_recv(xid, ses, server, flags, num_rqst - 2, &rqst[1], &resp_buftype[1], &rsp_iov[1]); } else { - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); for (i = 0; i < num_rqst; i++) smb2_set_replay(server, &rqst[i]); + } rc = compound_send_recv(xid, ses, server, flags, num_rqst, @@ -1210,7 +1218,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, { struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; __le16 *utf16_path __free(kfree) = NULL; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; struct TCP_Server_Info *server; struct cifs_open_parms oparms; struct smb2_create_req *creq; @@ -1220,7 +1228,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, struct kvec close_iov; int resp_buftype[2]; struct cifs_fid fid; - int flags = 0; + int flags = CIFS_CP_CREATE_CLOSE_OP; __u8 oplock; int rc; @@ -1274,6 +1282,9 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, smb2_set_related(&rqst[1]); if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); for (int i = 0; i < ARRAY_SIZE(rqst); i++) smb2_set_replay(server, &rqst[i]); } @@ -1294,7 +1305,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name, if (rc == -EINVAL && dentry) { dentry = NULL; retries = 0; - cur_sleep = 1; + cur_sleep = 0; goto again; } /* diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c index d701bdfa585f..34d2401c6c66 100644 --- a/fs/smb/client/smb2misc.c +++ b/fs/smb/client/smb2misc.c @@ -830,7 +830,8 @@ smb2_cancelled_close_fid(struct work_struct *work) */ static int __smb2_handle_cancelled_cmd(struct cifs_tcon *tcon, __u16 cmd, __u64 mid, - __u64 persistent_fid, __u64 volatile_fid) + __u64 persistent_fid, __u64 volatile_fid, + bool account_remote_open) { struct close_cancelled_open *cancelled; @@ -844,6 +845,8 @@ __smb2_handle_cancelled_cmd(struct cifs_tcon *tcon, __u16 cmd, __u64 mid, cancelled->cmd = cmd; cancelled->mid = mid; INIT_WORK(&cancelled->work, smb2_cancelled_close_fid); + if (account_remote_open) + atomic_inc(&tcon->num_remote_opens); WARN_ON(queue_work(cifsiod_wq, &cancelled->work) == false); return 0; @@ -880,7 +883,7 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid, spin_unlock(&tcon->tc_lock); rc = __smb2_handle_cancelled_cmd(tcon, SMB2_CLOSE_HE, 0, - persistent_fid, volatile_fid); + persistent_fid, volatile_fid, false); if (rc) cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cancelled_close); @@ -908,7 +911,7 @@ smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *serve le16_to_cpu(hdr->Command), le64_to_cpu(hdr->MessageId), rsp->PersistentFileId, - rsp->VolatileFileId); + rsp->VolatileFileId, true); if (rc) cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cancelled_mid); diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 19c82ad224a1..2026e627bc44 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -1210,7 +1210,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, struct smb2_file_full_ea_info *ea; struct smb2_query_info_rsp *rsp; int rc, used_len = 0; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -1341,6 +1341,9 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, smb2_set_related(&rqst[2]); if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst[0]); smb2_set_replay(server, &rqst[1]); smb2_set_replay(server, &rqst[2]); @@ -1605,7 +1608,7 @@ smb2_ioctl_query_info(const unsigned int xid, void *data[2]; int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR; void (*free_req1_func)(struct smb_rqst *r); - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -1755,6 +1758,9 @@ smb2_ioctl_query_info(const unsigned int xid, smb2_set_related(&rqst[2]); if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst[0]); smb2_set_replay(server, &rqst[1]); smb2_set_replay(server, &rqst[2]); @@ -2545,7 +2551,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, struct smb2_query_directory_rsp *qd_rsp = NULL; struct smb2_create_rsp *op_rsp = NULL; struct TCP_Server_Info *server; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -2603,6 +2609,9 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon, smb2_set_related(&rqst[1]); if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst[0]); smb2_set_replay(server, &rqst[1]); } @@ -2879,10 +2888,14 @@ bool smb2_should_replay(struct cifs_tcon *tcon, return false; if (tcon->retry || (*pretries)++ < tcon->ses->server->retrans) { - msleep(*pcur_sleep); - (*pcur_sleep) = ((*pcur_sleep) << 1); - if ((*pcur_sleep) > CIFS_MAX_SLEEP) - (*pcur_sleep) = CIFS_MAX_SLEEP; + /* Update sleep time for exponential backoff */ + if (!(*pcur_sleep)) + (*pcur_sleep) = 1; + else { + (*pcur_sleep) = ((*pcur_sleep) << 1); + if ((*pcur_sleep) > CIFS_MAX_SLEEP) + (*pcur_sleep) = CIFS_MAX_SLEEP; + } return true; } @@ -2913,7 +2926,7 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, int rc; __le16 *utf16_path; struct cached_fid *cfid; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -3003,6 +3016,9 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon, smb2_set_related(&rqst[2]); if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); if (!cfid) { smb2_set_replay(server, &rqst[0]); smb2_set_replay(server, &rqst[2]); @@ -3469,8 +3485,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, struct inode *inode = file_inode(file); struct cifsInodeInfo *cifsi = CIFS_I(inode); struct cifsFileInfo *cfile = file->private_data; - struct netfs_inode *ictx = netfs_inode(inode); - unsigned long long i_size, new_size, remote_size; + unsigned long long i_size, new_size; long rc; unsigned int xid; @@ -3489,20 +3504,20 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, filemap_invalidate_lock(inode->i_mapping); i_size = i_size_read(inode); - remote_size = ictx->remote_i_size; - if (offset + len >= remote_size && offset < i_size) { - unsigned long long top = umin(offset + len, i_size); - rc = filemap_write_and_wait_range(inode->i_mapping, offset, top - 1); - if (rc < 0) - goto zero_range_exit; - } + rc = filemap_write_and_wait_range(inode->i_mapping, offset, + offset + len - 1); + if (rc < 0) + goto zero_range_exit; /* * We zero the range through ioctl, so we need remove the page caches * first, otherwise the data may be inconsistent with the server. + * + * Start at the old EOF when extending so the folio straddling it, which + * may hold data written past EOF through an mmap, is dropped too. */ - truncate_pagecache_range(inode, offset, offset + len - 1); + truncate_pagecache_range(inode, min(offset, i_size), offset + len - 1); netfs_wait_for_outstanding_io(inode); /* if file not oplocked can't be sure whether asking to extend size */ @@ -3656,7 +3671,8 @@ static int smb3_simple_fallocate_write_range(unsigned int xid, static int smb3_simple_fallocate_range(unsigned int xid, struct cifs_tcon *tcon, struct cifsFileInfo *cfile, - loff_t off, loff_t len) + loff_t off, loff_t len, + loff_t old_eof) { struct file_allocated_range_buffer in_data, *out_data = NULL, *tmp_data; struct inode *inode = d_inode(cfile->dentry); @@ -3672,12 +3688,30 @@ static int smb3_simple_fallocate_range(unsigned int xid, goto out; } - if (off >= i_size_read(inode)) { + if (off >= old_eof) { rc = smb3_simple_fallocate_write_range(xid, tcon, cfile, off, len, buf); goto out; } + filemap_invalidate_lock(inode->i_mapping); + + /* + * Flush and commit the data to the server, otherwise + * FSCTL_QUERY_ALLOCATED_RANGES might report recently written data as + * unallocated holes on Windows Servers, and the loop below would + * then zero-fill them and corrupt the file. + */ + rc = filemap_write_and_wait_range(inode->i_mapping, off, + off + len - 1); + if (rc) + goto out_unlock; + netfs_wait_for_outstanding_io(inode); + rc = SMB2_flush(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid); + if (rc) + goto out_unlock; + in_data.file_offset = cpu_to_le64(off); in_data.length = cpu_to_le64(len); rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, @@ -3687,7 +3721,7 @@ static int smb3_simple_fallocate_range(unsigned int xid, 1024 * sizeof(struct file_allocated_range_buffer), (char **)&out_data, &out_data_len); if (rc) - goto out; + goto out_unlock; tmp_data = out_data; while (len) { @@ -3697,12 +3731,12 @@ static int smb3_simple_fallocate_range(unsigned int xid, if (out_data_len == 0) { rc = smb3_simple_fallocate_write_range(xid, tcon, cfile, off, len, buf); - goto out; + goto out_unlock; } if (out_data_len < sizeof(struct file_allocated_range_buffer)) { rc = -EINVAL; - goto out; + goto out_unlock; } range_start = le64_to_cpu(tmp_data->file_offset); @@ -3710,7 +3744,7 @@ static int smb3_simple_fallocate_range(unsigned int xid, if (check_add_overflow(range_start, range_len, &range_end) || range_end > S64_MAX) { rc = -EINVAL; - goto out; + goto out_unlock; } if (off < range_start) { @@ -3725,11 +3759,11 @@ static int smb3_simple_fallocate_range(unsigned int xid, rc = smb3_simple_fallocate_write_range(xid, tcon, cfile, off, l, buf); if (rc) - goto out; + goto out_unlock; off = off + l; len = len - l; if (len == 0) - goto out; + goto out_unlock; } /* * We are at a section of allocated data, just skip forward @@ -3748,6 +3782,8 @@ static int smb3_simple_fallocate_range(unsigned int xid, out_data_len -= sizeof(struct file_allocated_range_buffer); } + out_unlock: + filemap_invalidate_unlock(inode->i_mapping); out: kfree(out_data); kvfree(buf); @@ -3776,14 +3812,31 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, trace_smb3_falloc_enter(xid, cfile->fid.persistent_fid, tcon->tid, tcon->ses->Suid, off, len); - /* if file not oplocked can't be sure whether asking to extend size */ - if (!CIFS_CACHE_READ(cifsi)) - if (!keep_size) { + + if (!keep_size && !CIFS_CACHE_READ(cifsi)) { + unsigned long long server_eof; + + rc = filemap_write_and_wait(inode->i_mapping); + if (rc) { + trace_smb3_falloc_err(xid, cfile->fid.persistent_fid, + tcon->tid, tcon->ses->Suid, off, len, rc); + free_xid(xid); + return rc; + } + netfs_wait_for_outstanding_io(inode); + + rc = SMB2_query_info(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, &file_inf); + if (rc) { trace_smb3_falloc_err(xid, cfile->fid.persistent_fid, tcon->tid, tcon->ses->Suid, off, len, rc); free_xid(xid); return rc; } + server_eof = le64_to_cpu(file_inf.EndOfFile); + /* Only use the larger EOF to decide whether we're extending. */ + old_eof = max_t(loff_t, old_eof, server_eof); + } /* * Extending the file @@ -3807,7 +3860,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, } rc = smb3_simple_fallocate_range(xid, tcon, cfile, - off, len); + off, len, old_eof); if (rc) { spin_lock(&inode->i_lock); cifsi->time = 0; @@ -3886,7 +3939,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, } } - if ((keep_size == true) || (i_size_read(inode) >= off + len)) { + if (keep_size || old_eof >= off + len) { /* * At this point, we are trying to fallocate an internal * regions of a sparse file. Since smb2 does not have a @@ -3903,7 +3956,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, */ if (len <= 1024 * 1024) { rc = smb3_simple_fallocate_range(xid, tcon, cfile, - off, len); + off, len, old_eof); goto out; } @@ -3915,7 +3968,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, * ie potentially making a few extra pages at the beginning * or end of the file non-sparse via set_sparse is harmless. */ - if ((off > 8192) || (off + len + 8192 < i_size_read(inode))) { + if (off > 8192 || off + len + 8192 < old_eof) { rc = -EOPNOTSUPP; goto out; } diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index e0edfce3fbe5..cb6db40c4358 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2867,7 +2867,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, unsigned int total_len; __le16 *utf16_path = NULL; struct TCP_Server_Info *server; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -2980,8 +2980,12 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE, FILE_WRITE_ATTRIBUTES); - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } /* resource #4: response buffer */ rc = cifs_send_recv(xid, ses, server, @@ -3215,7 +3219,7 @@ SMB2_open_free(struct smb_rqst *rqst) int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, - __u8 *oplock, struct smb2_file_all_info *buf, + __u8 *oplock, struct cifs_open_info_data *buf, struct create_posix_rsp *posix, struct kvec *err_iov, int *buftype) { @@ -3229,7 +3233,8 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, int resp_buftype = CIFS_NO_BUFFER; int rc = 0; int flags = 0; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; + struct smb2_file_all_info *file_info = buf ? &buf->fi : NULL; replay_again: /* reinitialize for possible replay */ @@ -3259,8 +3264,12 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path, oparms->create_options, oparms->desired_access); - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, ses, server, &rqst, &resp_buftype, flags, @@ -3285,9 +3294,6 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, goto creat_exit; } else if (rsp == NULL) /* unlikely to happen, but safer to check */ goto creat_exit; - else - trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid, - oparms->create_options, oparms->desired_access); atomic_inc(&tcon->num_remote_opens); oparms->fid->persistent_fid = rsp->PersistentFileId; @@ -3297,21 +3303,27 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, oparms->fid->mid = le64_to_cpu(rsp->hdr.MessageId); #endif /* CIFS_DEBUG2 */ - if (buf) { - buf->CreationTime = rsp->CreationTime; - buf->LastAccessTime = rsp->LastAccessTime; - buf->LastWriteTime = rsp->LastWriteTime; - buf->ChangeTime = rsp->ChangeTime; - buf->AllocationSize = rsp->AllocationSize; - buf->EndOfFile = rsp->EndofFile; - buf->Attributes = rsp->FileAttributes; - buf->NumberOfLinks = cpu_to_le32(1); - buf->DeletePending = 0; /* successful open = not delete pending */ + if (file_info) { + file_info->CreationTime = rsp->CreationTime; + file_info->LastAccessTime = rsp->LastAccessTime; + file_info->LastWriteTime = rsp->LastWriteTime; + file_info->ChangeTime = rsp->ChangeTime; + file_info->AllocationSize = rsp->AllocationSize; + file_info->EndOfFile = rsp->EndofFile; + file_info->Attributes = rsp->FileAttributes; + file_info->NumberOfLinks = cpu_to_le32(1); + file_info->DeletePending = 0; /* successful open = not delete pending */ } rc = smb2_parse_contexts(server, &rsp_iov, &oparms->fid->epoch, - oparms->fid->lease_key, oplock, buf, posix); + oparms->fid->lease_key, oplock, file_info, posix); + if (rc) + SMB2_close(xid, tcon, oparms->fid->persistent_fid, + oparms->fid->volatile_fid); + + trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid, + oparms->create_options, oparms->desired_access); creat_exit: SMB2_open_free(&rqst); free_rsp_buf(resp_buftype, rsp); @@ -3444,7 +3456,7 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, int resp_buftype = CIFS_NO_BUFFER; int rc = 0; int flags = 0; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; if (!tcon) return -EIO; @@ -3486,8 +3498,12 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, if (rc) goto ioctl_exit; - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, ses, server, &rqst, &resp_buftype, flags, @@ -3641,7 +3657,7 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, int rc = 0; int flags = 0; bool query_attrs = false; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -3675,8 +3691,12 @@ __SMB2_close(const unsigned int xid, struct cifs_tcon *tcon, if (rc) goto close_exit; - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, ses, server, &rqst, &resp_buftype, flags, &rsp_iov); @@ -3846,7 +3866,7 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, struct TCP_Server_Info *server; int flags = 0; bool allocated = false; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; cifs_dbg(FYI, "Query Info\n"); @@ -3882,8 +3902,12 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid, ses->Suid, info_class, (__u32)info_type); - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, ses, server, &rqst, &resp_buftype, flags, &rsp_iov); @@ -4039,7 +4063,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, int resp_buftype = CIFS_NO_BUFFER; int flags = 0; int rc = 0; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -4072,8 +4096,12 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon, trace_smb3_notify_enter(xid, persistent_fid, tcon->tid, ses->Suid, (u8)watch_tree, completion_filter); - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, ses, server, &rqst, &resp_buftype, flags, &rsp_iov); @@ -4380,7 +4408,7 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, int resp_buftype = CIFS_NO_BUFFER; int flags = 0; int rc = 0; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -4408,8 +4436,12 @@ SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, trace_smb3_flush_enter(xid, persistent_fid, tcon->tid, ses->Suid); - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, ses, server, &rqst, &resp_buftype, flags, &rsp_iov); @@ -4674,14 +4706,20 @@ smb2_readv_callback(struct mid_q_entry *mid) rdata->got_bytes); if (rdata->result == -ENODATA) { - __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); rdata->result = 0; + if (rdata->subreq.start + rdata->subreq.transferred >= i_size_read(&ictx->inode)) + __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); + else + __set_bit(NETFS_SREQ_CLEAR_TAIL, &rdata->subreq.flags); } else { size_t trans = rdata->subreq.transferred + rdata->got_bytes; if (trans < rdata->subreq.len && rdata->subreq.start + trans >= ictx->remote_i_size) { - __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); rdata->result = 0; + if (rdata->subreq.start + trans >= i_size_read(&ictx->inode)) + __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); + else + __set_bit(NETFS_SREQ_CLEAR_TAIL, &rdata->subreq.flags); } if (rdata->got_bytes) __set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags); @@ -5175,7 +5213,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, int flags = 0; unsigned int total_len; struct TCP_Server_Info *server; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -5226,8 +5264,12 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, iov_iter_kvec(&rqst.rq_iter, ITER_SOURCE, &iov[1], n_vec, io_parms->length); - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, io_parms->tcon->ses, server, &rqst, @@ -5578,7 +5620,7 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_ses *ses = tcon->ses; struct TCP_Server_Info *server; int flags = 0; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -5603,8 +5645,12 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, if (rc) goto qdir_exit; - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, ses, server, &rqst, &resp_buftype, flags, &rsp_iov); @@ -5713,7 +5759,7 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, struct cifs_ses *ses = tcon->ses; struct TCP_Server_Info *server; int flags = 0; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -5748,8 +5794,12 @@ send_set_info(const unsigned int xid, struct cifs_tcon *tcon, return rc; } - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, ses, server, &rqst, &resp_buftype, flags, @@ -5828,7 +5878,7 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, struct kvec iov[1]; struct kvec rsp_iov; int resp_buf_type; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -5858,8 +5908,12 @@ SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, rqst.rq_iov = iov; rqst.rq_nvec = 1; - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, ses, server, &rqst, &resp_buf_type, flags, &rsp_iov); @@ -5961,7 +6015,7 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, struct TCP_Server_Info *server; FILE_SYSTEM_POSIX_INFO *info = NULL; int flags = 0; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -5982,8 +6036,12 @@ SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, rqst.rq_iov = &iov; rqst.rq_nvec = 1; - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, ses, server, &rqst, &resp_buftype, flags, &rsp_iov); @@ -6026,7 +6084,7 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, struct TCP_Server_Info *server; unsigned int rsp_len, offset; int flags = 0; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -6063,8 +6121,12 @@ SMB2_QFS_attr(const unsigned int xid, struct cifs_tcon *tcon, rqst.rq_iov = &iov; rqst.rq_nvec = 1; - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, ses, server, &rqst, &resp_buftype, flags, &rsp_iov); @@ -6126,7 +6188,7 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, int flags = CIFS_NO_RSP_BUF; unsigned int total_len; struct TCP_Server_Info *server; - int retries = 0, cur_sleep = 1; + int retries = 0, cur_sleep = 0; replay_again: /* reinitialize for possible replay */ @@ -6162,8 +6224,12 @@ smb2_lockv(const unsigned int xid, struct cifs_tcon *tcon, rqst.rq_iov = iov; rqst.rq_nvec = 2; - if (retries) + if (retries) { + /* Back-off before retry */ + if (cur_sleep) + msleep(cur_sleep); smb2_set_replay(server, &rqst); + } rc = cifs_send_recv(xid, tcon->ses, server, &rqst, &resp_buf_type, flags, diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 92e6b93d72c4..2dddf655cf1f 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -147,7 +147,7 @@ extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, __u8 *oplock, - struct smb2_file_all_info *buf, + struct cifs_open_info_data *buf, struct create_posix_rsp *posix, struct kvec *err_iov, int *resp_buftype); extern int SMB2_open_init(struct cifs_tcon *tcon, diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 4da3d62b6481..342664eae295 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -804,6 +804,18 @@ cifs_cancelled_callback(struct mid_q_entry *mid) release_mid(mid); } +static void +cifs_mark_compound_mids_cancelled(struct mid_q_entry **mid, int count) +{ + int i; + + for (i = 0; i < count; i++) { + spin_lock(&mid[i]->mid_lock); + mid[i]->wait_cancelled = true; + spin_unlock(&mid[i]->mid_lock); + } +} + /* * cifs_pick_channel - pick an eligible channel for network operations * @@ -864,7 +876,8 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, int *resp_buf_type, struct kvec *resp_iov) { int i, j, optype, rc = 0; - struct mid_q_entry *midQ[MAX_COMPOUND]; + int num_processed = 0; + struct mid_q_entry *mid[MAX_COMPOUND]; bool cancelled_mid[MAX_COMPOUND] = {false}; struct cifs_credits credits[MAX_COMPOUND] = { { .value = 0, .instance = 0 } @@ -930,35 +943,35 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, } for (i = 0; i < num_rqst; i++) { - midQ[i] = server->ops->setup_request(ses, server, &rqst[i]); - if (IS_ERR(midQ[i])) { + mid[i] = server->ops->setup_request(ses, server, &rqst[i]); + if (IS_ERR(mid[i])) { revert_current_mid(server, i); for (j = 0; j < i; j++) - delete_mid(midQ[j]); + delete_mid(mid[j]); cifs_server_unlock(server); /* Update # of requests on wire to server */ for (j = 0; j < num_rqst; j++) add_credits(server, &credits[j], optype); - return PTR_ERR(midQ[i]); + return PTR_ERR(mid[i]); } - midQ[i]->mid_state = MID_REQUEST_SUBMITTED; - midQ[i]->optype = optype; + mid[i]->mid_state = MID_REQUEST_SUBMITTED; + mid[i]->optype = optype; /* * Invoke callback for every part of the compound chain * to calculate credits properly. Wake up this thread only when * the last element is received. */ if (i < num_rqst - 1) - midQ[i]->callback = cifs_compound_callback; + mid[i]->callback = cifs_compound_callback; else - midQ[i]->callback = cifs_compound_last_callback; + mid[i]->callback = cifs_compound_last_callback; } rc = smb_send_rqst(server, num_rqst, rqst, flags); for (i = 0; i < num_rqst; i++) - cifs_save_when_sent(midQ[i]); + cifs_save_when_sent(mid[i]); if (rc < 0) { revert_current_mid(server, num_rqst); @@ -1001,23 +1014,31 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, spin_unlock(&ses->ses_lock); for (i = 0; i < num_rqst; i++) { - rc = wait_for_response(server, midQ[i]); + rc = wait_for_response(server, mid[i]); if (rc != 0) break; } if (rc != 0) { + /* + * A completed CREATE earlier in the compound chain may have + * opened a remote handle even though a later wait was + * interrupted. Mark it cancelled so __release_mid() invokes + * the existing unmatched-open cleanup. + */ + cifs_mark_compound_mids_cancelled(mid, i); + for (; i < num_rqst; i++) { cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n", - midQ[i]->mid, le16_to_cpu(midQ[i]->command)); - send_cancel(server, &rqst[i], midQ[i]); - spin_lock(&midQ[i]->mid_lock); - midQ[i]->wait_cancelled = true; - if (midQ[i]->callback) { - midQ[i]->callback = cifs_cancelled_callback; + mid[i]->mid, le16_to_cpu(mid[i]->command)); + send_cancel(server, &rqst[i], mid[i]); + spin_lock(&mid[i]->mid_lock); + mid[i]->wait_cancelled = true; + if (mid[i]->callback) { + mid[i]->callback = cifs_cancelled_callback; cancelled_mid[i] = true; credits[i].value = 0; } - spin_unlock(&midQ[i]->mid_lock); + spin_unlock(&mid[i]->mid_lock); } } @@ -1025,57 +1046,78 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, if (rc < 0) goto out; - rc = cifs_sync_mid_result(midQ[i], server); + rc = cifs_sync_mid_result(mid[i], server); if (rc != 0) { + /* + * A previous CREATE may have completed before this + * response failed. Mark it cancelled so its remote + * handle is closed when the mid is released. + */ + cifs_mark_compound_mids_cancelled(mid, i); + /* Keep their response buffers for cancelled-mid cleanup. */ + num_processed = 0; /* mark this mid as cancelled to not free it below */ cancelled_mid[i] = true; goto out; } - if (!midQ[i]->resp_buf || - midQ[i]->mid_state != MID_RESPONSE_READY) { + if (!mid[i]->resp_buf || + mid[i]->mid_state != MID_RESPONSE_READY) { rc = -EIO; cifs_dbg(FYI, "Bad MID state?\n"); + cifs_mark_compound_mids_cancelled(mid, i); + num_processed = 0; goto out; } - buf = (char *)midQ[i]->resp_buf; - resp_iov[i].iov_base = buf; - resp_iov[i].iov_len = midQ[i]->resp_buf_size + - HEADER_PREAMBLE_SIZE(server); - - if (midQ[i]->large_buf) - resp_buf_type[i] = CIFS_LARGE_BUFFER; - else - resp_buf_type[i] = CIFS_SMALL_BUFFER; - - rc = server->ops->check_receive(midQ[i], server, - flags & CIFS_LOG_ERROR); - - /* mark it so buf will not be freed by delete_mid */ - if ((flags & CIFS_NO_RSP_BUF) == 0) - midQ[i]->resp_buf = NULL; + rc = server->ops->check_receive(mid[i], server, + flags & CIFS_LOG_ERROR); + num_processed = i + 1; + } +out: + /* + * Delay moving response buffers out of their mids until response + * synchronization completes. This lets cancelled-mid cleanup inspect + * an earlier CREATE response if a later MID fails. + */ + if (resp_iov) { + for (i = 0; i < num_processed; i++) { + buf = (char *)mid[i]->resp_buf; + resp_iov[i].iov_base = buf; + resp_iov[i].iov_len = mid[i]->resp_buf_size + + HEADER_PREAMBLE_SIZE(server); + + if (mid[i]->large_buf) + resp_buf_type[i] = CIFS_LARGE_BUFFER; + else + resp_buf_type[i] = CIFS_SMALL_BUFFER; + + /* mark it so buf will not be freed by delete_mid */ + if ((flags & CIFS_NO_RSP_BUF) == 0) + mid[i]->resp_buf = NULL; + } } /* * Compounding is never used during session establish. */ - spin_lock(&ses->ses_lock); - if ((ses->ses_status == SES_NEW) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) { - struct kvec iov = { - .iov_base = resp_iov[0].iov_base, - .iov_len = resp_iov[0].iov_len - }; - spin_unlock(&ses->ses_lock); - cifs_server_lock(server); - smb311_update_preauth_hash(ses, server, &iov, 1); - cifs_server_unlock(server); + if (num_processed == num_rqst) { spin_lock(&ses->ses_lock); + if ((ses->ses_status == SES_NEW) || (optype & CIFS_NEG_OP) || (optype & CIFS_SESS_OP)) { + struct kvec iov = { + .iov_base = resp_iov[0].iov_base, + .iov_len = resp_iov[0].iov_len + }; + spin_unlock(&ses->ses_lock); + cifs_server_lock(server); + smb311_update_preauth_hash(ses, server, &iov, 1); + cifs_server_unlock(server); + spin_lock(&ses->ses_lock); + } + spin_unlock(&ses->ses_lock); } - spin_unlock(&ses->ses_lock); -out: /* * This will dequeue all mids. After this it is important that the * demultiplex_thread will not process any of these mids any further. @@ -1084,7 +1126,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, */ for (i = 0; i < num_rqst; i++) { if (!cancelled_mid[i]) - delete_mid(midQ[i]); + delete_mid(mid[i]); } return rc; diff --git a/fs/verity/Kconfig b/fs/verity/Kconfig index 76d1c5971b82..b20882963ffb 100644 --- a/fs/verity/Kconfig +++ b/fs/verity/Kconfig @@ -2,6 +2,9 @@ config FS_VERITY bool "FS Verity (read-only file-based authenticity protection)" + # Filesystems cache the Merkle tree at a 64K aligned offset in the + # pagecache. That approach assumes the page size is at most 64K. + depends on PAGE_SHIFT <= 16 select CRYPTO_HASH_INFO select CRYPTO_LIB_SHA256 select CRYPTO_LIB_SHA512 diff --git a/fs/verity/open.c b/fs/verity/open.c index 77b1c977af02..2aa5eae5a540 100644 --- a/fs/verity/open.c +++ b/fs/verity/open.c @@ -384,14 +384,6 @@ int __fsverity_file_open(struct inode *inode, struct file *filp) } EXPORT_SYMBOL_GPL(__fsverity_file_open); -int __fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr) -{ - if (attr->ia_valid & ATTR_SIZE) - return -EPERM; - return 0; -} -EXPORT_SYMBOL_GPL(__fsverity_prepare_setattr); - void __fsverity_cleanup_inode(struct inode *inode) { struct fsverity_info **vi_addr = fsverity_info_addr(inode); diff --git a/fs/xfs/scrub/newbt.c b/fs/xfs/scrub/newbt.c index 951ae8b71566..2a9547789c5c 100644 --- a/fs/xfs/scrub/newbt.c +++ b/fs/xfs/scrub/newbt.c @@ -195,9 +195,11 @@ xrep_newbt_add_blocks( struct xrep_newbt_resv *resv; int error; - resv = kmalloc(sizeof(struct xrep_newbt_resv), XCHK_GFP_FLAGS); - if (!resv) - return -ENOMEM; + /* + * We have no way to clean up the allocated space *and* return an + * ENOMEM if we fail to allocate this control structure. + */ + resv = kmalloc(sizeof(struct xrep_newbt_resv), GFP_KERNEL | __GFP_NOFAIL); INIT_LIST_HEAD(&resv->list); resv->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 5bc7280425a7..86fb1708676b 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -179,7 +179,6 @@ int fsverity_get_digest(struct inode *inode, /* open.c */ int __fsverity_file_open(struct inode *inode, struct file *filp); -int __fsverity_prepare_setattr(struct dentry *dentry, struct iattr *attr); void __fsverity_cleanup_inode(struct inode *inode); /** @@ -251,12 +250,6 @@ static inline int __fsverity_file_open(struct inode *inode, struct file *filp) return -EOPNOTSUPP; } -static inline int __fsverity_prepare_setattr(struct dentry *dentry, - struct iattr *attr) -{ - return -EOPNOTSUPP; -} - static inline void fsverity_cleanup_inode(struct inode *inode) { } @@ -338,22 +331,4 @@ static inline int fsverity_file_open(struct inode *inode, struct file *filp) return 0; } -/** - * fsverity_prepare_setattr() - prepare to change a verity inode's attributes - * @dentry: dentry through which the inode is being changed - * @attr: attributes to change - * - * Verity files are immutable, so deny truncates. This isn't covered by the - * open-time check because sys_truncate() takes a path, not a file descriptor. - * - * Return: 0 on success, -errno on failure - */ -static inline int fsverity_prepare_setattr(struct dentry *dentry, - struct iattr *attr) -{ - if (IS_VERITY(d_inode(dentry))) - return __fsverity_prepare_setattr(dentry, attr); - return 0; -} - #endif /* _LINUX_FSVERITY_H */ diff --git a/include/linux/netfilter_netdev.h b/include/linux/netfilter_netdev.h index 3175073a66ba..2a854a0bbd4b 100644 --- a/include/linux/netfilter_netdev.h +++ b/include/linux/netfilter_netdev.h @@ -133,7 +133,7 @@ static inline struct sk_buff *nf_hook_egress(struct sk_buff *skb, int *rc, static inline void nf_skip_egress(struct sk_buff *skb, bool skip) { -#ifdef CONFIG_NETFILTER_SKIP_EGRESS +#ifdef CONFIG_NET_EGRESS skb->nf_skip_egress = skip; #endif } diff --git a/include/linux/netfs.h b/include/linux/netfs.h index 62a528f90666..40eedb7bb06d 100644 --- a/include/linux/netfs.h +++ b/include/linux/netfs.h @@ -402,6 +402,8 @@ ssize_t netfs_unbuffered_write_iter(struct kiocb *iocb, struct iov_iter *from); ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *iter, struct netfs_group *netfs_group); ssize_t netfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from); +void netfs_clear_stale_post_isize(struct inode *inode, unsigned long long from, + unsigned long long to); /* Single, monolithic object read/write API. */ void netfs_single_mark_inode_dirty(struct inode *inode); diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index fd1d91017b99..c8acdb026c62 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1515,9 +1515,10 @@ is_default_overflow_handler(struct perf_event *event) } extern void -perf_event_header__init_id(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_event *event); +perf_event_header__init(struct perf_event_header *header, + struct perf_sample_data *data, + u32 type, u16 misc, u16 size, + struct perf_event *event); extern void perf_event__output_id_sample(struct perf_event *event, struct perf_output_handle *handle, diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index ea39dd23a197..077d2b486de0 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -178,7 +178,12 @@ void net_dec_ingress_queue(void); #ifdef CONFIG_NET_EGRESS void net_inc_egress_queue(void); void net_dec_egress_queue(void); -void netdev_xmit_skip_txqueue(bool skip); +bool netdev_xmit_skip_txqueue(bool skip); +#else +static inline bool netdev_xmit_skip_txqueue(bool skip) +{ + return false; +} #endif void rtnetlink_init(void); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 37fbdf08a8e0..237e8b0cb08a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1019,7 +1019,7 @@ struct sk_buff { #ifdef CONFIG_NET_REDIRECT __u8 from_ingress:1; #endif -#ifdef CONFIG_NETFILTER_SKIP_EGRESS +#ifdef CONFIG_NET_EGRESS __u8 nf_skip_egress:1; #endif #ifdef CONFIG_SKB_DECRYPTED diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h index 16d68622954a..7c2807c392ec 100644 --- a/include/linux/soc/qcom/geni-se.h +++ b/include/linux/soc/qcom/geni-se.h @@ -303,17 +303,12 @@ struct geni_se { #define QUP_SE_VERSION_2_5 0x20050000 /* - * Define bandwidth thresholds that cause the underlying Core 2X interconnect - * clock to run at the named frequency. These baseline values are recommended - * by the hardware team, and are not dynamically scaled with GENI bandwidth - * beyond basic on/off. + * QUP Core 2X clock votes used by GENI clients through the "qup-core" ICC + * path. Values are in Bps and must be converted with Bps_to_icc() before + * setting avg_bw. */ -#define CORE_2X_19_2_MHZ 960 -#define CORE_2X_50_MHZ 2500 -#define CORE_2X_100_MHZ 5000 -#define CORE_2X_150_MHZ 7500 -#define CORE_2X_200_MHZ 10000 -#define CORE_2X_236_MHZ 16383 +#define CORE_2X_19_2_MHZ 9600000 +#define CORE_2X_50_MHZ 25000000 #define GENI_DEFAULT_BW Bps_to_icc(1000) diff --git a/include/linux/tty.h b/include/linux/tty.h index 0a46e4054dec..ad4e4a835f90 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -230,6 +230,7 @@ struct tty_struct { struct fasync_struct *fasync; wait_queue_head_t write_wait; wait_queue_head_t read_wait; + wait_queue_head_t break_wait; struct work_struct hangup_work; void *disc_data; void *driver_data; diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 188ee9b768eb..77d078964239 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -69,6 +69,11 @@ struct serial_struct; * Do not create numbered ``/dev`` nodes. For example, create * ``/dev/ttyprintk`` and not ``/dev/ttyprintk0``. Applicable only when a * driver for a single tty device is being allocated. + * + * @TTY_DRIVER_RESET_SAVED_TERMIOS: + * Reset any saved termios settings on device registration when reusing a + * minor number. Must only be set by drivers that guarantee that the minor + * number is no longer in use. */ enum tty_driver_flag { TTY_DRIVER_INSTALLED = BIT(0), @@ -79,6 +84,7 @@ enum tty_driver_flag { TTY_DRIVER_HARDWARE_BREAK = BIT(5), TTY_DRIVER_DYNAMIC_ALLOC = BIT(6), TTY_DRIVER_UNNUMBERED_NODE = BIT(7), + TTY_DRIVER_RESET_SAVED_TERMIOS = BIT(9), }; enum tty_driver_type { diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h index 660c254f1efe..5d23023ae2dd 100644 --- a/include/linux/tty_port.h +++ b/include/linux/tty_port.h @@ -232,7 +232,8 @@ bool tty_port_carrier_raised(struct tty_port *port); void tty_port_raise_dtr_rts(struct tty_port *port); void tty_port_lower_dtr_rts(struct tty_port *port); void tty_port_hangup(struct tty_port *port); -void __tty_port_tty_hangup(struct tty_port *port, bool check_clocal, bool async); +void tty_port_tty_hangup(struct tty_port *port, bool check_clocal); +void tty_port_tty_vhangup(struct tty_port *port); void tty_port_tty_wakeup(struct tty_port *port); int tty_port_block_til_ready(struct tty_port *port, struct tty_struct *tty, struct file *filp); @@ -251,25 +252,6 @@ static inline int tty_port_users(struct tty_port *port) return port->count + port->blocked_open; } -/** - * tty_port_tty_hangup - helper to hang up a tty asynchronously - * @port: tty port - * @check_clocal: hang only ttys with %CLOCAL unset? - */ -static inline void tty_port_tty_hangup(struct tty_port *port, bool check_clocal) -{ - __tty_port_tty_hangup(port, check_clocal, true); -} - -/** - * tty_port_tty_vhangup - helper to hang up a tty synchronously - * @port: tty port - */ -static inline void tty_port_tty_vhangup(struct tty_port *port) -{ - __tty_port_tty_hangup(port, false, false); -} - #ifdef CONFIG_TTY void tty_kref_put(struct tty_struct *tty); __DEFINE_CLASS_IS_CONDITIONAL(tty_port_tty, true); diff --git a/include/linux/units.h b/include/linux/units.h index 00e15de33eca..0c296a004e89 100644 --- a/include/linux/units.h +++ b/include/linux/units.h @@ -25,9 +25,12 @@ #define MICROHZ_PER_HZ 1000000UL #define MILLIHZ_PER_HZ 1000UL +/* Hz based multipliers */ #define HZ_PER_KHZ 1000UL #define HZ_PER_MHZ 1000000UL +#define HZ_PER_GHZ 1000000000UL +/* kHz based multipliers */ #define KHZ_PER_MHZ 1000UL #define KHZ_PER_GHZ 1000000UL diff --git a/include/linux/unwind_deferred.h b/include/linux/unwind_deferred.h index 26122d00708a..25f4dffebd1b 100644 --- a/include/linux/unwind_deferred.h +++ b/include/linux/unwind_deferred.h @@ -8,7 +8,9 @@ struct unwind_work; -typedef void (*unwind_callback_t)(struct unwind_work *work, struct unwind_stacktrace *trace, u64 cookie); +typedef void (*unwind_callback_t)(struct unwind_work *work, + struct unwind_stacktrace *trace, + u64 cookie); struct unwind_work { struct list_head list; @@ -68,9 +70,17 @@ static __always_inline void unwind_reset_info(void) static inline void unwind_task_init(struct task_struct *task) {} static inline void unwind_task_free(struct task_struct *task) {} -static inline int unwind_user_faultable(struct unwind_stacktrace *trace) { return -ENOSYS; } -static inline int unwind_deferred_init(struct unwind_work *work, unwind_callback_t func) { return -ENOSYS; } -static inline int unwind_deferred_request(struct unwind_work *work, u64 *timestamp) { return -ENOSYS; } +static inline int unwind_user_faultable(struct unwind_stacktrace *trace) +{ return -ENOSYS; } + +static inline int +unwind_deferred_init(struct unwind_work *work, unwind_callback_t func) +{ return -ENOSYS; } + +static inline int +unwind_deferred_request(struct unwind_work *work, u64 *timestamp) +{ return -ENOSYS; } + static inline void unwind_deferred_cancel(struct unwind_work *work) {} static inline void unwind_deferred_task_exit(struct task_struct *task) {} diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 75b2b763f1ba..df50ca80ec08 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -380,6 +380,7 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, int usb_serial_bus_register(struct usb_serial_driver *device); void usb_serial_bus_deregister(struct usb_serial_driver *device); +void usb_serial_bus_remove_new_id(struct usb_serial_driver *driver); extern const struct bus_type usb_serial_bus_type; extern struct tty_driver *usb_serial_tty_driver; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9dea729fd232..4dc8e6c39c01 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -65,7 +65,7 @@ struct inquiry_entry { NAME_PENDING, NAME_KNOWN, } name_state; - __u32 timestamp; + unsigned long timestamp; struct inquiry_data data; }; @@ -81,7 +81,7 @@ struct discovery_state { struct list_head all; /* All devices found during inquiry */ struct list_head unknown; /* Name state not known */ struct list_head resolve; /* Name needs to be resolved */ - __u32 timestamp; + unsigned long timestamp; bdaddr_t last_adv_addr; u8 last_adv_addr_type; s8 last_adv_rssi; @@ -563,6 +563,7 @@ struct hci_dev { struct list_head link_keys; struct list_head long_term_keys; struct list_head identity_resolving_keys; + struct mutex remote_oob_lock; struct list_head remote_oob_data; struct list_head le_accept_list; struct list_head le_resolv_list; diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index 1fc2fb03ce3f..f45d1e3163f0 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -164,8 +164,11 @@ static inline struct metadata_dst *tun_dst_unclone(struct sk_buff *skb) if (!new_md) return ERR_PTR(-ENOMEM); - memcpy(&new_md->u.tun_info, &md_dst->u.tun_info, - sizeof(struct ip_tunnel_info) + md_size); + /* Copy in two stages to keep the __counted_by happy. */ + new_md->u.tun_info = md_dst->u.tun_info; + memcpy(ip_tunnel_info_opts(&new_md->u.tun_info), + ip_tunnel_info_opts(&md_dst->u.tun_info), md_size); + #ifdef CONFIG_DST_CACHE /* Unclone the dst cache if there is one */ if (new_md->u.tun_info.dst_cache.cache) { diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d19b95d3c3a4..2fa6fc593df6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1892,12 +1892,16 @@ enum ieee80211_vif_flags { * @IEEE80211_OFFLOAD_DECAP_ENABLED: rx encapsulation offload is enabled * The driver supports passing received 802.11 frames as 802.3 frames to * mac80211. + * @IEEE80211_OFFLOAD_ENCAP_MCAST: tx multicast encapsulation offload is enabled + * The driver supports sending multicast frames passed as 802.3 frames + * by mac80211. */ enum ieee80211_offload_flags { IEEE80211_OFFLOAD_ENCAP_ENABLED = BIT(0), IEEE80211_OFFLOAD_ENCAP_4ADDR = BIT(1), IEEE80211_OFFLOAD_DECAP_ENABLED = BIT(2), + IEEE80211_OFFLOAD_ENCAP_MCAST = BIT(3), }; /** diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h index e199f1d44c8e..a134b1235279 100644 --- a/include/net/mana/mana.h +++ b/include/net/mana/mana.h @@ -302,6 +302,14 @@ struct mana_recv_buf_oob { void *buf_va; bool from_pool; /* allocated from a page pool */ + /* head page of the page_pool fragment; valid only when + * from_pool && frag_count > 1. + */ + struct page *pp_page; + /* Fragment offset plus rxq->headroom, passed to + * page_pool_dma_sync_for_cpu(). + */ + u32 dma_sync_offset; /* SGL of the buffer going to be sent as part of the work request. */ u32 num_sge; diff --git a/include/net/neighbour.h b/include/net/neighbour.h index c13c758aca7e..862e53007fd2 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -92,15 +92,17 @@ struct neigh_parms { static inline void neigh_var_set(struct neigh_parms *p, int index, int val) { set_bit(index, p->data_state); - p->data[index] = val; + WRITE_ONCE(p->data[index], val); } -#define NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr]) +#define __NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr]) +#define NEIGH_VAR(p, attr) READ_ONCE(__NEIGH_VAR(p, attr)) +#define NEIGH_VAR_PTR(p, attr) (&(__NEIGH_VAR(p, attr))) /* In ndo_neigh_setup, NEIGH_VAR_INIT should be used. * In other cases, NEIGH_VAR_SET should be used. */ -#define NEIGH_VAR_INIT(p, attr, val) (NEIGH_VAR(p, attr) = val) +#define NEIGH_VAR_INIT(p, attr, val) (__NEIGH_VAR(p, attr) = val) #define NEIGH_VAR_SET(p, attr, val) neigh_var_set(p, NEIGH_VAR_ ## attr, val) static inline void neigh_parms_data_state_setall(struct neigh_parms *p) @@ -378,6 +380,13 @@ struct net *neigh_parms_net(const struct neigh_parms *parms) unsigned long neigh_rand_reach_time(unsigned long base); +static inline void neigh_set_reach_time(struct neigh_parms *p) +{ + unsigned long base = NEIGH_VAR(p, BASE_REACHABLE_TIME); + + WRITE_ONCE(p->reachable_time, neigh_rand_reach_time(base)); +} + void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, struct sk_buff *skb); struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, struct net *net, diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h index 7c330caae52b..9778ef5e26c6 100644 --- a/include/net/netfilter/nf_flow_table.h +++ b/include/net/netfilter/nf_flow_table.h @@ -166,10 +166,10 @@ enum nf_flow_flags { NF_FLOW_DNAT, NF_FLOW_CLOSING, NF_FLOW_TEARDOWN, + NF_FLOW_PENDING, NF_FLOW_HW, NF_FLOW_HW_DYING, NF_FLOW_HW_DEAD, - NF_FLOW_HW_PENDING, NF_FLOW_HW_BIDIRECTIONAL, NF_FLOW_HW_ESTABLISHED, }; diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 97c1b2828bcd..7d62fde583bd 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -772,6 +772,15 @@ static inline bool skb_at_tc_ingress(const struct sk_buff *skb) #endif } +static inline bool skb_at_tc_egress(const struct sk_buff *skb) +{ +#ifdef CONFIG_NET_EGRESS + return skb->nf_skip_egress && !skb_at_tc_ingress(skb); +#else + return false; +#endif +} + static inline bool skb_skip_tc_classify(struct sk_buff *skb) { #ifdef CONFIG_NET_CLS_ACT diff --git a/include/net/xdp.h b/include/net/xdp.h index aa742f413c35..07231adfb5f8 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -106,6 +106,11 @@ struct xdp_buff { }; }; +static __always_inline void xdp_reinit_buff(struct xdp_buff *xdp) +{ + xdp->flags = 0; +} + static __always_inline bool xdp_buff_has_frags(const struct xdp_buff *xdp) { return !!(xdp->flags & XDP_FLAGS_HAS_FRAGS); diff --git a/include/sound/core.h b/include/sound/core.h index 618055761fe0..0b7148b0d9d7 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -316,6 +316,15 @@ static inline void snd_card_unref(struct snd_card *card) DEFINE_FREE(snd_card_unref, struct snd_card *, if (_T) snd_card_unref(_T)) +/* + * For automatic error handling at probe time, assign the card like: + * struct snd_card *card __free(snd_card_free) = NULL; + * then create and process as usual. + * But, don't forget to clear to NULL at successful return for avoiding + * the unexpected cleanup! + */ +DEFINE_FREE(snd_card_free, struct snd_card *, if (_T) snd_card_free(_T)) + #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr)) /* device.c */ diff --git a/include/uapi/linux/random.h b/include/uapi/linux/random.h index 1dd047ec98a1..ef6614d9c704 100644 --- a/include/uapi/linux/random.h +++ b/include/uapi/linux/random.h @@ -58,7 +58,7 @@ struct rand_pool_info { /** * struct vgetrandom_opaque_params - arguments for allocating memory for vgetrandom * - * @size_per_opaque_state: Size of each state that is to be passed to vgetrandom(). + * @size_of_opaque_state: Size of each state passed to vgetrandom(). * @mmap_prot: Value of the prot argument in mmap(2). * @mmap_flags: Value of the flags argument in mmap(2). * @reserved: Reserved for future use. diff --git a/init/Kconfig b/init/Kconfig index 6ce315af48c1..1858e55bfd7c 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -142,6 +142,11 @@ config CC_HAS_COUNTED_BY config CC_HAS_MULTIDIMENSIONAL_NONSTRING def_bool $(success,echo 'char tag[][4] __attribute__((__nonstring__)) = { };' | $(CC) $(CLANG_FLAGS) -x c - -c -o /dev/null -Werror) +config CC_OPT_INLINE_MEMSET + string + default "-finline-stringops=memset" if $(cc-option,-finline-stringops=memset) + default "-mllvm -max-store-memset=4294967294" if $(cc-option,-mllvm -max-store-memset=4294967294) + config LD_CAN_USE_KEEP_IN_OVERLAY # ld.lld prior to 21.0.0 did not support KEEP within an overlay description # https://github.com/llvm/llvm-project/pull/130661 diff --git a/io_uring/cmd_net.c b/io_uring/cmd_net.c index 54d05a205e62..5cb5d9850c15 100644 --- a/io_uring/cmd_net.c +++ b/io_uring/cmd_net.c @@ -53,8 +53,8 @@ static inline int io_uring_cmd_setsockopt(struct socket *sock, optlen); } -static bool io_process_timestamp_skb(struct io_uring_cmd *cmd, struct sock *sk, - struct sk_buff *skb, unsigned issue_flags) +static int io_process_timestamp_skb(struct io_uring_cmd *cmd, struct sock *sk, + struct sk_buff *skb, unsigned int issue_flags) { struct sock_exterr_skb *serr = SKB_EXT_ERR(skb); struct io_uring_cqe cqe[2]; @@ -67,7 +67,7 @@ static bool io_process_timestamp_skb(struct io_uring_cmd *cmd, struct sock *sk, ret = skb_get_tx_timestamp(skb, sk, &ts); if (ret < 0) - return false; + return ret; tskey = serr->ee.ee_data; tstype = serr->ee.ee_info; @@ -82,7 +82,9 @@ static bool io_process_timestamp_skb(struct io_uring_cmd *cmd, struct sock *sk, iots = (struct io_timespec *)&cqe[1]; iots->tv_sec = ts.tv_sec; iots->tv_nsec = ts.tv_nsec; - return io_uring_cmd_post_mshot_cqe32(cmd, issue_flags, cqe); + if (!io_uring_cmd_post_mshot_cqe32(cmd, issue_flags, cqe)) + return -ENOBUFS; + return 0; } static int io_uring_cmd_timestamp(struct socket *sock, @@ -119,7 +121,8 @@ static int io_uring_cmd_timestamp(struct socket *sock, skb = skb_peek(&list); if (!skb) break; - if (!io_process_timestamp_skb(cmd, sk, skb, issue_flags)) + ret = io_process_timestamp_skb(cmd, sk, skb, issue_flags); + if (ret) break; __skb_dequeue(&list); consume_skb(skb); @@ -129,6 +132,12 @@ static int io_uring_cmd_timestamp(struct socket *sock, scoped_guard(spinlock_irqsave, &q->lock) skb_queue_splice(&list, q); } + /* + * Aux CQEs cannot overflow and the poll is edge triggered, so nothing + * re-runs the command once the CQ drains. End the multishot instead. + */ + if (ret == -ENOBUFS) + return -ENOBUFS; return -EAGAIN; } diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c index fd64ba7a0927..524669ee1998 100644 --- a/io_uring/io_uring.c +++ b/io_uring/io_uring.c @@ -1341,6 +1341,9 @@ static void io_req_normal_work_add(struct io_kiocb *req) struct io_uring_task *tctx = req->tctx; struct io_ring_ctx *ctx = req->ctx; + /* SQPOLL can retire the request on push, see io_ring_exit_work() */ + guard(rcu)(); + /* task_work already pending, we're done */ if (!llist_add(&req->io_task_work.node, &tctx->task_list)) return; @@ -3146,8 +3149,8 @@ static __cold void io_ring_exit_work(struct work_struct *work) spin_lock(&ctx->completion_lock); spin_unlock(&ctx->completion_lock); - /* pairs with RCU read section in io_req_local_work_add() */ - if (ctx->flags & IORING_SETUP_DEFER_TASKRUN) + /* pairs with the RCU read sections in the task_work add paths */ + if (ctx->flags & (IORING_SETUP_DEFER_TASKRUN | IORING_SETUP_SQPOLL)) synchronize_rcu(); io_ring_ctx_free(ctx); diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c index b768f43f0fd1..56a6a0e52e51 100644 --- a/io_uring/zcrx.c +++ b/io_uring/zcrx.c @@ -322,6 +322,7 @@ struct io_zcrx_args { struct io_zcrx_ifq *ifq; struct socket *sock; unsigned nr_skbs; + bool stopped_early; }; static const struct memory_provider_ops io_uring_pp_zc_ops; @@ -1205,6 +1206,9 @@ io_zcrx_recv_skb(read_descriptor_t *desc, struct sk_buff *skb, } out: + /* Bytes left in len mean an error stopped the walk early. */ + if (len) + args->stopped_early = true; if (offset == start_off) return ret; desc->count -= (offset - start_off); @@ -1242,8 +1246,9 @@ static int io_zcrx_tcp_recvmsg(struct io_kiocb *req, struct io_zcrx_ifq *ifq, ret = -ENOTCONN; else ret = -EAGAIN; - } else if (unlikely(args.nr_skbs > IO_SKBS_PER_CALL_LIMIT) && - (issue_flags & IO_URING_F_MULTISHOT)) { + } else if ((issue_flags & IO_URING_F_MULTISHOT) && + (unlikely(args.nr_skbs > IO_SKBS_PER_CALL_LIMIT) || + args.stopped_early)) { ret = IOU_REQUEUE; } else if (sock_flag(sk, SOCK_DONE)) { /* Make it to retry until it finally gets 0. */ diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index f2c13a62bfb6..f8686c7f502d 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -545,22 +545,38 @@ static void kill_rules(struct audit_context *context, struct audit_tree *tree) { struct audit_krule *rule, *next; struct audit_entry *entry; + bool need_sync = false; list_for_each_entry_safe(rule, next, &tree->rules, rlist) { entry = container_of(rule, struct audit_entry, rule); - list_del_init(&rule->rlist); if (rule->tree) { /* not a half-baked one */ audit_tree_log_remove_rule(context, rule); - if (entry->rule.exe) - audit_remove_mark(entry->rule.exe); rule->tree = NULL; list_del_rcu(&entry->list); list_del(&entry->rule.list); - call_rcu(&entry->rcu, audit_free_rule_rcu); + if (entry->rule.exe) + need_sync = true; + } else { + list_del_init(&rule->rlist); } } + + if (list_empty(&tree->rules)) + return; + + if (need_sync) + synchronize_rcu(); + + list_for_each_entry_safe(rule, next, &tree->rules, rlist) { + entry = container_of(rule, struct audit_entry, rule); + + list_del_init(&rule->rlist); + if (entry->rule.exe) + audit_remove_mark(entry->rule.exe); + call_rcu(&entry->rcu, audit_free_rule_rcu); + } } /* diff --git a/kernel/events/core.c b/kernel/events/core.c index e98e164919b7..018a1e4ef5b0 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7316,9 +7316,11 @@ static void perf_sigtrap(struct perf_event *event) { /* * Both perf_pending_task() and perf_pending_irq() can race with the - * task exiting. + * task exiting or exec-ing. We can determine if such a race has + * occurred by checking if perf_event_exit_task(), which will set + * ctx->task to TASK_TOMBSTONE, has already been called. */ - if (current->flags & PF_EXITING) + if (event->ctx->task == TASK_TOMBSTONE) return; /* @@ -7792,10 +7794,15 @@ static void __perf_event_header__init_id(struct perf_sample_data *data, } } -void perf_event_header__init_id(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_event *event) +void perf_event_header__init(struct perf_event_header *header, + struct perf_sample_data *data, + u32 type, u16 misc, u16 size, + struct perf_event *event) { + header->type = type; + header->misc = misc; + header->size = size; + if (event->attr.sample_id_all) { header->size += event->id_header_size; __perf_event_header__init_id(data, event, event->attr.sample_type); @@ -8623,17 +8630,16 @@ perf_event_read_event(struct perf_event *event, struct perf_output_handle handle; struct perf_sample_data sample; struct perf_read_event read_event = { - .header = { - .type = PERF_RECORD_READ, - .misc = 0, - .size = sizeof(read_event) + event->read_size, - }, .pid = perf_event_pid(event, task), .tid = perf_event_tid(event, task), }; int ret; - perf_event_header__init_id(&read_event.header, &sample, event); + perf_event_header__init(&read_event.header, &sample, + PERF_RECORD_READ, + /* misc= */ 0, + sizeof(read_event) + event->read_size, + event); ret = perf_output_begin(&handle, &sample, event, read_event.header.size); if (ret) return; @@ -8874,6 +8880,7 @@ struct perf_task_event { u32 ptid; u64 time; } event_id; + int new; }; static int perf_event_task_match(struct perf_event *event) @@ -8890,17 +8897,21 @@ static void perf_event_task_output(struct perf_event *event, struct perf_output_handle handle; struct perf_sample_data sample; struct task_struct *task = task_event->task; - int ret, size = task_event->event_id.header.size; + int ret; if (!perf_event_task_match(event)) return; - perf_event_header__init_id(&task_event->event_id.header, &sample, event); + perf_event_header__init(&task_event->event_id.header, &sample, + task_event->new ? PERF_RECORD_FORK : PERF_RECORD_EXIT, + /* misc= */ 0, + sizeof(task_event->event_id), + event); ret = perf_output_begin(&handle, &sample, event, task_event->event_id.header.size); if (ret) - goto out; + return; task_event->event_id.pid = perf_event_pid(event, task); task_event->event_id.tid = perf_event_tid(event, task); @@ -8922,8 +8933,6 @@ static void perf_event_task_output(struct perf_event *event, perf_event__output_id_sample(event, &handle, &sample); perf_output_end(&handle); -out: - task_event->event_id.header.size = size; } static void perf_event_task(struct task_struct *task, @@ -8940,18 +8949,7 @@ static void perf_event_task(struct task_struct *task, task_event = (struct perf_task_event){ .task = task, .task_ctx = task_ctx, - .event_id = { - .header = { - .type = new ? PERF_RECORD_FORK : PERF_RECORD_EXIT, - .misc = 0, - .size = sizeof(task_event.event_id), - }, - /* .pid */ - /* .ppid */ - /* .tid */ - /* .ptid */ - /* .time */ - }, + .new = new, }; perf_iterate_sb(perf_event_task_output, @@ -9028,6 +9026,7 @@ struct perf_comm_event { u32 pid; u32 tid; } event_id; + bool exec; }; static int perf_event_comm_match(struct perf_event *event) @@ -9041,18 +9040,21 @@ static void perf_event_comm_output(struct perf_event *event, struct perf_comm_event *comm_event = data; struct perf_output_handle handle; struct perf_sample_data sample; - int size = comm_event->event_id.header.size; int ret; if (!perf_event_comm_match(event)) return; - perf_event_header__init_id(&comm_event->event_id.header, &sample, event); + perf_event_header__init(&comm_event->event_id.header, &sample, + PERF_RECORD_COMM, + comm_event->exec ? PERF_RECORD_MISC_COMM_EXEC : 0, + sizeof(comm_event->event_id) + comm_event->comm_size, + event); ret = perf_output_begin(&handle, &sample, event, comm_event->event_id.header.size); if (ret) - goto out; + return; comm_event->event_id.pid = perf_event_pid(event, comm_event->task); comm_event->event_id.tid = perf_event_tid(event, comm_event->task); @@ -9064,8 +9066,6 @@ static void perf_event_comm_output(struct perf_event *event, perf_event__output_id_sample(event, &handle, &sample); perf_output_end(&handle); -out: - comm_event->event_id.header.size = size; } static void perf_event_comm_event(struct perf_comm_event *comm_event) @@ -9080,8 +9080,6 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event) comm_event->comm = comm; comm_event->comm_size = size; - comm_event->event_id.header.size = sizeof(comm_event->event_id) + size; - perf_iterate_sb(perf_event_comm_output, comm_event, NULL); @@ -9098,15 +9096,8 @@ void perf_event_comm(struct task_struct *task, bool exec) .task = task, /* .comm */ /* .comm_size */ - .event_id = { - .header = { - .type = PERF_RECORD_COMM, - .misc = exec ? PERF_RECORD_MISC_COMM_EXEC : 0, - /* .size */ - }, - /* .pid */ - /* .tid */ - }, + /* .event_id */ + .exec = exec, }; perf_event_comm_event(&comm_event); @@ -9140,18 +9131,20 @@ static void perf_event_namespaces_output(struct perf_event *event, struct perf_namespaces_event *namespaces_event = data; struct perf_output_handle handle; struct perf_sample_data sample; - u16 header_size = namespaces_event->event_id.header.size; int ret; if (!perf_event_namespaces_match(event)) return; - perf_event_header__init_id(&namespaces_event->event_id.header, - &sample, event); + perf_event_header__init(&namespaces_event->event_id.header, &sample, + PERF_RECORD_NAMESPACES, + /* misc= */ 0, + sizeof(namespaces_event->event_id), + event); ret = perf_output_begin(&handle, &sample, event, namespaces_event->event_id.header.size); if (ret) - goto out; + return; namespaces_event->event_id.pid = perf_event_pid(event, namespaces_event->task); @@ -9163,8 +9156,6 @@ static void perf_event_namespaces_output(struct perf_event *event, perf_event__output_id_sample(event, &handle, &sample); perf_output_end(&handle); -out: - namespaces_event->event_id.header.size = header_size; } static void perf_fill_ns_link_info(struct perf_ns_link_info *ns_link_info, @@ -9195,11 +9186,7 @@ void perf_event_namespaces(struct task_struct *task) namespaces_event = (struct perf_namespaces_event){ .task = task, .event_id = { - .header = { - .type = PERF_RECORD_NAMESPACES, - .misc = 0, - .size = sizeof(namespaces_event.event_id), - }, + /* .header */ /* .pid */ /* .tid */ .nr_namespaces = NR_NAMESPACES, @@ -9267,18 +9254,19 @@ static void perf_event_cgroup_output(struct perf_event *event, void *data) struct perf_cgroup_event *cgroup_event = data; struct perf_output_handle handle; struct perf_sample_data sample; - u16 header_size = cgroup_event->event_id.header.size; int ret; + u16 size = sizeof(cgroup_event->event_id) + cgroup_event->path_size; if (!perf_event_cgroup_match(event)) return; - perf_event_header__init_id(&cgroup_event->event_id.header, - &sample, event); + perf_event_header__init(&cgroup_event->event_id.header, &sample, + PERF_RECORD_CGROUP, /* misc= */ 0, size, + event); ret = perf_output_begin(&handle, &sample, event, cgroup_event->event_id.header.size); if (ret) - goto out; + return; perf_output_put(&handle, cgroup_event->event_id); __output_copy(&handle, cgroup_event->path, cgroup_event->path_size); @@ -9286,8 +9274,6 @@ static void perf_event_cgroup_output(struct perf_event *event, void *data) perf_event__output_id_sample(event, &handle, &sample); perf_output_end(&handle); -out: - cgroup_event->event_id.header.size = header_size; } static void perf_event_cgroup(struct cgroup *cgrp) @@ -9302,11 +9288,6 @@ static void perf_event_cgroup(struct cgroup *cgrp) cgroup_event = (struct perf_cgroup_event){ .event_id = { - .header = { - .type = PERF_RECORD_CGROUP, - .misc = 0, - .size = sizeof(cgroup_event.event_id), - }, .id = cgroup_id(cgrp), }, }; @@ -9329,7 +9310,6 @@ static void perf_event_cgroup(struct cgroup *cgrp) while (!IS_ALIGNED(size, sizeof(u64))) cgroup_event.path[size++] = '\0'; - cgroup_event.event_id.header.size += size; cgroup_event.path_size = size; perf_iterate_sb(perf_event_cgroup_output, @@ -9385,38 +9365,40 @@ static void perf_event_mmap_output(struct perf_event *event, struct perf_mmap_event *mmap_event = data; struct perf_output_handle handle; struct perf_sample_data sample; - int size = mmap_event->event_id.header.size; - u32 type = mmap_event->event_id.header.type; - bool use_build_id; + int size = sizeof(mmap_event->event_id) + mmap_event->file_size; + u32 type = PERF_RECORD_MMAP; + u16 misc = PERF_RECORD_MISC_USER; + bool use_build_id = false; int ret; if (!perf_event_mmap_match(event, data)) return; if (event->attr.mmap2) { - mmap_event->event_id.header.type = PERF_RECORD_MMAP2; - mmap_event->event_id.header.size += sizeof(mmap_event->maj); - mmap_event->event_id.header.size += sizeof(mmap_event->min); - mmap_event->event_id.header.size += sizeof(mmap_event->ino); - mmap_event->event_id.header.size += sizeof(mmap_event->ino_generation); - mmap_event->event_id.header.size += sizeof(mmap_event->prot); - mmap_event->event_id.header.size += sizeof(mmap_event->flags); - } - - perf_event_header__init_id(&mmap_event->event_id.header, &sample, event); + type = PERF_RECORD_MMAP2; + size += sizeof(mmap_event->maj); + size += sizeof(mmap_event->min); + size += sizeof(mmap_event->ino); + size += sizeof(mmap_event->ino_generation); + size += sizeof(mmap_event->prot); + size += sizeof(mmap_event->flags); + use_build_id = event->attr.build_id && mmap_event->build_id_size; + if (use_build_id) + misc |= PERF_RECORD_MISC_MMAP_BUILD_ID; + } + if (!(mmap_event->vma->vm_flags & VM_EXEC)) + misc |= PERF_RECORD_MISC_MMAP_DATA; + + perf_event_header__init(&mmap_event->event_id.header, &sample, + type, misc, size, event); ret = perf_output_begin(&handle, &sample, event, mmap_event->event_id.header.size); if (ret) - goto out; + return; mmap_event->event_id.pid = perf_event_pid(event, current); mmap_event->event_id.tid = perf_event_tid(event, current); - use_build_id = event->attr.build_id && mmap_event->build_id_size; - - if (event->attr.mmap2 && use_build_id) - mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_BUILD_ID; - perf_output_put(&handle, mmap_event->event_id); if (event->attr.mmap2) { @@ -9441,9 +9423,6 @@ static void perf_event_mmap_output(struct perf_event *event, perf_event__output_id_sample(event, &handle, &sample); perf_output_end(&handle); -out: - mmap_event->event_id.header.size = size; - mmap_event->event_id.header.type = type; } static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) @@ -9539,11 +9518,6 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event) mmap_event->prot = prot; mmap_event->flags = flags; - if (!(vma->vm_flags & VM_EXEC)) - mmap_event->event_id.header.misc |= PERF_RECORD_MISC_MMAP_DATA; - - mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size; - if (atomic_read(&nr_build_id_events)) build_id_parse_nofault(vma, mmap_event->build_id, &mmap_event->build_id_size); @@ -9663,11 +9637,7 @@ void perf_event_mmap(struct vm_area_struct *vma) /* .file_name */ /* .file_size */ .event_id = { - .header = { - .type = PERF_RECORD_MMAP, - .misc = PERF_RECORD_MISC_USER, - /* .size */ - }, + /* .header */ /* .pid */ /* .tid */ .start = vma->vm_start, @@ -9697,18 +9667,15 @@ void perf_event_aux_event(struct perf_event *event, unsigned long head, u64 size; u64 flags; } rec = { - .header = { - .type = PERF_RECORD_AUX, - .misc = 0, - .size = sizeof(rec), - }, .offset = head, .size = size, .flags = flags, }; int ret; - perf_event_header__init_id(&rec.header, &sample, event); + perf_event_header__init(&rec.header, &sample, + PERF_RECORD_AUX, /* misc= */ 0, sizeof(rec), + event); ret = perf_output_begin(&handle, &sample, event, rec.header.size); if (ret) @@ -9733,15 +9700,14 @@ void perf_log_lost_samples(struct perf_event *event, u64 lost) struct perf_event_header header; u64 lost; } lost_samples_event = { - .header = { - .type = PERF_RECORD_LOST_SAMPLES, - .misc = 0, - .size = sizeof(lost_samples_event), - }, .lost = lost, }; - perf_event_header__init_id(&lost_samples_event.header, &sample, event); + perf_event_header__init(&lost_samples_event.header, &sample, + PERF_RECORD_LOST_SAMPLES, + /* misc= */ 0, + sizeof(lost_samples_event), + event); ret = perf_output_begin(&handle, &sample, event, lost_samples_event.header.size); @@ -9766,6 +9732,8 @@ struct perf_switch_event { u32 next_prev_pid; u32 next_prev_tid; } event_id; + bool sched_in; + bool preempt; }; static int perf_event_switch_match(struct perf_event *event) @@ -9778,6 +9746,9 @@ static void perf_event_switch_output(struct perf_event *event, void *data) struct perf_switch_event *se = data; struct perf_output_handle handle; struct perf_sample_data sample; + u32 type; + u16 misc; + u16 size; int ret; if (!perf_event_switch_match(event)) @@ -9785,18 +9756,22 @@ static void perf_event_switch_output(struct perf_event *event, void *data) /* Only CPU-wide events are allowed to see next/prev pid/tid */ if (event->ctx->task) { - se->event_id.header.type = PERF_RECORD_SWITCH; - se->event_id.header.size = sizeof(se->event_id.header); + type = PERF_RECORD_SWITCH; + size = sizeof(se->event_id.header); } else { - se->event_id.header.type = PERF_RECORD_SWITCH_CPU_WIDE; - se->event_id.header.size = sizeof(se->event_id); + type = PERF_RECORD_SWITCH_CPU_WIDE; + size = sizeof(se->event_id); se->event_id.next_prev_pid = perf_event_pid(event, se->next_prev); se->event_id.next_prev_tid = perf_event_tid(event, se->next_prev); } + misc = se->sched_in ? 0 : PERF_RECORD_MISC_SWITCH_OUT; + if (se->preempt) + misc |= PERF_RECORD_MISC_SWITCH_OUT_PREEMPT; - perf_event_header__init_id(&se->event_id.header, &sample, event); + perf_event_header__init(&se->event_id.header, &sample, + type, misc, size, event); ret = perf_output_begin(&handle, &sample, event, se->event_id.header.size); if (ret) @@ -9822,22 +9797,11 @@ static void perf_event_switch(struct task_struct *task, switch_event = (struct perf_switch_event){ .task = task, .next_prev = next_prev, - .event_id = { - .header = { - /* .type */ - .misc = sched_in ? 0 : PERF_RECORD_MISC_SWITCH_OUT, - /* .size */ - }, - /* .next_prev_pid */ - /* .next_prev_tid */ - }, + /* .event_id */ + .sched_in = sched_in, + .preempt = !sched_in && task_is_runnable(task), }; - if (!sched_in && task_is_runnable(task)) { - switch_event.event_id.header.misc |= - PERF_RECORD_MISC_SWITCH_OUT_PREEMPT; - } - perf_iterate_sb(perf_event_switch_output, &switch_event, NULL); } @@ -9857,20 +9821,17 @@ static void perf_log_throttle(struct perf_event *event, int enable) u64 id; u64 stream_id; } throttle_event = { - .header = { - .type = PERF_RECORD_THROTTLE, - .misc = 0, - .size = sizeof(throttle_event), - }, .time = perf_event_clock(event), .id = primary_event_id(event), .stream_id = event->id, }; - if (enable) - throttle_event.header.type = PERF_RECORD_UNTHROTTLE; - - perf_event_header__init_id(&throttle_event.header, &sample, event); + perf_event_header__init(&throttle_event.header, &sample, + enable ? PERF_RECORD_UNTHROTTLE + : PERF_RECORD_THROTTLE, + /* misc= */ 0, + sizeof(throttle_event), + event); ret = perf_output_begin(&handle, &sample, event, throttle_event.header.size); @@ -9909,12 +9870,14 @@ static void perf_event_ksymbol_output(struct perf_event *event, void *data) struct perf_output_handle handle; struct perf_sample_data sample; int ret; + u16 size = sizeof(ksymbol_event->event_id) + ksymbol_event->name_len; if (!perf_event_ksymbol_match(event)) return; - perf_event_header__init_id(&ksymbol_event->event_id.header, - &sample, event); + perf_event_header__init(&ksymbol_event->event_id.header, &sample, + PERF_RECORD_KSYMBOL, /* misc= */ 0, size, + event); ret = perf_output_begin(&handle, &sample, event, ksymbol_event->event_id.header.size); if (ret) @@ -9955,11 +9918,6 @@ void perf_event_ksymbol(u16 ksym_type, u64 addr, u32 len, bool unregister, .name = name, .name_len = name_len, .event_id = { - .header = { - .type = PERF_RECORD_KSYMBOL, - .size = sizeof(ksymbol_event.event_id) + - name_len, - }, .addr = addr, .len = len, .ksym_type = ksym_type, @@ -10003,8 +9961,11 @@ static void perf_event_bpf_output(struct perf_event *event, void *data) if (!perf_event_bpf_match(event)) return; - perf_event_header__init_id(&bpf_event->event_id.header, - &sample, event); + perf_event_header__init(&bpf_event->event_id.header, &sample, + PERF_RECORD_BPF_EVENT, + /* misc= */ 0, + sizeof(bpf_event->event_id), + event); ret = perf_output_begin(&handle, &sample, event, bpf_event->event_id.header.size); if (ret) @@ -10060,10 +10021,6 @@ void perf_event_bpf_event(struct bpf_prog *prog, bpf_event = (struct perf_bpf_event){ .prog = prog, .event_id = { - .header = { - .type = PERF_RECORD_BPF_EVENT, - .size = sizeof(bpf_event.event_id), - }, .type = type, .flags = flags, .id = prog->aux->id, @@ -10079,7 +10036,8 @@ void perf_event_bpf_event(struct bpf_prog *prog, struct perf_text_poke_event { const void *old_bytes; const void *new_bytes; - size_t pad; + u16 tot; + u16 pad; u16 old_len; u16 new_len; @@ -10100,13 +10058,18 @@ static void perf_event_text_poke_output(struct perf_event *event, void *data) struct perf_text_poke_event *text_poke_event = data; struct perf_output_handle handle; struct perf_sample_data sample; + u16 size = sizeof(text_poke_event->event_id) + text_poke_event->tot + text_poke_event->pad; u64 padding = 0; int ret; if (!perf_event_text_poke_match(event)) return; - perf_event_header__init_id(&text_poke_event->event_id.header, &sample, event); + perf_event_header__init(&text_poke_event->event_id.header, &sample, + PERF_RECORD_TEXT_POKE, + PERF_RECORD_MISC_KERNEL, + size, + event); ret = perf_output_begin(&handle, &sample, event, text_poke_event->event_id.header.size); @@ -10144,15 +10107,11 @@ void perf_event_text_poke(const void *addr, const void *old_bytes, text_poke_event = (struct perf_text_poke_event){ .old_bytes = old_bytes, .new_bytes = new_bytes, + .tot = tot, .pad = pad, .old_len = old_len, .new_len = new_len, .event_id = { - .header = { - .type = PERF_RECORD_TEXT_POKE, - .misc = PERF_RECORD_MISC_KERNEL, - .size = sizeof(text_poke_event.event_id) + tot + pad, - }, .addr = (unsigned long)addr, }, }; @@ -10183,13 +10142,12 @@ static void perf_log_itrace_start(struct perf_event *event) event->attach_state & PERF_ATTACH_ITRACE) return; - rec.header.type = PERF_RECORD_ITRACE_START; - rec.header.misc = 0; - rec.header.size = sizeof(rec); rec.pid = perf_event_pid(event, current); rec.tid = perf_event_tid(event, current); - perf_event_header__init_id(&rec.header, &sample, event); + perf_event_header__init(&rec.header, &sample, + PERF_RECORD_ITRACE_START, /* misc= */ 0, sizeof(rec), + event); ret = perf_output_begin(&handle, &sample, event, rec.header.size); if (ret) @@ -10214,12 +10172,10 @@ void perf_report_aux_output_id(struct perf_event *event, u64 hw_id) if (event->parent) event = event->parent; - rec.header.type = PERF_RECORD_AUX_OUTPUT_HW_ID; - rec.header.misc = 0; - rec.header.size = sizeof(rec); - rec.hw_id = hw_id; - - perf_event_header__init_id(&rec.header, &sample, event); + rec.hw_id = hw_id; + perf_event_header__init(&rec.header, &sample, + PERF_RECORD_AUX_OUTPUT_HW_ID, /* misc= */ 0, + sizeof(rec), event); ret = perf_output_begin(&handle, &sample, event, rec.header.size); if (ret) @@ -13534,7 +13490,9 @@ SYSCALL_DEFINE5(perf_event_open, if (err) return err; - if (!attr.exclude_kernel) { + if (!attr.exclude_kernel || attr.text_poke || + ((attr.sample_type & PERF_SAMPLE_CALLCHAIN) && + !attr.exclude_callchain_kernel)) { err = perf_allow_kernel(); if (err) return err; diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c index 6d805a7168be..444c7f370ba2 100644 --- a/kernel/events/ring_buffer.c +++ b/kernel/events/ring_buffer.c @@ -246,14 +246,13 @@ __perf_output_begin(struct perf_output_handle *handle, handle->size = (1UL << page_shift) - offset; if (unlikely(have_lost)) { - lost_event.header.size = sizeof(lost_event); - lost_event.header.type = PERF_RECORD_LOST; - lost_event.header.misc = 0; lost_event.id = event->id; lost_event.lost = local_xchg(&rb->lost, 0); /* XXX mostly redundant; @data is already fully initializes */ - perf_event_header__init_id(&lost_event.header, data, event); + perf_event_header__init(&lost_event.header, data, + PERF_RECORD_LOST, /* misc= */ 0, + sizeof(lost_event), event); perf_output_put(handle, lost_event); perf_event__output_id_sample(event, handle, data); } diff --git a/kernel/kprobes.c b/kernel/kprobes.c index caf335bd5628..0b0e2fc2e078 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -493,14 +493,16 @@ static bool kprobe_queued(struct kprobe *p) static struct kprobe *get_optimized_kprobe(kprobe_opcode_t *addr) { int i; - struct kprobe *p = NULL; + struct kprobe *p; struct optimized_kprobe *op; /* Don't check i == 0, since that is a breakpoint case. */ - for (i = 1; !p && i < MAX_OPTIMIZED_LENGTH / sizeof(kprobe_opcode_t); i++) + for (i = 1; i < MAX_OPTIMIZED_LENGTH / sizeof(kprobe_opcode_t); i++) { p = get_kprobe(addr - i); + /* A disabled probe can have prepared, but inactive, optinsns. */ + if (!p || !kprobe_optready(p) || kprobe_disarmed(p)) + continue; - if (p && kprobe_optready(p)) { op = container_of(p, struct optimized_kprobe, kp); if (arch_within_optimized_kprobe(op, addr)) return p; diff --git a/kernel/module/main.c b/kernel/module/main.c index d34187b02d14..769463d2b254 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -3516,8 +3516,9 @@ static int load_module(struct load_info *info, const char __user *uargs, goto sysfs_cleanup; } - if (codetag_load_module(mod)) - goto sysfs_cleanup; + err = codetag_load_module(mod); + if (err) + goto livepatch_cleanup; /* Get rid of temporary copy. */ free_copy(info, flags); @@ -3527,6 +3528,9 @@ static int load_module(struct load_info *info, const char __user *uargs, return do_init_module(mod); + livepatch_cleanup: + if (is_livepatch_module(mod)) + free_module_elf(mod); sysfs_cleanup: mod_sysfs_teardown(mod); coming_cleanup: diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c index 1c9ae332afad..a236baed157a 100644 --- a/kernel/trace/fprobe.c +++ b/kernel/trace/fprobe.c @@ -47,6 +47,10 @@ static struct rhltable fprobe_ip_table; static DEFINE_MUTEX(fprobe_mutex); static struct fgraph_ops fprobe_graph_ops; +DEFINE_LOCK_GUARD_0(rcu_sched_notrace, + rcu_read_lock_sched_notrace(), + rcu_read_unlock_sched_notrace()) + static u32 fprobe_node_hashfn(const void *data, u32 len, u32 seed) { return hash_ptr(*(unsigned long **)data, 32); @@ -260,16 +264,14 @@ static void fprobe_ftrace_entry(unsigned long ip, unsigned long parent_ip, struct fprobe *fp; int bit; + if (!rcu_is_watching()) + return; + bit = ftrace_test_recursion_trylock(ip, parent_ip); if (bit < 0) return; - /* - * ftrace_test_recursion_trylock() disables preemption, but - * rhltable_lookup() checks whether rcu_read_lcok is held. - * So we take rcu_read_lock() here. - */ - rcu_read_lock(); + guard(rcu_sched_notrace)(); head = rhltable_lookup(&fprobe_ip_table, &ip, fprobe_rht_params); rhl_for_each_entry_rcu(node, pos, head, hlist) { @@ -284,7 +286,6 @@ static void fprobe_ftrace_entry(unsigned long ip, unsigned long parent_ip, else __fprobe_handler(ip, parent_ip, fp, fregs, NULL); } - rcu_read_unlock(); ftrace_test_recursion_unlock(bit); } NOKPROBE_SYMBOL(fprobe_ftrace_entry); @@ -425,9 +426,13 @@ static int fprobe_fgraph_entry(struct ftrace_graph_ent *trace, struct fgraph_ops struct fprobe *fp; int used, ret; + if (!rcu_is_watching()) + return 0; + if (WARN_ON_ONCE(!fregs)) return 0; + guard(rcu_sched_notrace)(); head = rhltable_lookup(&fprobe_ip_table, &func, fprobe_rht_params); reserved_words = 0; rhl_for_each_entry_rcu(node, pos, head, hlist) { @@ -520,13 +525,16 @@ static void fprobe_return(struct ftrace_graph_ret *trace, int size, curr; int size_words; + if (!rcu_is_watching()) + return; + fgraph_data = (unsigned long *)fgraph_retrieve_data(gops->idx, &size); if (WARN_ON_ONCE(!fgraph_data)) return; size_words = SIZE_IN_LONG(size); ret_ip = ftrace_regs_get_instruction_pointer(fregs); - preempt_disable_notrace(); + guard(rcu_sched_notrace)(); curr = 0; while (size_words > curr) { @@ -542,7 +550,6 @@ static void fprobe_return(struct ftrace_graph_ret *trace, } curr += size; } - preempt_enable_notrace(); } NOKPROBE_SYMBOL(fprobe_return); diff --git a/mm/damon/core.c b/mm/damon/core.c index c0dcb190b06e..016d38c127d6 100644 --- a/mm/damon/core.c +++ b/mm/damon/core.c @@ -1734,16 +1734,18 @@ static bool damos_valid_target(struct damon_ctx *c, struct damon_target *t, * This function checks if a given region should be skipped or not for the * reason. If only the starting part of the region has previously charged, * this function splits the region into two so that the second one covers the - * area that not charged in the previous charge widnow and saves the second - * region in *rp and returns false, so that the caller can apply DAMON action - * to the second one. + * area that not charged in the previous charge widnow, and return true. The + * caller can see the second one on the next iteration of the region walk. + * Note that this means the caller should use damon_for_each_region() instead + * of damon_for_each_region_safe(). If damon_for_each_region_safe() is used, + * the second region will just be ignored. * - * Return: true if the region should be entirely skipped, false otherwise. + * Return: true if the region should be skipped, false otherwise. */ static bool damos_skip_charged_region(struct damon_target *t, - struct damon_region **rp, struct damos *s, unsigned long min_sz_region) + struct damon_region *r, struct damos *s, + unsigned long min_sz_region) { - struct damon_region *r = *rp; struct damos_quota *quota = &s->quota; unsigned long sz_to_skip; bool skip = false; @@ -1770,9 +1772,7 @@ static bool damos_skip_charged_region(struct damon_target *t, sz_to_skip = min_sz_region; } damon_split_region_at(t, r, sz_to_skip); - r = damon_next_region(r); - *rp = r; - skip = false; + skip = true; } } out: @@ -2034,7 +2034,7 @@ static void damon_do_apply_schemes(struct damon_ctx *c, if (quota->esz && quota->charged_sz >= quota->esz) continue; - if (damos_skip_charged_region(t, &r, s, c->min_sz_region)) + if (damos_skip_charged_region(t, r, s, c->min_sz_region)) continue; if (!damos_valid_target(c, t, r, s)) @@ -2248,7 +2248,8 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s) unsigned long cumulated_sz, cached_esz; unsigned int score, max_score = 0; - if (!quota->ms && !quota->sz && list_empty("a->goals)) + if (!quota->esz && !quota->ms && !quota->sz && + list_empty("a->goals)) return; /* First charge window */ @@ -2306,7 +2307,7 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s) static void kdamond_apply_schemes(struct damon_ctx *c) { struct damon_target *t; - struct damon_region *r, *next_r; + struct damon_region *r; struct damos *s; unsigned long sample_interval = c->attrs.sample_interval ? c->attrs.sample_interval : 1; @@ -2329,7 +2330,7 @@ static void kdamond_apply_schemes(struct damon_ctx *c) mutex_lock(&c->walk_control_lock); damon_for_each_target(t, c) { - damon_for_each_region_safe(r, next_r, t) + damon_for_each_region(r, t) damon_do_apply_schemes(c, t, r); } diff --git a/mm/execmem.c b/mm/execmem.c index 810a4ba9c924..084a207e4278 100644 --- a/mm/execmem.c +++ b/mm/execmem.c @@ -203,13 +203,6 @@ static int execmem_cache_add_locked(void *ptr, size_t size, gfp_t gfp_mask) return mas_store_gfp(&mas, (void *)lower, gfp_mask); } -static int execmem_cache_add(void *ptr, size_t size, gfp_t gfp_mask) -{ - guard(mutex)(&execmem_cache.mutex); - - return execmem_cache_add_locked(ptr, size, gfp_mask); -} - static bool within_range(struct execmem_range *range, struct ma_state *mas, size_t size) { @@ -225,18 +218,16 @@ static bool within_range(struct execmem_range *range, struct ma_state *mas, return false; } -static void *__execmem_cache_alloc(struct execmem_range *range, size_t size) +static void *execmem_cache_alloc_locked(struct execmem_range *range, size_t size) { struct maple_tree *free_areas = &execmem_cache.free_areas; struct maple_tree *busy_areas = &execmem_cache.busy_areas; MA_STATE(mas_free, free_areas, 0, ULONG_MAX); MA_STATE(mas_busy, busy_areas, 0, ULONG_MAX); - struct mutex *mutex = &execmem_cache.mutex; unsigned long addr, last, area_size = 0; void *area, *ptr = NULL; int err; - mutex_lock(mutex); mas_for_each(&mas_free, area, ULONG_MAX) { area_size = mas_range_len(&mas_free); @@ -245,7 +236,7 @@ static void *__execmem_cache_alloc(struct execmem_range *range, size_t size) } if (area_size < size) - goto out_unlock; + return NULL; addr = mas_free.index; last = mas_free.last; @@ -254,7 +245,7 @@ static void *__execmem_cache_alloc(struct execmem_range *range, size_t size) mas_set_range(&mas_busy, addr, addr + size - 1); err = mas_store_gfp(&mas_busy, (void *)addr, GFP_KERNEL); if (err) - goto out_unlock; + return NULL; mas_store_gfp(&mas_free, NULL, GFP_KERNEL); if (area_size > size) { @@ -268,19 +259,25 @@ static void *__execmem_cache_alloc(struct execmem_range *range, size_t size) err = mas_store_gfp(&mas_free, ptr, GFP_KERNEL); if (err) { mas_store_gfp(&mas_busy, NULL, GFP_KERNEL); - goto out_unlock; + return NULL; } } ptr = (void *)addr; -out_unlock: - mutex_unlock(mutex); return ptr; } -static int execmem_cache_populate(struct execmem_range *range, size_t size) +static void *__execmem_cache_alloc(struct execmem_range *range, size_t size) +{ + guard(mutex)(&execmem_cache.mutex); + + return execmem_cache_alloc_locked(range, size); +} + +static void *execmem_cache_populate_alloc(struct execmem_range *range, size_t size) { unsigned long vm_flags = VM_ALLOW_HUGE_VMAP; + struct mutex *mutex = &execmem_cache.mutex; struct vm_struct *vm; size_t alloc_size; int err = -ENOMEM; @@ -294,7 +291,7 @@ static int execmem_cache_populate(struct execmem_range *range, size_t size) } if (!p) - return err; + return NULL; vm = find_vm_area(p); if (!vm) @@ -307,33 +304,39 @@ static int execmem_cache_populate(struct execmem_range *range, size_t size) if (err) goto err_free_mem; - err = execmem_cache_add(p, alloc_size, GFP_KERNEL); + /* + * New memory blocks must be allocated and added to the cache + * as an atomic operation, otherwise they may be consumed + * by a parallel call to the execmem_cache_alloc function. + */ + mutex_lock(mutex); + err = execmem_cache_add_locked(p, alloc_size, GFP_KERNEL); if (err) goto err_reset_direct_map; - return 0; + p = execmem_cache_alloc_locked(range, size); + + mutex_unlock(mutex); + + return p; err_reset_direct_map: + mutex_unlock(mutex); execmem_set_direct_map_valid(vm, true); err_free_mem: vfree(p); - return err; + return NULL; } static void *execmem_cache_alloc(struct execmem_range *range, size_t size) { void *p; - int err; p = __execmem_cache_alloc(range, size); if (p) return p; - err = execmem_cache_populate(range, size); - if (err) - return NULL; - - return __execmem_cache_alloc(range, size); + return execmem_cache_populate_alloc(range, size); } static inline bool is_pending_free(void *ptr) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index e0c7b7efd38a..df4a3e6215d4 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -3797,7 +3797,7 @@ static int __folio_split(struct folio *folio, unsigned int new_order, gfp_t gfp; mapping = folio->mapping; - min_order = mapping_min_folio_order(folio->mapping); + min_order = mapping_min_folio_order(mapping); if (new_order < min_order) { ret = -EINVAL; goto out; @@ -3811,6 +3811,8 @@ static int __folio_split(struct folio *folio, unsigned int new_order, goto out; } + mapping_set_update(&xas, mapping); + if (uniform_split) { xas_set_order(&xas, folio->index, new_order); xas_split_alloc(&xas, folio, folio_order(folio), gfp); diff --git a/mm/kasan/common.c b/mm/kasan/common.c index 3341474507f9..9510b235ed80 100644 --- a/mm/kasan/common.c +++ b/mm/kasan/common.c @@ -114,12 +114,23 @@ void kasan_unpoison_task_stack(struct task_struct *task) /* Unpoison the stack for the current task beyond a watermark sp value. */ asmlinkage void kasan_unpoison_task_stack_below(const void *watermark) { + void *base; + + /* + * Only the generic mode needs this. In the tag-based mode the + * compiler fully initializes the shadow of stack variables on + * function entry, so stale tags left below the watermark are + * harmless. + */ + if (!IS_ENABLED(CONFIG_KASAN_GENERIC)) + return; + /* * Calculate the task stack base address. Avoid using 'current' * because this function is called by early resume code which hasn't * yet set up the percpu register (%gs). */ - void *base = (void *)((unsigned long)watermark & ~(THREAD_SIZE - 1)); + base = (void *)((unsigned long)watermark & ~(THREAD_SIZE - 1)); kasan_unpoison(base, watermark - base, false); } diff --git a/mm/shmem.c b/mm/shmem.c index 3c329b794ae4..0100110f77b8 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -1812,8 +1812,11 @@ unsigned long shmem_allowable_huge_orders(struct inode *inode, global_orders = shmem_huge_global_enabled(inode, index, write_end, shmem_huge_force, vma, vm_flags); - /* Tmpfs huge pages allocation */ - if (!vma || !vma_is_anon_shmem(vma)) + /* + * Tmpfs huge pages allocation or forced collapse ignores + * sysfs configs. + */ + if (!vma || !vma_is_anon_shmem(vma) || shmem_huge_force) return global_orders; /* diff --git a/mm/vma.c b/mm/vma.c index 5beb18b0610b..d1158fdcde28 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -2382,7 +2382,7 @@ static void update_ksm_flags(struct mmap_state *map) } /* - * __mmap_prepare() - Prepare to gather any overlapping VMAs that need to be + * __mmap_setup() - Prepare to gather any overlapping VMAs that need to be * unmapped once the map operation is completed, check limits, account mapping * and clean up any pre-existing VMAs. * @@ -2391,7 +2391,7 @@ static void update_ksm_flags(struct mmap_state *map) * * Returns: 0 on success, error code otherwise. */ -static int __mmap_prepare(struct mmap_state *map, struct list_head *uf) +static int __mmap_setup(struct mmap_state *map, struct list_head *uf) { int error; struct vma_iterator *vmi = map->vmi; @@ -2693,14 +2693,15 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, { struct mm_struct *mm = current->mm; struct vm_area_struct *vma = NULL; - int error; - bool have_mmap_prepare = file && file->f_op->mmap_prepare; + const bool have_mmap_prepare = file && file->f_op->mmap_prepare; VMA_ITERATOR(vmi, mm, addr); MMAP_STATE(map, mm, &vmi, addr, len, pgoff, vm_flags, file); + bool allocated_new; + int error; map.check_ksm_early = can_set_ksm_flags_early(&map); - error = __mmap_prepare(&map, uf); + error = __mmap_setup(&map, uf); if (error) goto abort_munmap; if (have_mmap_prepare) @@ -2719,20 +2720,21 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, } /* ...but if we can't, allocate a new VMA. */ - if (!vma) { + allocated_new = !vma; + if (allocated_new) { error = __mmap_new_vma(&map, &vma); if (error) goto unacct_error; } - if (have_mmap_prepare) + if (have_mmap_prepare && allocated_new) set_vma_user_defined_fields(vma, &map); __mmap_complete(&map, vma); return addr; - /* Accounting was done by __mmap_prepare(). */ + /* Accounting was done by __mmap_setup(). */ unacct_error: if (map.charged) vm_unacct_memory(map.charged); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index d50fa9eea42c..fab41702ea57 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -305,11 +305,13 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data) cp.tx_bandwidth = cpu_to_le32(0x00001f40); cp.rx_bandwidth = cpu_to_le32(0x00001f40); + hci_dev_lock(hdev); + switch (conn->codec.id) { case BT_CODEC_MSBC: if (!find_next_esco_param(conn, esco_param_msbc, ARRAY_SIZE(esco_param_msbc))) - return -EINVAL; + goto unlock; param = &esco_param_msbc[conn->attempt - 1]; cp.tx_coding_format.id = 0x05; @@ -335,7 +337,7 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data) case BT_CODEC_TRANSPARENT: if (!find_next_esco_param(conn, esco_param_msbc, ARRAY_SIZE(esco_param_msbc))) - return -EINVAL; + goto unlock; param = &esco_param_msbc[conn->attempt - 1]; cp.tx_coding_format.id = 0x03; @@ -362,11 +364,11 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data) if (conn->parent && lmp_esco_capable(conn->parent)) { if (!find_next_esco_param(conn, esco_param_cvsd, ARRAY_SIZE(esco_param_cvsd))) - return -EINVAL; + goto unlock; param = &esco_param_cvsd[conn->attempt - 1]; } else { if (conn->attempt > ARRAY_SIZE(sco_param_cvsd)) - return -EINVAL; + goto unlock; param = &sco_param_cvsd[conn->attempt - 1]; } cp.tx_coding_format.id = 2; @@ -389,9 +391,11 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data) cp.out_transport_unit_size = 16; break; default: - return -EINVAL; + goto unlock; } + hci_dev_unlock(hdev); + cp.retrans_effort = param->retrans_effort; cp.pkt_type = __cpu_to_le16(param->pkt_type); cp.max_latency = __cpu_to_le16(param->max_latency); @@ -400,6 +404,10 @@ static int hci_enhanced_setup_sync(struct hci_dev *hdev, void *data) return -EIO; return 0; + +unlock: + hci_dev_unlock(hdev); + return -EINVAL; } static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c0a8bd7af781..90287b7b62a4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1525,8 +1525,10 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, BT_DBG("%s removing %pMR (%u)", hdev->name, bdaddr, bdaddr_type); + mutex_lock(&hdev->remote_oob_lock); list_del(&data->list); kfree(data); + mutex_unlock(&hdev->remote_oob_lock); return 0; } @@ -1535,10 +1537,12 @@ void hci_remote_oob_data_clear(struct hci_dev *hdev) { struct oob_data *data, *n; + mutex_lock(&hdev->remote_oob_lock); list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) { list_del(&data->list); kfree(data); } + mutex_unlock(&hdev->remote_oob_lock); } int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, @@ -1547,11 +1551,14 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, { struct oob_data *data; + mutex_lock(&hdev->remote_oob_lock); data = hci_find_remote_oob_data(hdev, bdaddr, bdaddr_type); if (!data) { data = kmalloc(sizeof(*data), GFP_KERNEL); - if (!data) + if (!data) { + mutex_unlock(&hdev->remote_oob_lock); return -ENOMEM; + } bacpy(&data->bdaddr, bdaddr); data->bdaddr_type = bdaddr_type; @@ -1584,6 +1591,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, BT_DBG("%s for %pMR", hdev->name, bdaddr); + mutex_unlock(&hdev->remote_oob_lock); + return 0; } @@ -2521,6 +2530,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) mutex_init(&hdev->lock); mutex_init(&hdev->req_lock); mutex_init(&hdev->mgmt_pending_lock); + mutex_init(&hdev->remote_oob_lock); ida_init(&hdev->unset_handle_ida); @@ -2593,8 +2603,10 @@ int hci_register_dev(struct hci_dev *hdev) return id; error = dev_set_name(&hdev->dev, "hci%u", id); - if (error) + if (error) { + ida_free(&hci_index_ida, id); return error; + } hdev->name = dev_name(&hdev->dev); hdev->id = id; @@ -3362,6 +3374,8 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue, skb_shinfo(skb)->frag_list = NULL; + spin_lock_bh(&queue->lock); + __skb_queue_tail(queue, skb); do { @@ -3376,6 +3390,8 @@ static void hci_queue_iso(struct hci_conn *conn, struct sk_buff_head *queue, __skb_queue_tail(queue, skb); } while (list); + + spin_unlock_bh(&queue->lock); } bt_dev_dbg(hdev, "hcon %p queued %d", conn, skb_queue_len(queue)); @@ -3439,9 +3455,6 @@ static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, struct hci_conn *conn = NULL, *c; unsigned int num = 0, min = ~0; - /* We don't have to lock device here. Connections are always - * added and removed with TX task disabled. */ - rcu_read_lock(); list_for_each_entry_rcu(c, &h->list, list) { @@ -3646,13 +3659,15 @@ static void __check_timeout(struct hci_dev *hdev, unsigned int cnt, u8 type) } /* Schedule SCO */ -static void hci_sched_sco(struct hci_dev *hdev, __u8 type) +static void __hci_sched_sco(struct hci_dev *hdev, __u8 type) { struct hci_conn *conn; struct sk_buff *skb; int quote, *cnt; unsigned int pkts = hdev->sco_pkts; + lockdep_assert_held(&hdev->lock); + bt_dev_dbg(hdev, "type %u", type); if (!hci_conn_num(hdev, type) || !pkts) @@ -3687,6 +3702,13 @@ static void hci_sched_sco(struct hci_dev *hdev, __u8 type) queue_work(hdev->workqueue, &hdev->tx_work); } +static void hci_sched_sco(struct hci_dev *hdev, __u8 type) +{ + hci_dev_lock(hdev); + __hci_sched_sco(hdev, type); + hci_dev_unlock(hdev); +} + static void hci_sched_acl_pkt(struct hci_dev *hdev) { unsigned int cnt = hdev->acl_cnt; @@ -3696,6 +3718,8 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev) __check_timeout(hdev, cnt, ACL_LINK); + hci_dev_lock(hdev); + while (hdev->acl_cnt && (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { u32 priority = (skb_peek(&chan->data_q))->priority; @@ -3720,13 +3744,15 @@ static void hci_sched_acl_pkt(struct hci_dev *hdev) chan->conn->sent++; /* Send pending SCO packets right away */ - hci_sched_sco(hdev, SCO_LINK); - hci_sched_sco(hdev, ESCO_LINK); + __hci_sched_sco(hdev, SCO_LINK); + __hci_sched_sco(hdev, ESCO_LINK); } } if (cnt != hdev->acl_cnt) hci_prio_recalculate(hdev, ACL_LINK); + + hci_dev_unlock(hdev); } static void hci_sched_acl(struct hci_dev *hdev) @@ -3755,6 +3781,8 @@ static void hci_sched_le(struct hci_dev *hdev) __check_timeout(hdev, *cnt, LE_LINK); + hci_dev_lock(hdev); + tmp = *cnt; while (*cnt && (chan = hci_chan_sent(hdev, LE_LINK, "e))) { u32 priority = (skb_peek(&chan->data_q))->priority; @@ -3776,13 +3804,15 @@ static void hci_sched_le(struct hci_dev *hdev) chan->conn->sent++; /* Send pending SCO packets right away */ - hci_sched_sco(hdev, SCO_LINK); - hci_sched_sco(hdev, ESCO_LINK); + __hci_sched_sco(hdev, SCO_LINK); + __hci_sched_sco(hdev, ESCO_LINK); } } if (*cnt != tmp) hci_prio_recalculate(hdev, LE_LINK); + + hci_dev_unlock(hdev); } /* Schedule iso */ @@ -3801,6 +3831,8 @@ static void hci_sched_iso(struct hci_dev *hdev, __u8 type) __check_timeout(hdev, *cnt, type); + hci_dev_lock(hdev); + while (*cnt && (conn = hci_low_sent(hdev, type, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); @@ -3814,6 +3846,8 @@ static void hci_sched_iso(struct hci_dev *hdev, __u8 type) (*cnt)--; } } + + hci_dev_unlock(hdev); } static void hci_tx_work(struct work_struct *work) diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c index 99e2e9fc70e8..9ae6d9224c3b 100644 --- a/net/bluetooth/hci_debugfs.c +++ b/net/bluetooth/hci_debugfs.c @@ -367,7 +367,7 @@ static int inquiry_cache_show(struct seq_file *f, void *p) list_for_each_entry(e, &cache->all, all) { struct inquiry_data *data = &e->data; - seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n", + seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %lu\n", &data->bdaddr, data->pscan_rep_mode, data->pscan_period_mode, data->pscan_mode, data->dev_class[2], diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 969ad4317d4b..c1db8a37726d 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -312,6 +312,10 @@ static void hci_cmd_sync_work(struct work_struct *work) while (1) { struct hci_cmd_sync_work_entry *entry; + /* Leave the backlog to hci_cmd_sync_clear() */ + if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) + break; + mutex_lock(&hdev->cmd_sync_work_lock); entry = list_first_entry_or_null(&hdev->cmd_sync_work_list, struct hci_cmd_sync_work_entry, @@ -658,6 +662,8 @@ void hci_cmd_sync_clear(struct hci_dev *hdev) { struct hci_cmd_sync_work_entry *entry, *tmp; + /* cmd_work is disabled, the pending request can only time out */ + hci_cmd_sync_cancel_sync(hdev, ENODEV); cancel_work_sync(&hdev->cmd_sync_work); cancel_work_sync(&hdev->reenable_adv_work); @@ -5599,6 +5605,7 @@ int hci_stop_discovery_sync(struct hci_dev *hdev) { struct discovery_state *d = &hdev->discovery; struct inquiry_entry *e; + bdaddr_t addr; int err; bt_dev_dbg(hdev, "state %u", hdev->discovery.state); @@ -5634,15 +5641,21 @@ int hci_stop_discovery_sync(struct hci_dev *hdev) return 0; if (d->state == DISCOVERY_RESOLVING || d->state == DISCOVERY_STOPPING) { + hci_dev_lock(hdev); e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING); - if (!e) + if (!e) { + hci_dev_unlock(hdev); return 0; + } + + bacpy(&addr, &e->data.bdaddr); + hci_dev_unlock(hdev); /* Ignore cancel errors since it should interfere with stopping * of the discovery. */ - hci_remote_name_cancel_sync(hdev, &e->data.bdaddr); + hci_remote_name_cancel_sync(hdev, &addr); } return 0; @@ -7075,6 +7088,7 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data) bacpy(&cp.bdaddr, &conn->dst); cp.pscan_rep_mode = 0x02; + hci_dev_lock(hdev); ie = hci_inquiry_cache_lookup(hdev, &conn->dst); if (ie) { if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { @@ -7086,6 +7100,7 @@ static int hci_acl_create_conn_sync(struct hci_dev *hdev, void *data) memcpy(conn->dev_class, ie->data.dev_class, 3); } + hci_dev_unlock(hdev); cp.pkt_type = cpu_to_le16(conn->pkt_type); if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)) diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index 63f208abbd51..df0f62016652 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -465,7 +465,7 @@ static int __rfcomm_release_dev(void __user *arg) /* Shut down TTY synchronously before freeing rfcomm_dev */ tty_port_tty_vhangup(&dev->port); - if (!test_bit(RFCOMM_TTY_OWNED, &dev->status)) + if (!test_and_set_bit(RFCOMM_TTY_OWNED, &dev->status)) tty_port_put(&dev->port); tty_port_put(&dev->port); @@ -727,10 +727,9 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty) * when the last process closes the tty. The behaviour is expected by * userspace. */ - if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { - set_bit(RFCOMM_TTY_OWNED, &dev->status); + if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) && + !test_and_set_bit(RFCOMM_TTY_OWNED, &dev->status)) tty_port_put(&dev->port); - } return 0; } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 51e0545a9e24..81bf67af87fc 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -683,6 +683,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, else bdaddr_type = BDADDR_LE_RANDOM; + mutex_lock(&hdev->remote_oob_lock); oob_data = hci_find_remote_oob_data(hdev, &hcon->dst, bdaddr_type); if (oob_data && oob_data->present) { @@ -693,6 +694,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn, SMP_DBG("OOB Remote Confirmation: %16phN", smp->pcnf); SMP_DBG("OOB Remote Random: %16phN", smp->rr); } + mutex_unlock(&hdev->remote_oob_lock); } else { authreq &= ~SMP_AUTH_SC; diff --git a/net/core/dev.c b/net/core/dev.c index 6569605cc666..10e02845fea4 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3756,20 +3756,36 @@ static netdev_features_t dflt_features_check(struct sk_buff *skb, return vlan_features_check(skb, features); } -static bool skb_gso_has_extension_hdr(const struct sk_buff *skb) -{ - if (!skb->encapsulation) - return ((skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6 || - (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4 && - vlan_get_protocol(skb) == htons(ETH_P_IPV6))) && - skb_transport_header_was_set(skb) && - skb_network_header_len(skb) != sizeof(struct ipv6hdr)); - else - return (!skb_inner_network_header_was_set(skb) || - ((skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6 || - (skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4 && - inner_ip_hdr(skb)->version == 6)) && - skb_inner_network_header_len(skb) != sizeof(struct ipv6hdr))); +static bool __skb_has_ipv6_ext_hdr(const struct sk_buff *skb, int nhoff) +{ + const struct ipv6hdr *ip6h; + struct ipv6hdr _ip6h; + + ip6h = skb_header_pointer(skb, nhoff, sizeof(_ip6h), &_ip6h); + return ip6h && ip6h->version == 6 && ipv6_ext_hdr(ip6h->nexthdr); +} + +static bool skb_has_ipv6_extension_hdr(const struct sk_buff *skb) +{ + if (vlan_get_protocol(skb) == htons(ETH_P_IPV6)) { + if (__skb_has_ipv6_ext_hdr(skb, skb_network_offset(skb))) + return true; + + /* Catch tunnels without skb->encapsulation (e.g., virtio). */ + if (!skb->encapsulation && + skb_transport_header_was_set(skb) && + skb_network_header_len(skb) != sizeof(struct ipv6hdr)) + return true; + } + + /* Tunnels without an inner network header, such as SCTP-in-UDP or + * PSP, have no inner IP header and thus no inner extension header. + */ + if (skb->encapsulation && skb_inner_network_header_was_set(skb) && + __skb_has_ipv6_ext_hdr(skb, skb_inner_network_offset(skb))) + return true; + + return false; } static netdev_features_t gso_features_check(const struct sk_buff *skb, @@ -3824,7 +3840,7 @@ static netdev_features_t gso_features_check(const struct sk_buff *skb, * so neither does TSO that depends on it. */ if (features & NETIF_F_IPV6_CSUM && - skb_gso_has_extension_hdr(skb) && + skb_has_ipv6_extension_hdr(skb) && !ipv6_has_hopopt_jumbo(skb)) features &= ~(NETIF_F_IPV6_CSUM | NETIF_F_TSO6 | NETIF_F_GSO_UDP_L4); @@ -3927,8 +3943,7 @@ int skb_csum_hwoffload_help(struct sk_buff *skb, return 0; if (features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) { - if (vlan_get_protocol(skb) == htons(ETH_P_IPV6) && - skb_network_header_len(skb) != sizeof(struct ipv6hdr) && + if (skb_has_ipv6_extension_hdr(skb) && !ipv6_has_hopopt_jumbo(skb)) goto sw_checksum; @@ -4314,9 +4329,14 @@ EXPORT_SYMBOL(dev_loopback_xmit); static struct netdev_queue * netdev_tx_queue_mapping(struct net_device *dev, struct sk_buff *skb) { - int qm = skb_get_queue_mapping(skb); + int queue = skb_get_queue_mapping(skb); + int capped; - return netdev_get_tx_queue(dev, netdev_cap_txqueue(dev, qm)); + capped = netdev_cap_txqueue(dev, queue); + if (unlikely(capped != queue)) + skb_set_queue_mapping(skb, capped); + + return netdev_get_tx_queue(dev, capped); } #ifndef CONFIG_PREEMPT_RT @@ -4325,9 +4345,13 @@ static bool netdev_xmit_txqueue_skipped(void) return __this_cpu_read(softnet_data.xmit.skip_txqueue); } -void netdev_xmit_skip_txqueue(bool skip) +bool netdev_xmit_skip_txqueue(bool skip) { + bool prev = netdev_xmit_txqueue_skipped(); + __this_cpu_write(softnet_data.xmit.skip_txqueue, skip); + + return prev; } EXPORT_SYMBOL_GPL(netdev_xmit_skip_txqueue); @@ -4337,9 +4361,13 @@ static bool netdev_xmit_txqueue_skipped(void) return current->net_xmit.skip_txqueue; } -void netdev_xmit_skip_txqueue(bool skip) +bool netdev_xmit_skip_txqueue(bool skip) { + bool prev = netdev_xmit_txqueue_skipped(); + current->net_xmit.skip_txqueue = skip; + + return prev; } EXPORT_SYMBOL_GPL(netdev_xmit_skip_txqueue); #endif @@ -4728,21 +4756,25 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev) tcx_set_ingress(skb, false); #ifdef CONFIG_NET_EGRESS if (static_branch_unlikely(&egress_needed_key)) { + bool skip_txq; + if (nf_hook_egress_active()) { skb = nf_hook_egress(skb, &rc, dev); if (!skb) goto out; } - netdev_xmit_skip_txqueue(false); + skip_txq = netdev_xmit_skip_txqueue(false); nf_skip_egress(skb, true); skb = sch_handle_egress(skb, &rc, dev); - if (!skb) + if (!skb) { + netdev_xmit_skip_txqueue(skip_txq); goto out; + } nf_skip_egress(skb, false); - if (netdev_xmit_txqueue_skipped()) + if (netdev_xmit_skip_txqueue(skip_txq)) txq = netdev_tx_queue_mapping(dev, skb); } #endif diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 862867874e12..ce537eca1640 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -996,8 +996,7 @@ static void neigh_periodic_work(struct work_struct *work) WRITE_ONCE(tbl->last_rand, jiffies); list_for_each_entry(p, &tbl->parms_list, list) - p->reachable_time = - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); + neigh_set_reach_time(p); } if (atomic_read(&tbl->entries) < READ_ONCE(tbl->gc_thresh1)) @@ -1750,8 +1749,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, if (p) { p->tbl = tbl; refcount_set(&p->refcnt, 1); - p->reachable_time = - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); + neigh_set_reach_time(p); p->qlen = 0; netdev_hold(dev, &p->dev_tracker, GFP_KERNEL); p->dev = dev; @@ -1765,7 +1763,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, } write_lock_bh(&tbl->lock); - list_add(&p->list, &tbl->parms.list); + list_add_rcu(&p->list, &tbl->parms.list); write_unlock_bh(&tbl->lock); neigh_parms_data_state_cleanall(p); @@ -1787,7 +1785,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) if (!parms || parms == &tbl->parms) return; write_lock_bh(&tbl->lock); - list_del(&parms->list); + list_del_rcu(&parms->list); parms->dead = 1; write_unlock_bh(&tbl->lock); netdev_put(parms->dev, &parms->dev_tracker); @@ -1811,8 +1809,7 @@ void neigh_table_init(int index, struct neigh_table *tbl) list_add(&tbl->parms.list, &tbl->parms_list); write_pnet(&tbl->parms.net, &init_net); refcount_set(&tbl->parms.refcnt, 1); - tbl->parms.reachable_time = - neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME)); + neigh_set_reach_time(&tbl->parms); tbl->parms.qlen = 0; tbl->stats = alloc_percpu(struct neigh_statistics); @@ -2195,7 +2192,7 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) NEIGH_VAR(parms, MCAST_PROBES)) || nla_put_u32(skb, NDTPA_MCAST_REPROBES, NEIGH_VAR(parms, MCAST_REPROBES)) || - nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time, + nla_put_msecs(skb, NDTPA_REACHABLE_TIME, READ_ONCE(parms->reachable_time), NDTPA_PAD) || nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME, NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) || @@ -2474,8 +2471,7 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, * only be effective after the next time neigh_periodic_work * decides to recompute it (can be multiple minutes) */ - p->reachable_time = - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); + neigh_set_reach_time(p); break; case NDTPA_GC_STALETIME: NEIGH_VAR_SET(p, GC_STALETIME, @@ -3733,8 +3729,7 @@ static int neigh_proc_base_reachable_time(const struct ctl_table *ctl, int write * only be effective after the next time neigh_periodic_work * decides to recompute it */ - p->reachable_time = - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); + neigh_set_reach_time(p); } return ret; } diff --git a/net/core/page_pool.c b/net/core/page_pool.c index d1fa5640a912..e02bdee3c5fd 100644 --- a/net/core/page_pool.c +++ b/net/core/page_pool.c @@ -949,8 +949,8 @@ static void page_pool_recycle_ring_bulk(struct page_pool *pool, } } - page_pool_producer_unlock(pool, in_softirq); recycle_stat_add(pool, ring, i); + page_pool_producer_unlock(pool, in_softirq); /* Hopefully all pages were returned into ptr_ring */ if (likely(i == bulk_len)) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 9ef8b31dbc87..559b027b7a2c 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -7327,7 +7327,8 @@ nodefer: kfree_skb_napi_cache(skb); } static void skb_splice_csum_page(struct sk_buff *skb, struct page *page, - size_t offset, size_t len) + size_t offset, size_t len, + unsigned int csum_offset) { const char *kaddr; __wsum csum; @@ -7335,7 +7336,7 @@ static void skb_splice_csum_page(struct sk_buff *skb, struct page *page, kaddr = kmap_local_page(page); csum = csum_partial(kaddr + offset, len, 0); kunmap_local(kaddr); - skb->csum = csum_block_add(skb->csum, csum, skb->len); + skb->csum = csum_block_add(skb->csum, csum, csum_offset); } /** @@ -7395,7 +7396,8 @@ ssize_t skb_splice_from_iter(struct sk_buff *skb, struct iov_iter *iter, } if (skb->ip_summed == CHECKSUM_NONE) - skb_splice_csum_page(skb, page, off, part); + skb_splice_csum_page(skb, page, off, part, + skb->len + spliced); off = 0; spliced += part; diff --git a/net/core/sock.c b/net/core/sock.c index 0d5f167e6ce6..9031349d08c2 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1024,7 +1024,7 @@ static int sock_reserve_memory(struct sock *sk, int bytes) bool charged; int pages; - if (!mem_cgroup_sk_enabled(sk) || !sk_has_account(sk)) + if (!mem_cgroup_sk_enabled(sk) || !sk_is_tcp(sk)) return -EOPNOTSUPP; if (!bytes) @@ -1645,7 +1645,7 @@ int sk_setsockopt(struct sock *sk, int level, int optname, { int delta; - if (val < 0) { + if (val < 0 || val > SZ_1G) { ret = -EINVAL; break; } diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4f105a0d0cfc..fbde60bf52a2 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -156,7 +156,7 @@ void inet_sock_destruct(struct sock *sk) WARN_ON_ONCE(sk->sk_wmem_queued); WARN_ON_ONCE(sk->sk_forward_alloc); - kfree(rcu_dereference_protected(inet->inet_opt, 1)); + kfree_rcu(rcu_dereference_protected(inet->inet_opt, 1), rcu); dst_release(rcu_dereference_protected(sk->sk_dst_cache, 1)); dst_release(rcu_dereference_protected(sk->sk_rx_dst, 1)); psp_sk_assoc_free(sk); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d9b07a3b9390..e1785140bf9b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4204,6 +4204,12 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) return 1; old_ack: + /* An old ACK can carry new data. Update TS.Recent before SACK + * processing can trigger a retransmission. + */ + if (flag & FLAG_UPDATE_TS_RECENT) + tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); + /* If data was SACKed, tag it and see if we should send more data. * If data was DSACKed, see if we can undo a cwnd reduction. */ diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index caefe3db53a9..042183a0076e 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1235,7 +1235,7 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, */ static void tcp_v4_reqsk_destructor(struct request_sock *req) { - kfree(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1)); + kfree_rcu(rcu_dereference_protected(inet_rsk(req)->ireq_opt, 1), rcu); } #ifdef CONFIG_TCP_MD5SIG diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 80706368a303..81f5bda2a89f 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4861,7 +4861,7 @@ static int modify_prefix_route(struct net *net, struct inet6_ifaddr *ifp, fib6_clean_expires(f6i); fib6_may_remove_gc_list(net, f6i); } else { - fib6_set_expires(f6i, expires); + fib6_set_expires(f6i, jiffies + clock_t_to_jiffies(expires)); fib6_add_gc_list(f6i); } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 7262356de10d..73732ca910fc 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1450,7 +1450,7 @@ static enum skb_drop_reason ndisc_router_discovery(struct sk_buff *skb) BASE_REACHABLE_TIME, rtime); NEIGH_VAR_SET(in6_dev->nd_parms, GC_STALETIME, 3 * rtime); - in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime); + neigh_set_reach_time(in6_dev->nd_parms); in6_dev->tstamp = jiffies; send_ifinfo_notify = true; } @@ -1951,9 +1951,9 @@ int ndisc_ifinfo_sysctl_change(const struct ctl_table *ctl, int write, void *buf ret = -1; if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) { - if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)) - idev->nd_parms->reachable_time = - neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)); + if (ctl->data == NEIGH_VAR_PTR(idev->nd_parms, BASE_REACHABLE_TIME)) + neigh_set_reach_time(idev->nd_parms); + WRITE_ONCE(idev->tstamp, jiffies); inet6_ifinfo_notify(RTM_NEWLINK, idev); in6_dev_put(idev); diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c index ead677bca490..d18f73ccf3d4 100644 --- a/net/ipv6/seg6_iptunnel.c +++ b/net/ipv6/seg6_iptunnel.c @@ -116,7 +116,7 @@ static __be32 seg6_make_flowlabel(struct net *net, struct sk_buff *skb, u32 hash; if (do_flowlabel > 0) { - hash = skb_get_hash(skb); + hash = skb_get_hash_net(net, skb); hash = rol32(hash, 16); flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK; } else if (!do_flowlabel && skb->protocol == htons(ETH_P_IPV6)) { diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index e38f46ffebfa..4f9d6fa770d6 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -103,7 +103,7 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, if (!tid_rx) return; - timer_delete_sync(&tid_rx->session_timer); + timer_shutdown_sync(&tid_rx->session_timer); /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */ spin_lock_bh(&tid_rx->reorder_lock); diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 8403b5248a95..b733822c452d 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -47,6 +47,13 @@ int ieee80211_chanctx_refcount(struct ieee80211_local *local, ieee80211_chanctx_num_reserved(local, ctx); } +static bool +ieee80211_chanctx_has_replace_partner(struct ieee80211_chanctx *ctx) +{ + return ctx->replace_state == IEEE80211_CHANCTX_WILL_BE_REPLACED && + ctx->replace_ctx; +} + static int ieee80211_num_chanctx(struct ieee80211_local *local, int radio_idx) { struct ieee80211_chanctx *ctx; @@ -1104,6 +1111,7 @@ void ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link) { struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_chanctx *ctx = link->reserved_chanctx; + struct ieee80211_chanctx *old_ctx = NULL; lockdep_assert_wiphy(sdata->local->hw.wiphy); @@ -1118,6 +1126,7 @@ void ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link) if (WARN_ON(!ctx->replace_ctx)) return; + old_ctx = ctx->replace_ctx; WARN_ON(ctx->replace_ctx->replace_state != IEEE80211_CHANCTX_WILL_BE_REPLACED); WARN_ON(ctx->replace_ctx->replace_ctx != ctx); @@ -1128,6 +1137,11 @@ void ieee80211_link_unreserve_chanctx(struct ieee80211_link_data *link) list_del_rcu(&ctx->list); kfree_rcu(ctx, rcu_head); + + if (ieee80211_chanctx_refcount(sdata->local, + old_ctx) == 0) + ieee80211_free_chanctx(sdata->local, old_ctx, + false); } else { ieee80211_free_chanctx(sdata->local, ctx, false); } @@ -1404,7 +1418,8 @@ ieee80211_link_use_reserved_reassign(struct ieee80211_link_data *link) ieee80211_check_fast_xmit_iface(sdata); - if (ieee80211_chanctx_refcount(local, old_ctx) == 0) + if (ieee80211_chanctx_refcount(local, old_ctx) == 0 && + !ieee80211_chanctx_has_replace_partner(old_ctx)) ieee80211_free_chanctx(local, old_ctx, false); ieee80211_recalc_chanctx_min_def(local, new_ctx, NULL, false); @@ -1470,7 +1485,8 @@ ieee80211_link_use_reserved_assign(struct ieee80211_link_data *link) } static bool -ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link) +ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link, + struct ieee80211_chanctx *ctx) { struct ieee80211_sub_if_data *sdata = link->sdata; struct ieee80211_chanctx *old_ctx, *new_ctx; @@ -1480,6 +1496,9 @@ ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link) new_ctx = link->reserved_chanctx; old_ctx = ieee80211_link_get_chanctx(link); + if (new_ctx != ctx) + return false; + if (!old_ctx) return false; @@ -1492,6 +1511,12 @@ ieee80211_link_has_in_place_reservation(struct ieee80211_link_data *link) if (new_ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) return false; + if (new_ctx->replace_ctx != old_ctx) + return false; + + if (old_ctx->replace_ctx != new_ctx) + return false; + return true; } @@ -1521,7 +1546,7 @@ static int ieee80211_chsw_switch_vifs(struct ieee80211_local *local, list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { - if (!ieee80211_link_has_in_place_reservation(link)) + if (!ieee80211_link_has_in_place_reservation(link, ctx)) continue; old_ctx = ieee80211_link_get_chanctx(link); @@ -1624,7 +1649,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) list_for_each_entry(link, &ctx->replace_ctx->assigned_links, assigned_chanctx_list) { n_assigned++; - if (link->reserved_chanctx) { + if (ieee80211_link_has_in_place_reservation(link, ctx)) { n_reserved++; if (link->reserved_ready) n_ready++; @@ -1645,7 +1670,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) ctx->conf.radar_enabled = false; list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { - if (ieee80211_link_has_in_place_reservation(link) && + if (ieee80211_link_has_in_place_reservation(link, ctx) && !link->reserved_ready) return -EAGAIN; @@ -1687,7 +1712,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) list_for_each_entry(link, &ctx->reserved_links, reserved_chanctx_list) { - if (!ieee80211_link_has_in_place_reservation(link)) + if (!ieee80211_link_has_in_place_reservation(link, ctx)) continue; ieee80211_chan_bw_change(local, @@ -1736,7 +1761,7 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) struct ieee80211_bss_conf *link_conf = link->conf; u64 changed = 0; - if (!ieee80211_link_has_in_place_reservation(link)) + if (!ieee80211_link_has_in_place_reservation(link, ctx)) continue; rcu_assign_pointer(link_conf->chanctx_conf, @@ -1790,7 +1815,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) */ list_for_each_entry_safe(link, link_tmp, &ctx->reserved_links, reserved_chanctx_list) { - if (WARN_ON(ieee80211_link_has_in_place_reservation(link))) + if (WARN_ON(ieee80211_link_has_in_place_reservation(link, + ctx))) continue; if (WARN_ON(link->reserved_chanctx != ctx)) @@ -1879,7 +1905,8 @@ void __ieee80211_link_release_channel(struct ieee80211_link_data *link, } ieee80211_assign_link_chanctx(link, NULL, false); - if (ieee80211_chanctx_refcount(local, ctx) == 0) + if (ieee80211_chanctx_refcount(local, ctx) == 0 && + !ieee80211_chanctx_has_replace_partner(ctx)) ieee80211_free_chanctx(local, ctx, skip_idle_recalc); link->radar_required = false; diff --git a/net/mac80211/drop.h b/net/mac80211/drop.h index eb9ab310f91c..f433ee17cce5 100644 --- a/net/mac80211/drop.h +++ b/net/mac80211/drop.h @@ -2,7 +2,7 @@ /* * mac80211 drop reason list * - * Copyright (C) 2023-2024 Intel Corporation + * Copyright (C) 2023-2024, 2026 Intel Corporation */ #ifndef MAC80211_DROP_H @@ -65,6 +65,50 @@ typedef unsigned int __bitwise ieee80211_rx_result; /* 0x30 */ \ R(RX_DROP_U_BAD_MGMT_KEYIDX) \ R(RX_DROP_U_UNKNOWN_ACTION_REJECTED) \ + R(RX_DROP_U_MESH_DS_BITS) \ + R(RX_DROP_U_MESH_A3_MISMATCH) \ + R(RX_DROP_U_MESH_NO_A4) \ + R(RX_DROP_U_MESH_A4_MISMATCH) \ + R(RX_DROP_U_MESH_UNEXP_DATA) \ + R(RX_DROP_U_MESH_WRONG_ACTION) \ + R(RX_DROP_U_MESH_UNEXP_MGMT) \ + R(RX_DROP_U_SPURIOUS_NOTIF) \ + R(RX_DROP_U_RUNT_DATA) \ + R(RX_DROP_U_KEY_TAINTED) \ + R(RX_DROP_U_UNPROTECTED) \ + R(RX_DROP_U_MCAST_FRAGMENT) \ + R(RX_DROP_U_DEFRAG_MISMATCH) \ + R(RX_DROP_U_RUNT_MESH_DATA) \ + /* 0x40 */ \ + R(RX_DROP_U_MESH_NO_TTL) \ + R(RX_DROP_U_MESH_RMC) \ + R(RX_DROP_U_MESH_BAD_AE) \ + R(RX_DROP_U_MESH_TTL_EXPIRED) \ + R(RX_DROP_U_MESH_NOT_FORWARDING) \ + R(RX_DROP_U_AMSDU_WITHOUT_DATA) \ + R(RX_DROP_U_NULL_DATA) \ + R(RX_DROP_U_UNEXPECTED_4ADDR) \ + R(RX_DROP_U_PORT_CONTROL) \ + R(RX_DROP_U_UNKNOWN_STA) \ + R(RX_DROP_U_RUNT_BAR) \ + R(RX_DROP_U_BAR_OUTSIDE_SESSION) \ + R(RX_DROP_U_CTRL_FRAME) \ + R(RX_DROP_U_RUNT_MGMT) \ + R(RX_DROP_U_EXPECTED_MGMT) \ + R(RX_DROP_U_NONBCAST_BEACON) \ + /* 0x50 */ \ + R(RX_DROP_U_MALFORMED_ACTION) \ + R(RX_DROP_U_UNKNOWN_MCAST_ACTION) \ + R(RX_DROP_U_UNEXPECTED_EXT_FRAME) \ + R(RX_DROP_U_UNHANDLED_MGMT) \ + R(RX_DROP_U_MCAST_DEAUTH) \ + R(RX_DROP_U_UNHANDLED_DEAUTH) \ + R(RX_DROP_U_MCAST_DISASSOC) \ + R(RX_DROP_U_UNHANDLED_DISASSOC) \ + R(RX_DROP_U_UNHANDLED_PREQ) \ + R(RX_DROP_U_UNHANDLED_MGMT_STYPE) \ + R(RX_DROP_U_NO_LINK) \ + R(RX_DROP_U_DEFRAG_OVERFLOW) \ /* this line for the trailing \ - add before this */ /* having two enums allows for checking ieee80211_rx_result use with sparse */ @@ -85,7 +129,6 @@ enum ___mac80211_drop_reason { enum mac80211_drop_reason { RX_CONTINUE = (__force ieee80211_rx_result)___RX_CONTINUE, RX_QUEUED = (__force ieee80211_rx_result)___RX_QUEUED, - RX_DROP = (__force ieee80211_rx_result)___RX_DROP_UNUSABLE, #define DEF(x) x = (__force ieee80211_rx_result)___ ## x, MAC80211_DROP_REASONS_UNUSABLE(DEF) #undef DEF diff --git a/net/mac80211/fils_aead.c b/net/mac80211/fils_aead.c index 912c46f74d24..622e8ee7ab0d 100644 --- a/net/mac80211/fils_aead.c +++ b/net/mac80211/fils_aead.c @@ -95,6 +95,14 @@ static int aes_siv_encrypt(const u8 *key, size_t key_len, if (res) return res; + /* With an empty plaintext there is no ciphertext to produce and + * the S2V result is the complete output. + */ + if (!plain_len) { + memcpy(out, v, AES_BLOCK_SIZE); + return 0; + } + /* Use a temporary buffer of the plaintext to handle need for * overwriting this during AES-CTR. */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a942986797fa..01e4edf315ae 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2403,7 +2403,7 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, /* sta_out needs to be checked for ERR_PTR() before using */ int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct sta_info **sta_out); + struct sta_info **sta_out, bool bss); static inline void ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 0319674be832..8653f7fd52ce 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -577,6 +577,12 @@ void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata, goto unlock_sta; spin_lock(&cache->walk_lock); + if ((READ_ONCE(mpath->flags) & MESH_PATH_DELETED) || + (mppath && (READ_ONCE(mppath->flags) & MESH_PATH_DELETED))) { + kfree(entry); + goto unlock_cache; + } + prev = rhashtable_lookup_get_insert_fast(&cache->rht, &entry->rhash, fast_tx_rht_params); @@ -694,8 +700,10 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata, return ERR_PTR(-ENOSPC); new_mpath = mesh_path_new(sdata, dst, GFP_ATOMIC); - if (!new_mpath) + if (!new_mpath) { + atomic_dec(&sdata->u.mesh.mpaths); return ERR_PTR(-ENOMEM); + } tbl = &sdata->u.mesh.mesh_paths; spin_lock_bh(&tbl->walk_lock); @@ -708,6 +716,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata, if (mpath) { kfree(new_mpath); + atomic_dec(&sdata->u.mesh.mpaths); if (IS_ERR(mpath)) return mpath; @@ -733,10 +742,15 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata, if (is_multicast_ether_addr(dst)) return -EOPNOTSUPP; + if (!atomic_add_unless(&sdata->u.mesh.mpaths, 1, MESH_MAX_MPATHS)) + return -ENOSPC; + new_mpath = mesh_path_new(sdata, dst, GFP_ATOMIC); - if (!new_mpath) + if (!new_mpath) { + atomic_dec(&sdata->u.mesh.mpaths); return -ENOMEM; + } memcpy(new_mpath->mpp, mpp, ETH_ALEN); tbl = &sdata->u.mesh.mpp_paths; @@ -749,10 +763,12 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata, hlist_add_head_rcu(&new_mpath->walk_list, &tbl->walk_head); spin_unlock_bh(&tbl->walk_lock); - if (ret) + if (ret) { kfree(new_mpath); - else + atomic_dec(&sdata->u.mesh.mpaths); + } else { mesh_fast_tx_flush_addr(sdata, dst); + } sdata->u.mesh.mpp_paths_generation++; return ret; @@ -798,7 +814,8 @@ static void mesh_path_free_rcu(struct mesh_table *tbl, struct ieee80211_sub_if_data *sdata = mpath->sdata; spin_lock_bh(&mpath->state_lock); - mpath->flags |= MESH_PATH_RESOLVING | MESH_PATH_DELETED; + WRITE_ONCE(mpath->flags, + mpath->flags | MESH_PATH_RESOLVING | MESH_PATH_DELETED); mesh_gate_del(tbl, mpath); spin_unlock_bh(&mpath->state_lock); timer_shutdown_sync(&mpath->timer); @@ -812,6 +829,9 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath) { hlist_del_rcu(&mpath->walk_list); rhashtable_remove_fast(&tbl->rhead, &mpath->rhash, mesh_rht_params); + spin_lock_bh(&mpath->state_lock); + WRITE_ONCE(mpath->flags, mpath->flags | MESH_PATH_DELETED); + spin_unlock_bh(&mpath->state_lock); if (tbl == &mpath->sdata->u.mesh.mpp_paths) mesh_fast_tx_flush_addr(mpath->sdata, mpath->dst); else diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 0f4bd59a95ec..4f42108aafd4 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -5235,6 +5235,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, bool is_6ghz = cbss->channel->band == NL80211_BAND_6GHZ; bool is_s1g = cbss->channel->band == NL80211_BAND_S1GHZ; const struct cfg80211_bss_ies *bss_ies = NULL; + struct ieee802_11_elems *bss_elems = NULL; struct ieee80211_supported_band *sband; struct ieee802_11_elems *elems; const __le16 prof_bss_param_ch_present = @@ -5318,7 +5319,6 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, (is_5ghz && link->u.mgd.conn.mode >= IEEE80211_CONN_MODE_VHT && (!elems->vht_cap_elem || !elems->vht_operation)))) { const struct cfg80211_bss_ies *ies; - struct ieee802_11_elems *bss_elems; rcu_read_lock(); ies = rcu_dereference(cbss->ies); @@ -5380,7 +5380,6 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, "AP bug: VHT operation missing from AssocResp\n"); } } - kfree(bss_elems); } /* @@ -5632,6 +5631,7 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link, ret = true; out: kfree(elems); + kfree(bss_elems); kfree(bss_ies); return ret; } diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index f66910013218..5f094597f111 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1960,14 +1961,39 @@ minstrel_ht_alloc(struct ieee80211_hw *hw) } #ifdef CONFIG_MAC80211_DEBUGFS +static int minstrel_ht_fixed_rate_idx_get(void *data, u64 *val) +{ + *val = *(u32 *)data; + return 0; +} + +static int minstrel_ht_fixed_rate_idx_set(void *data, u64 val) +{ + u32 idx = val; + + /* U32_MAX is the default and keeps fixed rate processing disabled */ + if (val != U32_MAX && + (val > U16_MAX || + MI_RATE_GROUP(idx) >= ARRAY_SIZE(minstrel_mcs_groups) || + MI_RATE_IDX(idx) >= MCS_GROUP_RATES)) + return -EINVAL; + + *(u32 *)data = idx; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(minstrel_ht_fixed_rate_idx_fops, + minstrel_ht_fixed_rate_idx_get, + minstrel_ht_fixed_rate_idx_set, "%llu\n"); + static void minstrel_ht_add_debugfs(struct ieee80211_hw *hw, void *priv, struct dentry *debugfsdir) { struct minstrel_priv *mp = priv; mp->fixed_rate_idx = (u32) -1; - debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, - &mp->fixed_rate_idx); + debugfs_create_file("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, + &mp->fixed_rate_idx, &minstrel_ht_fixed_rate_idx_fops); } #endif diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 13b7432d732f..3a9d7020d8d5 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -6,7 +6,7 @@ * Copyright 2007-2010 Johannes Berg * Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2025 Intel Corporation + * Copyright (C) 2018-2026 Intel Corporation */ #include @@ -1056,14 +1056,14 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) if (is_multicast_ether_addr(hdr->addr1)) { if (ieee80211_has_tods(hdr->frame_control) || !ieee80211_has_fromds(hdr->frame_control)) - return RX_DROP; + return RX_DROP_U_MESH_DS_BITS; if (ether_addr_equal(hdr->addr3, dev_addr)) - return RX_DROP; + return RX_DROP_U_MESH_A3_MISMATCH; } else { if (!ieee80211_has_a4(hdr->frame_control)) - return RX_DROP; + return RX_DROP_U_MESH_NO_A4; if (ether_addr_equal(hdr->addr4, dev_addr)) - return RX_DROP; + return RX_DROP_U_MESH_A4_MISMATCH; } } @@ -1075,20 +1075,20 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) struct ieee80211_mgmt *mgmt; if (!ieee80211_is_mgmt(hdr->frame_control)) - return RX_DROP; + return RX_DROP_U_MESH_UNEXP_DATA; if (ieee80211_is_action(hdr->frame_control)) { u8 category; /* make sure category field is present */ if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE) - return RX_DROP; + return RX_DROP_U_RUNT_ACTION; mgmt = (struct ieee80211_mgmt *)hdr; category = mgmt->u.action.category; if (category != WLAN_CATEGORY_MESH_ACTION && category != WLAN_CATEGORY_SELF_PROTECTED) - return RX_DROP; + return RX_DROP_U_MESH_WRONG_ACTION; return RX_CONTINUE; } @@ -1098,7 +1098,7 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) ieee80211_is_auth(hdr->frame_control)) return RX_CONTINUE; - return RX_DROP; + return RX_DROP_U_MESH_UNEXP_MGMT; } return RX_CONTINUE; @@ -1524,7 +1524,7 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) hdrlen = ieee80211_hdrlen(hdr->frame_control); if (rx->skb->len < hdrlen + 8) - return RX_DROP; + return RX_DROP_U_RUNT_DATA; skb_copy_bits(rx->skb, hdrlen + 6, ðertype, 2); if (ethertype == rx->sdata->control_port_protocol) @@ -1534,9 +1534,9 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) if (rx->sdata->vif.type == NL80211_IFTYPE_AP && cfg80211_rx_spurious_frame(rx->sdata->dev, hdr->addr2, rx->link_id, GFP_ATOMIC)) - return RX_DROP_U_SPURIOUS; + return RX_DROP_U_SPURIOUS_NOTIF; - return RX_DROP; + return RX_DROP_U_SPURIOUS; } return RX_CONTINUE; @@ -2027,7 +2027,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (rx->link_sta) { if (ieee80211_is_group_privacy_action(skb) && test_sta_flag(rx->sta, WLAN_STA_MFP)) - return RX_DROP; + return RX_DROP_U_UNPROTECTED; rx->key = rcu_dereference(rx->link_sta->gtk[mmie_keyidx]); } @@ -2112,11 +2112,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (rx->key) { if (unlikely(rx->key->flags & KEY_FLAG_TAINTED)) - return RX_DROP; + return RX_DROP_U_KEY_TAINTED; /* TODO: add threshold stuff again */ } else { - return RX_DROP; + return RX_DROP_U_UNPROTECTED; } switch (rx->key->conf.cipher) { @@ -2290,7 +2290,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) goto out; if (is_multicast_ether_addr(hdr->addr1)) - return RX_DROP; + return RX_DROP_U_MCAST_FRAGMENT; I802_DEBUG_INC(rx->local->rx_handlers_fragments); @@ -2345,7 +2345,7 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) rx->seqno_idx, hdr); if (!entry) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); - return RX_DROP; + return RX_DROP_U_DEFRAG_MISMATCH; } /* "The receiver shall discard MSDUs and MMPDUs whose constituent @@ -2392,6 +2392,12 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) } skb_pull(rx->skb, ieee80211_hdrlen(fc)); + if (unlikely((u32)entry->extra_len + rx->skb->len > U16_MAX)) { + I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); + __skb_queue_purge(&entry->skb_list); + return RX_DROP_U_DEFRAG_OVERFLOW; + } + __skb_queue_tail(&entry->skb_list, rx->skb); entry->last_frag = frag; entry->extra_len += rx->skb->len; @@ -2867,25 +2873,25 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta return RX_CONTINUE; if (!pskb_may_pull(skb, sizeof(*eth) + 6)) - return RX_DROP; + return RX_DROP_U_RUNT_MESH_DATA; mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(*eth)); mesh_hdrlen = ieee80211_get_mesh_hdrlen(mesh_hdr); if (!pskb_may_pull(skb, sizeof(*eth) + mesh_hdrlen)) - return RX_DROP; + return RX_DROP_U_RUNT_MESH_DATA; eth = (struct ethhdr *)skb->data; multicast = is_multicast_ether_addr(eth->h_dest); mesh_hdr = (struct ieee80211s_hdr *)(eth + 1); if (!mesh_hdr->ttl) - return RX_DROP; + return RX_DROP_U_MESH_NO_TTL; /* frame is in RMC, don't forward */ if (is_multicast_ether_addr(eth->h_dest) && mesh_rmc_check(sdata, eth->h_source, mesh_hdr)) - return RX_DROP; + return RX_DROP_U_MESH_RMC; /* forward packet */ if (sdata->crypto_tx_tailroom_needed_cnt) @@ -2902,7 +2908,7 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta /* has_a4 already checked in ieee80211_rx_mesh_check */ proxied_addr = mesh_hdr->eaddr2; else - return RX_DROP; + return RX_DROP_U_MESH_BAD_AE; rcu_read_lock(); mppath = mpp_path_lookup(sdata, proxied_addr); @@ -2934,14 +2940,14 @@ ieee80211_rx_mesh_data(struct ieee80211_sub_if_data *sdata, struct sta_info *sta goto rx_accept; IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_ttl); - return RX_DROP; + return RX_DROP_U_MESH_TTL_EXPIRED; } if (!ifmsh->mshcfg.dot11MeshForwarding) { if (is_multicast_ether_addr(eth->h_dest)) goto rx_accept; - return RX_DROP; + return RX_DROP_U_MESH_NOT_FORWARDING; } skb_set_queue_mapping(skb, ieee802_1d_to_ac[skb->priority]); @@ -3127,7 +3133,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) return RX_CONTINUE; if (unlikely(!ieee80211_is_data_present(fc))) - return RX_DROP; + return RX_DROP_U_AMSDU_WITHOUT_DATA; if (unlikely(ieee80211_has_a4(hdr->frame_control))) { switch (rx->sdata->vif.type) { @@ -3184,7 +3190,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) return RX_CONTINUE; if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) - return RX_DROP; + return RX_DROP_U_NULL_DATA; /* Send unexpected-4addr-frame event to hostapd */ if (ieee80211_has_a4(hdr->frame_control) && @@ -3194,7 +3200,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) cfg80211_rx_unexpected_4addr_frame( rx->sdata->dev, rx->sta->sta.addr, rx->link_id, GFP_ATOMIC); - return RX_DROP; + return RX_DROP_U_UNEXPECTED_4ADDR; } res = __ieee80211_data_to_8023(rx, &port_control); @@ -3206,7 +3212,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) return res; if (!ieee80211_frame_allowed(rx, fc)) - return RX_DROP; + return RX_DROP_U_PORT_CONTROL; /* directly handle TDLS channel switch requests/responses */ if (unlikely(((struct ethhdr *)rx->skb->data)->h_proto == @@ -3271,11 +3277,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) }; if (!rx->sta) - return RX_DROP; + return RX_DROP_U_UNKNOWN_STA; if (skb_copy_bits(skb, offsetof(struct ieee80211_bar, control), &bar_data, sizeof(bar_data))) - return RX_DROP; + return RX_DROP_U_RUNT_BAR; tid = le16_to_cpu(bar_data.control) >> 12; @@ -3287,7 +3293,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]); if (!tid_agg_rx) - return RX_DROP; + return RX_DROP_U_BAR_OUTSIDE_SESSION; start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4; event.u.ba.tid = tid; @@ -3311,7 +3317,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) return RX_QUEUED; } - return RX_DROP; + return RX_DROP_U_CTRL_FRAME; } static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata, @@ -3420,10 +3426,10 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) * and unknown (reserved) frames are useless. */ if (rx->skb->len < 24) - return RX_DROP; + return RX_DROP_U_RUNT_MGMT; if (!ieee80211_is_mgmt(mgmt->frame_control)) - return RX_DROP; + return RX_DROP_U_EXPECTED_MGMT; /* drop too small action frames */ if (ieee80211_is_action(mgmt->frame_control) && @@ -3433,7 +3439,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) /* Drop non-broadcast Beacon frames */ if (ieee80211_is_beacon(mgmt->frame_control) && !is_broadcast_ether_addr(mgmt->da)) - return RX_DROP; + return RX_DROP_U_NONBCAST_BEACON; if (rx->sdata->vif.type == NL80211_IFTYPE_AP && ieee80211_is_beacon(mgmt->frame_control) && @@ -3962,10 +3968,10 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) if (!(status->rx_flags & IEEE80211_RX_MALFORMED_ACTION_FRM) && (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) - return RX_DROP; + return RX_DROP_U_MALFORMED_ACTION; if (is_multicast_ether_addr(mgmt->da)) - return RX_DROP; + return RX_DROP_U_UNKNOWN_MCAST_ACTION; /* do not return rejected action frames */ if (mgmt->u.action.category & 0x80) @@ -4010,7 +4016,7 @@ ieee80211_rx_h_ext(struct ieee80211_rx_data *rx) return RX_CONTINUE; if (sdata->vif.type != NL80211_IFTYPE_STATION) - return RX_DROP; + return RX_DROP_U_UNEXPECTED_EXT_FRAME; /* for now only beacons are ext, so queue them */ ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb); @@ -4031,7 +4037,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) sdata->vif.type != NL80211_IFTYPE_ADHOC && sdata->vif.type != NL80211_IFTYPE_OCB && sdata->vif.type != NL80211_IFTYPE_STATION) - return RX_DROP; + return RX_DROP_U_UNHANDLED_MGMT; switch (stype) { case cpu_to_le16(IEEE80211_STYPE_AUTH): @@ -4042,32 +4048,32 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) case cpu_to_le16(IEEE80211_STYPE_DEAUTH): if (is_multicast_ether_addr(mgmt->da) && !is_broadcast_ether_addr(mgmt->da)) - return RX_DROP; + return RX_DROP_U_MCAST_DEAUTH; /* process only for station/IBSS */ if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_ADHOC) - return RX_DROP; + return RX_DROP_U_UNHANDLED_DEAUTH; break; case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP): case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP): case cpu_to_le16(IEEE80211_STYPE_DISASSOC): if (is_multicast_ether_addr(mgmt->da) && !is_broadcast_ether_addr(mgmt->da)) - return RX_DROP; + return RX_DROP_U_MCAST_DISASSOC; /* process only for station */ if (sdata->vif.type != NL80211_IFTYPE_STATION) - return RX_DROP; + return RX_DROP_U_UNHANDLED_DISASSOC; break; case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ): /* process only for ibss and mesh */ if (sdata->vif.type != NL80211_IFTYPE_ADHOC && sdata->vif.type != NL80211_IFTYPE_MESH_POINT) - return RX_DROP; + return RX_DROP_U_UNHANDLED_PREQ; break; default: - return RX_DROP; + return RX_DROP_U_UNHANDLED_MGMT_STYPE; } ieee80211_queue_skb_to_iface(sdata, rx->link_id, rx->sta, rx->skb); @@ -4095,7 +4101,7 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx, static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, struct sk_buff_head *frames) { - ieee80211_rx_result res = RX_DROP; + ieee80211_rx_result res; struct sk_buff *skb; #define CALL_RXH(rxh) \ @@ -4121,8 +4127,10 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, */ rx->skb = skb; - if (WARN_ON_ONCE(!rx->link)) + if (WARN_ON_ONCE(!rx->link)) { + res = RX_DROP_U_NO_LINK; goto rxh_next; + } CALL_RXH(ieee80211_rx_h_check_more_data); CALL_RXH(ieee80211_rx_h_uapsd_and_pspoll); @@ -4159,7 +4167,7 @@ static void ieee80211_rx_handlers(struct ieee80211_rx_data *rx, static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) { struct sk_buff_head reorder_release; - ieee80211_rx_result res = RX_DROP; + ieee80211_rx_result res; __skb_queue_head_init(&reorder_release); diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c index 080235ca23fc..b343a83e8d18 100644 --- a/net/mac80211/spectmgmt.c +++ b/net/mac80211/spectmgmt.c @@ -111,8 +111,8 @@ validate_chandef_by_ht_vht_oper(struct ieee80211_sub_if_data *sdata, switch (chan_width) { case NL80211_CHAN_WIDTH_320: - WARN_ON(1); - break; + chandef->chan = NULL; + return; case NL80211_CHAN_WIDTH_160: vht_oper.chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ; vht_oper.center_freq_seg1_idx = vht_oper.center_freq_seg0_idx; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 54a6b20a4c5c..5d4d9e372eb7 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -137,6 +137,8 @@ static void __cleanup_single_sta(struct sta_info *sta) struct ieee80211_local *local = sdata->local; struct ps_data *ps; + cancel_work_sync(&sta->drv_deliver_wk); + if (test_sta_flag(sta, WLAN_STA_PS_STA) || test_sta_flag(sta, WLAN_STA_PS_DRIVER) || test_sta_flag(sta, WLAN_STA_PS_DELIVER)) { @@ -166,8 +168,6 @@ static void __cleanup_single_sta(struct sta_info *sta) if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_sta_cleanup(sta); - cancel_work_sync(&sta->drv_deliver_wk); - /* * Destroy aggregation state here. It would be nice to wait for the * driver to finish aggregation stop and then clean up, but for now @@ -1529,6 +1529,8 @@ static void __sta_info_destroy_part2(struct sta_info *sta, bool recalc) sta->dead = true; + cancel_work_sync(&sta->drv_deliver_wk); + local->num_sta--; local->sta_generation++; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 931846f45c2e..d77f9f9810a0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2501,7 +2501,7 @@ static inline bool ieee80211_is_tdls_setup(struct sk_buff *skb) int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, - struct sta_info **sta_out) + struct sta_info **sta_out, bool bss) { struct sta_info *sta; @@ -2522,7 +2522,10 @@ int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, *sta_out = ERR_PTR(-ENOENT); return 0; } - sta = sta_info_get_bss(sdata, skb->data); + if (bss) + sta = sta_info_get_bss(sdata, skb->data); + else + sta = sta_info_get(sdata, skb->data); break; #ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: @@ -4342,7 +4345,8 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb, ieee80211_mesh_xmit_fast(sdata, skb, ctrl_flags)) goto out; - if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) + if (ieee80211_lookup_ra_sta(sdata, skb, &sta, + skb->protocol == sdata->control_port_protocol)) goto out_free; if (IS_ERR(sta)) @@ -4655,7 +4659,8 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, { struct ieee80211_tx_info *info; struct ieee80211_local *local = sdata->local; - struct tid_ampdu_tx *tid_tx; + struct ieee80211_chanctx_conf *chanctx_conf; + struct tid_ampdu_tx *tid_tx = NULL; struct sk_buff *seg, *next; unsigned int skbs = 0, len = 0; u16 queue; @@ -4675,7 +4680,9 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, ieee80211_aggr_check(sdata, sta, skb); tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; - tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]); + + if (sta) + tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]); if (tid_tx) { if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { /* fall back to non-offload slow path */ @@ -4702,6 +4709,16 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, sdata = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); + /* MLD transmissions must not rely on the band */ + if (!ieee80211_vif_is_mld(&sdata->vif)) { + chanctx_conf = rcu_dereference(sdata->vif.bss_conf.chanctx_conf); + if (unlikely(!chanctx_conf)) { + kfree_skb_list(skb); + return; + } + info->band = chanctx_conf->def.chan->band; + } + info->flags |= IEEE80211_TX_CTL_HW_80211_ENCAP; info->control.vif = &sdata->vif; @@ -4723,8 +4740,11 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, } dev_sw_netstats_tx_add(dev, skbs, len); - sta->deflink.tx_stats.packets[queue] += skbs; - sta->deflink.tx_stats.bytes[queue] += len; + + if (sta) { + sta->deflink.tx_stats.packets[queue] += skbs; + sta->deflink.tx_stats.bytes[queue] += len; + } ieee80211_tpt_led_trig_tx(local, len); @@ -4736,34 +4756,68 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata, kfree_skb(skb); } -netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb, - struct net_device *dev) +static bool ieee80211_check_mcast_offload(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) +{ + struct ethhdr *ehdr = (struct ethhdr *)skb->data; + + if ((ieee80211_vif_is_mld(&sdata->vif) && + (sdata->vif.type == NL80211_IFTYPE_AP && + !ieee80211_hw_check(&sdata->local->hw, MLO_MCAST_MULTI_LINK_TX))) || + (sdata->vif.type == NL80211_IFTYPE_AP_VLAN && + !sdata->wdev.use_4addr)) + return false; + + if (!is_multicast_ether_addr(skb->data) || + !(sdata->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_MCAST) || + sdata->control_port_protocol == ehdr->h_proto) + return false; + + return true; +} + +static void __ieee80211_subif_start_xmit_8023(struct sk_buff *skb, + struct net_device *dev) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ethhdr *ehdr = (struct ethhdr *)skb->data; + struct ieee80211_link_data *link; struct ieee80211_key *key; struct sta_info *sta; - if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) { - kfree_skb(skb); - return NETDEV_TX_OK; - } - rcu_read_lock(); - if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { + if (unlikely(sdata->control_port_protocol == ehdr->h_proto)) + goto skip_offload; + + if (ieee80211_lookup_ra_sta(sdata, skb, &sta, false)) { kfree_skb(skb); goto out; } - if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded || - !test_sta_flag(sta, WLAN_STA_AUTHORIZED) || - sdata->control_port_protocol == ehdr->h_proto)) + /* + * If STA is invalid, use the multicast offload path when applicable. + * In AP mode, drop the frame if there are no associated stations; + * otherwise use the default link and multicast key for transmission. + */ + if (unlikely(IS_ERR_OR_NULL(sta) && + ieee80211_check_mcast_offload(sdata, skb))) { + sta = NULL; + if (ieee80211_vif_get_num_mcast_if(sdata) <= 0) { + /* No associated STAs - no need to send multicast frames. */ + kfree_skb(skb); + goto out; + } + link = &sdata->deflink; + key = rcu_dereference(link->default_multicast_key); + } else if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded || + !test_sta_flag(sta, WLAN_STA_AUTHORIZED))) { goto skip_offload; - - key = rcu_dereference(sta->ptk[sta->ptk_idx]); - if (!key) - key = rcu_dereference(sdata->default_unicast_key); + } else { + key = rcu_dereference(sta->ptk[sta->ptk_idx]); + if (!key) + key = rcu_dereference(sdata->default_unicast_key); + } if (key && (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) || key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)) @@ -4777,6 +4831,30 @@ netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb, ieee80211_subif_start_xmit(skb, dev); out: rcu_read_unlock(); +} + +netdev_tx_t ieee80211_subif_start_xmit_8023(struct sk_buff *skb, + struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ethhdr *ehdr = (struct ethhdr *)skb->data; + + if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) { + kfree_skb(skb); + return NETDEV_TX_OK; + } + + if (unlikely(is_multicast_ether_addr(ehdr->h_dest) && + ieee80211_multicast_to_unicast(skb, dev))) { + struct sk_buff_head queue; + + __skb_queue_head_init(&queue); + ieee80211_convert_to_unicast(skb, dev, &queue); + while ((skb = __skb_dequeue(&queue))) + __ieee80211_subif_start_xmit_8023(skb, dev); + } else { + __ieee80211_subif_start_xmit_8023(skb, dev); + } return NETDEV_TX_OK; } @@ -4794,7 +4872,7 @@ ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); - if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { + if (ieee80211_lookup_ra_sta(sdata, skb, &sta, false)) { kfree_skb(skb); skb = ERR_PTR(-EINVAL); goto out; @@ -4865,7 +4943,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local, } result = ieee80211_tx(sdata, NULL, skb, true); } else if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { - if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { + if (ieee80211_lookup_ra_sta(sdata, skb, &sta, true)) { dev_kfree_skb(skb); return true; } @@ -6451,7 +6529,7 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, * AF_PACKET */ rcu_read_lock(); - err = ieee80211_lookup_ra_sta(sdata, skb, &sta); + err = ieee80211_lookup_ra_sta(sdata, skb, &sta, true); if (err) { dev_kfree_skb(skb); rcu_read_unlock(); diff --git a/net/mctp/device.c b/net/mctp/device.c index 7861d83aaad2..a18164357123 100644 --- a/net/mctp/device.c +++ b/net/mctp/device.c @@ -344,13 +344,13 @@ static struct mctp_dev *mctp_add_dev(struct net_device *dev) mdev->net = mctp_default_net(dev_net(dev)); - /* associate to net_device */ refcount_set(&mdev->refs, 1); - rcu_assign_pointer(dev->mctp_ptr, mdev); - dev_hold(dev); mdev->dev = dev; + /* Associate to net_device, publish the mdev. */ + rcu_assign_pointer(dev->mctp_ptr, mdev); + return mdev; } diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 7a1696ac92dc..e14a49180eef 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3312,7 +3312,7 @@ static int mptcp_disconnect(struct sock *sk, int flags) /* The later subflow close can not kick again the tout timer, * as the msk is already in closed status. */ - msk->timer_ival = icsk->icsk_rto_min; + msk->timer_ival = TCP_RTO_MIN; sk_stop_timer_sync(sk, &sk->mptcp_retransmit_timer); icsk->icsk_mtup.probe_timestamp = 0; sk_stop_timer_sync(sk, &icsk->mptcp_tout_timer); diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h index ca1119f651ef..25278f44ed2a 100644 --- a/net/netfilter/ipset/ip_set_bitmap_gen.h +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h @@ -159,7 +159,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, if (SET_WITH_COUNTER(set)) ip_set_init_counter(ext_counter(x, set), ext); - if (SET_WITH_COMMENT(set)) + if (SET_WITH_COMMENT(set) && !ext->target) ip_set_init_comment(set, ext_comment(x, set), ext); if (SET_WITH_SKBINFO(set)) ip_set_init_skbinfo(ext_skbinfo(x, set), ext); diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index 7da11628073b..6bedad1f48fc 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -591,6 +591,9 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest) if (cp->protocol != IPPROTO_UDP) conn_flags &= ~IP_VS_CONN_F_ONE_PACKET; flags = cp->flags; + /* Only visible templates can control multiple connections */ + if (flags & IP_VS_CONN_F_TEMPLATE) + conn_flags &= ~IP_VS_CONN_F_ONE_PACKET; /* Bind with the destination and its corresponding transmitter */ if (flags & IP_VS_CONN_F_SYNC) { /* Synced conns are hashed, so they can not get this flag */ diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c index 9bb1e05063dc..832066f11e67 100644 --- a/net/netfilter/ipvs/ip_vs_lblc.c +++ b/net/netfilter/ipvs/ip_vs_lblc.c @@ -204,7 +204,11 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr, if (en->dest == dest) return en; ip_vs_lblc_del(en); + atomic_dec(&tbl->entries); } + if (atomic_read(&tbl->entries) >= tbl->max_size * 3 / 2) + return NULL; + en = kmalloc(sizeof(*en), GFP_ATOMIC); if (!en) return NULL; diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c index 1a53c1254fe5..073d3ad17704 100644 --- a/net/netfilter/ipvs/ip_vs_lblcr.c +++ b/net/netfilter/ipvs/ip_vs_lblcr.c @@ -364,6 +364,9 @@ ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr, en = ip_vs_lblcr_get(af, tbl, daddr); if (!en) { + if (atomic_read(&tbl->entries) >= tbl->max_size * 3 / 2) + return NULL; + en = kmalloc(sizeof(*en), GFP_ATOMIC); if (!en) return NULL; diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 699651e84d83..b835f61886d6 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -950,6 +950,21 @@ static void ip_vs_proc_conn(struct netns_ipvs *ipvs, struct ip_vs_conn_param *pa ip_vs_conn_put(cp); } +/* Check for incompatible flags */ +static bool ip_vs_sync_validate_flags(u32 flags) +{ + /* We do not expect NO_CPORT, especially to allow lookups + * to hit templates + */ + if (flags & IP_VS_CONN_F_NO_CPORT) { + if (flags & IP_VS_CONN_F_TEMPLATE) + return false; + } + if (flags & IP_VS_CONN_F_ONE_PACKET) + return false; + return true; +} + /* * Process received multicast message for Version 0 */ @@ -973,8 +988,7 @@ static void ip_vs_process_message_v0(struct netns_ipvs *ipvs, const char *buffer return; } s = (struct ip_vs_sync_conn_v0 *) p; - flags = ntohs(s->flags) | IP_VS_CONN_F_SYNC; - flags &= ~IP_VS_CONN_F_HASHED; + flags = ntohs(s->flags); if (flags & IP_VS_CONN_F_SEQ_MASK) { opt = (struct ip_vs_sync_conn_options *)&s[1]; p += FULL_CONN_SIZE; @@ -987,6 +1001,13 @@ static void ip_vs_process_message_v0(struct netns_ipvs *ipvs, const char *buffer p += SIMPLE_CONN_SIZE; } + if (!ip_vs_sync_validate_flags(flags)) { + IP_VS_DBG(2, "BACKUP v0, Invalid flags 0x%X\n", flags); + continue; + } + flags &= IP_VS_CONN_F_BACKUP_MASK; + flags |= IP_VS_CONN_F_SYNC; + state = ntohs(s->state); if (!(flags & IP_VS_CONN_F_TEMPLATE)) { pp = ip_vs_proto_get(s->protocol); @@ -1142,7 +1163,13 @@ static inline int ip_vs_proc_sync_conn(struct netns_ipvs *ipvs, __u8 *p, __u8 *m } /* Get flags and Mask off unsupported */ - flags = ntohl(s->v4.flags) & IP_VS_CONN_F_BACKUP_MASK; + flags = ntohl(s->v4.flags); + if (!ip_vs_sync_validate_flags(flags)) { + IP_VS_DBG(3, "BACKUP, Invalid flags 0x%X\n", flags); + retc = 25; + goto out; + } + flags &= IP_VS_CONN_F_BACKUP_MASK; flags |= IP_VS_CONN_F_SYNC; state = ntohs(s->v4.state); diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index 2fc2e08aecfb..f1f119062c86 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -568,7 +568,12 @@ static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct) static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table, struct flow_offload *flow, void *data) { - bool teardown = test_bit(NF_FLOW_TEARDOWN, &flow->flags); + bool teardown; + + if (test_bit(NF_FLOW_PENDING, &flow->flags)) + return; + + teardown = test_bit(NF_FLOW_TEARDOWN, &flow->flags); if (nf_flow_has_expired(flow) || nf_ct_is_dying(flow->ct) || diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c index 8e3edc7c37b3..2af7d6469604 100644 --- a/net/netfilter/nf_flow_table_offload.c +++ b/net/netfilter/nf_flow_table_offload.c @@ -993,6 +993,7 @@ static void flow_offload_work_del(struct flow_offload_work *offload) flow_offload_tuple_del(offload, FLOW_OFFLOAD_DIR_ORIGINAL); if (test_bit(NF_FLOW_HW_BIDIRECTIONAL, &offload->flow->flags)) flow_offload_tuple_del(offload, FLOW_OFFLOAD_DIR_REPLY); + set_bit(NF_FLOW_HW_DEAD, &offload->flow->flags); } static void flow_offload_tuple_stats(struct flow_offload_work *offload, @@ -1054,13 +1055,8 @@ static void flow_offload_work_handler(struct work_struct *work) default: WARN_ON_ONCE(1); } - - clear_bit(NF_FLOW_HW_PENDING, &offload->flow->flags); - if (offload->cmd == FLOW_CLS_DESTROY) { - /* Publish after the worker's last flow access. */ - smp_mb__before_atomic(); - set_bit(NF_FLOW_HW_DEAD, &offload->flow->flags); - } + smp_mb__before_atomic(); + clear_bit(NF_FLOW_PENDING, &offload->flow->flags); kfree(offload); } @@ -1087,12 +1083,12 @@ nf_flow_offload_work_alloc(struct nf_flowtable *flowtable, { struct flow_offload_work *offload; - if (test_and_set_bit(NF_FLOW_HW_PENDING, &flow->flags)) + if (test_and_set_bit(NF_FLOW_PENDING, &flow->flags)) return NULL; offload = kmalloc(sizeof(struct flow_offload_work), GFP_ATOMIC); if (!offload) { - clear_bit(NF_FLOW_HW_PENDING, &flow->flags); + clear_bit(NF_FLOW_PENDING, &flow->flags); return NULL; } diff --git a/net/netfilter/nf_nat_bpf.c b/net/netfilter/nf_nat_bpf.c index 481be15609b1..ed01633c9289 100644 --- a/net/netfilter/nf_nat_bpf.c +++ b/net/netfilter/nf_nat_bpf.c @@ -39,6 +39,9 @@ __bpf_kfunc int bpf_ct_set_nat_info(struct nf_conn___init *nfct, if (proto != NFPROTO_IPV4 && proto != NFPROTO_IPV6) return -EINVAL; + if (manip != NF_NAT_MANIP_SRC && manip != NF_NAT_MANIP_DST) + return -EINVAL; + memset(&range, 0, sizeof(struct nf_nat_range2)); range.flags = NF_NAT_RANGE_MAP_IPS; range.min_addr = *addr; diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index 658b0f143834..f628122bf8a8 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -779,8 +779,9 @@ nf_nat_setup_info(struct nf_conn *ct, if (nf_ct_is_confirmed(ct)) return NF_ACCEPT; - WARN_ON(maniptype != NF_NAT_MANIP_SRC && - maniptype != NF_NAT_MANIP_DST); + if (WARN_ON(maniptype != NF_NAT_MANIP_SRC && + maniptype != NF_NAT_MANIP_DST)) + return NF_DROP; if (WARN_ON(nf_nat_initialized(ct, maniptype))) return NF_DROP; diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c index 3e1d6c6295b9..a787e2d45fc5 100644 --- a/net/netfilter/nft_flow_offload.c +++ b/net/netfilter/nft_flow_offload.c @@ -159,6 +159,7 @@ static int nft_flow_offload_init(const struct nft_ctx *ctx, struct nft_flow_offload *priv = nft_expr_priv(expr); u8 genmask = nft_genmask_next(ctx->net); struct nft_flowtable *flowtable; + int err; if (!tb[NFTA_FLOW_TABLE_NAME]) return -EINVAL; @@ -173,7 +174,11 @@ static int nft_flow_offload_init(const struct nft_ctx *ctx, priv->flowtable = flowtable; - return nf_ct_netns_get(ctx->net, ctx->family); + err = nf_ct_netns_get(ctx->net, ctx->family); + if (err < 0) + nft_use_dec(&flowtable->use); + + return err; } static void nft_flow_offload_deactivate(const struct nft_ctx *ctx, diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 846f24e22cbb..003727af1748 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2873,6 +2873,9 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) vnet_hdr.hdr_len); has_vnet_hdr = true; } + /* Prevent the byte count from wrapping into a negative errno */ + if (unlikely(tp_len > INT_MAX - len_sum)) + break; copylen = max_t(int, copylen, hard_header_len); skb = sock_alloc_send_skb(&po->sk, hlen + tlen + sizeof(struct sockaddr_ll) + diff --git a/net/rds/tcp.c b/net/rds/tcp.c index f6d243c4e52c..eab960d10ab0 100644 --- a/net/rds/tcp.c +++ b/net/rds/tcp.c @@ -232,16 +232,19 @@ void rds_tcp_set_callbacks(struct socket *sock, struct rds_conn_path *cp) rdsdebug("setting sock %p callbacks to tc %p\n", sock, tc); write_lock_bh(&sock->sk->sk_callback_lock); - /* done under the callback_lock to serialize with write_space */ + /* done under the callback_lock to serialize with write_space. + * Set t_sock inside rds_tcp_tc_list_lock so readers walking + * rds_tcp_tc_list under the same lock cannot observe an + * entry whose t_sock is NULL. + */ spin_lock(&rds_tcp_tc_list_lock); + tc->t_sock = sock; list_add_tail(&tc->t_list_item, &rds_tcp_tc_list); spin_unlock(&rds_tcp_tc_list_lock); /* accepted sockets need our listen data ready undone */ if (sock->sk->sk_data_ready == rds_tcp_listen_data_ready) sock->sk->sk_data_ready = sock->sk->sk_user_data; - - tc->t_sock = sock; tc->t_cpath = cp; tc->t_orig_data_ready = sock->sk->sk_data_ready; tc->t_orig_write_space = sock->sk->sk_write_space; diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c index 1adfd61733a1..161c62dafaa1 100644 --- a/net/sched/act_ct.c +++ b/net/sched/act_ct.c @@ -287,7 +287,7 @@ static bool tcf_ct_flow_is_outdated(const struct flow_offload *flow) { return test_bit(IPS_SEEN_REPLY_BIT, &flow->ct->status) && test_bit(IPS_HW_OFFLOAD_BIT, &flow->ct->status) && - !test_bit(NF_FLOW_HW_PENDING, &flow->flags) && + !test_bit(NF_FLOW_PENDING, &flow->flags) && !test_bit(NF_FLOW_HW_ESTABLISHED, &flow->flags); } diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index 8691fe1e67da..c52f25e0c0a0 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -72,9 +72,8 @@ TC_INDIRECT_SCOPE int tcf_skbedit_act(struct sk_buff *skb, } if (params->flags & SKBEDIT_F_QUEUE_MAPPING && skb->dev->real_num_tx_queues > params->queue_mapping) { -#ifdef CONFIG_NET_EGRESS - netdev_xmit_skip_txqueue(true); -#endif + if (skb_at_tc_egress(skb)) + netdev_xmit_skip_txqueue(true); skb_set_queue_mapping(skb, tcf_skbedit_hash(params, skb)); } if (params->flags & SKBEDIT_F_MARK) { diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 8a881048e71e..0bc0c010434c 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -2463,7 +2463,20 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n, } errout: - if (err && tp_state == TP_CREATED) + if (err && !IS_ERR_OR_NULL(tp) && + (tp_state == TP_CREATED || tp->ops->delete_empty)) + /* + * The request is dropping its reference to tp. If it was + * the last user (the idr is empty now), reclaim the proto. + * A tp this request created is reclaimed unconditionally: + * it is the only owner, so marking it for deletion is + * safe. Otherwise only classifiers with a delete_empty + * callback are reclaimed -- the callback admits an empty + * proto only, so a live shared proto is never unlinked. + * Classifiers without one (deleting is set + * unconditionally) are rtnl-serialized, so the raced + * window this guard closes cannot arise for them. + */ tcf_chain_tp_delete_empty(chain, tp, rtnl_held, NULL); errout_tp: if (chain) { diff --git a/net/sched/sch_codel.c b/net/sched/sch_codel.c index 1d2caed1bf5b..4a639555de79 100644 --- a/net/sched/sch_codel.c +++ b/net/sched/sch_codel.c @@ -206,7 +206,7 @@ static int codel_init(struct Qdisc *sch, struct nlattr *opt, codel_params_init(&q->params); codel_vars_init(&q->vars); codel_stats_init(&q->stats); - q->params.mtu = clamp_t(u32, psched_mtu(qdisc_dev(sch)), 256, 1 << 20); + q->params.mtu = min_t(u32, psched_mtu(qdisc_dev(sch)), 1 << 20); if (opt) { int err = codel_change(sch, opt, extack); diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index 3b3401dc5c6f..c135b1dd5972 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -515,8 +515,8 @@ static int fq_codel_init(struct Qdisc *sch, struct nlattr *opt, q->flows_cnt = 1024; q->memory_limit = 32 << 20; /* 32 MBytes */ q->drop_batch_size = 64; - mtu = clamp_t(u32, psched_mtu(qdisc_dev(sch)), 256, FQ_CODEL_QUANTUM_MAX); - q->quantum = mtu; + mtu = min_t(u32, psched_mtu(qdisc_dev(sch)), FQ_CODEL_QUANTUM_MAX); + q->quantum = clamp_t(u32, mtu, 256, FQ_CODEL_QUANTUM_MAX); INIT_LIST_HEAD(&q->new_flows); INIT_LIST_HEAD(&q->old_flows); codel_params_init(&q->cparams); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index b4f706a975be..b08e829cd195 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1843,7 +1843,7 @@ static int sctp_sendmsg_to_asoc(struct sctp_association *asoc, if (asoc->ep->intl_enable) { timeo = sock_sndtimeo(sk, 0); err = sctp_wait_for_connect(asoc, &timeo); - if (err) { + if (err || sk->sk_shutdown & RCV_SHUTDOWN) { err = -ESRCH; goto err; } diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 55f810a22c6a..1f9d14e46c9d 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -373,7 +373,13 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv, listen_id = svc_rdma_create_listen_id(net, sa, cma_xprt); if (IS_ERR(listen_id)) { - kfree(cma_xprt); + /* _svc_xprt_create() acquired one module reference and + * puts it on xpo_create failure. svc_xprt_free() puts + * a second one when the kref drops to zero. Take a + * compensating reference so both puts are balanced. + */ + __module_get(cma_xprt->sc_xprt.xpt_class->xcl_owner); + svc_xprt_put(&cma_xprt->sc_xprt); return ERR_CAST(listen_id); } cma_xprt->sc_cm_id = listen_id; diff --git a/net/tipc/crypto.c b/net/tipc/crypto.c index d388fe8e477e..b450802936aa 100644 --- a/net/tipc/crypto.c +++ b/net/tipc/crypto.c @@ -144,7 +144,7 @@ struct tipc_tfm { * @rcu: struct rcu_head * @key: the aead key * @gen: the key's generation - * @seqno: the key seqno (cluster scope) + * @seqno: the per-key TX nonce counter * @refcnt: the key reference counter */ struct tipc_aead { @@ -190,7 +190,6 @@ struct tipc_crypto_stats { * @rekeying_intv: rekeying interval (in minutes) * @stats: the crypto statistics * @name: the crypto name - * @sndnxt: the per-peer sndnxt (TX) * @timer1: general timer 1 (jiffies) * @timer2: general timer 2 (jiffies) * @working: the crypto is working or not @@ -219,7 +218,6 @@ struct tipc_crypto { struct tipc_crypto_stats __percpu *stats; char name[48]; - atomic64_t sndnxt ____cacheline_aligned; unsigned long timer1; unsigned long timer2; union { @@ -1060,14 +1058,11 @@ static int tipc_ehdr_build(struct net *net, struct tipc_aead *aead, WARN_ON(skb_headroom(skb) < ehsz); ehdr = (struct tipc_ehdr *)skb_push(skb, ehsz); - /* Obtain a seqno first: - * Use the key seqno (= cluster wise) if dest is unknown or we're in - * cluster key mode, otherwise it's better for a per-peer seqno! + /* + * Keep the nonce unique for the lifetime of the TX key, + * including key state changes and peer reconnection. */ - if (!__rx || aead->mode == CLUSTER_KEY) - seqno = atomic64_inc_return(&aead->seqno); - else - seqno = atomic64_inc_return(&__rx->sndnxt); + seqno = atomic64_inc_return(&aead->seqno); /* Revoke the key if seqno is wrapped around */ if (unlikely(!seqno)) @@ -1246,7 +1241,6 @@ void tipc_crypto_key_flush(struct tipc_crypto *c) tipc_crypto_key_set_state(c, 0, 0, 0); for (k = KEY_MIN; k <= KEY_MAX; k++) tipc_crypto_key_detach(c->aead[k], &c->lock); - atomic64_set(&c->sndnxt, 0); spin_unlock_bh(&c->lock); } @@ -1393,8 +1387,6 @@ static struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx, * It also considers if peer has no key, then we need to make own master key * (if any) taking over i.e. starting grace period and also trigger key * distributing process. - * - * The "per-peer" sndnxt is also reset when the peer key has switched. */ static void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb) { @@ -1445,7 +1437,6 @@ static void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb) if (cur) tipc_aead_users_dec(tx->aead[cur], 0); - atomic64_set(&rx->sndnxt, 0); /* Mark the point TX key users changed */ tx->timer1 = jiffies; @@ -1510,7 +1501,6 @@ int tipc_crypto_start(struct tipc_crypto **crypto, struct net *net, tipc_crypto_key_set_state(c, 0, 0, 0); atomic_set(&c->key_distr, 0); atomic_set(&c->peer_rx_active, 0); - atomic64_set(&c->sndnxt, 0); c->timer1 = jiffies; c->timer2 = jiffies; c->rekeying_intv = TIPC_REKEYING_INTV_DEF; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 28b9cd017ae3..356b612d935f 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4193,12 +4193,13 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) rdev->wiphy.retry_long = retry_long; if (changed & WIPHY_PARAM_FRAG_THRESHOLD) rdev->wiphy.frag_threshold = frag_threshold; - if ((changed & WIPHY_PARAM_RTS_THRESHOLD) && - old_radio_rts_threshold) { + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { rdev->wiphy.rts_threshold = rts_threshold; - for (i = 0 ; i < rdev->wiphy.n_radio; i++) - rdev->wiphy.radio_cfg[i].rts_threshold = - rdev->wiphy.rts_threshold; + if (old_radio_rts_threshold) { + for (i = 0; i < rdev->wiphy.n_radio; i++) + rdev->wiphy.radio_cfg[i].rts_threshold = + rdev->wiphy.rts_threshold; + } } if (changed & WIPHY_PARAM_COVERAGE_CLASS) rdev->wiphy.coverage_class = coverage_class; diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 29e150b4511f..3d3956e4cce2 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1965,20 +1965,22 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev, return false; } - old = rcu_access_pointer(known->pub.beacon_ies); + if (!new->pub.hidden_beacon_bss) { + old = rcu_access_pointer(known->pub.beacon_ies); - rcu_assign_pointer(known->pub.beacon_ies, new->pub.beacon_ies); + rcu_assign_pointer(known->pub.beacon_ies, new->pub.beacon_ies); - /* Override IEs if they were from a beacon before */ - if (old == rcu_access_pointer(known->pub.ies)) - rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies); + /* Override IEs if they were from a beacon before */ + if (old == rcu_access_pointer(known->pub.ies)) + rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies); - cfg80211_update_hidden_bsses(known, - rcu_access_pointer(new->pub.beacon_ies), - old); + cfg80211_update_hidden_bsses(known, + rcu_access_pointer(new->pub.beacon_ies), + old); - if (old) - kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); + if (old) + kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head); + } } known->pub.beacon_interval = new->pub.beacon_interval; diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs index 835d9c11948e..fc0d8b2cb7b2 100644 --- a/rust/kernel/devres.rs +++ b/rust/kernel/devres.rs @@ -13,23 +13,16 @@ ffi::c_void, prelude::*, revocable::{Revocable, RevocableGuard}, - sync::{aref::ARef, rcu, Completion}, - types::{ForeignOwnable, Opaque, ScopeGuard}, + sync::{aref::ARef, rcu, Arc, Completion}, + types::ForeignOwnable, }; -use pin_init::Wrapper; - -/// [`Devres`] inner data accessed from [`Devres::callback`]. #[pin_data] -struct Inner { +struct Inner { #[pin] data: Revocable, - /// Tracks whether [`Devres::callback`] has been completed. - #[pin] - devm: Completion, - /// Tracks whether revoking [`Self::data`] has been completed. #[pin] - revoke: Completion, + revocation: Completion, } /// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to @@ -46,6 +39,10 @@ struct Inner { /// After the [`Devres`] has been unbound it is not possible to access the encapsulated resource /// anymore. /// +/// When a [`Devres`] is dropped, it is guaranteed that `T` has been fully dropped by the time +/// [`Devres::drop`] returns, even if a concurrent revocation through the release callback is in +/// progress. +/// /// [`Devres`] users should make sure to simply free the corresponding backing resource in `T`'s /// [`Drop`] implementation. /// @@ -105,107 +102,82 @@ struct Inner { /// # fn no_run(dev: &Device) -> Result<(), Error> { /// // SAFETY: Invalid usage for example purposes. /// let iomem = unsafe { IoMem::<{ core::mem::size_of::() }>::new(0xBAAAAAAD)? }; -/// let devres = KBox::pin_init(Devres::new(dev, iomem), GFP_KERNEL)?; +/// let devres = Devres::new(dev, iomem)?; /// /// let res = devres.try_access().ok_or(ENXIO)?; /// res.write8(0x42, 0x0); /// # Ok(()) /// # } /// ``` -/// -/// # Invariants -/// -/// `Self::inner` is guaranteed to be initialized and is always accessed read-only. -#[pin_data(PinnedDrop)] -pub struct Devres { +pub struct Devres { dev: ARef, /// Pointer to [`Self::devres_callback`]. /// /// Has to be stored, since Rust does not guarantee to always return the same address for a /// function. However, the C API uses the address as a key. callback: unsafe extern "C" fn(*mut c_void), - /// Contains all the fields shared with [`Self::callback`]. - // TODO: Replace with `UnsafePinned`, once available. - // - // Subsequently, the `drop_in_place()` in `Devres::drop` and `Devres::new` as well as the - // explicit `Send` and `Sync' impls can be removed. - #[pin] - inner: Opaque>, - _add_action: (), + inner: Arc>, } -impl Devres { +impl Devres { /// Creates a new [`Devres`] instance of the given `data`. /// /// The `data` encapsulated within the returned `Devres` instance' `data` will be /// (revoked)[`Revocable`] once the device is detached. - pub fn new<'a, E>( - dev: &'a Device, - data: impl PinInit + 'a, - ) -> impl PinInit + 'a + pub fn new(dev: &Device, data: impl PinInit) -> Result where - T: 'a, Error: From, { - try_pin_init!(&this in Self { - dev: dev.into(), - callback: Self::devres_callback, - // INVARIANT: `inner` is properly initialized. - inner <- Opaque::pin_init(try_pin_init!(Inner { - devm <- Completion::new(), - revoke <- Completion::new(), - data <- Revocable::new(data), - })), - // TODO: Replace with "initializer code blocks" [1] once available. - // - // [1] https://github.com/Rust-for-Linux/pin-init/pull/69 - _add_action: { - // SAFETY: `this` is a valid pointer to uninitialized memory. - let inner = unsafe { &raw mut (*this.as_ptr()).inner }; + let callback = Self::devres_callback; + let inner = Arc::pin_init::( + try_pin_init!(Inner { + data <- Revocable::new(data), + revocation <- Completion::new(), + }), + GFP_KERNEL, + )?; + let devres_inner = inner.clone(); + + // SAFETY: + // - `dev.as_raw()` is a pointer to a valid bound device. + // - `inner` is guaranteed to be a valid for the duration of the lifetime of `Self`. + // - `devm_add_action()` is guaranteed not to call `callback` for the entire lifetime of + // `dev`. + to_result(unsafe { + bindings::devm_add_action( + dev.as_raw(), + Some(callback), + Arc::as_ptr(&inner).cast_mut().cast(), + ) + })?; - // SAFETY: - // - `dev.as_raw()` is a pointer to a valid bound device. - // - `inner` is guaranteed to be a valid for the duration of the lifetime of `Self`. - // - `devm_add_action()` is guaranteed not to call `callback` until `this` has been - // properly initialized, because we require `dev` (i.e. the *bound* device) to - // live at least as long as the returned `impl PinInit`. - to_result(unsafe { - bindings::devm_add_action(dev.as_raw(), Some(*callback), inner.cast()) - }).inspect_err(|_| { - let inner = Opaque::cast_into(inner); + // `devm_add_action()` was successful and has consumed the reference count. + core::mem::forget(devres_inner); - // SAFETY: `inner` is a valid pointer to an `Inner` and valid for both reads - // and writes. - unsafe { core::ptr::drop_in_place(inner) }; - })?; - }, + Ok(Self { + dev: dev.into(), + callback, + inner, }) } - fn inner(&self) -> &Inner { - // SAFETY: By the type invairants of `Self`, `inner` is properly initialized and always - // accessed read-only. - unsafe { &*self.inner.get() } - } - fn data(&self) -> &Revocable { - &self.inner().data + &self.inner.data } #[allow(clippy::missing_safety_doc)] unsafe extern "C" fn devres_callback(ptr: *mut kernel::ffi::c_void) { - // SAFETY: In `Self::new` we've passed a valid pointer to `Inner` to `devm_add_action()`, - // hence `ptr` must be a valid pointer to `Inner`. - let inner = unsafe { &*ptr.cast::>() }; - - // Ensure that `inner` can't be used anymore after we signal completion of this callback. - let inner = ScopeGuard::new_with_data(inner, |inner| inner.devm.complete_all()); + // SAFETY: In `Self::new` we've passed a valid pointer of `Inner` to + // `devm_add_action()`, hence `ptr` must be a valid pointer to `Inner`. + let inner = unsafe { Arc::from_raw(ptr.cast::>()) }; - if !inner.data.revoke() { - // If `revoke()` returns false, it means that `Devres::drop` already started revoking - // `data` for us. Hence we have to wait until `Devres::drop` signals that it - // completed revoking `data`. - inner.revoke.wait_for_completion(); + if inner.data.revoke() { + inner.revocation.complete_all(); + } else { + // Devres::drop() is concurrently revoking; wait for it to finish `drop_in_place()` + // before returning to `devres_release_all()`, ensuring `T` is fully torn down before + // the device finishes unbinding. + inner.revocation.wait_for_completion(); } } @@ -218,7 +190,7 @@ fn remove_action(&self) -> bool { bindings::devm_remove_action_nowarn( self.dev.as_raw(), Some(self.callback), - core::ptr::from_ref(self.inner()).cast_mut().cast(), + Arc::as_ptr(&self.inner).cast_mut().cast(), ) } == 0) } @@ -289,31 +261,25 @@ unsafe impl Send for Devres {} // SAFETY: `Devres` can be shared with any task, if `T: Sync`. unsafe impl Sync for Devres {} -#[pinned_drop] -impl PinnedDrop for Devres { - fn drop(self: Pin<&mut Self>) { +impl Drop for Devres { + fn drop(&mut self) { // SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data // anymore, hence it is safe not to wait for the grace period to finish. if unsafe { self.data().revoke_nosync() } { - // We revoked `self.data` before the devres action did, hence try to remove it. - if !self.remove_action() { - // We could not remove the devres action, which means that it now runs concurrently, - // hence signal that `self.data` has been revoked by us successfully. - self.inner().revoke.complete_all(); + self.inner.revocation.complete_all(); - // Wait for `Self::devres_callback` to be done using this object. - self.inner().devm.wait_for_completion(); + // We revoked `self.data` before the devres action did, hence try to remove it. + if self.remove_action() { + // SAFETY: In `Self::new` we have taken an additional reference count of `self.inner` + // for `devm_add_action()`. Since `remove_action()` was successful, we have to drop + // this additional reference count. + drop(unsafe { Arc::from_raw(Arc::as_ptr(&self.inner)) }); } } else { - // `Self::devres_callback` revokes `self.data` for us, hence wait for it to be done - // using this object. - self.inner().devm.wait_for_completion(); + // The release callback is concurrently revoking; wait for it to finish + // `drop_in_place()` of the wrapped object before returning. + self.inner.revocation.wait_for_completion(); } - - // INVARIANT: At this point it is guaranteed that `inner` can't be accessed any more. - // - // SAFETY: `inner` is valid for dropping. - unsafe { core::ptr::drop_in_place(self.inner.get()) }; } } diff --git a/rust/kernel/irq/request.rs b/rust/kernel/irq/request.rs index 2ceeaeb0543a..70700f43ddd3 100644 --- a/rust/kernel/irq/request.rs +++ b/rust/kernel/irq/request.rs @@ -14,7 +14,7 @@ use crate::irq::flags::Flags; use crate::prelude::*; use crate::str::CStr; -use crate::sync::Arc; +use crate::sync::{aref::ARef, Arc}; /// The value that can be returned from a [`Handler`] or a [`ThreadedHandler`]. #[repr(u32)] @@ -54,13 +54,18 @@ fn handle(&self, device: &Device) -> IrqReturn { /// # Invariants /// /// - `self.irq` is the same as the one passed to `request_{threaded}_irq`. -/// - `cookie` was passed to `request_{threaded}_irq` as the cookie. It is guaranteed to be unique +/// - `&self` was passed to `request_{threaded}_irq` as the cookie. It is guaranteed to be unique /// by the type system, since each call to `new` will return a different instance of /// `Registration`. +/// - `self.handler` points to a valid instance of the handler `T` that lives at least until +/// `Self::drop` completes. #[pin_data(PinnedDrop)] struct RegistrationInner { irq: u32, - cookie: *mut c_void, + dev: ARef, + handler: *const c_void, + #[pin] + _pin: PhantomPinned, } impl RegistrationInner { @@ -77,18 +82,22 @@ fn drop(self: Pin<&mut Self>) { // // Safe as per the invariants of `RegistrationInner` and: // - // - The containing struct is `!Unpin` and was initialized using + // - `RegistrationInner` is `!Unpin` and was initialized using // pin-init, so it occupied the same memory location for the entirety of // its lifetime. // // Notice that this will block until all handlers finish executing, // i.e.: at no point will &self be invalid while the handler is running. - unsafe { bindings::free_irq(self.irq, self.cookie) }; + unsafe { + bindings::free_irq( + self.irq, + core::ptr::from_mut::(self.get_unchecked_mut()).cast::(), + ) + }; } } -// SAFETY: We only use `inner` on drop, which called at most once with no -// concurrent access. +// SAFETY: `RegistrationInner` has no interior mutability and `handler` points to a `Sync` handler. unsafe impl Sync for RegistrationInner {} // SAFETY: It is safe to send `RegistrationInner` across threads. @@ -180,7 +189,7 @@ pub fn irq(&self) -> u32 { /// /// # Invariants /// -/// * We own an irq handler whose cookie is a pointer to `Self`. +/// * We own an irq handler whose cookie is a pointer to `Self::inner`. #[pin_data] pub struct Registration { #[pin] @@ -207,10 +216,13 @@ pub fn new<'a>( handler <- handler, inner <- Devres::new( request.dev, - try_pin_init!(RegistrationInner { - // INVARIANT: `this` is a valid pointer to the `Registration` instance - cookie: this.as_ptr().cast::(), - irq: { + try_pin_init!(&inner_this in RegistrationInner { + irq: request.irq, + dev: request.dev.into(), + // SAFETY: `this` is a valid pointer to the `Registration` instance. + handler: unsafe { &raw const (*this.as_ptr()).handler }.cast(), + _pin: PhantomPinned, + _: { // SAFETY: // - The callbacks are valid for use with request_irq. // - If this succeeds, the slot is guaranteed to be valid until the @@ -225,11 +237,10 @@ pub fn new<'a>( Some(handle_irq_callback::), flags.into_inner(), name.as_char_ptr(), - this.as_ptr().cast::(), + inner_this.as_ptr().cast::(), ) })?; - request.irq - } + }, }) ), _pin: PhantomPinned, @@ -265,13 +276,15 @@ pub fn synchronize(&self, dev: &Device) -> Result { _irq: i32, ptr: *mut c_void, ) -> c_uint { - // SAFETY: `ptr` is a pointer to `Registration` set in `Registration::new` - let registration = unsafe { &*(ptr as *const Registration) }; + // SAFETY: `ptr` is a pointer to `RegistrationInner` set in `Registration::new` + let inner = unsafe { &*(ptr as *const RegistrationInner) }; + // SAFETY: `inner.handler` is a pointer to `T` set in `Registration::new` + let handler = unsafe { &*inner.handler.cast::() }; // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq // callback is running implies that the device has not yet been unbound. - let device = unsafe { registration.inner.device().as_bound() }; + let device = unsafe { inner.dev.as_bound() }; - T::handle(®istration.handler, device) as c_uint + T::handle(handler, device) as c_uint } /// The value that can be returned from [`ThreadedHandler::handle`]. @@ -401,7 +414,7 @@ fn handle_threaded(&self, device: &Device) -> IrqReturn { /// /// # Invariants /// -/// * We own an irq handler whose cookie is a pointer to `Self`. +/// * We own an irq handler whose cookie is a pointer to `Self::inner`. #[pin_data] pub struct ThreadedRegistration { #[pin] @@ -428,10 +441,13 @@ pub fn new<'a>( handler <- handler, inner <- Devres::new( request.dev, - try_pin_init!(RegistrationInner { - // INVARIANT: `this` is a valid pointer to the `ThreadedRegistration` instance. - cookie: this.as_ptr().cast::(), - irq: { + try_pin_init!(&inner_this in RegistrationInner { + irq: request.irq, + dev: request.dev.into(), + // SAFETY: `this` is a valid pointer to the `ThreadedRegistration` instance. + handler: unsafe { &raw const (*this.as_ptr()).handler }.cast(), + _pin: PhantomPinned, + _: { // SAFETY: // - The callbacks are valid for use with request_threaded_irq. // - If this succeeds, the slot is guaranteed to be valid until the @@ -447,11 +463,10 @@ pub fn new<'a>( Some(thread_fn_callback::), flags.into_inner(), name.as_char_ptr(), - this.as_ptr().cast::(), + inner_this.as_ptr().cast::(), ) })?; - request.irq - } + }, }) ), _pin: PhantomPinned, @@ -487,13 +502,15 @@ pub fn synchronize(&self, dev: &Device) -> Result { _irq: i32, ptr: *mut c_void, ) -> c_uint { - // SAFETY: `ptr` is a pointer to `ThreadedRegistration` set in `ThreadedRegistration::new` - let registration = unsafe { &*(ptr as *const ThreadedRegistration) }; + // SAFETY: `ptr` is a pointer to `RegistrationInner` set in `ThreadedRegistration::new` + let inner = unsafe { &*(ptr as *const RegistrationInner) }; + // SAFETY: `inner.handler` is a pointer to `T` set in `ThreadedRegistration::new` + let handler = unsafe { &*inner.handler.cast::() }; // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq // callback is running implies that the device has not yet been unbound. - let device = unsafe { registration.inner.device().as_bound() }; + let device = unsafe { inner.dev.as_bound() }; - T::handle(®istration.handler, device) as c_uint + T::handle(handler, device) as c_uint } /// # Safety @@ -503,11 +520,13 @@ pub fn synchronize(&self, dev: &Device) -> Result { _irq: i32, ptr: *mut c_void, ) -> c_uint { - // SAFETY: `ptr` is a pointer to `ThreadedRegistration` set in `ThreadedRegistration::new` - let registration = unsafe { &*(ptr as *const ThreadedRegistration) }; + // SAFETY: `ptr` is a pointer to `RegistrationInner` set in `ThreadedRegistration::new` + let inner = unsafe { &*(ptr as *const RegistrationInner) }; + // SAFETY: `inner.handler` is a pointer to `T` set in `ThreadedRegistration::new` + let handler = unsafe { &*inner.handler.cast::() }; // SAFETY: The irq callback is removed before the device is unbound, so the fact that the irq // callback is running implies that the device has not yet been unbound. - let device = unsafe { registration.inner.device().as_bound() }; + let device = unsafe { inner.dev.as_bound() }; - T::handle_threaded(®istration.handler, device) as c_uint + T::handle_threaded(handler, device) as c_uint } diff --git a/sound/core/seq/seq_compat.c b/sound/core/seq/seq_compat.c index 643af4c1e838..ee9bfdf781b1 100644 --- a/sound/core/seq/seq_compat.c +++ b/sound/core/seq/seq_compat.c @@ -44,7 +44,9 @@ static int snd_seq_call_port_info_ioctl(struct snd_seq_client *client, unsigned return -EFAULT; data->kernel = NULL; - err = snd_seq_kernel_client_ctl(client->number, cmd, data); + scoped_guard(mutex, &client->ioctl_mutex) { + err = snd_seq_kernel_client_ctl(client->number, cmd, data); + } if (err < 0) return err; diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index 681cdb00a11d..6bf500c0b5f9 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -7236,7 +7236,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x3ef0, "ASUS Strix G635LR_LW_LX", ALC287_FIXUP_TXNW2781_I2C), SND_PCI_QUIRK(0x1043, 0x3f00, "ASUS Strix G815LH_LM_LP", ALC287_FIXUP_TXNW2781_I2C), SND_PCI_QUIRK(0x1043, 0x3f10, "ASUS Strix G835LR_LW_LX", ALC287_FIXUP_TXNW2781_I2C), - SND_PCI_QUIRK(0x1043, 0x3f20, "ASUS Strix G615LR_LW", ALC287_FIXUP_TXNW2781_I2C), + SND_PCI_QUIRK(0x1043, 0x3f20, "ASUS Strix G615LR_LW", ALC287_FIXUP_TXNW2781_I2C_ASUS), SND_PCI_QUIRK(0x1043, 0x3f30, "ASUS Strix G815LR_LW", ALC287_FIXUP_TXNW2781_I2C), SND_PCI_QUIRK(0x1043, 0x3fd0, "ASUS B3605CVA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x3ff0, "ASUS B5405CVA", ALC245_FIXUP_CS35L41_SPI_2), @@ -7259,6 +7259,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN), SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE), + SND_PCI_QUIRK(0x10ec, 0x111e, "Higole F9B", ALC290_FIXUP_MONO_SPEAKERS), SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE), SND_PCI_QUIRK(0x10ec, 0x119e, "Positivo SU C1400", ALC269_FIXUP_ASPIRE_HEADSET_MIC), SND_PCI_QUIRK(0x10ec, 0x11bc, "VAIO VJFE-IL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), diff --git a/sound/hda/controllers/tegra.c b/sound/hda/controllers/tegra.c index 6ab338f37db5..d7f2eb80763c 100644 --- a/sound/hda/controllers/tegra.c +++ b/sound/hda/controllers/tegra.c @@ -374,7 +374,8 @@ static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) * in powers of 2, next available ratio is 16 which can be * used as a limiting factor here. */ - if (of_device_is_compatible(np, "nvidia,tegra30-hda")) + if (of_device_is_compatible(np, "nvidia,tegra30-hda") || + of_device_is_compatible(np, "nvidia,tegra194-hda")) chip->bus.core.sdo_limit = 16; /* codec detection */ diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index e20f6bfcbdb8..376df1aa497b 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -2523,7 +2523,7 @@ static int snd_ice1712_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; - struct snd_card *card __free(snd_card_unref) = NULL; + struct snd_card *card __free(snd_card_free) = NULL; struct snd_ice1712 *ice; int pcm_dev = 0, err; const struct snd_ice1712_card_info * const *tbl, *c; diff --git a/sound/soc/codecs/max98363.c b/sound/soc/codecs/max98363.c index 25af78ab30d5..259c51a16f01 100644 --- a/sound/soc/codecs/max98363.c +++ b/sound/soc/codecs/max98363.c @@ -204,7 +204,7 @@ static int max98363_sdw_dai_hw_params(struct snd_pcm_substream *substream, struct max98363_priv *max98363 = snd_soc_component_get_drvdata(component); - struct sdw_stream_config stream_config; + struct sdw_stream_config stream_config = {0}; struct sdw_port_config port_config; enum sdw_data_direction direction; struct sdw_stream_runtime *stream; diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c index a9c000876be8..7a7321fbb283 100644 --- a/sound/soc/codecs/rt1017-sdca-sdw.c +++ b/sound/soc/codecs/rt1017-sdca-sdw.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -574,11 +575,10 @@ static int rt1017_sdca_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct rt1017_sdca_priv *rt1017 = snd_soc_component_get_drvdata(component); - struct sdw_stream_config stream_config; + struct sdw_stream_config stream_config = {0}; struct sdw_port_config port_config; - enum sdw_data_direction direction; struct sdw_stream_runtime *sdw_stream; - int retval, port, num_channels, ch_mask; + int retval, port; unsigned int sampling_rate; dev_dbg(dai->dev, "%s %s", __func__, dai->name); @@ -592,28 +592,17 @@ static int rt1017_sdca_pcm_hw_params(struct snd_pcm_substream *substream, /* SoundWire specific configuration */ /* port 1 for playback */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - direction = SDW_DATA_DIR_RX; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) port = 1; - } else { - direction = SDW_DATA_DIR_TX; + else port = 2; - } - - num_channels = params_channels(params); - ch_mask = (1 << num_channels) - 1; - - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = num_channels; - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = direction; - port_config.ch_mask = ch_mask; + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); port_config.num = port; dev_dbg(dai->dev, "frame_rate %d, ch_count %d, bps %d, direction %d, ch_mask %d, port: %d\n", - params_rate(params), num_channels, snd_pcm_format_width(params_format(params)), - direction, ch_mask, port); + stream_config.frame_rate, stream_config.ch_count, stream_config.bps, + stream_config.direction, port_config.ch_mask, port); retval = sdw_stream_add_slave(rt1017->sdw_slave, &stream_config, &port_config, 1, sdw_stream); diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index 2c055c45111f..ea0639dae86c 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -619,9 +619,11 @@ static int rt274_hw_params(struct snd_pcm_substream *substream, unsigned int val = 0; int d_len_code = 0, c_len_code = 0; + /* bit 14 Sample Rate Base, 0: 48kHz 1: 44.1kHz */ switch (params_rate(params)) { - /* bit 14 0:48K 1:44.1K */ case 44100: + val |= BIT(14); + break; case 48000: break; default: diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index fd8de8b49793..7b70e0dd923d 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -951,7 +951,7 @@ static int rt286_probe(struct snd_soc_component *component) if (rt286->i2c->irq) schedule_delayed_work(&rt286->jack_detect_work, - msecs_to_jiffies(50)); + msecs_to_jiffies(1250)); return 0; } diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index f7d726e3052c..e9858aaf6ca8 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -677,7 +677,7 @@ SOC_ENUM("DRC Decay Rate", drc_decay), SOC_ENUM("DRC FF Delay", drc_ff_delay), SOC_SINGLE("DRC Anticlip Switch", WM8903_DRC_0, 1, 1, 0), SOC_SINGLE("DRC QR Switch", WM8903_DRC_0, 2, 1, 0), -SOC_SINGLE_TLV("DRC QR Threshold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max), +SOC_SINGLE_TLV("DRC QR Threshold Volume", WM8903_DRC_1, 6, 3, 0, drc_tlv_max), SOC_ENUM("DRC QR Decay Rate", drc_qr_decay), SOC_SINGLE("DRC Smoothing Switch", WM8903_DRC_0, 3, 1, 0), SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8903_DRC_0, 0, 1, 0), diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 242bc16da36d..079177a6d81e 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -1234,8 +1234,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) } if (drvdata->mi2s_playback_sd_mode[dai_id] == LPAIF_I2SCTL_MODE_QUAD01) { - variant->dai_driver[dai_id].playback.channels_min = 4; - variant->dai_driver[dai_id].playback.channels_max = 4; + variant->dai_driver[i].playback.channels_min = 4; + variant->dai_driver[i].playback.channels_max = 4; } } diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index fd0092eb7924..03cb4a8c79b4 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -943,7 +943,7 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai_link_ch_map *ch_maps; int ch = params_channels(params); - unsigned int ch_mask; + unsigned int cpu_ch_mask, codec_ch_mask; int num_codecs; int step; int i; @@ -953,8 +953,9 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream, /* Identical data will be sent to all codecs in playback */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ch_mask = GENMASK(ch - 1, 0); + cpu_ch_mask = GENMASK(ch - 1, 0); step = 0; + codec_ch_mask = 0; } else { num_codecs = rtd->dai_link->num_codecs; @@ -964,17 +965,24 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - ch_mask = GENMASK(ch / num_codecs - 1, 0); - step = hweight_long(ch_mask); + cpu_ch_mask = GENMASK(ch / num_codecs - 1, 0); + step = hweight_long(cpu_ch_mask); + codec_ch_mask = cpu_ch_mask; } /* * The captured data will be combined from each cpu DAI if the dai * link has more than one codec DAIs. Set codec channel mask and * ASoC will set the corresponding channel numbers for each cpu dai. + * + * sdw_stream_add_slave() assigns different payload offsets to each + * codec in a capture stream, so that the same channels on each + * codec map to different channels on the CPU. */ - for_each_link_ch_maps(rtd->dai_link, i, ch_maps) - ch_maps->cpu_ch_mask = ch_mask << (i * step); + for_each_link_ch_maps(rtd->dai_link, i, ch_maps) { + ch_maps->cpu_ch_mask = cpu_ch_mask << (i * step); + ch_maps->codec_ch_mask = codec_ch_mask; + } return 0; } diff --git a/sound/soc/tegra/tegra186_asrc.c b/sound/soc/tegra/tegra186_asrc.c index 851509ae07f5..fae24046a54f 100644 --- a/sound/soc/tegra/tegra186_asrc.c +++ b/sound/soc/tegra/tegra186_asrc.c @@ -829,7 +829,7 @@ static const struct snd_kcontrol_new tegra186_asrc_controls[] = { tegra186_asrc_put_input_threshold), SOC_SINGLE_EXT("Stream6 Input Threshold", - ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 4), 0, 3, 0, + ASRC_STREAM_REG(TEGRA186_ASRC_RX_THRESHOLD, 5), 0, 3, 0, tegra186_asrc_get_input_threshold, tegra186_asrc_put_input_threshold), diff --git a/sound/usb/caiaq/device.c b/sound/usb/caiaq/device.c index 3d821fde4582..f604846ec6e6 100644 --- a/sound/usb/caiaq/device.c +++ b/sound/usb/caiaq/device.c @@ -562,6 +562,9 @@ static int snd_probe(struct usb_interface *intf, ret = init_card(caiaqdev(card)); if (ret < 0) { dev_err(&usb_dev->dev, "unable to init card! (ret=%d)\n", ret); +#ifdef CONFIG_SND_USB_CAIAQ_INPUT + snd_usb_caiaq_input_disconnect(caiaqdev(card)); +#endif snd_card_free(card); return ret; } diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c index 9f26f66e6792..2e70ca5456c5 100644 --- a/sound/usb/line6/playback.c +++ b/sound/usb/line6/playback.c @@ -182,6 +182,13 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) fsize *= bytes_per_frame; + if (fsize > line6pcm->max_packet_size_out) { + dev_err(line6pcm->line6->ifcdev, + "playback packet too large: %d > %d\n", + fsize, line6pcm->max_packet_size_out); + return -EMSGSIZE; + } + fout->offset = urb_size; fout->length = fsize; urb_size += fsize; diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index 586ef13097a3..426171aa6dd2 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -1002,6 +1002,15 @@ static int detect_usb_format(struct ua101 *ua) } ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd)); ua->playback.max_packet_bytes = usb_endpoint_maxp(epd); + + if (ua->capture.max_packet_bytes / ua->capture.frame_bytes * + ua->playback.frame_bytes > ua->playback.max_packet_bytes) { + dev_err(&ua->dev->dev, + "playback packet size %u too small for %u capture frames\n", + ua->playback.max_packet_bytes, + ua->capture.max_packet_bytes / ua->capture.frame_bytes); + return -ENXIO; + } return 0; } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 860257cc7245..b08e07324f83 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -2381,8 +2381,6 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_SET_IFACE_FIRST), DEVICE_FLG(0x262a, 0x9302, /* ddHiFi TC44C */ 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 */ @@ -2457,6 +2455,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = { QUIRK_FLAG_DSD_RAW), VENDOR_FLG(0x2622, /* IAG Limited devices */ QUIRK_FLAG_DSD_RAW), + VENDOR_FLG(0x2708, /* Audient devices */ + QUIRK_FLAG_IGNORE_CTL_ERROR), VENDOR_FLG(0x2772, /* Musical Fidelity devices */ QUIRK_FLAG_DSD_RAW), VENDOR_FLG(0x278b, /* Rotel? */ diff --git a/tools/testing/selftests/mm/hugepage-mremap.c b/tools/testing/selftests/mm/hugepage-mremap.c index 928c1045e295..d6caa075a86a 100644 --- a/tools/testing/selftests/mm/hugepage-mremap.c +++ b/tools/testing/selftests/mm/hugepage-mremap.c @@ -97,6 +97,7 @@ static void register_region_with_uffd(char *addr, size_t len) int main(int argc, char *argv[]) { + unsigned long hugepage_size; size_t length = 0; int ret = 0, fd; @@ -114,7 +115,11 @@ int main(int argc, char *argv[]) else length = DEFAULT_LENGTH_MB; + hugepage_size = default_huge_page_size(); + if (!hugepage_size) + ksft_exit_skip("Could not detect default hugetlb page size\n"); length = MB_TO_BYTES(length); + length = (length + hugepage_size - 1) & ~(hugepage_size - 1); fd = memfd_create(argv[0], MFD_HUGETLB); if (fd < 0) ksft_exit_fail_msg("Open failed: %s\n", strerror(errno));