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 BE9693890E4; Fri, 25 Sep 2026 14:46:09 +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=1790347613; cv=none; b=B6/Ha1Z3ha3VfPYmgk8JF6n0It1ESWcThoMX2cQ1bXcnYQzO6kSZro9BJymxPTvDiYfJaWsOshqfc/eiBjAaq7kxXZYQURZC+1w1Z2qa4VYKq/bKYVy72FOujZJa+ddlT5LU1e1Je0J9tcrOIjiaxH+Syu673rBrFASgBTwBM7Q= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790347613; c=relaxed/simple; bh=9mJFxXs6+rg7vRyMYT/3X8k4U2WZtwwSwriSNI9CibA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=JjVix1ddoH37tJLWpYKNdtjFpPkP6IWKj1yYsKZkiDcaChnQ8Q3YHRYTcII2TMcOa87xqs/KVdf1Jj0fXWq6LlIR7kjv8he3jsjAyF5o2pic713ajiBSSGfHBZebieiHV2DtpkujYxuM7j4PhEY9SkFKz6XLXBcLS5Xo+9TlWKs= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=BWtX/eTS; 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="BWtX/eTS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4D18E1F00899; Fri, 25 Sep 2026 14:46:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1790347568; bh=2x+6omvdU2F53dbgJPUS3nJi2r3Qo9qUAMQFTQnQ+Go=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=BWtX/eTSgF4eHmZoukQS/PfvUPsNpJasPM1UW9nTXAgWatZ8A0fIgr8Yn+jNfxoyr RqubzMgZ+uYgaNkq8IfgWmF8dGBOhVjXdjNZdXYZRi7BHLg+av2Yt9ffE1SLznFFi9 eZjTuLzqeEVA7KytRODYwbGdPktzG9BrxxZNPYeA= 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.54 Date: Fri, 25 Sep 2026 16:45:56 +0200 Message-ID: <2026092556-tiptop-dislocate-c2cb@gregkh> X-Mailer: git-send-email 2.55.0 In-Reply-To: <2026092556-opulently-lantern-c4b0@gregkh> References: <2026092556-opulently-lantern-c4b0@gregkh> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit diff --git a/Documentation/ABI/testing/sysfs-devices-platform-trackpoint b/Documentation/ABI/testing/sysfs-devices-platform-trackpoint index df11901a6b3d..7954434b0434 100644 --- a/Documentation/ABI/testing/sysfs-devices-platform-trackpoint +++ b/Documentation/ABI/testing/sysfs-devices-platform-trackpoint @@ -5,7 +5,7 @@ Contact: linux-input@vger.kernel.org Description: (RW) Trackpoint sensitivity. -What: /sys/devices/platform/i8042/.../intertia +What: /sys/devices/platform/i8042/.../inertia Date: Aug, 2005 KernelVersion: 2.6.14 Contact: linux-input@vger.kernel.org diff --git a/Documentation/hwmon/cgbc-hwmon.rst b/Documentation/hwmon/cgbc-hwmon.rst index 3a5e6e6e8639..c6d09232392a 100644 --- a/Documentation/hwmon/cgbc-hwmon.rst +++ b/Documentation/hwmon/cgbc-hwmon.rst @@ -28,34 +28,44 @@ system. Name Description ============= ====================== temp1_input CPU temperature -temp2_input Box temperature +temp2_input Case temperature temp3_input Ambient temperature -temp4_input Board temperature -temp5_input Carrier temperature -temp6_input Chipset temperature -temp7_input Video temperature +temp4_input CPU Board temperature +temp5_input Carrier Board temperature +temp6_input System Chipset temperature +temp7_input Video Controller/Board temperature temp8_input Other temperature -temp9_input TOPDIM temperature -temp10_input BOTTOMDIM temperature -in0_input CPU voltage +temp9_input Top DIMM 0 temperature +temp10_input Bottom DIMM 0 temperature +temp11_input Alternate Board temperature +temp12_input Top DIMM 1 temperature +temp13_input Top DIMM 2 temperature +temp14_input Top DIMM 3 temperature +temp15_input Top DIMM 4 temperature +temp16_input Top DIMM 5 temperature +temp17_input Top DIMM 6 temperature +temp18_input Top DIMM 7 temperature +temp19_input Bottom DIMM 1 temperature +in0_input CPU Core voltage in1_input DC Runtime voltage in2_input DC Standby voltage in3_input CMOS Battery voltage -in4_input Battery voltage +in4_input Battery Supply voltage in5_input AC voltage in6_input Other voltage -in7_input 5V voltage +in7_input 5V Runtime voltage in8_input 5V Standby voltage -in9_input 3V3 voltage +in9_input 3V3 Runtime voltage in10_input 3V3 Standby voltage in11_input VCore A voltage in12_input VCore B voltage -in13_input 12V voltage -curr1_input DC current -curr2_input 5V current -curr3_input 12V current +in13_input 12V Runtime voltage +in14_input 12V Standby voltage +curr1_input DC Runtime current +curr2_input 5V Runtime current +curr3_input 12V Runtime current fan1_input CPU fan -fan2_input Box fan +fan2_input Case fan fan3_input Ambient fan fan4_input Chiptset fan fan5_input Video fan diff --git a/Documentation/netlink/specs/rt-neigh.yaml b/Documentation/netlink/specs/rt-neigh.yaml index 2f568a6231c9..e366e958234e 100644 --- a/Documentation/netlink/specs/rt-neigh.yaml +++ b/Documentation/netlink/specs/rt-neigh.yaml @@ -341,6 +341,9 @@ attribute-sets: - name: interval-probe-time-ms type: u64 + checks: + min: 1 + max: 86400000 operations: enum-model: directional diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst index 7a637e87005f..27a861053b2f 100644 --- a/Documentation/networking/ip-sysctl.rst +++ b/Documentation/networking/ip-sysctl.rst @@ -230,7 +230,7 @@ neigh/default/unres_qlen - INTEGER neigh/default/interval_probe_time_ms - INTEGER The probe interval for neighbor entries with NTF_MANAGED flag, - the min value is 1. + the min value is 1, and the max value is 86400000 (1 day). Default: 5000 @@ -844,6 +844,8 @@ tcp_rmem - vector of 3 INTEGERs: min, default, max case this value is ignored. Default: between 131072 and 32MB, depending on RAM size. + Each of the three values cannot be set below 4096. + tcp_sack - BOOLEAN Enable select acknowledgments (SACKS). diff --git a/Makefile b/Makefile index f1562b84fb2e..56bb2168e656 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 18 -SUBLEVEL = 53 +SUBLEVEL = 54 EXTRAVERSION = NAME = Baby Opossum Posse diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig index eb72c240c248..528c5c1368c3 100644 --- a/arch/arm/mach-socfpga/Kconfig +++ b/arch/arm/mach-socfpga/Kconfig @@ -16,7 +16,7 @@ menuconfig ARCH_INTEL_SOCFPGA select ARM_ERRATA_775420 select PL310_ERRATA_588369 select PL310_ERRATA_727915 - select PL310_ERRATA_753970 if PL310 + select PL310_ERRATA_753970 select PL310_ERRATA_769419 select RESET_CONTROLLER diff --git a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi index b496495c59a6..7a5f5e31ea13 100644 --- a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi @@ -891,6 +891,7 @@ ufs: ufs@e6860000 { clocks = <&cpg CPG_MOD 1514>, <&ufs30_clk>; clock-names = "fck", "ref_clk"; freq-table-hz = <200000000 200000000>, <38400000 38400000>; + lanes-per-direction = <1>; power-domains = <&sysc R8A779F0_PD_ALWAYS_ON>; resets = <&cpg 1514>; status = "disabled"; diff --git a/arch/arm64/boot/dts/renesas/r9a09g047.dtsi b/arch/arm64/boot/dts/renesas/r9a09g047.dtsi index 47d843c79021..603810ed3947 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g047.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g047.dtsi @@ -973,23 +973,28 @@ queue3 { mtl_tx_setup0: tx-queues-config { snps,tx-queues-to-use = <4>; + snps,tx-sched-wrr; queue0 { + snps,weight = <0x10>; snps,dcb-algorithm; snps,priority = <0x1>; }; queue1 { + snps,weight = <0x12>; snps,dcb-algorithm; snps,priority = <0x2>; }; queue2 { + snps,weight = <0x14>; snps,dcb-algorithm; snps,priority = <0x4>; }; queue3 { + snps,weight = <0x18>; snps,dcb-algorithm; snps,priority = <0x8>; }; @@ -1073,23 +1078,28 @@ queue3 { mtl_tx_setup1: tx-queues-config { snps,tx-queues-to-use = <4>; + snps,tx-sched-wrr; queue0 { + snps,weight = <0x10>; snps,dcb-algorithm; snps,priority = <0x1>; }; queue1 { + snps,weight = <0x12>; snps,dcb-algorithm; snps,priority = <0x2>; }; queue2 { + snps,weight = <0x14>; snps,dcb-algorithm; snps,priority = <0x4>; }; queue3 { + snps,weight = <0x18>; snps,dcb-algorithm; snps,priority = <0x8>; }; diff --git a/arch/arm64/boot/dts/renesas/r9a09g056.dtsi b/arch/arm64/boot/dts/renesas/r9a09g056.dtsi index 887110878906..cde453fd35e2 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g056.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g056.dtsi @@ -827,23 +827,28 @@ queue3 { mtl_tx_setup0: tx-queues-config { snps,tx-queues-to-use = <4>; + snps,tx-sched-wrr; queue0 { + snps,weight = <0x10>; snps,dcb-algorithm; snps,priority = <0x1>; }; queue1 { + snps,weight = <0x12>; snps,dcb-algorithm; snps,priority = <0x2>; }; queue2 { + snps,weight = <0x14>; snps,dcb-algorithm; snps,priority = <0x4>; }; queue3 { + snps,weight = <0x18>; snps,dcb-algorithm; snps,priority = <0x8>; }; @@ -928,23 +933,28 @@ queue3 { mtl_tx_setup1: tx-queues-config { snps,tx-queues-to-use = <4>; + snps,tx-sched-wrr; queue0 { + snps,weight = <0x10>; snps,dcb-algorithm; snps,priority = <0x1>; }; queue1 { + snps,weight = <0x12>; snps,dcb-algorithm; snps,priority = <0x2>; }; queue2 { + snps,weight = <0x14>; snps,dcb-algorithm; snps,priority = <0x4>; }; queue3 { + snps,weight = <0x18>; snps,dcb-algorithm; snps,priority = <0x8>; }; diff --git a/arch/arm64/boot/dts/renesas/r9a09g057.dtsi b/arch/arm64/boot/dts/renesas/r9a09g057.dtsi index 100d5cab9b12..dc41290ed9c5 100644 --- a/arch/arm64/boot/dts/renesas/r9a09g057.dtsi +++ b/arch/arm64/boot/dts/renesas/r9a09g057.dtsi @@ -1160,23 +1160,28 @@ queue3 { mtl_tx_setup0: tx-queues-config { snps,tx-queues-to-use = <4>; + snps,tx-sched-wrr; queue0 { + snps,weight = <0x10>; snps,dcb-algorithm; snps,priority = <0x1>; }; queue1 { + snps,weight = <0x12>; snps,dcb-algorithm; snps,priority = <0x2>; }; queue2 { + snps,weight = <0x14>; snps,dcb-algorithm; snps,priority = <0x4>; }; queue3 { + snps,weight = <0x18>; snps,dcb-algorithm; snps,priority = <0x8>; }; @@ -1261,23 +1266,28 @@ queue3 { mtl_tx_setup1: tx-queues-config { snps,tx-queues-to-use = <4>; + snps,tx-sched-wrr; queue0 { + snps,weight = <0x10>; snps,dcb-algorithm; snps,priority = <0x1>; }; queue1 { + snps,weight = <0x12>; snps,dcb-algorithm; snps,priority = <0x2>; }; queue2 { + snps,weight = <0x14>; snps,dcb-algorithm; snps,priority = <0x4>; }; queue3 { + snps,weight = <0x18>; snps,dcb-algorithm; snps,priority = <0x8>; }; diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index b57b2bb00967..8cf4068ce1b5 100644 --- a/arch/arm64/include/asm/percpu.h +++ b/arch/arm64/include/asm/percpu.h @@ -77,7 +77,7 @@ __percpu_##name##_case_##sz(void *ptr, unsigned long val) \ " stxr" #sfx "\t%w[loop], %" #w "[tmp], %[ptr]\n" \ " cbnz %w[loop], 1b", \ /* LSE atomics */ \ - #op_lse "\t%" #w "[val], %" #w "[tmp], %[ptr]\n" \ + #op_lse #sfx "\t%" #w "[val], %" #w "[tmp], %[ptr]\n" \ __nops(3)) \ : [loop] "=&r" (loop), [tmp] "=&r" (tmp), \ [ptr] "+Q"(*(u##sz *)ptr) \ @@ -98,7 +98,7 @@ __percpu_##name##_return_case_##sz(void *ptr, unsigned long val) \ " stxr" #sfx "\t%w[loop], %" #w "[ret], %[ptr]\n" \ " cbnz %w[loop], 1b", \ /* LSE atomics */ \ - #op_lse "\t%" #w "[val], %" #w "[ret], %[ptr]\n" \ + #op_lse #sfx "\t%" #w "[val], %" #w "[ret], %[ptr]\n" \ #op_llsc "\t%" #w "[ret], %" #w "[ret], %" #w "[val]\n" \ __nops(2)) \ : [loop] "=&r" (loop), [ret] "=&r" (ret), \ @@ -179,13 +179,13 @@ PERCPU_RET_OP(add, add, ldadd) _pcp_protect_return(__percpu_read_64, pcp) #define this_cpu_write_1(pcp, val) \ - _pcp_protect(__percpu_write_8, pcp, (unsigned long)val) + _pcp_protect(__percpu_write_8, pcp, (unsigned long)(val)) #define this_cpu_write_2(pcp, val) \ - _pcp_protect(__percpu_write_16, pcp, (unsigned long)val) + _pcp_protect(__percpu_write_16, pcp, (unsigned long)(val)) #define this_cpu_write_4(pcp, val) \ - _pcp_protect(__percpu_write_32, pcp, (unsigned long)val) + _pcp_protect(__percpu_write_32, pcp, (unsigned long)(val)) #define this_cpu_write_8(pcp, val) \ - _pcp_protect(__percpu_write_64, pcp, (unsigned long)val) + _pcp_protect(__percpu_write_64, pcp, (unsigned long)(val)) #define this_cpu_add_1(pcp, val) \ _pcp_protect(__percpu_add_case_8, pcp, val) @@ -206,13 +206,13 @@ PERCPU_RET_OP(add, add, ldadd) _pcp_protect_return(__percpu_add_return_case_64, pcp, val) #define this_cpu_and_1(pcp, val) \ - _pcp_protect(__percpu_andnot_case_8, pcp, ~val) + _pcp_protect(__percpu_andnot_case_8, pcp, ~(u8)(val)) #define this_cpu_and_2(pcp, val) \ - _pcp_protect(__percpu_andnot_case_16, pcp, ~val) + _pcp_protect(__percpu_andnot_case_16, pcp, ~(u16)(val)) #define this_cpu_and_4(pcp, val) \ - _pcp_protect(__percpu_andnot_case_32, pcp, ~val) + _pcp_protect(__percpu_andnot_case_32, pcp, ~(u32)(val)) #define this_cpu_and_8(pcp, val) \ - _pcp_protect(__percpu_andnot_case_64, pcp, ~val) + _pcp_protect(__percpu_andnot_case_64, pcp, ~(u64)(val)) #define this_cpu_or_1(pcp, val) \ _pcp_protect(__percpu_or_case_8, pcp, val) diff --git a/arch/arm64/kernel/hibernate-asm.S b/arch/arm64/kernel/hibernate-asm.S index 0e1d9c3c6a93..2baefe7a82d3 100644 --- a/arch/arm64/kernel/hibernate-asm.S +++ b/arch/arm64/kernel/hibernate-asm.S @@ -89,6 +89,8 @@ alternative_insn "dc cvau, x4", "dc civac, x4", ARM64_WORKAROUND_CLEAN_CACHE isb cbz x24, 3f /* Do we need to re-initialise EL2? */ + mov x1, x24 + mov x0, #HVC_SET_VECTORS hvc #0 3: ret SYM_CODE_END(swsusp_arch_suspend_exit) diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index 7bf117427777..424291c547f0 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -423,8 +423,8 @@ int __nocfi swsusp_arch_resume(void) * Create a second copy of just the linear map, and use this when * restoring. */ - rc = trans_pgd_create_copy(&trans_info, &tmp_pg_dir, PAGE_OFFSET, - PAGE_END); + rc = trans_pgd_create_copy(&trans_info, &tmp_pg_dir, + _PAGE_OFFSET(vabits_actual), PAGE_END); if (rc) return rc; diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c index 47677b5d7ed0..f53c98372e0b 100644 --- a/arch/mips/cavium-octeon/octeon-platform.c +++ b/arch/mips/cavium-octeon/octeon-platform.c @@ -18,7 +18,7 @@ #include #include -#ifdef CONFIG_USB +#if IS_ENABLED(CONFIG_USB) #include #include #include @@ -1080,7 +1080,7 @@ int __init octeon_prune_device_tree(void) ; } -#ifdef CONFIG_USB +#if IS_ENABLED(CONFIG_USB) /* OHCI/UHCI USB */ alias_prop = fdt_getprop(initial_boot_params, aliases, "uctl", NULL); diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 244eb4857e7f..0a7d14f651e8 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -1075,7 +1075,7 @@ int iommu_tce_check_ioba(unsigned long page_shift, if (ioba < offset) return -EINVAL; - if ((ioba + 1) > (offset + size)) + if ((ioba + npages < ioba) || (ioba - offset + npages > size)) return -EINVAL; return 0; diff --git a/arch/powerpc/kvm/book3s_hv_nested.c b/arch/powerpc/kvm/book3s_hv_nested.c index 5f8c2321cfb5..7b10caa3424c 100644 --- a/arch/powerpc/kvm/book3s_hv_nested.c +++ b/arch/powerpc/kvm/book3s_hv_nested.c @@ -1204,8 +1204,10 @@ static void kvmhv_emulate_tlbie_all_lpid(struct kvm_vcpu *vcpu, int ric) spin_lock(&kvm->mmu_lock); idr_for_each_entry(&kvm->arch.kvm_nested_guest_idr, gp, lpid) { + ++gp->refcnt; spin_unlock(&kvm->mmu_lock); kvmhv_emulate_tlbie_lpid(vcpu, gp, ric); + kvmhv_put_nested(gp); spin_lock(&kvm->mmu_lock); } spin_unlock(&kvm->mmu_lock); diff --git a/arch/powerpc/kvm/book3s_hv_uvmem.c b/arch/powerpc/kvm/book3s_hv_uvmem.c index 03f8c34fa0a2..01ab5c653d7c 100644 --- a/arch/powerpc/kvm/book3s_hv_uvmem.c +++ b/arch/powerpc/kvm/book3s_hv_uvmem.c @@ -779,8 +779,11 @@ static int kvmppc_svm_page_in(struct vm_area_struct *vma, if (spage) { ret = uv_page_in(kvm->arch.lpid, pfn << page_shift, gpa, 0, page_shift); - if (ret) + if (ret) { + unlock_page(dpage); + put_page(dpage); goto out_finalize; + } } } diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 755d64bb9d26..d8ee9ee52068 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -255,10 +255,21 @@ config CC_HAS_MARCH_NATIVE # usage warnings that only appear wth '-march=native'. depends on CC_IS_GCC || CLANG_VERSION >= 190100 +config RUSTC_HAS_APXF + # The kernel isn't ready for in-kernel APX instructions. Without + # explicit frontend gating of APX, the backend may emit those + # instructions in native builds. + # + # Rust 1.88 added the `apxf` feature option, but versions before 1.93 + # emit an `apxf` target attribute that only LLVM 23+ can interpret. + def_bool (RUSTC_VERSION >= 108800 && RUSTC_LLVM_MAJOR_VERSION >= 23) || \ + RUSTC_VERSION >= 109300 + config X86_NATIVE_CPU bool "Build and optimize for local/native CPU" depends on X86_64 depends on CC_HAS_MARCH_NATIVE + depends on !RUST || RUSTC_HAS_APXF help Optimize for the current CPU used to compile the kernel. Use this option if you intend to build the kernel for your diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 5aa6d5f4c197..9f3553263f7b 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -168,6 +168,11 @@ else ifdef CONFIG_X86_NATIVE_CPU KBUILD_CFLAGS += -march=native + # Prevent the compiler from generating EGPR use. The kernel is + # not yet prepared for general in-kernel use. + KBUILD_CFLAGS += $(call cc-option,-mno-apx-features=egpr) + + # generate_rust_target.rs handles Rust APX gating. KBUILD_RUSTFLAGS += -Ctarget-cpu=native else KBUILD_CFLAGS += -march=x86-64 -mtune=generic diff --git a/arch/x86/entry/entry_fred.c b/arch/x86/entry/entry_fred.c index 9f50f0c1c00f..c43c750fa26d 100644 --- a/arch/x86/entry/entry_fred.c +++ b/arch/x86/entry/entry_fred.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -71,7 +72,15 @@ static noinstr void fred_intx(struct pt_regs *regs) #endif default: - return exc_general_protection(regs, 0); + /* + * Reconstruct the #GP fault state that IDT delivery would produce. + * Clear the software event flag so ERETU with TF set does not trap + * before the resumed instruction. See prevent_single_step_upon_eretu(). + */ + regs->ip -= regs->fred_ss.insnlen; + regs->flags |= X86_EFLAGS_RF; + regs->fred_ss.swevent = 0; + return exc_general_protection(regs, (regs->fred_ss.vector << 3) | 2); } } diff --git a/arch/x86/include/asm/text-patching.h b/arch/x86/include/asm/text-patching.h index f2d142a0a862..ea09381070e8 100644 --- a/arch/x86/include/asm/text-patching.h +++ b/arch/x86/include/asm/text-patching.h @@ -164,9 +164,9 @@ unsigned long int3_emulate_pop(struct pt_regs *regs) } static __always_inline -void int3_emulate_call(struct pt_regs *regs, unsigned long func) +void int3_emulate_call(struct pt_regs *regs, unsigned long ip, unsigned long func) { - int3_emulate_push(regs, regs->ip - INT3_INSN_SIZE + CALL_INSN_SIZE); + int3_emulate_push(regs, ip); int3_emulate_jmp(regs, func); } diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 109a285cca51..9c980b4f1943 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -2266,21 +2266,34 @@ int alternatives_text_reserved(void *start, void *end) * See entry_{32,64}.S for more details. */ -/* - * We define the int3_magic() function in assembly to control the calling - * convention such that we can 'call' it from assembly. - */ +extern void int3_selftest_asm(unsigned int *ptr); + +asm ( +" .pushsection .init.text, \"ax\", @progbits\n" +" .type int3_selftest_asm, @function\n" +"int3_selftest_asm:\n" + ANNOTATE_NOENDBR + /* + * INT3 padded with NOP to CALL_INSN_SIZE. The INT3 triggers an + * exception, then the int3_exception_nb notifier emulates a call to + * int3_selftest_callee(). + */ +" int3; nop; nop; nop; nop\n" + ASM_RET +" .size int3_selftest_asm, . - int3_selftest_asm\n" +" .popsection\n" +); -extern void int3_magic(unsigned int *ptr); /* defined in asm */ +extern void int3_selftest_callee(unsigned int *ptr); asm ( " .pushsection .init.text, \"ax\", @progbits\n" -" .type int3_magic, @function\n" -"int3_magic:\n" +" .type int3_selftest_callee, @function\n" +"int3_selftest_callee:\n" ANNOTATE_NOENDBR -" movl $1, (%" _ASM_ARG1 ")\n" +" movl $0x1234, (%" _ASM_ARG1 ")\n" ASM_RET -" .size int3_magic, .-int3_magic\n" +" .size int3_selftest_callee, . - int3_selftest_callee\n" " .popsection\n" ); @@ -2289,9 +2302,10 @@ extern void int3_selftest_ip(void); /* defined in asm below */ static int __init int3_exception_notify(struct notifier_block *self, unsigned long val, void *data) { - unsigned long selftest = (unsigned long)&int3_selftest_ip; + unsigned long selftest = (unsigned long)&int3_selftest_asm; struct die_args *args = data; struct pt_regs *regs = args->regs; + unsigned long ip; OPTIMIZER_HIDE_VAR(selftest); @@ -2304,7 +2318,8 @@ int3_exception_notify(struct notifier_block *self, unsigned long val, void *data if (regs->ip - INT3_INSN_SIZE != selftest) return NOTIFY_DONE; - int3_emulate_call(regs, (unsigned long)&int3_magic); + ip = regs->ip - INT3_INSN_SIZE + CALL_INSN_SIZE; + int3_emulate_call(regs, ip, (unsigned long)&int3_selftest_callee); return NOTIFY_STOP; } @@ -2320,19 +2335,11 @@ static noinline void __init int3_selftest(void) BUG_ON(register_die_notifier(&int3_exception_nb)); /* - * Basically: int3_magic(&val); but really complicated :-) - * - * INT3 padded with NOP to CALL_INSN_SIZE. The int3_exception_nb - * notifier above will emulate CALL for us. + * Basically: int3_selftest_callee(&val); but really complicated :-) */ - asm volatile ("int3_selftest_ip:\n\t" - ANNOTATE_NOENDBR - " int3; nop; nop; nop; nop\n\t" - : ASM_CALL_CONSTRAINT - : __ASM_SEL_RAW(a, D) (&val) - : "memory"); + int3_selftest_asm(&val); - BUG_ON(val != 1); + BUG_ON(val != 0x1234); unregister_die_notifier(&int3_exception_nb); } @@ -2884,7 +2891,7 @@ noinstr int smp_text_poke_int3_handler(struct pt_regs *regs) break; case CALL_INSN_OPCODE: - int3_emulate_call(regs, (long)ip + tpl->disp); + int3_emulate_call(regs, (long)ip, (long)ip + tpl->disp); break; case JMP32_INSN_OPCODE: diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index 371ca6eac00e..9e014c9241f9 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c @@ -257,6 +257,26 @@ static void save_microcode_patch(struct microcode_intel *patch) pr_err("Unable to allocate microcode memory size: %u\n", size); } +static bool revision_is_safe(struct cpu_signature *sig, u32 rev) +{ + u32 vfm = IFM(x86_family(sig->sig), x86_model(sig->sig)); + + /* + * Erratum GNR98 can cause #MCs if "jumping over" revision 0x1000405. + * Avoid the jumps. + */ + if (vfm == INTEL_GRANITERAPIDS_X && + x86_stepping(sig->sig) == 1 && + sig->pf & 0x95 && + sig->rev < 0x1000405 && + rev > 0x1000405) { + pr_err_once("Erratum GNR98: skipping revision 0x%x.\n", rev); + return false; + } + + return true; +} + /* Scan blob for microcode matching the boot CPUs family, model, stepping */ static __init struct microcode_intel *scan_microcode(void *data, size_t size, struct ucode_cpu_info *uci, @@ -278,6 +298,9 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size, if (!intel_find_matching_signature(data, &uci->cpu_sig)) continue; + if (!revision_is_safe(&uci->cpu_sig, mc_header->rev)) + continue; + /* * For saving the early microcode, find the matching revision which * was loaded on the BSP. @@ -534,6 +557,9 @@ static enum ucode_state parse_microcode_blobs(int cpu, struct iov_iter *iter) if (!intel_find_matching_signature(mc, &uci->cpu_sig)) continue; + if (!revision_is_safe(&uci->cpu_sig, mc_header.rev)) + continue; + is_safe = ucode_validate_minrev(&mc_header); if (force_minrev && !is_safe) continue; diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 3863d7709386..95ab48b3b0f8 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -511,10 +511,9 @@ NOKPROBE_SYMBOL(kprobe_emulate_ret); static void kprobe_emulate_call(struct kprobe *p, struct pt_regs *regs) { - unsigned long func = regs->ip - INT3_INSN_SIZE + p->ainsn.size; + unsigned long ip = regs->ip - INT3_INSN_SIZE + p->ainsn.size; - func += p->ainsn.rel32; - int3_emulate_call(regs, func); + int3_emulate_call(regs, ip, ip + p->ainsn.rel32); } NOKPROBE_SYMBOL(kprobe_emulate_call); diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 06589bf488f7..1b4d2e11a1b1 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -166,7 +166,7 @@ static int __acpi_processor_start(struct acpi_device *device) if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS)) dev_dbg(&device->dev, "CPPC data invalid or not present\n"); - if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) + if (cpuidle_get_driver() == &acpi_idle_driver) acpi_processor_power_init(pr); acpi_pss_perf_init(pr); diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index c79abdfcd7a9..ecb56bb50fd7 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -748,15 +748,28 @@ void ahci_start_fis_rx(struct ata_port *ap) struct ahci_port_priv *pp = ap->private_data; u32 tmp; - /* set FIS registers */ + /* + * On HBAs that only support 32-bit addressing PxCLBU is read only '0'. + * When applying the AHCI_HFLAG_32BIT_ONLY quirk, PxCLBU is RW, and the + * reset value is Implementation Specific, so we need to clear it to 0. + */ if (hpriv->cap & HOST_CAP_64) writel((pp->cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI); + else if (hpriv->flags & AHCI_HFLAG_32BIT_ONLY) + writel(0, port_mmio + PORT_LST_ADDR_HI); writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); + /* + * On HBAs that only support 32-bit addressing PxFBU is read only '0'. + * When applying the AHCI_HFLAG_32BIT_ONLY quirk, PxFBU is RW, and the + * reset value is Implementation Specific, so we need to clear it to 0. + */ if (hpriv->cap & HOST_CAP_64) writel((pp->rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI); + else if (hpriv->flags & AHCI_HFLAG_32BIT_ONLY) + writel(0, port_mmio + PORT_FIS_ADDR_HI); writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR); /* enable FIS reception */ diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 91d44302eac9..7308d48cf748 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -623,10 +623,10 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev, of_platform_device_create(child, NULL, NULL); port_dev = of_find_device_by_node(child); - if (port_dev) { rc = ahci_platform_get_regulator(hpriv, port, &port_dev->dev); + put_device(&port_dev->dev); if (rc == -EPROBE_DEFER) goto err_out; } diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 2eb96136632a..1b5757aae57b 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -556,6 +556,7 @@ static blk_status_t vdc_queue_rq(struct blk_mq_hw_ctx *hctx, struct vdc_port *port = hctx->queue->queuedata; struct vio_dring_state *dr; unsigned long flags; + int ret; dr = &port->vio.drings[VIO_DRIVER_TX_RING]; @@ -577,7 +578,13 @@ static blk_status_t vdc_queue_rq(struct blk_mq_hw_ctx *hctx, return BLK_STS_DEV_RESOURCE; } - if (__send_request(bd->rq) < 0) { + ret = __send_request(bd->rq); + if (ret == -EAGAIN) { + spin_unlock_irqrestore(&port->vio.lock, flags); + /* already spun for 10msec, defer 10msec and retry */ + blk_mq_delay_kick_requeue_list(hctx->queue, 10); + return BLK_STS_DEV_RESOURCE; + } else if (ret < 0) { spin_unlock_irqrestore(&port->vio.lock, flags); return BLK_STS_IOERR; } diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 56ba643d5ff7..8d3129aa2a1a 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -361,6 +361,12 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data, if (tfd_index > txq->count) return -ERANGE; + if (skb->len > BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN) { + bt_dev_err(hdev, "TX skb too large (%u > %u)", skb->len, + BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN); + return -EMSGSIZE; + } + /* Firmware raises alive interrupt on HCI_OP_RESET or * BTINTEL_HCI_OP_RESET */ @@ -459,7 +465,7 @@ static int btintel_pcie_submit_rx(struct btintel_pcie_data *data) frbd_index = data->ia.tr_hia[BTINTEL_PCIE_RXQ_NUM]; - if (frbd_index > rxq->count) + if (frbd_index >= rxq->count) return -ERANGE; /* Prepare for RX submit. It updates the FRBD with the address of DMA diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index d1817dd6ab65..c525e2685a86 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -709,7 +709,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev, case BTMTK_WMT_FUNC_CTRL: if (!skb_pull_data(data->evt_skb, sizeof(wmt_evt_funcc->status))) { - status = BTMTK_WMT_ON_UNDONE; + /* A plain enable/disable request is acked with just + * the WMT header and no trailing status word; the + * result is carried in the header's own flag byte. + */ + status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE : + BTMTK_WMT_ON_DONE; break; } diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index f7dcabc11b85..a9ca2d37b8c5 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -1245,10 +1245,8 @@ static int btmtksdio_shutdown(struct hci_dev *hdev) wmt_params.status = NULL; err = mtk_hci_wmt_sync(hdev, &wmt_params); - if (err < 0) { + if (err < 0) bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err); - return err; - } ignore_wmt_cmd: pm_runtime_put_noidle(bdev->dev); diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index f404eefbfc85..bdbb5801b240 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -818,6 +818,14 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, snprintf(config.fwname, sizeof(config.fwname), "qca/%s", rampatch_name); } else { switch (soc_type) { + case QCA_QCA2066: + snprintf(config.fwname, sizeof(config.fwname), + "qca/hpbtfw%02x.tlv", rom_ver); + break; + case QCA_QCA6390: + snprintf(config.fwname, sizeof(config.fwname), + "qca/htbtfw%02x.tlv", rom_ver); + break; case QCA_WCN3950: snprintf(config.fwname, sizeof(config.fwname), "qca/cmbtfw%02x.tlv", rom_ver); @@ -832,14 +840,6 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, snprintf(config.fwname, sizeof(config.fwname), "qca/apbtfw%02x.tlv", rom_ver); break; - case QCA_QCA2066: - snprintf(config.fwname, sizeof(config.fwname), - "qca/hpbtfw%02x.tlv", rom_ver); - break; - case QCA_QCA6390: - snprintf(config.fwname, sizeof(config.fwname), - "qca/htbtfw%02x.tlv", rom_ver); - break; case QCA_WCN6750: /* Choose mbn file by default.If mbn file is not found * then choose tlv file @@ -887,6 +887,16 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, } } else { switch (soc_type) { + case QCA_QCA2066: + qca_get_nvm_name_by_board(config.fwname, + sizeof(config.fwname), + "hpnv", soc_type, ver, + rom_ver, boardid); + break; + case QCA_QCA6390: + snprintf(config.fwname, sizeof(config.fwname), + "qca/htnv%02x.bin", rom_ver); + break; case QCA_WCN3950: if (le32_to_cpu(ver.soc_id) == QCA_WCN3950_SOC_ID_T) variant = "t"; @@ -909,15 +919,6 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, snprintf(config.fwname, sizeof(config.fwname), "qca/apnv%02x.bin", rom_ver); break; - case QCA_QCA2066: - qca_get_nvm_name_by_board(config.fwname, - sizeof(config.fwname), "hpnv", soc_type, ver, - rom_ver, boardid); - break; - case QCA_QCA6390: - snprintf(config.fwname, sizeof(config.fwname), - "qca/htnv%02x.bin", rom_ver); - break; case QCA_WCN6750: snprintf(config.fwname, sizeof(config.fwname), "qca/msnv%02x.bin", rom_ver); @@ -944,9 +945,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, } switch (soc_type) { - case QCA_WCN3991: case QCA_QCA2066: case QCA_QCA6390: + case QCA_WCN3991: case QCA_WCN6750: case QCA_WCN6855: case QCA_WCN7850: diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 81b25c0231c4..c496f746fafa 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -70,6 +70,15 @@ static struct usb_driver btusb_driver; #define BTUSB_BROKEN_EXT_SCAN BIT(29) static const struct usb_device_id btusb_table[] = { + /* + * NXP IW610 (0471:0215): the composite device reports Bluetooth + * class at the whole-device level, so the generic entry below + * would also match this WiFi vendor interface. Ignore it here + * first so mwifiex-nxp can bind it instead. + */ + { USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xff, 0xff, 0xff), + .driver_info = BTUSB_IGNORE }, + /* Generic Bluetooth USB device */ { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, @@ -474,6 +483,14 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, + /* + * NXP IW610 BT interfaces (Marvell-lineage silicon, same quirk as + * the 0x1286 entries above). Scoped to the BT interface class, + * not just VID/PID -- see the btusb_table entry above. + */ + { USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xe0, 0x01, 0x01), + .driver_info = BTUSB_MARVELL }, + /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_COMBINED }, diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index b510b03dae87..b3b267e77e4f 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -86,6 +86,7 @@ enum qca_flags { enum qca_capabilities { QCA_CAP_WIDEBAND_SPEECH = BIT(0), QCA_CAP_VALID_LE_STATES = BIT(1), + QCA_CAP_HFP_HW_OFFLOAD = BIT(2), }; /* HCI_IBS transmit side sleep protocol states */ @@ -228,6 +229,7 @@ struct qca_serdev { u32 init_speed; u32 oper_speed; bool bdaddr_property_broken; + bool support_hfp_hw_offload; const char *firmware_name[2]; }; @@ -1851,6 +1853,7 @@ static int qca_power_on(struct hci_dev *hdev) return 0; switch (soc_type) { + case QCA_QCA6390: case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: @@ -1859,7 +1862,6 @@ static int qca_power_on(struct hci_dev *hdev) case QCA_WCN6750: case QCA_WCN6855: case QCA_WCN7850: - case QCA_QCA6390: ret = qca_regulator_init(hu); break; @@ -1915,9 +1917,12 @@ static int qca_setup(struct hci_uart *hu) const char *rampatch_name = qca_get_rampatch_name(hu); int ret; struct qca_btsoc_version ver; - struct qca_serdev *qcadev; + struct qca_serdev *qcadev = NULL; const char *soc_name; + if (hu->serdev) + qcadev = serdev_device_get_drvdata(hu->serdev); + ret = qca_check_speeds(hu); if (ret) return ret; @@ -1979,8 +1984,7 @@ static int qca_setup(struct hci_uart *hu) case QCA_WCN6750: case QCA_WCN6855: case QCA_WCN7850: - qcadev = serdev_device_get_drvdata(hu->serdev); - if (qcadev->bdaddr_property_broken) + if (qcadev && qcadev->bdaddr_property_broken) hci_set_quirk(hdev, HCI_QUIRK_BDADDR_PROPERTY_BROKEN); hci_set_aosp_capable(hdev); @@ -2073,7 +2077,7 @@ static int qca_setup(struct hci_uart *hu) else hu->hdev->set_bdaddr = qca_set_bdaddr; - if (soc_type == QCA_QCA2066) + if (qcadev && qcadev->support_hfp_hw_offload) qca_configure_hfp_offload(hdev); qca->fw_version = le16_to_cpu(ver.patch_ver); @@ -2098,6 +2102,18 @@ static const struct hci_uart_proto qca_proto = { .dequeue = qca_dequeue, }; +static const struct qca_device_data qca_soc_data_qca2066 __maybe_unused = { + .soc_type = QCA_QCA2066, + .num_vregs = 0, + .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES | + QCA_CAP_HFP_HW_OFFLOAD, +}; + +static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = { + .soc_type = QCA_QCA6390, + .num_vregs = 0, +}; + static const struct qca_device_data qca_soc_data_wcn3950 __maybe_unused = { .soc_type = QCA_WCN3950, .vregs = (struct qca_vreg []) { @@ -2154,17 +2170,6 @@ static const struct qca_device_data qca_soc_data_wcn3998 __maybe_unused = { .num_vregs = 4, }; -static const struct qca_device_data qca_soc_data_qca2066 __maybe_unused = { - .soc_type = QCA_QCA2066, - .num_vregs = 0, - .capabilities = QCA_CAP_WIDEBAND_SPEECH | QCA_CAP_VALID_LE_STATES, -}; - -static const struct qca_device_data qca_soc_data_qca6390 __maybe_unused = { - .soc_type = QCA_QCA6390, - .num_vregs = 0, -}; - static const struct qca_device_data qca_soc_data_wcn6750 __maybe_unused = { .soc_type = QCA_WCN6750, .vregs = (struct qca_vreg []) { @@ -2219,8 +2224,8 @@ static void qca_power_shutdown(struct hci_uart *hu) bool sw_ctrl_state; struct qca_power *power; - /* From this point we go into power off state. But serial port is - * still open, stop queueing the IBS data and flush all the buffered + /* From this point we go into power off state. But serial port may + * still be open, stop queueing the IBS data and flush all the buffered * data in skb's. */ spin_lock_irqsave(&qca->hci_ibs_lock, flags); @@ -2237,6 +2242,24 @@ static void qca_power_shutdown(struct hci_uart *hu) qcadev = serdev_device_get_drvdata(hu->serdev); power = qcadev->bt_power; + switch (soc_type) { + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + /* Both of these write to the serial port which may have + * already been closed by hci_uart_close(), which closes + * the port if HCI_QUIRK_NON_PERSISTENT_SETUP is set. + */ + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + host_set_baudrate(hu, 2400); + qca_send_power_pulse(hu, false); + } + break; + default: + break; + } + if (power && power->pwrseq) { pwrseq_power_off(power->pwrseq); set_bit(QCA_BT_OFF, &qca->flags); @@ -2248,8 +2271,6 @@ static void qca_power_shutdown(struct hci_uart *hu) case QCA_WCN3990: case QCA_WCN3991: case QCA_WCN3998: - host_set_baudrate(hu, 2400); - qca_send_power_pulse(hu, false); qca_regulator_disable(qcadev); break; @@ -2401,6 +2422,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) qcadev->btsoc_type = QCA_ROME; switch (qcadev->btsoc_type) { + case QCA_QCA6390: case QCA_WCN3950: case QCA_WCN3988: case QCA_WCN3990: @@ -2409,7 +2431,6 @@ static int qca_serdev_probe(struct serdev_device *serdev) case QCA_WCN6750: case QCA_WCN6855: case QCA_WCN7850: - case QCA_QCA6390: qcadev->bt_power = devm_kzalloc(&serdev->dev, sizeof(struct qca_power), GFP_KERNEL); @@ -2421,9 +2442,14 @@ static int qca_serdev_probe(struct serdev_device *serdev) } switch (qcadev->btsoc_type) { + case QCA_WCN3950: + case QCA_WCN3988: + case QCA_WCN3990: + case QCA_WCN3991: + case QCA_WCN3998: + case QCA_WCN6750: case QCA_WCN6855: case QCA_WCN7850: - case QCA_WCN6750: if (!device_property_present(&serdev->dev, "enable-gpios")) { /* * Backward compatibility with old DT sources. If the @@ -2445,12 +2471,7 @@ static int qca_serdev_probe(struct serdev_device *serdev) else break; } - fallthrough; - case QCA_WCN3950: - case QCA_WCN3988: - case QCA_WCN3990: - case QCA_WCN3991: - case QCA_WCN3998: + qcadev->bt_power->dev = &serdev->dev; err = qca_init_regulators(qcadev->bt_power, data->vregs, data->num_vregs); @@ -2542,6 +2563,9 @@ static int qca_serdev_probe(struct serdev_device *serdev) if (!(data->capabilities & QCA_CAP_VALID_LE_STATES)) hci_set_quirk(hdev, HCI_QUIRK_BROKEN_LE_STATES); + + if (data->capabilities & QCA_CAP_HFP_HW_OFFLOAD) + qcadev->support_hfp_hw_offload = true; } return 0; diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index e082474250fe..48a0c314fc3d 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -85,7 +85,7 @@ static unsigned long scpi_dvfs_recalc_rate(struct clk_hw *hw, int idx = clk->scpi_ops->dvfs_get_idx(clk->id); const struct scpi_opp *opp; - if (idx < 0) + if (idx < 0 || idx >= clk->info->count) return 0; opp = clk->info->opps + idx; diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index e6d9d338a60a..fa2019d51918 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -428,6 +428,7 @@ static void dma_device_release(struct kref *ref) list_del_rcu(&device->global_node); dma_channel_rebalance(); + synchronize_rcu(); if (device->device_release) device->device_release(device); @@ -495,10 +496,13 @@ static int dma_chan_get(struct dma_chan *chan) */ static void dma_chan_put(struct dma_chan *chan) { + struct module *owner; + /* This channel is not in use, bail out */ if (!chan->client_count) return; + owner = dma_chan_to_owner(chan); chan->client_count--; /* This channel is not in use anymore, free it */ @@ -515,8 +519,10 @@ static void dma_chan_put(struct dma_chan *chan) chan->route_data = NULL; } - dma_device_put(chan->device); - module_put(dma_chan_to_owner(chan)); + /* This channel is not in use anymore, drop the device ref */ + if (!chan->client_count) + dma_device_put(chan->device); + module_put(owner); } enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index d12e729ee12c..bf77bc7d5e38 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -701,7 +701,7 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl, for_each_sg(sgl, sg, sg_len, i) { addr = sg_dma_address(sg); - avail = sg_dma_len(sgl); + avail = sg_dma_len(sg); do { len = min_t(size_t, avail, PDMA_MAX_DESC_BYTES); diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 187a090463ce..a74018253020 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -1212,7 +1212,7 @@ static int sprd_dma_probe(struct platform_device *pdev) ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) - goto err_rpm; + goto err_register; ret = dma_async_device_register(&sdev->dma_dev); if (ret < 0) { @@ -1234,7 +1234,6 @@ static int sprd_dma_probe(struct platform_device *pdev) err_register: pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); -err_rpm: sprd_dma_disable(sdev); return ret; } diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index ae362a2f7c40..69f4d27247a7 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -354,8 +354,10 @@ static size_t sun6i_get_chan_size(struct sun6i_pchan *pchan) size_t bytes; dma_addr_t pos; - pos = readl(pchan->base + DMA_CHAN_LLI_ADDR); - bytes = readl(pchan->base + DMA_CHAN_CUR_CNT); + do { + pos = readl(pchan->base + DMA_CHAN_LLI_ADDR); + bytes = readl(pchan->base + DMA_CHAN_CUR_CNT); + } while (pos != readl(pchan->base + DMA_CHAN_LLI_ADDR)); if (pos == LLI_LAST_ITEM) return bytes; @@ -969,7 +971,6 @@ static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan, struct sun6i_pchan *pchan = vchan->phy; struct sun6i_dma_lli *lli; struct virt_dma_desc *vd; - struct sun6i_desc *txd; enum dma_status ret; unsigned long flags; size_t bytes = 0; @@ -981,9 +982,9 @@ static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan, spin_lock_irqsave(&vchan->vc.lock, flags); vd = vchan_find_desc(&vchan->vc, cookie); - txd = to_sun6i_desc(&vd->tx); if (vd) { + struct sun6i_desc *txd = to_sun6i_desc(&vd->tx); for (lli = txd->v_lli; lli != NULL; lli = lli->v_lli_next) bytes += lli->len; } else if (!pchan || !pchan->desc) { diff --git a/drivers/dma/ti/k3-udma-glue.c b/drivers/dma/ti/k3-udma-glue.c index f87d244cc2d6..d651983fe381 100644 --- a/drivers/dma/ti/k3-udma-glue.c +++ b/drivers/dma/ti/k3-udma-glue.c @@ -1243,8 +1243,9 @@ void k3_udma_glue_release_rx_chn(struct k3_udma_glue_rx_channel *rx_chn) rx_chn->psil_paired = false; } - for (i = 0; i < rx_chn->flow_num; i++) - k3_udma_glue_release_rx_flow(rx_chn, i); + if (rx_chn->flows) + for (i = 0; i < rx_chn->flow_num; i++) + k3_udma_glue_release_rx_flow(rx_chn, i); if (xudma_rflow_is_gp(rx_chn->common.udmax, rx_chn->flow_id_base)) xudma_free_gp_rflow_range(rx_chn->common.udmax, diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index 30e3db94ddf0..8b010e0e0c5c 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -754,15 +754,25 @@ xilinx_aximcdma_alloc_tx_segment(struct xilinx_dma_chan *chan) return segment; } -static void xilinx_dma_clean_hw_desc(struct xilinx_axidma_desc_hw *hw) +static void xilinx_dma_clean_hw_desc(struct xilinx_dma_chan *chan, + struct xilinx_axidma_tx_segment *segment) { - u32 next_desc = hw->next_desc; - u32 next_desc_msb = hw->next_desc_msb; + dma_addr_t next; + u32 i; - memset(hw, 0, sizeof(struct xilinx_axidma_desc_hw)); + /* + * Restore the buffer descriptor's next descriptor pointer to the value + * set up in xilinx_dma_alloc_chan_resources(). Otherwise using the DMA + * in cyclic mode leaves the next descriptor pointer altered and + * prevents subsequent non-cyclic transfers. + */ + i = segment - chan->seg_v; + next = chan->seg_p + + sizeof(*chan->seg_v) * ((i + 1) % XILINX_DMA_NUM_DESCS); - hw->next_desc = next_desc; - hw->next_desc_msb = next_desc_msb; + memset(&segment->hw, 0, sizeof(segment->hw)); + segment->hw.next_desc = lower_32_bits(next); + segment->hw.next_desc_msb = upper_32_bits(next); } static void xilinx_mcdma_clean_hw_desc(struct xilinx_aximcdma_desc_hw *hw) @@ -784,7 +794,7 @@ static void xilinx_mcdma_clean_hw_desc(struct xilinx_aximcdma_desc_hw *hw) static void xilinx_dma_free_tx_segment(struct xilinx_dma_chan *chan, struct xilinx_axidma_tx_segment *segment) { - xilinx_dma_clean_hw_desc(&segment->hw); + xilinx_dma_clean_hw_desc(chan, segment); list_add_tail(&segment->node, &chan->free_seg_list); } @@ -918,9 +928,9 @@ static void xilinx_dma_free_descriptors(struct xilinx_dma_chan *chan) spin_lock_irqsave(&chan->lock, flags); - xilinx_dma_free_desc_list(chan, &chan->pending_list); xilinx_dma_free_desc_list(chan, &chan->done_list); xilinx_dma_free_desc_list(chan, &chan->active_list); + xilinx_dma_free_desc_list(chan, &chan->pending_list); spin_unlock_irqrestore(&chan->lock, flags); } diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 398642cc25d9..b8b7907089d7 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -631,8 +631,8 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain) if (ret) return ERR_PTR(ret); - if (!buf.opp_count) - return ERR_PTR(-ENOENT); + if (!buf.opp_count || buf.opp_count > MAX_DVFS_OPPS) + return ERR_PTR(-EINVAL); info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) diff --git a/drivers/gpio/gpio-virtuser.c b/drivers/gpio/gpio-virtuser.c index 1901b4ba558f..ce7ada0f1798 100644 --- a/drivers/gpio/gpio-virtuser.c +++ b/drivers/gpio/gpio-virtuser.c @@ -697,7 +697,8 @@ static int gpio_virtuser_interrupts_set(void *data, u64 val) atomic_set(&ld->irq, irq); } else { irq = atomic_xchg(&ld->irq, 0); - free_irq(irq, ld); + if (irq) + free_irq(irq, ld); } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index dda5d62c8e7b..6377501c70a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -5098,7 +5098,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) void amdgpu_device_fini_sw(struct amdgpu_device *adev) { - int i, idx; + int i; bool px; amdgpu_device_ip_fini(adev); @@ -5140,11 +5140,9 @@ void amdgpu_device_fini_sw(struct amdgpu_device *adev) if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA) vga_client_unregister(adev->pdev); - if (drm_dev_enter(adev_to_drm(adev), &idx)) { - + if (adev->rmmio) { iounmap(adev->rmmio); adev->rmmio = NULL; - drm_dev_exit(idx); } if (IS_ENABLED(CONFIG_PERF_EVENTS)) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c index f20d4bc58904..efa6214eee31 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c @@ -42,6 +42,7 @@ #include #include #include +#include static const struct dma_buf_attach_ops amdgpu_dma_buf_attach_ops; @@ -81,6 +82,7 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, struct drm_gem_object *obj = dmabuf->priv; struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); + int r; /* * Disable peer-to-peer access for DCC-enabled VRAM surfaces on GFX12+. @@ -98,9 +100,54 @@ static int amdgpu_dma_buf_attach(struct dma_buf *dmabuf, pci_p2pdma_distance(adev->pdev, attach->dev, false) < 0) attach->peer2peer = false; + /* + * Only allow P2P while the exporter is active, and keep it active + * until detach. With runtime PM disabled take a plain reference so + * the put in detach stays balanced. + */ + if (attach->peer2peer) { + struct device *dev = adev_to_drm(adev)->dev; + int ret = pm_runtime_get_if_active(dev); + + if (!ret) + attach->peer2peer = false; + else if (ret < 0) + pm_runtime_get_noresume(dev); + } + + r = dma_resv_lock(bo->tbo.base.resv, NULL); + if (r) + goto err_pm_put; + amdgpu_vm_bo_update_shared(bo); + dma_resv_unlock(bo->tbo.base.resv); + return 0; + +err_pm_put: + if (attach->peer2peer) + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); + return r; +} + +/** + * amdgpu_dma_buf_detach - &dma_buf_ops.detach implementation + * + * @dmabuf: DMA-buf where we remove the attachment from + * @attach: the attachment to remove + * + * Drop the runtime PM reference taken in amdgpu_dma_buf_attach(). + */ +static void amdgpu_dma_buf_detach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attach) +{ + struct drm_gem_object *obj = dmabuf->priv; + struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); + + if (attach->peer2peer) + pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); } /** @@ -329,6 +376,7 @@ static void amdgpu_dma_buf_vunmap(struct dma_buf *dma_buf, struct iosys_map *map const struct dma_buf_ops amdgpu_dmabuf_ops = { .attach = amdgpu_dma_buf_attach, + .detach = amdgpu_dma_buf_detach, .pin = amdgpu_dma_buf_pin, .unpin = amdgpu_dma_buf_unpin, .map_dma_buf = amdgpu_dma_buf_map, diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c index 1c22bc11c1f8..a71ad237972c 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c @@ -533,7 +533,7 @@ static void nbio_v7_9_handle_ras_controller_intr_no_bifring(struct amdgpu_device RAS_CNTLR_INTERRUPT_CLEAR, 1); WREG32_SOC15(NBIO, 0, regBIF_BX0_BIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl); - if (!ras->disable_ras_err_cnt_harvest) { + if (ras && !ras->disable_ras_err_cnt_harvest && obj) { /* * clear error status after ras_controller_intr * according to hw team and count ue number diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c index 1a11eebfbab0..4fc5f9573184 100644 --- a/drivers/gpu/drm/drm_atomic_uapi.c +++ b/drivers/gpu/drm/drm_atomic_uapi.c @@ -1244,10 +1244,12 @@ static int prepare_signaling(struct drm_device *dev, struct dma_fence *fence; struct drm_out_fence_state *f; + ret = -ENOMEM; + f = krealloc(*fence_state, sizeof(**fence_state) * (*num_fences + 1), GFP_KERNEL); if (!f) - return -ENOMEM; + goto err_free_event; memset(&f[*num_fences], 0, sizeof(*f)); @@ -1256,12 +1258,12 @@ static int prepare_signaling(struct drm_device *dev, fence = drm_crtc_create_fence(crtc); if (!fence) - return -ENOMEM; + goto err_free_event; ret = setup_out_fence(&f[(*num_fences)++], fence); if (ret) { dma_fence_put(fence); - return ret; + goto err_free_event; } crtc_state->event->base.fence = fence; @@ -1317,6 +1319,11 @@ static int prepare_signaling(struct drm_device *dev, } return 0; + +err_free_event: + drm_event_cancel_free(dev, &crtc_state->event->base); + crtc_state->event = NULL; + return ret; } static void complete_signaling(struct drm_device *dev, diff --git a/drivers/gpu/drm/gud/gud_pipe.c b/drivers/gpu/drm/gud/gud_pipe.c index 0d38eecd152d..8892ea631388 100644 --- a/drivers/gpu/drm/gud/gud_pipe.c +++ b/drivers/gpu/drm/gud/gud_pipe.c @@ -482,6 +482,9 @@ int gud_plane_atomic_check(struct drm_plane *plane, if (!new_plane_state->visible) return 0; + if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE) + new_plane_state->ignore_damage_clips = true; + if (old_plane_state->rotation != new_plane_state->rotation) crtc_state->mode_changed = true; @@ -562,8 +565,8 @@ int gud_plane_atomic_check(struct drm_plane *plane, goto out; } - req->properties[num_properties + i].prop = cpu_to_le16(prop); - req->properties[num_properties + i].val = cpu_to_le64(val); + req->properties[num_properties].prop = cpu_to_le16(prop); + req->properties[num_properties].val = cpu_to_le64(val); num_properties++; } diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c index 28f744f3caf7..5d598815de45 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_device.c +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c @@ -25,7 +25,7 @@ MODULE_PARM_DESC(disable_acd, "Forcefully disable GPU ACD"); module_param_unsafe(disable_acd, bool, 0400); static bool skip_gpu; -MODULE_PARM_DESC(no_gpu, "Disable GPU driver register (0=enable GPU driver register (default), 1=skip GPU driver register"); +MODULE_PARM_DESC(skip_gpu, "Disable GPU driver register (0=enable GPU driver register (default), 1=skip GPU driver register"); module_param(skip_gpu, bool, 0400); extern const struct adreno_gpulist a2xx_gpulist; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index 056a9e18cd4a..ef9798492bce 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -1245,6 +1245,8 @@ void adreno_gpu_cleanup(struct adreno_gpu *adreno_gpu) for (i = 0; i < ARRAY_SIZE(adreno_gpu->info->fw); i++) release_firmware(adreno_gpu->fw[i]); + pm_runtime_dont_use_autosuspend(&gpu->pdev->dev); + if (priv && pm_runtime_enabled(&priv->gpu_pdev->dev)) pm_runtime_disable(&priv->gpu_pdev->dev); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c index ac834db2e4c1..68ed99d8aec6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.c @@ -118,6 +118,7 @@ static inline void dpu_hw_ctl_clear_pending_flush(struct dpu_hw_ctl *ctx) ctx->pending_intf_flush_mask = 0; ctx->pending_wb_flush_mask = 0; ctx->pending_cwb_flush_mask = 0; + ctx->pending_periph_flush_mask = 0; ctx->pending_merge_3d_flush_mask = 0; ctx->pending_dsc_flush_mask = 0; ctx->pending_cdm_flush_mask = 0; diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 68043dbe72bf..131753ba57b5 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -930,6 +930,7 @@ enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge, u32 mode_rate_khz = 0, supported_rate_khz = 0, mode_bpp = 0; struct msm_dp *dp; int mode_pclk_khz = mode->clock; + int link_pclk_khz; bool is_yuv_420; dp = to_dp_bridge(bridge)->msm_dp_display; @@ -951,6 +952,8 @@ enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge, if (is_yuv_420 && !msm_dp_display->panel->vsc_sdp_supported) return MODE_NO_420; + link_pclk_khz = is_yuv_420 ? mode_pclk_khz / 2 : mode_pclk_khz; + if (is_yuv_420 || msm_dp_display->wide_bus_supported) mode_pclk_khz /= 2; @@ -962,9 +965,9 @@ enum drm_mode_status msm_dp_bridge_mode_valid(struct drm_bridge *bridge, mode_bpp = default_bpp; mode_bpp = msm_dp_panel_get_mode_bpp(msm_dp_display->panel, - mode_bpp, mode_pclk_khz); + mode_bpp, link_pclk_khz); - mode_rate_khz = mode_pclk_khz * mode_bpp; + mode_rate_khz = link_pclk_khz * mode_bpp; supported_rate_khz = link_info->num_lanes * link_info->rate * 8; if (mode_rate_khz > supported_rate_khz) @@ -1647,6 +1650,20 @@ void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge, msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display); + /* + * If .atomic_enable() bailed out - link training failure is the common + * case - the mainlink was never brought up and ->power_on stayed false. + * Driving the PUSH_IDLE pattern into a controller that was never + * enabled times out, and .atomic_post_disable() then drops the + * controller's runtime-PM reference without tearing the PHY back down, + * because msm_dp_display_disable() returns early on !power_on. On + * glymur (Snapdragon X2 Elite) that combination is answered by a + * TrustZone-level SOCCP/ADSP force-stop and a silent SoC reset. + * There is nothing to push idle, so leave it alone. + */ + if (!dp->power_on) + return; + msm_dp_ctrl_push_idle(msm_dp_display->ctrl); } diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 5110fe05ca84..4e93f8dd39d7 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -129,7 +129,7 @@ struct msm_dsi_host { struct clk *dsi_pll_pixel_clk; unsigned long byte_clk_rate; - unsigned long byte_intf_clk_rate; + bool byte_intf_clk_div_2; unsigned long pixel_clk_rate; unsigned long esc_clk_rate; @@ -381,8 +381,20 @@ int msm_dsi_runtime_resume(struct device *dev) int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) { + unsigned long byte_intf_clk_rate; + long rounded_byte_clk_rate; int ret; + rounded_byte_clk_rate = clk_round_rate(msm_host->byte_clk, + msm_host->byte_clk_rate); + if (rounded_byte_clk_rate < 0) { + pr_err("%s: failed to round byte clock rate, %ld\n", + __func__, rounded_byte_clk_rate); + return rounded_byte_clk_rate; + } + + msm_host->byte_clk_rate = rounded_byte_clk_rate; + DBG("Set clk rates: pclk=%lu, byteclk=%lu", msm_host->pixel_clk_rate, msm_host->byte_clk_rate); @@ -400,7 +412,11 @@ int dsi_link_clk_set_rate_6g(struct msm_dsi_host *msm_host) } if (msm_host->byte_intf_clk) { - ret = clk_set_rate(msm_host->byte_intf_clk, msm_host->byte_intf_clk_rate); + byte_intf_clk_rate = msm_host->byte_clk_rate; + if (msm_host->byte_intf_clk_div_2) + byte_intf_clk_rate /= 2; + + ret = clk_set_rate(msm_host->byte_intf_clk, byte_intf_clk_rate); if (ret) { pr_err("%s: Failed to set rate byte intf clk, %d\n", __func__, ret); @@ -668,24 +684,12 @@ static void dsi_calc_pclk(struct msm_dsi_host *msm_host, bool is_bonded_dsi) int dsi_calc_clk_rate_6g(struct msm_dsi_host *msm_host, bool is_bonded_dsi) { - long rounded_byte_clk_rate; - if (!msm_host->mode) { pr_err("%s: mode not set\n", __func__); return -EINVAL; } dsi_calc_pclk(msm_host, is_bonded_dsi); - - rounded_byte_clk_rate = clk_round_rate(msm_host->byte_clk, - msm_host->byte_clk_rate); - if (rounded_byte_clk_rate < 0) { - pr_err("%s: failed to round byte clock rate, %ld\n", - __func__, rounded_byte_clk_rate); - return rounded_byte_clk_rate; - } - - msm_host->byte_clk_rate = rounded_byte_clk_rate; msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk); return 0; } @@ -2470,9 +2474,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host, goto unlock_ret; } - msm_host->byte_intf_clk_rate = msm_host->byte_clk_rate; - if (phy_shared_timings->byte_intf_clk_div_2) - msm_host->byte_intf_clk_rate /= 2; + msm_host->byte_intf_clk_div_2 = phy_shared_timings->byte_intf_clk_div_2; msm_dsi_sfpb_config(msm_host, true); diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c index f726555bb681..6777cba9255e 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_phy.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy.c @@ -168,13 +168,13 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev) ret = msm_hdmi_phy_resource_enable(phy); if (ret) - return ret; + goto err_pm_disable; ret = msm_hdmi_phy_pll_init(pdev, phy->cfg->type); if (ret) { DRM_DEV_ERROR(dev, "couldn't init PLL\n"); msm_hdmi_phy_resource_disable(phy); - return ret; + goto err_pm_disable; } msm_hdmi_phy_resource_disable(phy); @@ -182,6 +182,10 @@ static int msm_hdmi_phy_probe(struct platform_device *pdev) platform_set_drvdata(pdev, phy); return 0; + +err_pm_disable: + pm_runtime_disable(dev); + return ret; } static void msm_hdmi_phy_remove(struct platform_device *pdev) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 94b32973cd6a..c2a8aaa33f84 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -55,7 +55,7 @@ MODULE_PARM_DESC(modeset, "Use kernel modesetting [KMS] (1=on (default), 0=disab module_param(modeset, bool, 0600); static bool separate_gpu_kms; -MODULE_PARM_DESC(separate_gpu_drm, "Use separate DRM device for the GPU (0=single DRM device for both GPU and display (default), 1=two DRM devices)"); +MODULE_PARM_DESC(separate_gpu_kms, "Use separate DRM device for the GPU (0=single DRM device for both GPU and display (default), 1=two DRM devices)"); module_param(separate_gpu_kms, bool, 0400); DECLARE_FAULT_ATTR(fail_gem_alloc); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index a4cf31853c50..1bf228d0f8da 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -68,6 +68,9 @@ struct msm_gem_vm { /** @base: Inherit from drm_gpuvm. */ struct drm_gpuvm base; + /** @rcu: RCU-delayed free so an exported sched fence->sched stays valid. */ + struct rcu_head rcu; + /** * @sched: Scheduler used for asynchronous VM_BIND request. * diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index 701fe4a0b73c..faccb9a77fbe 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -166,7 +166,7 @@ msm_gem_vm_free(struct drm_gpuvm *gpuvm) dma_fence_put(vm->last_fence); put_pid(vm->pid); kfree(vm->log); - kfree(vm); + kfree_rcu(vm, rcu); } /** diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index e09ec7f398d5..aa96efa66fee 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -140,5 +140,5 @@ void msm_ringbuffer_destroy(struct msm_ringbuffer *ring) msm_gem_kernel_put(ring->bo, ring->gpu->vm); - kfree(ring); + kfree_rcu(ring, rcu); } diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.h b/drivers/gpu/drm/msm/msm_ringbuffer.h index bace58a3dffb..f7127351e163 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.h +++ b/drivers/gpu/drm/msm/msm_ringbuffer.h @@ -53,6 +53,7 @@ struct msm_ringbuffer { /* * The job scheduler for this ring. */ + struct rcu_head rcu; struct drm_gpu_scheduler sched; bool sched_initialized; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c index e962d0e8f837..150e22fde2ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/fbsr.c @@ -208,7 +208,7 @@ r535_fbsr_resume(struct nvkm_gsp *gsp) } static int -r535_fbsr_suspend(struct nvkm_gsp *gsp, bool runtime) +r535_fbsr_suspend(struct nvkm_gsp *gsp) { struct nvkm_subdev *subdev = &gsp->subdev; struct nvkm_device *device = subdev->device; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c index a575a8dbf727..e8264a47820a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c @@ -1748,7 +1748,7 @@ r535_gsp_fini(struct nvkm_gsp *gsp, enum nvkm_suspend_state suspend) sr->sysmemAddrOfSuspendResumeData = gsp->sr.radix3.lvl0.addr; sr->sizeOfSuspendResumeData = len; - ret = rm->api->fbsr->suspend(gsp, suspend == NVKM_RUNTIME_SUSPEND); + ret = rm->api->fbsr->suspend(gsp); if (ret) { nvkm_gsp_mem_dtor(&gsp->sr.meta); nvkm_gsp_radix3_dtor(gsp, &gsp->sr.radix3); @@ -1760,8 +1760,12 @@ r535_gsp_fini(struct nvkm_gsp *gsp, enum nvkm_suspend_state suspend) * TODO: Debug the GSP firmware / RPC handling to find out why * without this Turing (but none of the other architectures) * ends up resetting all channels after resume. + * Additionally, runtime suspend on other architectures quickly + * becomes unreliable without this sleep. If you're experiencing + * issues with runtime suspend, try bumping this delay up and + * sending a patch if it fixes your GPU. */ - msleep(50); + msleep(200); } ret = r535_gsp_rpc_unloading_guest_driver(gsp, suspend); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/fbsr.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/fbsr.c index 8ef8b4f65588..af5aa5065c3d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/fbsr.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/fbsr.c @@ -62,7 +62,7 @@ r570_fbsr_resume(struct nvkm_gsp *gsp) } static int -r570_fbsr_init(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size, bool runtime) +r570_fbsr_init(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size) { NV2080_CTRL_INTERNAL_FBSR_INIT_PARAMS *ctrl; struct nvkm_gsp_object memlist; @@ -81,7 +81,7 @@ r570_fbsr_init(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size, bool runtim ctrl->hClient = gsp->internal.client.object.handle; ctrl->hSysMem = memlist.handle; ctrl->sysmemAddrOfSuspendResumeData = gsp->sr.meta.addr; - ctrl->bEnteringGcoffState = runtime ? 1 : 0; + ctrl->bEnteringGcoffState = 0; ret = nvkm_gsp_rm_ctrl_wr(&gsp->internal.device.subdevice, ctrl); if (ret) @@ -92,7 +92,7 @@ r570_fbsr_init(struct nvkm_gsp *gsp, struct sg_table *sgt, u64 size, bool runtim } static int -r570_fbsr_suspend(struct nvkm_gsp *gsp, bool runtime) +r570_fbsr_suspend(struct nvkm_gsp *gsp) { struct nvkm_subdev *subdev = &gsp->subdev; struct nvkm_device *device = subdev->device; @@ -133,7 +133,7 @@ r570_fbsr_suspend(struct nvkm_gsp *gsp, bool runtime) return ret; /* Initialise FBSR on RM. */ - ret = r570_fbsr_init(gsp, &gsp->sr.fbsr, size, runtime); + ret = r570_fbsr_init(gsp, &gsp->sr.fbsr, size); if (ret) { nvkm_gsp_sg_free(device, &gsp->sr.fbsr); return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c index 1488771c63fc..b45781cd0dfd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/gsp.c @@ -207,7 +207,8 @@ r570_gsp_set_rmargs(struct nvkm_gsp *gsp, bool resume) args->srInitArguments.bInPMTransition = 0; } else { args->srInitArguments.oldLevel = NV2080_CTRL_GPU_SET_POWER_STATE_GPU_LEVEL_3; - args->srInitArguments.flags = 0; + args->srInitArguments.flags = + GPU_STATE_FLAGS_PRESERVING | GPU_STATE_FLAGS_PM_TRANSITION; args->srInitArguments.bInPMTransition = 1; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/nvrm/gsp.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/nvrm/gsp.h index b6075021e74f..c458569af9d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/nvrm/gsp.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r570/nvrm/gsp.h @@ -523,6 +523,14 @@ typedef struct #define NV2080_CTRL_GPU_SET_POWER_STATE_GPU_LEVEL_3 (0x00000003U) +#define GPU_STATE_FLAGS_PRESERVING BIT(0) // GPU state is preserved +#define GPU_STATE_FLAGS_VGA_TRANSITION BIT(1) // To be used with GPU_STATE_FLAGS_PRESERVING. +#define GPU_STATE_FLAGS_PM_TRANSITION BIT(2) // To be used with GPU_STATE_FLAGS_PRESERVING. +#define GPU_STATE_FLAGS_PM_SUSPEND BIT(3) +#define GPU_STATE_FLAGS_PM_HIBERNATE BIT(4) +#define GPU_STATE_FLAGS_GC6_TRANSITION BIT(5) // To be used with GPU_STATE_FLAGS_PRESERVING. +#define GPU_STATE_FLAGS_FAST_UNLOAD BIT(6) // Used during windows restart, skips stateDestroy steps + typedef struct { // Magic for verification by secure ucode diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h index c069c2d97169..6d8d400c00af 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h @@ -79,7 +79,7 @@ struct nvkm_rm_api { } *device; const struct nvkm_rm_api_fbsr { - int (*suspend)(struct nvkm_gsp *, bool runtime); + int (*suspend)(struct nvkm_gsp *); void (*resume)(struct nvkm_gsp *); } *fbsr; diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 8f983edb81ff..20dad6245ac1 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -1162,7 +1162,7 @@ int vc4_kms_load(struct drm_device *dev) drm_mode_config_reset(dev); - drm_kms_helper_poll_init(dev); + drmm_kms_helper_poll_init(dev); return 0; } diff --git a/drivers/gpu/drm/xe/xe_mmio_gem.c b/drivers/gpu/drm/xe/xe_mmio_gem.c index 9a97c4387e4f..afb880c7955e 100644 --- a/drivers/gpu/drm/xe/xe_mmio_gem.c +++ b/drivers/gpu/drm/xe/xe_mmio_gem.c @@ -39,10 +39,20 @@ struct xe_mmio_gem { phys_addr_t phys_addr; }; +static int xe_mmio_gem_vm_may_split(struct vm_area_struct *area, unsigned long addr) +{ + /* + * Forbid splitting. Together with VM_DONTEXPAND, this keeps the VMA + * matching the GEM object exactly. + */ + return -EINVAL; +} + static const struct vm_operations_struct vm_ops = { .open = drm_gem_vm_open, .close = drm_gem_vm_close, .fault = xe_mmio_gem_vm_fault, + .may_split = xe_mmio_gem_vm_may_split, }; static const struct drm_gem_object_funcs xe_mmio_gem_funcs = { @@ -128,14 +138,16 @@ static void xe_mmio_gem_free(struct drm_gem_object *base) /** * xe_mmio_gem_destroy - Destroy the GEM object that exposes an MMIO region * @gem: the GEM object to destroy + * @file: DRM file descriptor previously passed to xe_mmio_gem_create() * * This function releases resources associated with the GEM object created by * xe_mmio_gem_create(). * * See: "Exposing MMIO regions to userspace" */ -void xe_mmio_gem_destroy(struct xe_mmio_gem *gem) +void xe_mmio_gem_destroy(struct xe_mmio_gem *gem, struct drm_file *file) { + drm_vma_node_revoke(&gem->base.vma_node, file); xe_mmio_gem_free(&gem->base); } @@ -162,14 +174,13 @@ static void xe_mmio_gem_release_dummy_page(struct drm_device *dev, void *res) __free_page((struct page *)res); } -static vm_fault_t xe_mmio_gem_vm_fault_dummy_page(struct vm_area_struct *vma) +static vm_fault_t xe_mmio_gem_vm_fault_dummy_page(struct vm_fault *vmf) { + struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *base = vma->vm_private_data; struct drm_device *dev = base->dev; - vm_fault_t ret = VM_FAULT_NOPAGE; struct page *page; unsigned long pfn; - unsigned long i; page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (!page) @@ -180,16 +191,8 @@ static vm_fault_t xe_mmio_gem_vm_fault_dummy_page(struct vm_area_struct *vma) pfn = page_to_pfn(page); - /* Map the entire VMA to the same dummy page */ - for (i = 0; i < base->size; i += PAGE_SIZE) { - unsigned long addr = vma->vm_start + i; - - ret = vmf_insert_pfn(vma, addr, pfn); - if (ret & VM_FAULT_ERROR) - break; - } - - return ret; + return vmf_insert_pfn_prot(vma, vmf->address, pfn, + vm_get_page_prot(vma->vm_flags)); } static vm_fault_t xe_mmio_gem_vm_fault(struct vm_fault *vmf) @@ -209,7 +212,7 @@ static vm_fault_t xe_mmio_gem_vm_fault(struct vm_fault *vmf) * It is assumed the userspace will receive the notification via some * other channel (e.g. drm uevent). */ - return xe_mmio_gem_vm_fault_dummy_page(vma); + return xe_mmio_gem_vm_fault_dummy_page(vmf); } for (i = 0; i < base->size; i += PAGE_SIZE) { diff --git a/drivers/gpu/drm/xe/xe_mmio_gem.h b/drivers/gpu/drm/xe/xe_mmio_gem.h index 4b76d5586ebb..80d7795f07c8 100644 --- a/drivers/gpu/drm/xe/xe_mmio_gem.h +++ b/drivers/gpu/drm/xe/xe_mmio_gem.h @@ -15,6 +15,6 @@ struct xe_mmio_gem; struct xe_mmio_gem *xe_mmio_gem_create(struct xe_device *xe, struct drm_file *file, phys_addr_t phys_addr, size_t size); u64 xe_mmio_gem_mmap_offset(struct xe_mmio_gem *gem); -void xe_mmio_gem_destroy(struct xe_mmio_gem *gem); +void xe_mmio_gem_destroy(struct xe_mmio_gem *gem, struct drm_file *file); #endif /* _XE_MMIO_GEM_H_ */ diff --git a/drivers/gpu/drm/xe/xe_shrinker.c b/drivers/gpu/drm/xe/xe_shrinker.c index 90244fe59b59..8a50fea09ef4 100644 --- a/drivers/gpu/drm/xe/xe_shrinker.c +++ b/drivers/gpu/drm/xe/xe_shrinker.c @@ -54,13 +54,14 @@ xe_shrinker_mod_pages(struct xe_shrinker *shrinker, long shrinkable, long purgea write_unlock(&shrinker->lock); } -static s64 __xe_shrinker_walk(struct xe_device *xe, +static int __xe_shrinker_walk(struct xe_device *xe, struct ttm_operation_ctx *ctx, const struct xe_bo_shrink_flags flags, - unsigned long to_scan, unsigned long *scanned) + unsigned long to_scan, unsigned long *scanned, + unsigned long *freed) { unsigned int mem_type; - s64 freed = 0, lret; + s64 lret; for (mem_type = XE_PL_SYSTEM; mem_type <= XE_PL_TT; ++mem_type) { struct ttm_resource_manager *man = ttm_manager_type(&xe->ttm, mem_type); @@ -82,7 +83,7 @@ static s64 __xe_shrinker_walk(struct xe_device *xe, if (lret < 0) return lret; - freed += lret; + *freed += lret; if (*scanned >= to_scan) break; } @@ -90,7 +91,7 @@ static s64 __xe_shrinker_walk(struct xe_device *xe, xe_assert(xe, !IS_ERR(ttm_bo)); } - return freed; + return 0; } /* @@ -99,40 +100,35 @@ static s64 __xe_shrinker_walk(struct xe_device *xe, * add writeback. This avoids stalls and explicit writebacks with light or * moderate memory pressure. */ -static s64 xe_shrinker_walk(struct xe_device *xe, +static int xe_shrinker_walk(struct xe_device *xe, struct ttm_operation_ctx *ctx, const struct xe_bo_shrink_flags flags, - unsigned long to_scan, unsigned long *scanned) + unsigned long to_scan, unsigned long *scanned, + unsigned long *freed) { bool no_wait_gpu = true; struct xe_bo_shrink_flags save_flags = flags; - s64 lret, freed; + int ret; swap(no_wait_gpu, ctx->no_wait_gpu); save_flags.writeback = false; - lret = __xe_shrinker_walk(xe, ctx, save_flags, to_scan, scanned); + ret = __xe_shrinker_walk(xe, ctx, save_flags, to_scan, scanned, freed); swap(no_wait_gpu, ctx->no_wait_gpu); - if (lret < 0 || *scanned >= to_scan) - return lret; + if (ret || *scanned >= to_scan) + return ret; - freed = lret; if (!ctx->no_wait_gpu) { - lret = __xe_shrinker_walk(xe, ctx, save_flags, to_scan, scanned); - if (lret < 0) - return lret; - freed += lret; - if (*scanned >= to_scan) - return freed; + ret = __xe_shrinker_walk(xe, ctx, save_flags, to_scan, scanned, + freed); + if (ret || *scanned >= to_scan) + return ret; } - if (flags.writeback) { - lret = __xe_shrinker_walk(xe, ctx, flags, to_scan, scanned); - if (lret < 0) - return lret; - freed += lret; - } + if (flags.writeback) + ret = __xe_shrinker_walk(xe, ctx, flags, to_scan, scanned, + freed); - return freed; + return ret; } static unsigned long @@ -214,7 +210,6 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con bool runtime_pm; bool purgeable; bool can_backup = !!(sc->gfp_mask & __GFP_FS); - s64 lret; nr_to_scan = sc->nr_to_scan; @@ -225,12 +220,9 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con /* Might need runtime PM. Try to wake early if it looks like it. */ runtime_pm = xe_shrinker_runtime_pm_get(shrinker, false, nr_to_scan, can_backup); - if (purgeable && nr_scanned < nr_to_scan) { - lret = xe_shrinker_walk(shrinker->xe, &ctx, shrink_flags, - nr_to_scan, &nr_scanned); - if (lret >= 0) - freed += lret; - } + if (purgeable && nr_scanned < nr_to_scan) + xe_shrinker_walk(shrinker->xe, &ctx, shrink_flags, + nr_to_scan, &nr_scanned, &freed); sc->nr_scanned = nr_scanned; if (nr_scanned >= nr_to_scan || !can_backup) @@ -242,10 +234,8 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con shrink_flags.purge = false; - lret = xe_shrinker_walk(shrinker->xe, &ctx, shrink_flags, - nr_to_scan, &nr_scanned); - if (lret >= 0) - freed += lret; + xe_shrinker_walk(shrinker->xe, &ctx, shrink_flags, + nr_to_scan, &nr_scanned, &freed); sc->nr_scanned = nr_scanned; out: diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 185bcdb538f2..e39052ff91d1 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -48,7 +48,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define FEATURE_REPORT_ID 0x0d #define INPUT_REPORT_ID 0x5d #define FEATURE_KBD_REPORT_ID 0x5a -#define FEATURE_KBD_REPORT_SIZE 16 +#define FEATURE_KBD_REPORT_SIZE 64 #define FEATURE_KBD_LED_REPORT_ID1 0x5d #define FEATURE_KBD_LED_REPORT_ID2 0x5e @@ -393,15 +393,41 @@ static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t bu static int asus_kbd_init(struct hid_device *hdev, u8 report_id) { + /* + * The handshake is first sent as a set_report, then retrieved + * from a get_report. They should be equal. + */ const u8 buf[] = { report_id, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; int ret; ret = asus_kbd_set_report(hdev, buf, sizeof(buf)); - if (ret < 0) - hid_err(hdev, "Asus failed to send init command: %d\n", ret); + if (ret < 0) { + hid_err(hdev, "Asus handshake %02x failed to send: %d\n", + report_id, ret); + return ret; + } - return ret; + u8 *readbuf __free(kfree) = kzalloc(FEATURE_KBD_REPORT_SIZE, GFP_KERNEL); + if (!readbuf) + return -ENOMEM; + + ret = hid_hw_raw_request(hdev, report_id, readbuf, + FEATURE_KBD_REPORT_SIZE, HID_FEATURE_REPORT, + HID_REQ_GET_REPORT); + if (ret < 0) { + hid_warn(hdev, "Asus handshake %02x failed to receive ack: %d\n", + report_id, ret); + } else if (memcmp(readbuf, buf, sizeof(buf)) != 0) { + hid_warn(hdev, "Asus handshake %02x returned invalid response: %*ph\n", + report_id, FEATURE_KBD_REPORT_SIZE, readbuf); + } + + /* + * Do not return error if handshake is wrong until this is + * verified to work for all devices. + */ + return 0; } static int asus_kbd_get_functions(struct hid_device *hdev, diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 83d625f361f4..94ffda22ef41 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -305,21 +305,22 @@ static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp, if (ret) { dbg_hid("__hidpp_send_report returned err: %d\n", ret); memset(response, 0, sizeof(struct hidpp_report)); - return ret; + goto out; } if (!wait_event_timeout(hidpp->wait, hidpp->answer_available, 5*HZ)) { dbg_hid("%s:timeout waiting for response\n", __func__); memset(response, 0, sizeof(struct hidpp_report)); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto out; } if (response->report_id == REPORT_ID_HIDPP_SHORT && response->rap.sub_id == HIDPP_ERROR) { ret = response->rap.params[1]; dbg_hid("%s:got hidpp error %02X\n", __func__, ret); - return ret; + goto out; } if ((response->report_id == REPORT_ID_HIDPP_LONG || @@ -327,10 +328,14 @@ static int __do_hidpp_send_message_sync(struct hidpp_device *hidpp, response->fap.feature_index == HIDPP20_ERROR) { ret = response->fap.params[1]; dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret); - return ret; + goto out; } - return 0; + ret = 0; + +out: + hidpp->send_receive_buf = NULL; + return ret; } /* @@ -3838,8 +3843,7 @@ static int hidpp_input_configured(struct hid_device *hdev, static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, int size) { - struct hidpp_report *question = hidpp->send_receive_buf; - struct hidpp_report *answer = hidpp->send_receive_buf; + struct hidpp_report *question, *answer; struct hidpp_report *report = (struct hidpp_report *)data; int ret; int last_online; @@ -3849,6 +3853,12 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data, * previously sent command. */ if (unlikely(mutex_is_locked(&hidpp->send_mutex))) { + question = hidpp->send_receive_buf; + answer = hidpp->send_receive_buf; + + if (!question) + return 0; + /* * Check for a correct hidpp20 answer or the corresponding * error diff --git a/drivers/hwmon/cgbc-hwmon.c b/drivers/hwmon/cgbc-hwmon.c index 3aff4e092132..230062a46907 100644 --- a/drivers/hwmon/cgbc-hwmon.c +++ b/drivers/hwmon/cgbc-hwmon.c @@ -41,45 +41,60 @@ enum cgbc_sensor_types { static const char * const cgbc_hwmon_labels_temp[] = { "CPU Temperature", - "Box Temperature", + "Case Temperature", "Ambient Temperature", - "Board Temperature", - "Carrier Temperature", - "Chipset Temperature", - "Video Temperature", + "CPU Board Temperature", + "Carrier Board Temperature", + "System Chipset Temperature", + "Video Controller/Board Temperature", "Other Temperature", - "TOPDIM Temperature", - "BOTTOMDIM Temperature", + "Top DIMM 0 Temperature", + "Bottom DIMM 0 Temperature", + "Alternate Board Temperature", + "Top DIMM 1 Temperature", + "Top DIMM 2 Temperature", + "Top DIMM 3 Temperature", + "Top DIMM 4 Temperature", + "Top DIMM 5 Temperature", + "Top DIMM 6 Temperature", + "Top DIMM 7 Temperature", + "Bottom DIMM 1 Temperature", }; +static const char * const cgbc_hwmon_labels_in[] = { + "CPU Core Voltage", + "DC Runtime Voltage", + "DC Standby Voltage", + "CMOS Battery Voltage", + "Battery Supply Voltage", + "AC Voltage", + "Other Voltage", + "5V Runtime Voltage", + "5V Standby Voltage", + "3V3 Runtime Voltage", + "3V3 Standby Voltage", + "VCore A Voltage", + "VCore B Voltage", + "12V Runtime Voltage", + "12V Standby Voltage", +}; + +/* + * Current sensors are a bit special, they don't have consecutive IDs like + * other types of sensors. So they need to be defined explicitly. + */ static const struct { - enum hwmon_sensor_types type; const char *label; -} cgbc_hwmon_labels_in[] = { - { hwmon_in, "CPU Voltage" }, - { hwmon_in, "DC Runtime Voltage" }, - { hwmon_in, "DC Standby Voltage" }, - { hwmon_in, "CMOS Battery Voltage" }, - { hwmon_in, "Battery Voltage" }, - { hwmon_in, "AC Voltage" }, - { hwmon_in, "Other Voltage" }, - { hwmon_in, "5V Voltage" }, - { hwmon_in, "5V Standby Voltage" }, - { hwmon_in, "3V3 Voltage" }, - { hwmon_in, "3V3 Standby Voltage" }, - { hwmon_in, "VCore A Voltage" }, - { hwmon_in, "VCore B Voltage" }, - { hwmon_in, "12V Voltage" }, - { hwmon_curr, "DC Current" }, - { hwmon_curr, "5V Current" }, - { hwmon_curr, "12V Current" }, + int id; +} cgbc_hwmon_labels_curr[] = { + { "DC Runtime Current", 0x12 }, + { "5V Runtime Current", 0x18 }, + { "12V Runtime Current", 0x1E }, }; -#define CGBC_HWMON_NB_IN_SENSORS 14 - static const char * const cgbc_hwmon_labels_fan[] = { "CPU Fan", - "Box Fan", + "Case Fan", "Ambient Fan", "Chipset Fan", "Video Fan", @@ -114,7 +129,8 @@ static int cgbc_hwmon_probe_sensors(struct device *dev, struct cgbc_hwmon_data * for (i = 0; i < nb_sensors; i++) { enum cgbc_sensor_types type; - unsigned int channel; + unsigned int channel, id; + int j; /* * No need to request data for the first sensor. @@ -128,32 +144,49 @@ static int cgbc_hwmon_probe_sensors(struct device *dev, struct cgbc_hwmon_data * } type = FIELD_GET(CGBC_HWMON_TYPE_MASK, data[1]); - channel = FIELD_GET(CGBC_HWMON_ID_MASK, data[1]) - 1; + id = FIELD_GET(CGBC_HWMON_ID_MASK, data[1]); + channel = id - 1; if (type == CGBC_HWMON_TYPE_TEMP && channel < ARRAY_SIZE(cgbc_hwmon_labels_temp)) { sensor->type = hwmon_temp; sensor->label = cgbc_hwmon_labels_temp[channel]; - } else if (type == CGBC_HWMON_TYPE_IN && - channel < ARRAY_SIZE(cgbc_hwmon_labels_in)) { + } else if (type == CGBC_HWMON_TYPE_IN) { /* * The Board Controller doesn't differentiate current and voltage sensors. - * Get the sensor type from cgbc_hwmon_labels_in[channel].type instead. + * First check if it is a current sensor. */ - sensor->type = cgbc_hwmon_labels_in[channel].type; - sensor->label = cgbc_hwmon_labels_in[channel].label; + for (j = 0; j < ARRAY_SIZE(cgbc_hwmon_labels_curr); j++) { + if (id == cgbc_hwmon_labels_curr[j].id) { + sensor->type = hwmon_curr; + sensor->label = cgbc_hwmon_labels_curr[j].label; + channel = j; + } + } + + /* If it's not a current sensor, it may be a voltage sensor. */ + if (!sensor->label && channel < ARRAY_SIZE(cgbc_hwmon_labels_in)) { + sensor->type = hwmon_in; + sensor->label = cgbc_hwmon_labels_in[channel]; + } } else if (type == CGBC_HWMON_TYPE_FAN && channel < ARRAY_SIZE(cgbc_hwmon_labels_fan)) { sensor->type = hwmon_fan; sensor->label = cgbc_hwmon_labels_fan[channel]; - } else { - dev_warn(dev, "Board Controller returned an unknown sensor (type=%d, channel=%d), ignore it", - type, channel); + } + + if (!sensor->label) { + dev_warn(dev, "Board Controller returned an unknown sensor (bc_type=%d, bc_id=%d), ignore it", + type, id); continue; } sensor->active = FIELD_GET(CGBC_HWMON_ACTIVE_BIT, data[1]); sensor->channel = channel; sensor->index = i; + + dev_dbg(dev, "Found sensor: bc_type=%d, bc_id=%d, hwmon_type=%d, hwmon_channel=%d, hwmon_label='%s', active=%d\n", + type, id, sensor->type, sensor->channel, sensor->label, sensor->active); + sensor++; hwmon->nb_sensors++; } @@ -167,14 +200,6 @@ static struct cgbc_hwmon_sensor *cgbc_hwmon_find_sensor(struct cgbc_hwmon_data * struct cgbc_hwmon_sensor *sensor = NULL; int i; - /* - * The Board Controller doesn't differentiate current and voltage sensors. - * The channel value (from the Board Controller point of view) shall be computed for current - * sensors. - */ - if (type == hwmon_curr) - channel += CGBC_HWMON_NB_IN_SENSORS; - for (i = 0; i < hwmon->nb_sensors; i++) { if (hwmon->sensors[i].type == type && hwmon->sensors[i].channel == channel) { sensor = &hwmon->sensors[i]; @@ -240,7 +265,12 @@ static const struct hwmon_channel_info * const cgbc_hwmon_info[] = { HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, - HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL), + HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL, + HWMON_T_INPUT | HWMON_T_LABEL), HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL, @@ -248,7 +278,8 @@ static const struct hwmon_channel_info * const cgbc_hwmon_info[] = { HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL, - HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL), + HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL, + HWMON_I_INPUT | HWMON_I_LABEL), HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_LABEL, HWMON_C_INPUT | HWMON_C_LABEL, HWMON_C_INPUT | HWMON_C_LABEL), diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index ea5ca2dea2a9..1dfc02df9bbb 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -68,7 +68,7 @@ static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id) schedule_work(&fan_data->alarm_work); - return IRQ_NONE; + return IRQ_HANDLED; } static ssize_t fan1_alarm_show(struct device *dev, @@ -103,7 +103,7 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data) irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH); return devm_request_irq(dev, alarm_irq, fan_alarm_irq_handler, - IRQF_SHARED, "GPIO fan alarm", fan_data); + 0, "GPIO fan alarm", fan_data); } /* diff --git a/drivers/hwmon/hp-wmi-sensors.c b/drivers/hwmon/hp-wmi-sensors.c index 03c684ba83bd..cfa0d6ad0fb3 100644 --- a/drivers/hwmon/hp-wmi-sensors.c +++ b/drivers/hwmon/hp-wmi-sensors.c @@ -526,14 +526,12 @@ static int check_wobj(const union acpi_object *wobj, for (prop = 0; prop <= last_prop; prop++) { type = elements[prop].type; valid_type = property_map[prop]; - if (type != valid_type) { - if (type == ACPI_TYPE_BUFFER && - valid_type == ACPI_TYPE_STRING && - is_raw_wmi_string(elements[prop].buffer.pointer, - elements[prop].buffer.length)) - continue; + if (type == ACPI_TYPE_BUFFER && + is_raw_wmi_string(elements[prop].buffer.pointer, + elements[prop].buffer.length)) + type = ACPI_TYPE_STRING; + if (type != valid_type) return -EINVAL; - } } return 0; @@ -579,6 +577,7 @@ static int check_numeric_sensor_wobj(const union acpi_object *wobj, int prop = HP_WMI_PROPERTY_NAME; acpi_object_type valid_type; union acpi_object *elements; + union acpi_object *element; u32 elem_count; int last_prop; bool is_new; @@ -602,13 +601,20 @@ static int check_numeric_sensor_wobj(const union acpi_object *wobj, elem_count > HP_WMI_MAX_PROPERTIES) return -EINVAL; - type = elements[HP_WMI_PROPERTY_SIZE].type; + element = &elements[HP_WMI_PROPERTY_SIZE]; + type = element->type; switch (type) { case ACPI_TYPE_INTEGER: is_new = true; last_prop = HP_WMI_PROPERTY_RATE_UNITS; break; + case ACPI_TYPE_BUFFER: + if (!is_raw_wmi_string(element->buffer.pointer, + element->buffer.length)) + return -EINVAL; + fallthrough; + case ACPI_TYPE_STRING: is_new = false; last_prop = HP_WMI_PROPERTY_CURRENT_READING; @@ -631,6 +637,10 @@ static int check_numeric_sensor_wobj(const union acpi_object *wobj, for (i = 0; i < elem_count && prop <= last_prop; i++, prop++) { type = elements[i].type; valid_type = hp_wmi_property_map[prop]; + if (type == ACPI_TYPE_BUFFER && + is_raw_wmi_string(elements[i].buffer.pointer, + elements[i].buffer.length)) + type = ACPI_TYPE_STRING; if (type != valid_type) return -EINVAL; @@ -651,6 +661,10 @@ static int check_numeric_sensor_wobj(const union acpi_object *wobj, /* PossibleStates[0] has already been type-checked. */ for (j = 0; i + 1 < elem_count && j + 1 < count; j++) { type = elements[++i].type; + if (type == ACPI_TYPE_BUFFER && + is_raw_wmi_string(elements[i].buffer.pointer, + elements[i].buffer.length)) + type = ACPI_TYPE_STRING; if (type != valid_type) return -EINVAL; } @@ -1247,7 +1261,9 @@ static int fungible_show(struct seq_file *seqf, enum hp_wmi_property prop) break; case HP_WMI_PROPERTY_CURRENT_STATE: + mutex_lock(&state->lock); seq_printf(seqf, "%s\n", nsensor->current_state); + mutex_unlock(&state->lock); break; case HP_WMI_PROPERTY_UNIT_MODIFIER: diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h index e499cdae9442..d8833b0299a2 100644 --- a/drivers/hwmon/pmbus/pmbus.h +++ b/drivers/hwmon/pmbus/pmbus.h @@ -242,6 +242,7 @@ enum pmbus_regs { /* * OPERATION */ +#define PB_OPERATION_CONTROL_V_SRC GENMASK(5, 4) #define PB_OPERATION_CONTROL_ON BIT(7) /* @@ -386,7 +387,7 @@ enum pmbus_sensor_classes { }; #define PMBUS_PAGES 32 /* Per PMBus specification */ -#define PMBUS_PHASES 10 /* Maximum number of phases per page */ +#define PMBUS_PHASES 16 /* Maximum number of phases per page */ /* Functionality bit mask */ #define PMBUS_HAVE_VIN BIT(0) diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index 249974c13aa3..228fb9d1560e 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -187,7 +187,7 @@ static int tps53676_identify(struct i2c_client *client, return -EIO; for (i = 0; i < 2 * TPS53676_MAX_PHASES; i += 2) { if (buf[i + 1] & 0x80) { - if (buf[i] & 0x08) + if (buf[i] & BIT(4)) phases_b++; else phases_a++; @@ -200,6 +200,15 @@ static int tps53676_identify(struct i2c_client *client, if (phases_b > 0) { info->pages = 2; info->phases[1] = phases_b; + } else { + /* + * pmbus_set_page() does not update the PAGE register on + * single-page devices, so select page 0 explicitly in case + * the boot firmware left the device on another page. + */ + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); + if (ret < 0) + return ret; } return 0; } diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 37269db2de84..9bdbe63c7db8 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -484,7 +484,6 @@ static void pwm_fan_cleanup(void *__ctx) { struct pwm_fan_ctx *ctx = __ctx; - timer_delete_sync(&ctx->rpm_timer); if (ctx->pwm_shutdown) { ctx->enable_mode = pwm_enable_reg_enable; __set_pwm(ctx, ctx->pwm_shutdown); @@ -495,6 +494,13 @@ static void pwm_fan_cleanup(void *__ctx) } } +static void pwm_fan_timer_cleanup(void *__ctx) +{ + struct pwm_fan_ctx *ctx = __ctx; + + timer_shutdown_sync(&ctx->rpm_timer); +} + static int pwm_fan_probe(struct platform_device *pdev) { struct thermal_cooling_device *cdev; @@ -649,6 +655,10 @@ static int pwm_fan_probe(struct platform_device *pdev) } if (ctx->tach_count > 0) { + ret = devm_add_action_or_reset(dev, pwm_fan_timer_cleanup, ctx); + if (ret) + return ret; + ctx->sample_start = ktime_get(); mod_timer(&ctx->rpm_timer, jiffies + HZ); @@ -704,6 +714,7 @@ static void pwm_fan_shutdown(struct platform_device *pdev) { struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); + pwm_fan_timer_cleanup(ctx); pwm_fan_cleanup(ctx); } diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 996e36951f9d..21f421d7379f 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -1415,6 +1415,7 @@ static void w83791d_remove(struct i2c_client *client) struct w83791d_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &w83791d_group_fanpwm45); sysfs_remove_group(&client->dev.kobj, &w83791d_group); } diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index ec03745328a6..109d0834834e 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -1928,7 +1928,9 @@ static int w83793_probe(struct i2c_client *client) for (i = 0; i < ARRAY_SIZE(w83793_temp); i++) device_remove_file(dev, &w83793_temp[i].dev_attr); free_mem: - kfree(data); + mutex_lock(&watchdog_data_mutex); + kref_put(&data->kref, w83793_release_resources); + mutex_unlock(&watchdog_data_mutex); exit: return err; } diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c index b64adef778d4..8ca4556d9664 100644 --- a/drivers/i2c/busses/i2c-at91-core.c +++ b/drivers/i2c/busses/i2c-at91-core.c @@ -255,6 +255,7 @@ static int at91_twi_probe(struct platform_device *pdev) if (rc) { pm_runtime_disable(dev->dev); pm_runtime_set_suspended(dev->dev); + at91_twi_dma_release(dev); return rc; } @@ -270,6 +271,8 @@ static void at91_twi_remove(struct platform_device *pdev) i2c_del_adapter(&dev->adapter); + at91_twi_dma_release(dev); + pm_runtime_disable(dev->dev); pm_runtime_set_suspended(dev->dev); } diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c index 894cedbca99f..68238cc8aee0 100644 --- a/drivers/i2c/busses/i2c-at91-master.c +++ b/drivers/i2c/busses/i2c-at91-master.c @@ -817,11 +817,21 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) error: if (ret != -EPROBE_DEFER) dev_info(dev->dev, "can't get DMA channel, continue without DMA support\n"); + at91_twi_dma_release(dev); + return ret; +} + +void at91_twi_dma_release(struct at91_twi_dev *dev) +{ + struct at91_twi_dma *dma = &dev->dma; + if (dma->chan_rx) dma_release_channel(dma->chan_rx); if (dma->chan_tx) dma_release_channel(dma->chan_tx); - return ret; + dma->chan_rx = NULL; + dma->chan_tx = NULL; + dev->use_dma = false; } static int at91_init_twi_recovery_gpio(struct platform_device *pdev, diff --git a/drivers/i2c/busses/i2c-at91.h b/drivers/i2c/busses/i2c-at91.h index 942e9c3973bb..d68fcbbc3e0f 100644 --- a/drivers/i2c/busses/i2c-at91.h +++ b/drivers/i2c/busses/i2c-at91.h @@ -172,6 +172,7 @@ void at91_twi_irq_restore(struct at91_twi_dev *dev); void at91_init_twi_bus(struct at91_twi_dev *dev); void at91_init_twi_bus_master(struct at91_twi_dev *dev); +void at91_twi_dma_release(struct at91_twi_dev *dev); int at91_twi_probe_master(struct platform_device *pdev, u32 phy_addr, struct at91_twi_dev *dev); diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 9477d814fde9..cccff6e63db2 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1880,6 +1880,8 @@ static int i2c_imx_probe(struct platform_device *pdev) clk_notifier_unregister: clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); + if (i2c_imx->dma) + i2c_imx_dma_free(i2c_imx); free_irq(irq, i2c_imx); rpm_disable: pm_runtime_put_noidle(&pdev->dev); @@ -1920,6 +1922,7 @@ static void i2c_imx_remove(struct platform_device *pdev) pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); } static int i2c_imx_runtime_suspend(struct device *dev) diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index 776c3e36e915..52ef7f07c51c 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -499,10 +499,14 @@ static const struct dev_pm_ops qcom_cci_pm = { SET_RUNTIME_PM_OPS(cci_suspend_runtime, cci_resume_runtime, NULL) }; +static void cci_put_of_node(void *data) +{ + of_node_put(data); +} + static int cci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *child; struct resource *r; struct cci *cci; int ret, i; @@ -518,7 +522,7 @@ static int cci_probe(struct platform_device *pdev) if (!cci->data) return -ENOENT; - for_each_available_child_of_node(dev->of_node, child) { + for_each_available_child_of_node_scoped(dev->of_node, child) { struct cci_master *master; u32 idx; @@ -539,6 +543,9 @@ static int cci_probe(struct platform_device *pdev) master->adap.algo = &cci_algo; master->adap.dev.parent = dev; master->adap.dev.of_node = of_node_get(child); + ret = devm_add_action_or_reset(dev, cci_put_of_node, child); + if (ret) + return ret; master->master = idx; master->cci = cci; @@ -610,10 +617,8 @@ static int cci_probe(struct platform_device *pdev) continue; ret = i2c_add_adapter(&cci->master[i].adap); - if (ret < 0) { - of_node_put(cci->master[i].adap.dev.of_node); + if (ret < 0) goto error_i2c; - } } return 0; @@ -621,10 +626,8 @@ static int cci_probe(struct platform_device *pdev) error_i2c: for (--i ; i >= 0; i--) { - if (cci->master[i].cci) { + if (cci->master[i].cci) i2c_del_adapter(&cci->master[i].adap); - of_node_put(cci->master[i].adap.dev.of_node); - } } disable_clocks: cci_disable_clocks(cci); @@ -640,7 +643,6 @@ static void cci_remove(struct platform_device *pdev) for (i = 0; i < cci->data->num_masters; i++) { if (cci->master[i].cci) { i2c_del_adapter(&cci->master[i].adap); - of_node_put(cci->master[i].adap.dev.of_node); cci_halt(cci, i); } } diff --git a/drivers/i2c/i2c-atr.c b/drivers/i2c/i2c-atr.c index dd194476b118..a05cec38d8c5 100644 --- a/drivers/i2c/i2c-atr.c +++ b/drivers/i2c/i2c-atr.c @@ -864,6 +864,7 @@ int i2c_atr_add_adapter(struct i2c_atr *atr, struct i2c_atr_adap_desc *desc) ret = i2c_add_adapter(&chan->adap); if (ret) { + atr->adapter[chan_id] = NULL; dev_err(dev, "failed to add atr-adapter %u (error=%d)\n", chan_id, ret); goto err_free_alias_pool; diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c index eecb369898f5..2c30f5c43c85 100644 --- a/drivers/infiniband/core/iwpm_util.c +++ b/drivers/infiniband/core/iwpm_util.c @@ -314,10 +314,6 @@ struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq, if (!nlmsg_request) return NULL; - spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags); - list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list); - spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags); - kref_init(&nlmsg_request->kref); kref_get(&nlmsg_request->kref); nlmsg_request->nlmsg_seq = nlmsg_seq; @@ -326,6 +322,11 @@ struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq, nlmsg_request->err_code = 0; sema_init(&nlmsg_request->sem, 1); down(&nlmsg_request->sem); + + spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags); + list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list); + spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags); + return nlmsg_request; } diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 5150cd53d443..f7ad35233c2d 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -2059,6 +2059,8 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, int ret; INIT_LIST_HEAD(&mad_recv_wc->rmpp_list); + list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); + ret = ib_mad_enforce_security(mad_agent_priv, mad_recv_wc->wc->pkey_index); if (ret) { @@ -2067,7 +2069,6 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, return; } - list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); if (is_kernel_rmpp_data_response(mad_agent_priv, mad_recv_wc)) { spin_lock_irqsave(&mad_agent_priv->lock, flags); mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc); diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 797efd4a4728..3620d243cd4f 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1556,9 +1556,10 @@ static ssize_t ucma_process_join(struct ucma_file *file, mutex_lock(&ctx->mutex); ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *)&mc->addr, join_state, mc); - mutex_unlock(&ctx->mutex); - if (ret) + if (ret) { + mutex_unlock(&ctx->mutex); goto err_xa_erase; + } resp.id = mc->id; if (copy_to_user(u64_to_user_ptr(cmd->response), @@ -1566,6 +1567,7 @@ static ssize_t ucma_process_join(struct ucma_file *file, ret = -EFAULT; goto err_leave_multicast; } + mutex_unlock(&ctx->mutex); xa_store(&multicast_table, mc->id, mc, 0); @@ -1573,7 +1575,6 @@ static ssize_t ucma_process_join(struct ucma_file *file, return 0; err_leave_multicast: - mutex_lock(&ctx->mutex); rdma_leave_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr); mutex_unlock(&ctx->mutex); ucma_cleanup_mc_events(mc); diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 4357164a9976..fcc21fb5fb86 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2051,11 +2051,13 @@ int ib_get_eth_speed(struct ib_device *dev, u32 port_num, u16 *speed, u8 *width) return -ENODEV; rtnl_lock(); - rc = __ethtool_get_link_ksettings(netdev, &lksettings); - rtnl_unlock(); - - dev_put(netdev); + if (READ_ONCE(netdev->reg_state) != NETREG_REGISTERED) { + dev_put(netdev); + rtnl_unlock(); + return -ENODEV; + } + rc = __ethtool_get_link_ksettings(netdev, &lksettings); if (!rc && lksettings.base.speed != (u32)SPEED_UNKNOWN) { netdev_speed = lksettings.base.speed; } else { @@ -2064,6 +2066,8 @@ int ib_get_eth_speed(struct ib_device *dev, u32 port_num, u16 *speed, u8 *width) pr_warn("%s speed is unknown, defaulting to %u\n", netdev->name, netdev_speed); } + dev_put(netdev); + rtnl_unlock(); ib_get_width_and_speed(netdev_speed, lksettings.lanes, speed, width); diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index f33e006126fd..e8a4befd6ca0 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -356,9 +356,13 @@ static int bnxt_re_update_qp1_tos_dscp(struct bnxt_re_dev *rdev) return bnxt_qplib_modify_qp(&rdev->qplib_res, &qp->qplib_qp); } -static void bnxt_re_init_dcb_wq(struct bnxt_re_dev *rdev) +static int bnxt_re_init_dcb_wq(struct bnxt_re_dev *rdev) { rdev->dcb_wq = create_singlethread_workqueue("bnxt_re_dcb_wq"); + if (!rdev->dcb_wq) + return -ENOMEM; + + return 0; } static void bnxt_re_uninit_dcb_wq(struct bnxt_re_dev *rdev) @@ -2340,7 +2344,9 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 op_type) bnxt_re_debugfs_add_pdev(rdev); - bnxt_re_init_dcb_wq(rdev); + rc = bnxt_re_init_dcb_wq(rdev); + if (rc) + goto fail; bnxt_re_net_register_async_event(rdev); if (!rdev->is_virtfn) diff --git a/drivers/infiniband/hw/efa/efa_com.c b/drivers/infiniband/hw/efa/efa_com.c index e97b5f0d7003..21b9bd1c1fef 100644 --- a/drivers/infiniband/hw/efa/efa_com.c +++ b/drivers/infiniband/hw/efa/efa_com.c @@ -750,7 +750,7 @@ int efa_com_admin_init(struct efa_com_dev *edev, aq->dmadev = edev->dmadev; aq->efa_dev = edev->efa_dev; - set_bit(EFA_AQ_STATE_POLLING_BIT, &aq->state); + efa_com_set_admin_polling_mode(edev, true); sema_init(&aq->avail_cmds, aq->depth); @@ -768,8 +768,6 @@ int efa_com_admin_init(struct efa_com_dev *edev, if (err) goto err_destroy_sq; - efa_com_set_admin_polling_mode(edev, false); - err = efa_com_admin_init_aenq(edev, aenq_handlers); if (err) goto err_destroy_cq; @@ -1158,7 +1156,7 @@ static void efa_com_destroy_eq(struct efa_com_dev *edev, err); } -static void efa_com_arm_eq(struct efa_com_dev *edev, struct efa_com_eq *eeq) +void efa_com_arm_eq(struct efa_com_dev *edev, struct efa_com_eq *eeq) { u32 val = 0; @@ -1247,7 +1245,6 @@ int efa_com_eq_init(struct efa_com_dev *edev, struct efa_com_eq *eeq, eeq->phase = 1; eeq->depth = params.depth; eeq->cb = cb; - efa_com_arm_eq(edev, eeq); return 0; diff --git a/drivers/infiniband/hw/efa/efa_com.h b/drivers/infiniband/hw/efa/efa_com.h index 4d9ca97e4296..1f635f4047ac 100644 --- a/drivers/infiniband/hw/efa/efa_com.h +++ b/drivers/infiniband/hw/efa/efa_com.h @@ -157,6 +157,7 @@ int efa_com_admin_init(struct efa_com_dev *edev, void efa_com_admin_destroy(struct efa_com_dev *edev); int efa_com_eq_init(struct efa_com_dev *edev, struct efa_com_eq *eeq, efa_eqe_handler cb, u16 depth, u8 msix_vec); +void efa_com_arm_eq(struct efa_com_dev *edev, struct efa_com_eq *eeq); void efa_com_eq_destroy(struct efa_com_dev *edev, struct efa_com_eq *eeq); int efa_com_dev_reset(struct efa_com_dev *edev, enum efa_regs_reset_reason_types reset_reason); diff --git a/drivers/infiniband/hw/efa/efa_main.c b/drivers/infiniband/hw/efa/efa_main.c index 6c415b9adb5f..fdaf88f0122d 100644 --- a/drivers/infiniband/hw/efa/efa_main.c +++ b/drivers/infiniband/hw/efa/efa_main.c @@ -300,28 +300,30 @@ static void efa_set_host_info(struct efa_dev *dev) static void efa_destroy_eq(struct efa_dev *dev, struct efa_eq *eq) { - efa_com_eq_destroy(&dev->edev, &eq->eeq); efa_free_irq(dev, &eq->irq); + efa_com_eq_destroy(&dev->edev, &eq->eeq); } static int efa_create_eq(struct efa_dev *dev, struct efa_eq *eq, u32 msix_vec) { int err; - efa_setup_comp_irq(dev, eq, msix_vec); - err = efa_request_irq(dev, &eq->irq); + err = efa_com_eq_init(&dev->edev, &eq->eeq, efa_process_eqe, + dev->dev_attr.max_eq_depth, msix_vec); if (err) return err; - err = efa_com_eq_init(&dev->edev, &eq->eeq, efa_process_eqe, - dev->dev_attr.max_eq_depth, msix_vec); + efa_setup_comp_irq(dev, eq, msix_vec); + err = efa_request_irq(dev, &eq->irq); if (err) - goto err_free_comp_irq; + goto err_destroy_eq; + + efa_com_arm_eq(&dev->edev, &eq->eeq); return 0; -err_free_comp_irq: - efa_free_irq(dev, &eq->irq); +err_destroy_eq: + efa_com_eq_destroy(&dev->edev, &eq->eeq); return err; } @@ -611,18 +613,21 @@ static struct efa_dev *efa_probe_device(struct pci_dev *pdev) edev->aq.msix_vector_idx = dev->admin_msix_vector_idx; edev->aenq.msix_vector_idx = dev->admin_msix_vector_idx; - err = efa_set_mgmnt_irq(dev); + err = efa_com_admin_init(edev, &aenq_handlers); if (err) goto err_disable_msix; - err = efa_com_admin_init(edev, &aenq_handlers); + err = efa_set_mgmnt_irq(dev); if (err) - goto err_free_mgmnt_irq; + goto err_destroy_admin; + + efa_com_set_admin_polling_mode(edev, false); return dev; -err_free_mgmnt_irq: - efa_free_irq(dev, &dev->admin_irq); +err_destroy_admin: + efa_com_dev_reset(edev, EFA_REGS_RESET_INIT_ERR); + efa_com_admin_destroy(edev); err_disable_msix: efa_disable_msix(dev); err_reg_read_destroy: @@ -646,8 +651,8 @@ static void efa_remove_device(struct pci_dev *pdev, edev = &dev->edev; efa_com_dev_reset(edev, reset_reason); - efa_com_admin_destroy(edev); efa_free_irq(dev, &dev->admin_irq); + efa_com_admin_destroy(edev); efa_disable_msix(dev); efa_com_mmio_reg_read_destroy(edev); devm_iounmap(&pdev->dev, edev->reg_bar); diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index 503abec709c9..a7a8a39e69fb 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -326,6 +326,7 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) void *memvirt = NULL; dma_addr_t memdma = 0; u8 subctxt, mapio = 0, vmf = 0, type; + size_t memdmalen = 0; ssize_t memlen = 0; int ret = 0; u16 ctxt; @@ -371,7 +372,9 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) mapio = 1; break; case PIO_CRED: { + struct credit_return_base *cr = &dd->cr_base[uctxt->sc->node]; u64 cr_page_offset; + if (flags & VM_WRITE) { ret = -EPERM; goto done; @@ -381,11 +384,18 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) * second or third page allocated for credit returns (if number * of enabled contexts > 64 and 128 respectively). */ - cr_page_offset = ((u64)uctxt->sc->hw_free - - (u64)dd->cr_base[uctxt->numa_id].va) & - PAGE_MASK; - memvirt = dd->cr_base[uctxt->numa_id].va + cr_page_offset; - memdma = dd->cr_base[uctxt->numa_id].dma + cr_page_offset; + cr_page_offset = ((u64)uctxt->sc->hw_free - (u64)cr->va) & + PAGE_MASK; + /* + * dma_mmap_coherent() describes the whole coherent buffer and + * selects the page within it with vma->vm_pgoff, so pass the + * base of the allocation and its length and let vm_pgoff pick + * the page. + */ + vma->vm_pgoff = cr_page_offset >> PAGE_SHIFT; + memvirt = cr->va; + memdma = cr->dma; + memdmalen = TXE_NUM_CONTEXTS * sizeof(struct credit_return); memlen = PAGE_SIZE; flags &= ~VM_MAYWRITE; flags |= VM_DONTCOPY | VM_DONTEXPAND; @@ -567,7 +577,8 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) ret = 0; } else if (memdma) { ret = dma_mmap_coherent(&dd->pcidev->dev, vma, - memvirt, memdma, memlen); + memvirt, memdma, + memdmalen ? memdmalen : memlen); } else if (mapio) { ret = io_remap_pfn_range(vma, vma->vm_start, PFN_DOWN(memaddr), diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index 9ada0bc00bd0..40443d77365b 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -4165,7 +4165,7 @@ static int irdma_post_send(struct ib_qp *ibqp, stag_info.total_len = iwmr->ibmr.length; stag_info.reg_addr_pa = *palloc->level1.addr; stag_info.first_pm_pbl_index = palloc->level1.idx; - stag_info.local_fence = ib_wr->send_flags & IB_SEND_FENCE; + stag_info.local_fence = true; if (iwmr->npages > IRDMA_MIN_PAGES_PER_FMR) stag_info.chunk_size = 1; err = irdma_sc_mr_fast_register(&iwqp->sc_qp, &stag_info, diff --git a/drivers/infiniband/hw/mlx4/sysfs.c b/drivers/infiniband/hw/mlx4/sysfs.c index 1676f819c2f7..9e6a0a22663d 100644 --- a/drivers/infiniband/hw/mlx4/sysfs.c +++ b/drivers/infiniband/hw/mlx4/sysfs.c @@ -753,11 +753,13 @@ static int register_one_pkey_tree(struct mlx4_ib_dev *dev, int slave) kobject_put(p); } kobject_put(dev->dev_ports_parent[slave]); + dev->dev_ports_parent[slave] = NULL; err_ports: kobject_put(dev->pkeys.device_parent[slave]); /* extra put for the device_parent create_and_add */ kobject_put(dev->pkeys.device_parent[slave]); + dev->pkeys.device_parent[slave] = NULL; fail_dev: kobject_put(dev->iov_parent); @@ -787,6 +789,8 @@ static void unregister_pkey_tree(struct mlx4_ib_dev *device) return; for (slave = device->dev->persist->num_vfs; slave >= 0; --slave) { + if (!device->pkeys.device_parent[slave]) + continue; list_for_each_entry_safe(p, t, &device->pkeys.pkey_port_list[slave], entry) { diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index c6b0bb786739..3dd100cd9156 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1669,11 +1669,8 @@ static int mlx5_ib_query_port_speed_rep(struct mlx5_ib_dev *dev, u32 port_num, struct mlx5_core_dev *mdev; u16 op_mod; - if (!dev->port[port_num - 1].rep) { - mlx5_ib_warn(dev, "Representor doesn't exist for port %u\n", - port_num); - return -EINVAL; - } + if (!dev->port[port_num - 1].rep) + return -ENODEV; rep = dev->port[port_num - 1].rep; mdev = mlx5_eswitch_get_core_dev(rep->esw); diff --git a/drivers/infiniband/sw/rxe/rxe_mcast.c b/drivers/infiniband/sw/rxe/rxe_mcast.c index 07ff47bae31d..c14680c9a536 100644 --- a/drivers/infiniband/sw/rxe/rxe_mcast.c +++ b/drivers/infiniband/sw/rxe/rxe_mcast.c @@ -175,7 +175,9 @@ struct rxe_mcg *rxe_lookup_mcg(struct rxe_dev *rxe, union ib_gid *mgid) * @mgid: multicast address as a gid * @mcg: new mcg object * - * Context: caller should hold rxe->mcg lock + * Initializes the mcg fields. The mcg is private and not yet visible in + * mcg_tree, so this may run without rxe->mcg_lock; __rxe_publish_mcg() + * makes it visible under the lock once it is ready. */ static void __rxe_init_mcg(struct rxe_dev *rxe, union ib_gid *mgid, struct rxe_mcg *mcg) @@ -184,13 +186,22 @@ static void __rxe_init_mcg(struct rxe_dev *rxe, union ib_gid *mgid, memcpy(&mcg->mgid, mgid, sizeof(mcg->mgid)); INIT_LIST_HEAD(&mcg->qp_list); mcg->rxe = rxe; +} - /* caller holds a ref on mcg but that will be - * dropped when mcg goes out of scope. We need to take a ref - * on the pointer that will be saved in the red-black tree - * by __rxe_insert_mcg and used to lookup mcg from mgid later. - * Inserting mcg makes it visible to outside so this should - * be done last after the object is ready. +/** + * __rxe_publish_mcg - make a fully initialized mcg visible in mcg_tree + * @mcg: the mcg object + * + * Context: caller must hold rxe->mcg_lock and a reference on mcg + */ +static void __rxe_publish_mcg(struct rxe_mcg *mcg) +{ + /* caller holds a ref on mcg but that will be dropped when mcg goes + * out of scope. We need to take a ref on the pointer that will be + * saved in the red-black tree by __rxe_insert_mcg and used to lookup + * mcg from mgid later. Inserting mcg makes it visible to outside so + * this is done last after the object is ready and the multicast + * address has been programmed. */ kref_get(&mcg->ref_cnt); __rxe_insert_mcg(mcg); @@ -228,26 +239,37 @@ static struct rxe_mcg *rxe_get_mcg(struct rxe_dev *rxe, union ib_gid *mgid) err = -ENOMEM; goto err_dec; } + __rxe_init_mcg(rxe, mgid, mcg); + + /* program the multicast address while mcg is still private, before + * it is inserted into mcg_tree. dev_mc_add() may sleep so this must + * run outside mcg_lock. On failure mcg was never published, so a + * plain free is correct and the tree is untouched. + */ + err = rxe_mcast_add(rxe, mgid); + if (err) { + kfree(mcg); + goto err_dec; + } spin_lock_bh(&rxe->mcg_lock); - /* re-check to see if someone else just added it */ + /* re-check to see if someone else just added it while we were adding + * the multicast address; if so use theirs and drop ours + */ tmp = __rxe_lookup_mcg(rxe, mgid); if (tmp) { spin_unlock_bh(&rxe->mcg_lock); + rxe_mcast_del(rxe, mgid); atomic_dec(&rxe->mcg_num); kfree(mcg); return tmp; } - __rxe_init_mcg(rxe, mgid, mcg); + __rxe_publish_mcg(mcg); spin_unlock_bh(&rxe->mcg_lock); - /* add mcast address outside of lock */ - err = rxe_mcast_add(rxe, mgid); - if (!err) - return mcg; + return mcg; - kfree(mcg); err_dec: atomic_dec(&rxe->mcg_num); return ERR_PTR(err); diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c index 2c486bb616a7..cd787e24c9ac 100644 --- a/drivers/infiniband/sw/rxe/rxe_mr.c +++ b/drivers/infiniband/sw/rxe/rxe_mr.c @@ -33,7 +33,8 @@ int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length) case IB_MR_TYPE_USER: case IB_MR_TYPE_MEM_REG: if (iova < mr->ibmr.iova || - iova + length > mr->ibmr.iova + mr->ibmr.length) { + length > mr->ibmr.length || + iova - mr->ibmr.iova > mr->ibmr.length - length) { rxe_dbg_mr(mr, "iova/length out of range\n"); return -EINVAL; } diff --git a/drivers/infiniband/sw/rxe/rxe_odp.c b/drivers/infiniband/sw/rxe/rxe_odp.c index 16b3fbdf2f86..995c1cb5c958 100644 --- a/drivers/infiniband/sw/rxe/rxe_odp.c +++ b/drivers/infiniband/sw/rxe/rxe_odp.c @@ -126,19 +126,23 @@ int rxe_odp_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, } static inline bool rxe_check_pagefault(struct ib_umem_odp *umem_odp, u64 iova, - int length) + int length, bool write) { bool need_fault = false; + u64 access = HMM_PFN_VALID; u64 addr; int idx; + if (write) + access |= HMM_PFN_WRITE; + addr = iova & (~(BIT(umem_odp->page_shift) - 1)); /* Skim through all pages that are to be accessed. */ while (addr < iova + length) { idx = (addr - ib_umem_start(umem_odp)) >> umem_odp->page_shift; - if (!(umem_odp->map.pfn_list[idx] & HMM_PFN_VALID)) { + if ((umem_odp->map.pfn_list[idx] & access) != access) { need_fault = true; break; } @@ -161,6 +165,7 @@ static unsigned long rxe_odp_iova_to_page_offset(struct ib_umem_odp *umem_odp, u static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u32 flags) { struct ib_umem_odp *umem_odp = to_ib_umem_odp(mr->umem); + bool write = !(flags & RXE_PAGEFAULT_RDONLY); bool need_fault; int err; @@ -169,7 +174,7 @@ static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u mutex_lock(&umem_odp->umem_mutex); - need_fault = rxe_check_pagefault(umem_odp, iova, length); + need_fault = rxe_check_pagefault(umem_odp, iova, length, write); if (need_fault) { mutex_unlock(&umem_odp->umem_mutex); @@ -179,7 +184,7 @@ static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u if (err < 0) return err; - need_fault = rxe_check_pagefault(umem_odp, iova, length); + need_fault = rxe_check_pagefault(umem_odp, iova, length, write); if (need_fault) { mutex_unlock(&umem_odp->umem_mutex); return -EFAULT; @@ -341,8 +346,9 @@ int rxe_odp_flush_pmem_iova(struct rxe_mr *mr, u64 iova, int err; u8 *va; + /* A flush never modifies memory; read-only access suffices. */ err = rxe_odp_map_range_and_lock(mr, iova, length, - RXE_PAGEFAULT_DEFAULT); + RXE_PAGEFAULT_RDONLY); if (err) return err; diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index 23304765decf..a1c75ccea40d 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -1346,19 +1346,20 @@ static struct ib_mr *rxe_rereg_user_mr(struct ib_mr *ibmr, int flags, if (err) return ERR_PTR(err); + if ((flags & IB_MR_REREG_ACCESS) && + (access & ~RXE_ACCESS_SUPPORTED_MR)) { + rxe_err_mr(mr, "access = %#x not supported\n", access); + return ERR_PTR(-EOPNOTSUPP); + } + if (flags & IB_MR_REREG_PD) { rxe_put(old_pd); rxe_get(pd); mr->ibmr.pd = ibpd; } - if (flags & IB_MR_REREG_ACCESS) { - if (access & ~RXE_ACCESS_SUPPORTED_MR) { - rxe_err_mr(mr, "access = %#x not supported\n", access); - return ERR_PTR(-EOPNOTSUPP); - } + if (flags & IB_MR_REREG_ACCESS) mr->access = access; - } return NULL; } diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c index bb7d90963907..04fabab44058 100644 --- a/drivers/infiniband/sw/siw/siw_cm.c +++ b/drivers/infiniband/sw/siw/siw_cm.c @@ -1669,9 +1669,12 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) SIW_QP_ATTR_STATE | SIW_QP_ATTR_LLP_HANDLE | SIW_QP_ATTR_ORD | SIW_QP_ATTR_IRD | SIW_QP_ATTR_MPA); + if (rv) { + qp->cep = NULL; + siw_cep_put(cep); + goto error_unlock; + } up_write(&qp->state_lock); - if (rv) - goto error; siw_dbg_cep(cep, "[QP %u]: send mpa reply, %d byte pdata\n", qp_id(qp), params->private_data_len); diff --git a/drivers/infiniband/sw/siw/siw_qp_rx.c b/drivers/infiniband/sw/siw/siw_qp_rx.c index b566d163c5aa..e5b641c8d694 100644 --- a/drivers/infiniband/sw/siw/siw_qp_rx.c +++ b/drivers/infiniband/sw/siw/siw_qp_rx.c @@ -1079,7 +1079,7 @@ static int siw_get_hdr(struct siw_rx_stream *srx) if (iwarp_pktinfo[opcode].hdr_len > sizeof(struct iwarp_ctrl_tagged)) { int hdrlen = iwarp_pktinfo[opcode].hdr_len; - bytes = min_t(int, hdrlen - MIN_DDP_HDR, srx->skb_new); + bytes = min_t(int, hdrlen - srx->fpdu_part_rcvd, srx->skb_new); skb_copy_bits(skb, srx->skb_offset, (char *)c_hdr + srx->fpdu_part_rcvd, bytes); diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 91f866e3fb8b..143e03b64902 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -87,6 +87,7 @@ enum { IPOIB_FLAG_INITIALIZED = 1, IPOIB_FLAG_ADMIN_UP = 2, IPOIB_PKEY_ASSIGNED = 3, + IPOIB_FLAG_MCAST_FLUSH = 4, IPOIB_FLAG_SUBINTERFACE = 5, IPOIB_STOP_REAPER = 7, IPOIB_FLAG_ADMIN_CM = 9, @@ -414,6 +415,12 @@ struct ipoib_dev_priv { const struct net_device_ops *rn_ops; }; +static inline bool ipoib_mcast_allowed(struct ipoib_dev_priv *priv) +{ + return test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) && + !test_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags); +} + struct ipoib_ah { struct net_device *dev; struct ib_ah *ah; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 10b0dbda6cd5..8d9aa75b8320 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -1227,17 +1227,19 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, } if (level == IPOIB_FLUSH_LIGHT) { - int oper_up; ipoib_mark_paths_invalid(dev); - /* Set IPoIB operation as down to prevent races between: + /* Set MCAST_FLUSH to prevent races between: * the flush flow which leaves MCG and on the fly joins * which can happen during that time. mcast restart task * should deal with join requests we missed. + * + * Do not clear OPER_UP for this; restoring it races with + * ipoib_ib_dev_down() and can leave OPER_UP set after the + * device is down. */ - oper_up = test_and_clear_bit(IPOIB_FLAG_OPER_UP, &priv->flags); + set_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags); ipoib_mcast_dev_flush(dev); - if (oper_up) - set_bit(IPOIB_FLAG_OPER_UP, &priv->flags); + clear_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags); ipoib_reap_dead_ahs(priv); } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 8a4ab9ff0a68..4f7639bbc7dc 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -74,7 +74,7 @@ static void __ipoib_mcast_schedule_join_thread(struct ipoib_dev_priv *priv, struct ipoib_mcast *mcast, bool delay) { - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) return; /* @@ -469,7 +469,7 @@ static int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast) int ret = 0; if (!priv->broadcast || - !test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + !ipoib_mcast_allowed(priv)) return -EINVAL; init_completion(&mcast->done); @@ -555,7 +555,7 @@ void ipoib_mcast_join_task(struct work_struct *work) unsigned long delay_until = 0; struct ipoib_mcast *mcast = NULL; - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) return; if (ib_query_port(priv->ca, priv->port, &port_attr)) { @@ -577,7 +577,7 @@ void ipoib_mcast_join_task(struct work_struct *work) netif_addr_unlock_bh(dev); spin_lock_irq(&priv->lock); - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) goto out; if (!priv->broadcast) { @@ -749,7 +749,7 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb) spin_lock_irqsave(&priv->lock, flags); - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) || + if (!ipoib_mcast_allowed(priv) || !priv->broadcast || !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { ++dev->stats.tx_dropped; @@ -871,7 +871,7 @@ void ipoib_mcast_restart_task(struct work_struct *work) LIST_HEAD(remove_list); struct ib_sa_mcmember_rec rec; - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) /* * shortcut...on shutdown flush is called next, just * let it do all the work @@ -965,9 +965,9 @@ void ipoib_mcast_restart_task(struct work_struct *work) ipoib_mcast_remove_list(&remove_list); /* - * Double check that we are still up + * Double check that we are still up and not flushing */ - if (test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { + if (ipoib_mcast_allowed(priv)) { spin_lock_irq(&priv->lock); __ipoib_mcast_schedule_join_thread(priv, NULL, 0); spin_unlock_irq(&priv->lock); diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index f5f090dc4f1e..cf234ddbaaad 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -599,11 +599,8 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc, iser_dbg("conn %p: remote invalidation for rkey %#x\n", iser_conn, rkey); - if (unlikely(!iser_conn->snd_w_inv)) { - iser_err("conn %p: unexpected remote invalidation, terminating connection\n", - iser_conn); - return -EPROTO; - } + if (unlikely(!iser_conn->snd_w_inv)) + goto bad_inv; task = iscsi_itt_to_ctask(iser_conn->iscsi_conn, hdr->itt); if (likely(task)) { @@ -612,12 +609,16 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc, if (iser_task->dir[ISER_DIR_IN]) { desc = iser_task->rdma_reg[ISER_DIR_IN].desc; + if (unlikely(!desc)) + goto bad_inv; if (unlikely(iser_inv_desc(desc, rkey))) return -EINVAL; } if (iser_task->dir[ISER_DIR_OUT]) { desc = iser_task->rdma_reg[ISER_DIR_OUT].desc; + if (unlikely(!desc)) + goto bad_inv; if (unlikely(iser_inv_desc(desc, rkey))) return -EINVAL; } @@ -628,6 +629,11 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc, } return 0; + +bad_inv: + iser_err("conn %p: unexpected remote invalidation, terminating connection\n", + iser_conn); + return -EPROTO; } diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 6483a55170cd..b3fc753982a3 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "ib_isert.h" @@ -311,6 +312,7 @@ isert_init_conn(struct isert_conn *isert_conn) init_completion(&isert_conn->login_req_comp); init_waitqueue_head(&isert_conn->rem_wait); kref_init(&isert_conn->kref); + atomic_set(&isert_conn->ctrl_comp_cnt, 0); mutex_init(&isert_conn->mutex); INIT_WORK(&isert_conn->release_work, isert_release_work); } @@ -1697,6 +1699,8 @@ isert_do_control_comp(struct work_struct *work) struct isert_conn *isert_conn = isert_cmd->conn; struct ib_device *ib_dev = isert_conn->cm_id->device; struct iscsit_cmd *cmd = isert_cmd->iscsit_cmd; + /* The switch below may free isert_cmd. */ + bool counted = isert_cmd->ctrl_counted; isert_dbg("Cmd %p i_state %d\n", isert_cmd, cmd->i_state); @@ -1718,6 +1722,14 @@ isert_do_control_comp(struct work_struct *work) dump_stack(); break; } + + /* + * The count is what keeps isert_conn alive, so drop it last. The wait + * queue lives in the global hash table, not in isert_conn, so this is + * safe even if the waiter has already freed the connection. + */ + if (counted && atomic_dec_and_test(&isert_conn->ctrl_comp_cnt)) + wake_up_var(&isert_conn->ctrl_comp_cnt); } static void @@ -1761,6 +1773,12 @@ isert_send_done(struct ib_cq *cq, struct ib_wc *wc) case ISTATE_SEND_TEXTRSP: isert_unmap_tx_desc(tx_desc, ib_dev); + /* Paired with the wait in isert_wait_conn(). */ + isert_cmd->ctrl_counted = + isert_cmd->iscsit_cmd->i_state != ISTATE_SEND_LOGOUTRSP; + if (isert_cmd->ctrl_counted) + atomic_inc(&isert_conn->ctrl_comp_cnt); + INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp); queue_work(isert_comp_wq, &isert_cmd->comp_work); return; @@ -2605,6 +2623,10 @@ static void isert_wait_conn(struct iscsit_conn *conn) isert_wait4cmds(conn); isert_wait4logout(isert_conn); + /* Paired with the count taken in isert_send_done(). */ + wait_var_event(&isert_conn->ctrl_comp_cnt, + !atomic_read(&isert_conn->ctrl_comp_cnt)); + queue_work(isert_release_wq, &isert_conn->release_work); } diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h index 0bac5aa66c80..519b17e54bd3 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.h +++ b/drivers/infiniband/ulp/isert/ib_isert.h @@ -153,6 +153,7 @@ struct isert_cmd { struct work_struct comp_work; struct scatterlist sg; bool ctx_init_done; + bool ctrl_counted; }; static inline struct isert_cmd *tx_desc_to_cmd(struct iser_tx_desc *desc) @@ -187,6 +188,7 @@ struct isert_conn { struct mutex mutex; struct kref kref; struct work_struct release_work; + atomic_t ctrl_comp_cnt; bool logout_posted; bool snd_w_inv; wait_queue_head_t rem_wait; diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c index 8fa1d72bd20a..fea3b17611c5 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c @@ -1738,6 +1738,8 @@ static void destroy_con_cq_qp(struct rtrs_clt_con *con) /* * Be careful here: destroy_con_cq_qp() can be called even * create_con_cq_qp() failed, see comments there. + * Caller must set con->destroyed under this lock first so a + * racing ADDR_RESOLVED cannot ib_cq_pool_get() after we PUT/SKIP. */ lockdep_assert_held(&con->con_mutex); rtrs_cq_qp_destroy(&con->c); @@ -1772,6 +1774,10 @@ static int rtrs_rdma_addr_resolved(struct rtrs_clt_con *con) int err; mutex_lock(&con->con_mutex); + if (con->destroyed) { + mutex_unlock(&con->con_mutex); + return -ECONNABORTED; + } err = create_con_cq_qp(con); mutex_unlock(&con->con_mutex); if (err) { @@ -2202,6 +2208,7 @@ static void rtrs_clt_stop_and_destroy_conns(struct rtrs_clt_path *clt_path) break; con = to_clt_con(clt_path->s.con[cid]); mutex_lock(&con->con_mutex); + con->destroyed = true; destroy_con_cq_qp(con); mutex_unlock(&con->con_mutex); destroy_cm(con); @@ -2368,6 +2375,7 @@ static int init_conns(struct rtrs_clt_path *clt_path) if (con->c.cm_id) { stop_cm(con); mutex_lock(&con->con_mutex); + con->destroyed = true; destroy_con_cq_qp(con); mutex_unlock(&con->con_mutex); destroy_cm(con); diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.h b/drivers/infiniband/ulp/rtrs/rtrs-clt.h index 0f57759b3080..e1e7c7adc947 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.h +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.h @@ -75,6 +75,8 @@ struct rtrs_clt_con { unsigned int cpu; struct mutex con_mutex; int cm_err; + /* Set under con_mutex before CQ/QP teardown. */ + bool destroyed; }; /** diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 1cf5ab25dc0a..d3cf1a0d3390 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -1229,6 +1229,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, t = _IOC_NR(cmd) & ABS_MAX; + memset(&abs, 0, sizeof(abs)); + if (copy_from_user(&abs, p, min_t(size_t, size, sizeof(struct input_absinfo)))) return -EFAULT; diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c index a5043193ead8..8860a0730294 100644 --- a/drivers/input/input-compat.c +++ b/drivers/input/input-compat.c @@ -76,6 +76,8 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size, */ compat_effect = (struct ff_effect_compat *)effect; + memset(effect, 0, sizeof(*effect)); + if (copy_from_user(compat_effect, buffer, sizeof(struct ff_effect_compat))) return -EFAULT; diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 1b6f38f62905..3e0c52c74906 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -249,7 +249,7 @@ static const struct xpad_device { { 0x0e6f, 0x0139, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x013a, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, - { 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x0147, "PDP Marvel Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0e6f, 0x015d, "PDP Mirror's Edge Official Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0161, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, @@ -261,6 +261,7 @@ static const struct xpad_device { { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE }, + { 0x0e6f, 0x024c, "PDP Victrix Pro BFG Wired Controller for Xbox", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x02a0, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x02a1, "PDP Xbox One Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x02a2, "PDP Wired Controller for Xbox One - Crimson Red", 0, XTYPE_XBOXONE }, @@ -326,6 +327,12 @@ static const struct xpad_device { { 0x1689, 0xfd00, "Razer Onza Tournament Edition", 0, XTYPE_XBOX360 }, { 0x1689, 0xfd01, "Razer Onza Classic Edition", 0, XTYPE_XBOX360 }, { 0x1689, 0xfe00, "Razer Sabertooth", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x1103, "Azeron Cyro", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x113c, "Azeron Cyborg", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x1192, "Azeron Classic/Compact", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x1212, "Azeron Cyro Lefty", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x12f7, "Azeron Cyborg II", 0, XTYPE_XBOX360 }, + { 0x16d0, 0x13ea, "Azeron Keyzen", 0, XTYPE_XBOX360 }, { 0x17ef, 0x6182, "Lenovo Legion Controller for Windows", 0, XTYPE_XBOX360 }, { 0x1949, 0x041a, "Amazon Game Controller", 0, XTYPE_XBOX360 }, { 0x1a86, 0xe310, "Legion Go S", 0, XTYPE_XBOX360 }, @@ -568,6 +575,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x15e4), /* Numark Xbox 360 controllers */ XPAD_XBOX360_VENDOR(0x162e), /* Joytech Xbox 360 controllers */ XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */ + XPAD_XBOX360_VENDOR(0x16d0), /* Azeron controllers */ XPAD_XBOX360_VENDOR(0x17ef), /* Lenovo */ XPAD_XBOX360_VENDOR(0x1949), /* Amazon controllers */ XPAD_XBOX360_VENDOR(0x1a86), /* Nanjing Qinheng Microelectronics (WCH) */ diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 414fbef4abf9..8964a31ce59a 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -447,12 +447,6 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) mutex_init(&kpad->gpio_lock); - error = devm_gpiochip_add_data(dev, &kpad->gc, kpad); - if (error) { - dev_err(dev, "gpiochip_add failed: %d\n", error); - return error; - } - for (i = 0; i <= ADP5588_BANK(ADP5588_MAXGPIO); i++) { kpad->dat_out[i] = adp5588_read(kpad->client, GPIO_DAT_OUT1 + i); @@ -460,6 +454,12 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad) kpad->pull_dis[i] = adp5588_read(kpad->client, GPIO_PULL1 + i); } + error = devm_gpiochip_add_data(dev, &kpad->gc, kpad); + if (error) { + dev_err(dev, "gpiochip_add failed: %d\n", error); + return error; + } + return 0; } diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index db7762abfe5c..5facd6275c09 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -1975,6 +1975,14 @@ static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { }, .callback = atkbd_deactivate_fixup, }, + { + /* Xiaomi Redmi Book Pro 16 2026 (TM2425) */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "XIAOMI"), + DMI_MATCH(DMI_PRODUCT_NAME, "REDMI Book Pro 16 2026"), + }, + .callback = atkbd_deactivate_fixup, + }, { } }; diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index b8cad415c62c..f08e29af531f 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -16,6 +16,7 @@ #include #include #include +#include #include static bool use_low_level_irq; @@ -160,7 +161,7 @@ soc_button_device_create(struct platform_device *pdev, struct gpio_keys_platform_data *gpio_keys_pdata; const struct dmi_system_id *dmi_id; int invalid_acpi_index = -1; - int error, gpio, irq; + int error, gpio, irq = 0; int n_buttons = 0; for (info = button_info; info->name; info++) @@ -191,8 +192,9 @@ soc_button_device_create(struct platform_device *pdev, error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index, &gpio, &irq); if (error || irq < 0) { /* - * Skip GPIO if not present. Note we deliberately - * ignore -EPROBE_DEFER errors here. On some devices + * Propagate -EPROBE_DEFER, skip button on other errors. + * + * -EPROBE_DEFER is ignored on Bay & Cherry Trail. Here * Intel is using so called virtual GPIOs which are not * GPIOs at all but some way for AML code to check some * random status bits without need a custom opregion. @@ -201,6 +203,12 @@ soc_button_device_create(struct platform_device *pdev, * we do not have a driver for these so they will never * show up, therefore we ignore -EPROBE_DEFER. */ + if ((error == -EPROBE_DEFER || irq == -EPROBE_DEFER) && + !(soc_intel_is_byt() || soc_intel_is_cht())) { + error = -EPROBE_DEFER; + goto err_free_mem; + } + continue; } @@ -369,7 +377,7 @@ static struct soc_button_info *soc_button_get_button_info(struct device *dev) } } - if (!btns_desc) { + if (!btns_desc || !btns_desc->package.count) { dev_err(dev, "ACPI Button Descriptors not found\n"); button_info = ERR_PTR(-ENODEV); goto out; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 4fbb58cc145d..701377805dec 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -1837,6 +1837,14 @@ static int synaptics_setup_intertouch(struct psmouse *psmouse, return -ENXIO; } + + /* Disable intertouch on known-broken board revisions */ + if (info->board_id == 2722) { + psmouse_info(psmouse, + "Disabling intertouch for board id %u\n", + info->board_id); + return -ENXIO; + } } psmouse_info(psmouse, "Trying to set up SMBus access\n"); diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index ccd9338a44db..18d188696bfa 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -947,6 +947,15 @@ int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake) { int retval; + /* + * Transport driver will try to suspend RMI device even if physical + * driver did not bind to the RMI device, because transport device + * (I2C, SPI) is fully registered and operational. Exit early if + * there is no driver data attached to the RMI device. + */ + if (!dev_get_drvdata(&rmi_dev->dev)) + return 0; + retval = rmi_suspend_functions(rmi_dev); if (retval) dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n", @@ -961,6 +970,10 @@ int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake) { int retval; + /* Skip if not fully bound to RMI driver */ + if (!dev_get_drvdata(&rmi_dev->dev)) + return 0; + rmi_enable_irq(rmi_dev, clear_wake); retval = rmi_resume_functions(rmi_dev); diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c index f3d0b40721df..8118e755b24a 100644 --- a/drivers/input/rmi4/rmi_smbus.c +++ b/drivers/input/rmi4/rmi_smbus.c @@ -140,7 +140,7 @@ static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr, u8 commandcode; struct rmi_smb_xport *rmi_smb = container_of(xport, struct rmi_smb_xport, xport); - int cur_len = (int)len; + size_t cur_len = len; mutex_lock(&rmi_smb->page_mutex); @@ -148,7 +148,7 @@ static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr, /* * break into 32 bytes chunks to write get command code */ - int block_len = min_t(int, len, SMB_MAX_COUNT); + int block_len = min_t(size_t, cur_len, SMB_MAX_COUNT); retval = rmi_smb_get_command_code(xport, rmiaddr, block_len, false, &commandcode); @@ -161,9 +161,9 @@ static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr, goto exit; /* prepare to write next block of bytes */ - cur_len -= SMB_MAX_COUNT; - databuff += SMB_MAX_COUNT; - rmiaddr += SMB_MAX_COUNT; + cur_len -= block_len; + databuff += block_len; + rmiaddr += block_len; } exit: mutex_unlock(&rmi_smb->page_mutex); diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 1461ef319f92..ecf5347b63ab 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -981,7 +981,7 @@ static void hp_sdc_exit(void) free_irq(hp_sdc.irq, &hp_sdc); write_unlock_irq(&hp_sdc.lock); - timer_delete_sync(&hp_sdc.kicker); + timer_shutdown_sync(&hp_sdc.kicker); tasklet_kill(&hp_sdc.task); diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h index 8ebdf4fb9030..ec364559d9e7 100644 --- a/drivers/input/serio/i8042-acpipnpio.h +++ b/drivers/input/serio/i8042-acpipnpio.h @@ -258,6 +258,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { }, .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire AG15-42P"), + }, + .driver_data = (void *)(SERIO_QUIRK_RESET_ALWAYS) + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c index 071b7c9bf566..1b48cf2e6895 100644 --- a/drivers/input/touchscreen/cyttsp5.c +++ b/drivers/input/touchscreen/cyttsp5.c @@ -711,6 +711,7 @@ static irqreturn_t cyttsp5_handle_irq(int irq, void *handle) size = 2; } else { report_id = ts->input_buf[2]; + size = min(size, CY_MAX_INPUT); } switch (report_id) { diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 87eb18977b71..50f150d82f29 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -283,6 +283,7 @@ static const struct of_device_id of_eeti_ts_match[] = { { .compatible = "eeti,exc3000-i2c", }, { } }; +MODULE_DEVICE_TABLE(of, of_eeti_ts_match); #endif static struct i2c_driver eeti_ts_driver = { diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 20889f94610c..358467875697 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -454,8 +454,9 @@ static int video_i2c_thread_vid_cap(void *priv) spin_lock(&data->slock); if (!list_empty(&data->vid_cap_active)) { - vid_cap_buf = list_last_entry(&data->vid_cap_active, - struct video_i2c_buffer, list); + vid_cap_buf = list_first_entry(&data->vid_cap_active, + struct video_i2c_buffer, + list); list_del(&vid_cap_buf->list); } diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c index e3657efd045e..e2ebc4190026 100644 --- a/drivers/memstick/core/ms_block.c +++ b/drivers/memstick/core/ms_block.c @@ -2205,6 +2205,8 @@ static void msb_remove(struct memstick_dev *card) msb_data_clear(msb); mutex_unlock(&msb_disk_lock); + destroy_workqueue(msb->io_queue); + put_disk(msb->disk); memstick_set_drvdata(card, NULL); } diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c index 999026a1ae04..3eabab9f3c54 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #define NTSYNC_NAME "ntsync" @@ -845,6 +846,8 @@ static int ntsync_schedule(const struct ntsync_q *q, const struct ntsync_wait_ar if (args->flags & NTSYNC_WAIT_REALTIME) clock = CLOCK_REALTIME; + else + timeout = timens_ktime_to_host(clock, timeout); do { if (signal_pending(current)) { @@ -881,6 +884,9 @@ static int setup_wait(struct ntsync_device *dev, if (args->pad || (args->flags & ~NTSYNC_WAIT_REALTIME)) return -EINVAL; + if (!args->owner) + return -EINVAL; + if (size >= sizeof(fds)) return -EINVAL; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index ec4f3462bf80..f9905eb4f174 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -417,8 +417,8 @@ void mmc_remove_card(struct mmc_card *card) mmc_hostname(card->host), card->rca); } device_del(&card->dev); - of_node_put(card->dev.of_node); } + of_node_put(card->dev.of_node); if (host->cqe_enabled) { host->cqe_ops->cqe_disable(host); diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 88c95dbfd9cf..becb5a850a2f 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -693,6 +693,7 @@ EXPORT_SYMBOL(mmc_remove_host); void mmc_free_host(struct mmc_host *host) { cancel_delayed_work_sync(&host->detect); + cancel_work_sync(&host->sdio_irq_work); mmc_pwrseq_free(host); put_device(&host->class_dev); } diff --git a/drivers/mmc/core/sdio_uart.c b/drivers/mmc/core/sdio_uart.c index 7423a601e1e5..dd42a69125fb 100644 --- a/drivers/mmc/core/sdio_uart.c +++ b/drivers/mmc/core/sdio_uart.c @@ -104,6 +104,9 @@ static int sdio_uart_add_port(struct sdio_uart_port *port) } spin_unlock(&sdio_uart_table_lock); + if (ret) + kfifo_free(&port->xmit_fifo); + return ret; } diff --git a/drivers/mmc/host/mmc_hsq.c b/drivers/mmc/host/mmc_hsq.c index 79836705c176..57e172bd3487 100644 --- a/drivers/mmc/host/mmc_hsq.c +++ b/drivers/mmc/host/mmc_hsq.c @@ -7,6 +7,7 @@ * Author: Baolin Wang */ +#include #include #include #include @@ -345,6 +346,7 @@ static const struct mmc_cqe_ops mmc_hsq_ops = { int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc) { + int ret; int i; hsq->num_slots = HSQ_NUM_SLOTS; hsq->next_tag = HSQ_INVALID_TAG; @@ -363,7 +365,11 @@ int mmc_hsq_init(struct mmc_hsq *hsq, struct mmc_host *mmc) for (i = 0; i < HSQ_NUM_SLOTS; i++) hsq->tag_slot[i] = HSQ_INVALID_TAG; - INIT_WORK(&hsq->retry_work, mmc_hsq_retry_handler); + ret = devm_work_autocancel(mmc_dev(mmc), &hsq->retry_work, + mmc_hsq_retry_handler); + if (ret) + return ret; + spin_lock_init(&hsq->lock); init_waitqueue_head(&hsq->wait_queue); diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 42936e248c55..574fd8d1d2e7 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -952,6 +952,7 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq) status = mmc_spi_command_send(host, mrq, &stop, 0); crc_retry--; mrq->data->error = 0; + mrq->data->bytes_xfered = 0; goto crc_recover; } diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index e500051bd572..416bdb184ed4 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -2511,6 +2511,9 @@ static void mmci_remove(struct amba_device *dev) writel(0, host->base + MMCICOMMAND); writel(0, host->base + MMCIDATACTRL); + if (variant->busy_detect) + disable_delayed_work_sync(&host->ux500_busy_timeout_work); + mmci_dma_release(host); clk_disable_unprepare(host->clk); } diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index c405cfb8b269..097498a3f8ff 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -1173,6 +1173,10 @@ static void mxcmci_remove(struct platform_device *pdev) mmc_remove_host(mmc); + devm_free_irq(&pdev->dev, platform_get_irq(pdev, 0), host); + cancel_work_sync(&host->datawork); + timer_delete_sync(&host->watchdog); + if (host->pdata && host->pdata->exit) host->pdata->exit(&pdev->dev, mmc); diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 4db3328f46df..84f20e175df7 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -1501,6 +1501,11 @@ static void realtek_init_host(struct realtek_pci_sdmmc *host) mmc->caps = mmc->caps | MMC_CAP_AGGRESSIVE_PM; mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE | MMC_CAP2_NO_SDIO; + + if (pcr->pci->device == 0x522a && + pcr->pci->subsystem_vendor == PCI_VENDOR_ID_LENOVO && + pcr->pci->subsystem_device == 0x504a) + mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; mmc->max_current_330 = 400; mmc->max_current_180 = 800; mmc->ops = &realtek_pci_sdmmc_ops; diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c index ca97b01996b1..f2d133aca48d 100644 --- a/drivers/mmc/host/sdhci-of-aspeed.c +++ b/drivers/mmc/host/sdhci-of-aspeed.c @@ -555,12 +555,14 @@ static int aspeed_sdc_probe(struct platform_device *pdev) if (!cpdev) { of_node_put(child); ret = -ENODEV; - goto err_clk; + goto err_children; } } return 0; +err_children: + device_for_each_child_reverse(&pdev->dev, NULL, of_platform_device_destroy); err_clk: clk_disable_unprepare(sdc->clk); return ret; @@ -570,6 +572,7 @@ static void aspeed_sdc_remove(struct platform_device *pdev) { struct aspeed_sdc *sdc = dev_get_drvdata(&pdev->dev); + device_for_each_child_reverse(&pdev->dev, NULL, of_platform_device_destroy); clk_disable_unprepare(sdc->clk); } diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index d235b0aecfdb..8edfab5012ed 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -126,7 +126,7 @@ static const struct timing_data td[] = { NULL, MMC_CAP_UHS_SDR104}, [MMC_TIMING_UHS_DDR50] = {"ti,otap-del-sel-ddr50", - NULL, + "ti,itap-del-sel-ddr50", MMC_CAP_UHS_DDR50}, [MMC_TIMING_MMC_DDR52] = {"ti,otap-del-sel-ddr52", "ti,itap-del-sel-ddr52", @@ -144,6 +144,8 @@ struct sdhci_am654_data { u32 otap_del_sel[ARRAY_SIZE(td)]; u32 itap_del_sel[ARRAY_SIZE(td)]; u32 itap_del_ena[ARRAY_SIZE(td)]; + u32 itap_del_sel_dt_ddr50; + u32 itap_del_ena_dt_ddr50; int clkbuf_sel; int trm_icp; int drv_strength; @@ -151,7 +153,6 @@ struct sdhci_am654_data { u32 flags; u32 quirks; bool dll_enable; - u32 tuning_loop; #define SDHCI_AM654_QUIRK_FORCE_CDTEST BIT(0) #define SDHCI_AM654_QUIRK_SUPPRESS_V1P8_ENA BIT(1) @@ -443,15 +444,13 @@ static int sdhci_am654_execute_tuning(struct mmc_host *mmc, u32 opcode) struct sdhci_host *host = mmc_priv(mmc); int err = sdhci_execute_tuning(mmc, opcode); - if (err) - return err; /* * Tuning data remains in the buffer after tuning. * Do a command and data reset to get rid of it */ sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); - return 0; + return err; } static u32 sdhci_am654_cqhci_irq(struct sdhci_host *host, u32 intmask) @@ -530,7 +529,6 @@ static int sdhci_am654_do_tuning(struct sdhci_host *host, { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); - unsigned char timing = host->mmc->ios.timing; struct window fail_window[ITAPDLY_LENGTH]; struct device *dev = mmc_dev(host->mmc); u8 curr_pass, itap; @@ -539,11 +537,8 @@ static int sdhci_am654_do_tuning(struct sdhci_host *host, memset(fail_window, 0, sizeof(fail_window)); - /* Enable ITAPDLY */ - sdhci_am654->itap_del_ena[timing] = 0x1; - for (itap = 0; itap < ITAPDLY_LENGTH; itap++) { - sdhci_am654_write_itapdly(sdhci_am654, itap, sdhci_am654->itap_del_ena[timing]); + sdhci_am654_write_itapdly(sdhci_am654, itap, 0x1); curr_pass = !mmc_send_tuning(host->mmc, opcode, NULL); @@ -576,20 +571,36 @@ static int sdhci_am654_platform_execute_tuning(struct sdhci_host *host, struct sdhci_am654_data *sdhci_am654 = sdhci_pltfm_priv(pltfm_host); unsigned char timing = host->mmc->ios.timing; struct device *dev = mmc_dev(host->mmc); + unsigned int tuning_loop = 0; int itapdly; do { itapdly = sdhci_am654_do_tuning(host, opcode); if (itapdly >= 0) break; - } while (++sdhci_am654->tuning_loop < RETRY_TUNING_MAX); + } while (++tuning_loop < RETRY_TUNING_MAX); if (itapdly < 0) { - dev_err(dev, "Failed to find itapdly, fail tuning\n"); + if (timing == MMC_TIMING_UHS_DDR50) { + dev_dbg(dev, "Failed DDR50 tuning, fallback to DT ITAP\n"); + sdhci_am654->itap_del_sel[timing] = sdhci_am654->itap_del_sel_dt_ddr50; + sdhci_am654->itap_del_ena[timing] = sdhci_am654->itap_del_ena_dt_ddr50; + } else { + dev_err(dev, "Failed to find itapdly, fail tuning\n"); + sdhci_am654->itap_del_ena[timing] = 0; + sdhci_am654->itap_del_sel[timing] = 0; + } + + sdhci_am654_write_itapdly(sdhci_am654, + sdhci_am654->itap_del_sel[timing], + sdhci_am654->itap_del_ena[timing]); return -1; } dev_dbg(dev, "Passed tuning, final itapdly=%d\n", itapdly); + + /* Enable ITAPDLY */ + sdhci_am654->itap_del_ena[timing] = 0x1; sdhci_am654_write_itapdly(sdhci_am654, itapdly, sdhci_am654->itap_del_ena[timing]); /* Save ITAPDLY */ sdhci_am654->itap_del_sel[timing] = itapdly; @@ -758,6 +769,11 @@ static int sdhci_am654_get_otap_delay(struct sdhci_host *host, } } + sdhci_am654->itap_del_sel_dt_ddr50 = + sdhci_am654->itap_del_sel[MMC_TIMING_UHS_DDR50]; + sdhci_am654->itap_del_ena_dt_ddr50 = + sdhci_am654->itap_del_ena[MMC_TIMING_UHS_DDR50]; + return 0; } @@ -806,9 +822,6 @@ static int sdhci_am654_init(struct sdhci_host *host) regmap_update_bits(sdhci_am654->base, CTL_CFG_3, TUNINGFORSDR50_MASK, TUNINGFORSDR50_MASK); - /* Use to re-execute tuning */ - sdhci_am654->tuning_loop = 0; - ret = sdhci_setup_host(host); if (ret) return ret; diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index bf899c8e38f5..b536da1c96c1 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1462,6 +1462,7 @@ static int sh_mmcif_probe(struct platform_device *pdev) host->pd = pdev; spin_lock_init(&host->lock); + mutex_init(&host->thread_lock); mmc->ops = &sh_mmcif_ops; sh_mmcif_init_ocr(host); @@ -1520,8 +1521,6 @@ static int sh_mmcif_probe(struct platform_device *pdev) } } - mutex_init(&host->thread_lock); - ret = mmc_add_host(mmc); if (ret < 0) goto err_clk; diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index fe15d684990f..47e9ece4b37a 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -77,6 +77,7 @@ config BCMGENET select BCM7XXX_PHY select MDIO_BCM_UNIMAC select DIMLIB + select PAGE_POOL select BROADCOM_PHY if ARCH_BCM2835 help This driver supports the built-in Ethernet MACs found in the diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index fc5c8a4ae41e..41539f9f8061 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -52,6 +52,12 @@ #define RX_BUF_LENGTH 2048 #define SKB_ALIGNMENT 32 +/* Page pool RX buffer layout: + * RSB(64) + pad(2) | frame data | skb_shared_info + * The HW writes the 64B RSB + 2B alignment padding before the frame. + */ +#define GENET_RSB_PAD (sizeof(struct status_64) + 2) + /* 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)) @@ -744,8 +750,17 @@ static void bcmgenet_hfb_init(struct bcmgenet_priv *priv) INIT_LIST_HEAD(&priv->rxnfc_rules[i].list); priv->rxnfc_rules[i].state = BCMGENET_RXNFC_STATE_UNUSED; } +} + +static void bcmgenet_hfb_restore(struct bcmgenet_priv *priv) +{ + struct bcmgenet_rxnfc_rule *rule; bcmgenet_hfb_clear(priv); + + list_for_each_entry(rule, &priv->rxnfc_list, list) + if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) + bcmgenet_hfb_create_rxnfc_filter(priv, rule); } static int bcmgenet_begin(struct net_device *dev) @@ -1153,7 +1168,6 @@ static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { UMAC_RBUF_ERR_CNT_V1), STAT_GENET_MISC("mdf_err_cnt", mib.mdf_err_cnt, UMAC_MDF_ERR_CNT), STAT_GENET_SOFT_MIB("alloc_rx_buff_failed", mib.alloc_rx_buff_failed), - STAT_GENET_SOFT_MIB("rx_dma_failed", mib.rx_dma_failed), STAT_GENET_SOFT_MIB("tx_dma_failed", mib.tx_dma_failed), STAT_GENET_SOFT_MIB("tx_realloc_tsb", mib.tx_realloc_tsb), STAT_GENET_SOFT_MIB("tx_realloc_tsb_failed", @@ -1889,21 +1903,13 @@ static struct sk_buff *bcmgenet_free_tx_cb(struct device *dev, } /* Simple helper to free a receive control block's resources */ -static struct sk_buff *bcmgenet_free_rx_cb(struct device *dev, - struct enet_cb *cb) +static void bcmgenet_free_rx_cb(struct enet_cb *cb, + struct page_pool *pool) { - struct sk_buff *skb; - - skb = cb->skb; - cb->skb = NULL; - - if (dma_unmap_addr(cb, dma_addr)) { - dma_unmap_single(dev, dma_unmap_addr(cb, dma_addr), - dma_unmap_len(cb, dma_len), DMA_FROM_DEVICE); - dma_unmap_addr_set(cb, dma_addr, 0); + if (cb->rx_page) { + page_pool_put_full_page(pool, cb->rx_page, false); + cb->rx_page = NULL; } - - return skb; } /* Unlocked version of the reclaim routine */ @@ -2237,46 +2243,29 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) goto out; } -static struct sk_buff *bcmgenet_rx_refill(struct bcmgenet_priv *priv, - struct enet_cb *cb) +static int bcmgenet_rx_refill(struct bcmgenet_rx_ring *ring, + struct enet_cb *cb) { - struct device *kdev = &priv->pdev->dev; - struct sk_buff *skb; - struct sk_buff *rx_skb; + struct bcmgenet_priv *priv = ring->priv; dma_addr_t mapping; + struct page *page; - /* Allocate a new Rx skb */ - skb = __netdev_alloc_skb(priv->dev, priv->rx_buf_len + SKB_ALIGNMENT, - GFP_ATOMIC | __GFP_NOWARN); - if (!skb) { + page = page_pool_alloc_pages(ring->page_pool, + GFP_ATOMIC); + if (!page) { priv->mib.alloc_rx_buff_failed++; netif_err(priv, rx_err, priv->dev, - "%s: Rx skb allocation failed\n", __func__); - return NULL; - } - - /* DMA-map the new Rx skb */ - mapping = dma_map_single(kdev, skb->data, priv->rx_buf_len, - DMA_FROM_DEVICE); - if (dma_mapping_error(kdev, mapping)) { - priv->mib.rx_dma_failed++; - dev_kfree_skb_any(skb); - netif_err(priv, rx_err, priv->dev, - "%s: Rx skb DMA mapping failed\n", __func__); - return NULL; + "%s: Rx page allocation failed\n", __func__); + return -ENOMEM; } - /* Grab the current Rx skb from the ring and DMA-unmap it */ - rx_skb = bcmgenet_free_rx_cb(kdev, cb); + /* page_pool handles DMA mapping via PP_FLAG_DMA_MAP */ + mapping = page_pool_get_dma_addr(page); - /* Put the new Rx skb on the ring */ - cb->skb = skb; - dma_unmap_addr_set(cb, dma_addr, mapping); - dma_unmap_len_set(cb, dma_len, priv->rx_buf_len); + cb->rx_page = page; dmadesc_set_addr(priv, cb->bd_addr, mapping); - /* Return the current Rx skb to caller */ - return rx_skb; + return 0; } /* bcmgenet_desc_rx - descriptor based rx process. @@ -2328,25 +2317,29 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, while ((rxpktprocessed < rxpkttoprocess) && (rxpktprocessed < budget)) { struct status_64 *status; + struct page *rx_page; + void *hard_start; __be16 rx_csum; cb = &priv->rx_cbs[ring->read_ptr]; - skb = bcmgenet_rx_refill(priv, cb); - if (unlikely(!skb)) { + /* Save the received page before refilling */ + rx_page = cb->rx_page; + + if (bcmgenet_rx_refill(ring, cb)) { BCMGENET_STATS64_INC(stats, dropped); goto next; } - status = (struct status_64 *)skb->data; + /* 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, + RX_BUF_LENGTH); + + hard_start = page_address(rx_page); + status = (struct status_64 *)hard_start; dma_length_status = status->length_status; - if (dev->features & NETIF_F_RXCSUM) { - rx_csum = (__force __be16)(status->rx_csum & 0xffff); - if (rx_csum) { - skb->csum = (__force __wsum)ntohs(rx_csum); - skb->ip_summed = CHECKSUM_COMPLETE; - } - } /* DMA flags and length are still valid no matter how * we got the Receive Status Vector (64B RSB or register) @@ -2359,10 +2352,13 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, __func__, p_index, ring->c_index, ring->read_ptr, dma_length_status); - if (unlikely(len > RX_BUF_LENGTH)) { - netif_err(priv, rx_status, dev, "oversized packet\n"); + /* Reject lengths that would underflow the SKB build path. */ + if (unlikely(len > RX_BUF_LENGTH || len < GENET_RSB_PAD)) { + netif_err(priv, rx_status, dev, + "invalid packet length %d\n", len); BCMGENET_STATS64_INC(stats, length_errors); - dev_kfree_skb_any(skb); + page_pool_put_full_page(ring->page_pool, rx_page, + true); goto next; } @@ -2370,7 +2366,8 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, netif_err(priv, rx_status, dev, "dropping fragmented packet!\n"); BCMGENET_STATS64_INC(stats, fragmented_errors); - dev_kfree_skb_any(skb); + page_pool_put_full_page(ring->page_pool, rx_page, + true); goto next; } @@ -2398,21 +2395,42 @@ static unsigned int bcmgenet_desc_rx(struct bcmgenet_rx_ring *ring, DMA_RX_RXER)) == DMA_RX_RXER) u64_stats_inc(&stats->errors); u64_stats_update_end(&stats->syncp); - dev_kfree_skb_any(skb); + page_pool_put_full_page(ring->page_pool, rx_page, + true); goto next; } /* error packet */ - skb_put(skb, len); + /* 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); + if (unlikely(!skb)) { + BCMGENET_STATS64_INC(stats, dropped); + page_pool_put_full_page(ring->page_pool, rx_page, + true); + goto next; + } + + skb_mark_for_recycle(skb); - /* remove RSB and hardware 2bytes added for IP alignment */ - skb_pull(skb, 66); - len -= 66; + /* Reserve the RSB + pad, then set the data length */ + skb_reserve(skb, GENET_RSB_PAD); + __skb_put(skb, len - GENET_RSB_PAD); if (priv->crc_fwd_en) { - skb_trim(skb, len - ETH_FCS_LEN); - len -= ETH_FCS_LEN; + skb_trim(skb, skb->len - ETH_FCS_LEN); + } + + /* Set up checksum offload */ + if (dev->features & NETIF_F_RXCSUM) { + rx_csum = (__force __be16)(status->rx_csum & 0xffff); + if (rx_csum) { + skb->csum = (__force __wsum)ntohs(rx_csum); + skb->ip_summed = CHECKSUM_COMPLETE; + } } + len = skb->len; bytes_processed += len; /*Finish setting up the received SKB and send it to the kernel*/ @@ -2484,12 +2502,11 @@ static void bcmgenet_dim_work(struct work_struct *work) dim->state = DIM_START_MEASURE; } -/* Assign skb to RX DMA descriptor. */ +/* Assign page_pool pages to RX DMA descriptors. */ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv, struct bcmgenet_rx_ring *ring) { struct enet_cb *cb; - struct sk_buff *skb; int i; netif_dbg(priv, hw, priv->dev, "%s\n", __func__); @@ -2497,10 +2514,7 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv, /* loop here for each buffer needing assign */ for (i = 0; i < ring->size; i++) { cb = ring->cbs + i; - skb = bcmgenet_rx_refill(priv, cb); - if (skb) - dev_consume_skb_any(skb); - if (!cb->skb) + if (bcmgenet_rx_refill(ring, cb)) return -ENOMEM; } @@ -2509,16 +2523,18 @@ static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv, static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv) { - struct sk_buff *skb; + struct bcmgenet_rx_ring *ring; struct enet_cb *cb; - int i; + int q, i; - for (i = 0; i < priv->num_rx_bds; i++) { - cb = &priv->rx_cbs[i]; - - skb = bcmgenet_free_rx_cb(&priv->pdev->dev, cb); - if (skb) - dev_consume_skb_any(skb); + for (q = 0; q <= priv->hw_params->rx_queues; q++) { + ring = &priv->rx_rings[q]; + if (!ring->page_pool) + continue; + for (i = 0; i < ring->size; i++) { + cb = ring->cbs + i; + bcmgenet_free_rx_cb(cb, ring->page_pool); + } } } @@ -2736,6 +2752,30 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, netif_napi_add_tx(priv->dev, &ring->napi, bcmgenet_tx_poll); } +static int bcmgenet_rx_ring_create_pool(struct bcmgenet_priv *priv, + struct bcmgenet_rx_ring *ring) +{ + struct page_pool_params pp_params = { + .order = 0, + .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV, + .pool_size = ring->size, + .nid = NUMA_NO_NODE, + .dev = &priv->pdev->dev, + .dma_dir = DMA_FROM_DEVICE, + .max_len = RX_BUF_LENGTH, + }; + int err; + + ring->page_pool = page_pool_create(&pp_params); + if (IS_ERR(ring->page_pool)) { + err = PTR_ERR(ring->page_pool); + ring->page_pool = NULL; + return err; + } + + return 0; +} + /* Initialize a RDMA ring */ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, unsigned int index, unsigned int size, @@ -2743,7 +2783,7 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, { struct bcmgenet_rx_ring *ring = &priv->rx_rings[index]; u32 words_per_bd = WORDS_PER_BD(priv); - int ret; + int ret, i; ring->priv = priv; ring->index = index; @@ -2754,10 +2794,19 @@ static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, ring->cb_ptr = start_ptr; ring->end_ptr = end_ptr - 1; - ret = bcmgenet_alloc_rx_buffers(priv, ring); + ret = bcmgenet_rx_ring_create_pool(priv, ring); if (ret) return ret; + ret = bcmgenet_alloc_rx_buffers(priv, ring); + if (ret) { + for (i = 0; i < ring->size; i++) + bcmgenet_free_rx_cb(ring->cbs + i, ring->page_pool); + page_pool_destroy(ring->page_pool); + ring->page_pool = NULL; + return ret; + } + bcmgenet_init_dim(ring, bcmgenet_dim_work); bcmgenet_init_rx_coalesce(ring); @@ -2951,6 +3000,20 @@ static void bcmgenet_fini_rx_napi(struct bcmgenet_priv *priv) } } +static void bcmgenet_destroy_rx_page_pools(struct bcmgenet_priv *priv) +{ + struct bcmgenet_rx_ring *ring; + unsigned int i; + + for (i = 0; i <= priv->hw_params->rx_queues; ++i) { + ring = &priv->rx_rings[i]; + if (ring->page_pool) { + page_pool_destroy(ring->page_pool); + ring->page_pool = NULL; + } + } +} + /* Initialize Rx queues * * Queues 0-15 are priority queues. Hardware Filtering Block (HFB) can be @@ -3022,6 +3085,7 @@ static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) } bcmgenet_free_rx_buffers(priv); + bcmgenet_destroy_rx_page_pools(priv); kfree(priv->rx_cbs); kfree(priv->tx_cbs); } @@ -3100,6 +3164,7 @@ static int bcmgenet_init_dma(struct bcmgenet_priv *priv, bool flush_rx) if (ret) { netdev_err(priv->dev, "failed to initialize Rx queues\n"); bcmgenet_free_rx_buffers(priv); + bcmgenet_destroy_rx_page_pools(priv); kfree(priv->rx_cbs); kfree(priv->tx_cbs); return ret; @@ -3318,8 +3383,8 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_set_hw_addr(priv, dev->dev_addr); - /* HFB init */ - bcmgenet_hfb_init(priv); + /* Restore the filters, the MAC was reset above */ + bcmgenet_hfb_restore(priv); /* Reinitialize TDMA and RDMA and SW housekeeping */ ret = bcmgenet_init_dma(priv, true); @@ -4021,8 +4086,7 @@ static int bcmgenet_probe(struct platform_device *pdev) /* Mii wait queue */ init_waitqueue_head(&priv->wq); - /* Always use RX_BUF_LENGTH (2KB) buffer for all chips */ - priv->rx_buf_len = RX_BUF_LENGTH; + bcmgenet_hfb_init(priv); INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task); priv->clk_wol = devm_clk_get_optional(&priv->pdev->dev, "enet-wol"); @@ -4223,10 +4287,7 @@ static int bcmgenet_resume(struct device *d) bcmgenet_set_hw_addr(priv, dev->dev_addr); /* Restore hardware filters */ - bcmgenet_hfb_clear(priv); - list_for_each_entry(rule, &priv->rxnfc_list, list) - if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) - bcmgenet_hfb_create_rxnfc_filter(priv, rule); + bcmgenet_hfb_restore(priv); /* Reinitialize TDMA and RDMA and SW housekeeping */ ret = bcmgenet_init_dma(priv, false); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 9e4110c7fdf6..22a958ba9902 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -15,6 +15,7 @@ #include #include #include +#include #include "../unimac.h" @@ -149,7 +150,6 @@ struct bcmgenet_mib_counters { u32 rbuf_err_cnt; u32 mdf_err_cnt; u32 alloc_rx_buff_failed; - u32 rx_dma_failed; u32 tx_dma_failed; u32 tx_realloc_tsb; u32 tx_realloc_tsb_failed; @@ -469,6 +469,7 @@ struct bcmgenet_rx_stats64 { struct enet_cb { struct sk_buff *skb; + struct page *rx_page; void __iomem *bd_addr; DEFINE_DMA_UNMAP_ADDR(dma_addr); DEFINE_DMA_UNMAP_LEN(dma_len); @@ -575,6 +576,7 @@ struct bcmgenet_rx_ring { struct bcmgenet_net_dim dim; u32 rx_max_coalesced_frames; u32 rx_coalesce_usecs; + struct page_pool *page_pool; struct bcmgenet_priv *priv; }; @@ -609,7 +611,6 @@ struct bcmgenet_priv { void __iomem *rx_bds; struct enet_cb *rx_cbs; unsigned int num_rx_bds; - unsigned int rx_buf_len; struct bcmgenet_rxnfc_rule rxnfc_rules[MAX_NUM_OF_FS_RULES]; struct list_head rxnfc_list; diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c index d961a5faf355..97b72f633d3b 100644 --- a/drivers/net/ethernet/cadence/macb_ptp.c +++ b/drivers/net/ethernet/cadence/macb_ptp.c @@ -48,7 +48,12 @@ static int gem_tsu_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts, spin_lock_irqsave(&bp->tsu_clk_lock, flags); ptp_read_system_prets(sts); + /* explicit barriers are needed because gem_readl() is relaxed */ + if (sts) + rmb(); first = gem_readl(bp, TN); + if (sts) + rmb(); ptp_read_system_postts(sts); secl = gem_readl(bp, TSL); sech = gem_readl(bp, TSH); @@ -60,7 +65,11 @@ static int gem_tsu_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts, * (assume all done within 1s) */ ptp_read_system_prets(sts); + if (sts) + rmb(); ts->tv_nsec = gem_readl(bp, TN); + if (sts) + rmb(); ptp_read_system_postts(sts); secl = gem_readl(bp, TSL); sech = gem_readl(bp, TSH); diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c index 3215d26aa2d3..fddb068cc13c 100644 --- a/drivers/net/ethernet/cortina/gemini.c +++ b/drivers/net/ethernet/cortina/gemini.c @@ -1799,7 +1799,7 @@ static irqreturn_t gmac_irq(int irq, void *data) if (val & (GMAC0_RX_OVERRUN_INT_BIT << (netdev->dev_id * 8))) { spin_lock(&geth->irq_lock); - writel(GMAC0_RXDERR_INT_BIT << (netdev->dev_id * 8), + writel(GMAC0_RX_OVERRUN_INT_BIT << (netdev->dev_id * 8), geth->base + GLOBAL_INTERRUPT_STATUS_4_REG); u64_stats_update_begin(&port->ir_stats_syncp); ++port->stats.rx_fifo_errors; diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 79f8e0abfdbf..17ce1dfcccd1 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -5088,7 +5088,8 @@ static int mvpp2_change_mtu(struct net_device *dev, int mtu) netdev_warn(dev, "mtu %d too high, switching to shared buffers", mtu); mvpp2_bm_switch_buffers(priv, false); } - } else { + } else if (priv->hw_version >= MVPP22 && + mvpp2_get_nrxqs(priv) * 2 <= MVPP2_BM_MAX_POOLS) { bool jumbo = false; int i; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index dbe0855ecb57..0ea861ff40f5 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -311,6 +311,29 @@ fbnic_rx_csum(u64 rcd, struct sk_buff *skb, struct fbnic_ring *rcq, } } +static void fbnic_tx_doorbell(struct fbnic_ring *ring, __le64 *meta) +{ + *meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_COMPLETION); + ring->deferred_meta = -1; + + /* Force DMA writes to flush before writing to tail */ + dma_wmb(); + + writel(ring->tail, ring->doorbell); +} + +/* Packets handed to us with xmit_more set are left in the ring without a + * doorbell, and without a completion request, in the expectation that the + * packet ending the burst will ring for all of them. If that packet gets + * dropped instead we have to ring here, otherwise the descriptors sit in + * the ring until the next transmit, which may never come. + */ +static void fbnic_tx_flush_doorbell(struct fbnic_ring *ring) +{ + if (ring->deferred_meta >= 0) + fbnic_tx_doorbell(ring, &ring->desc[ring->deferred_meta]); +} + static bool fbnic_tx_map(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta) { @@ -378,14 +401,10 @@ fbnic_tx_map(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta) /* Verify there is room for another packet */ fbnic_maybe_stop_tx(skb->dev, ring, FBNIC_MAX_SKB_DESC); - if (fbnic_tx_sent_queue(skb, ring)) { - *meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_COMPLETION); - - /* Force DMA writes to flush before writing to tail */ - dma_wmb(); - - writel(tail, ring->doorbell); - } + if (fbnic_tx_sent_queue(skb, ring)) + fbnic_tx_doorbell(ring, meta); + else + ring->deferred_meta = meta - ring->desc; return false; dma_error: @@ -425,8 +444,10 @@ fbnic_xmit_frame_ring(struct sk_buff *skb, struct fbnic_ring *ring) * otherwise try next time */ desc_needed = skb_shinfo(skb)->nr_frags + 10; - if (fbnic_maybe_stop_tx(skb->dev, ring, desc_needed)) + if (fbnic_maybe_stop_tx(skb->dev, ring, desc_needed)) { + fbnic_tx_flush_doorbell(ring); return NETDEV_TX_BUSY; + } *meta = cpu_to_le64(FBNIC_TWD_FLAG_DEST_MAC); @@ -447,6 +468,8 @@ fbnic_xmit_frame_ring(struct sk_buff *skb, struct fbnic_ring *ring) err_free: dev_kfree_skb_any(skb); err_count: + fbnic_tx_flush_doorbell(ring); + u64_stats_update_begin(&ring->stats.syncp); ring->stats.dropped++; u64_stats_update_end(&ring->stats.syncp); @@ -2473,6 +2496,7 @@ static void fbnic_enable_twq0(struct fbnic_ring *twq) fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ0_CTL, FBNIC_QUEUE_TWQ_CTL_RESET); twq->tail = 0; twq->head = 0; + twq->deferred_meta = -1; /* Store descriptor ring address and size */ fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ0_BAL, lower_32_bits(twq->dma)); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h index f2ee2cbf3486..643e7d3ddb54 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -128,9 +128,14 @@ struct fbnic_ring { /* Rx BDQs only */ struct page_pool *page_pool; - /* Deferred_head is used to cache the head for TWQ1 if + /* TWQ0 only, index of the meta descriptor of the last packet + * placed in the ring without ringing the doorbell, -1 if the + * doorbell is in sync with the tail. + */ + s32 deferred_meta; + + /* TCQ only, used to cache the head for TWQ1 if * an attempt is made to clean TWQ1 with zero napi_budget. - * We do not use it for any other ring. */ s32 deferred_head; }; diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index 441bc7a789f0..a49432e6e50d 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -2588,7 +2588,7 @@ static int lan743x_rx_process_buffer(struct lan743x_rx *rx) rx->adapter->netdev); if (rx->adapter->netdev->features & NETIF_F_RXCSUM) { if (!is_ice && !is_tce && !is_icsm) - skb->ip_summed = CHECKSUM_UNNECESSARY; + rx->skb_head->ip_summed = CHECKSUM_UNNECESSARY; } netdev_dbg(netdev, "sending %d byte frame to OS", rx->skb_head->len); diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index ee890de69ffe..a432eb354049 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -2149,6 +2149,7 @@ static int netsec_probe(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); free_ndev: + of_node_put(priv->phy_np); free_netdev(ndev); dev_err(&pdev->dev, "init failed\n"); @@ -2166,6 +2167,7 @@ static void netsec_remove(struct platform_device *pdev) netif_napi_del(&priv->napi); pm_runtime_disable(&pdev->dev); + of_node_put(priv->phy_np); free_netdev(priv->ndev); } diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index 14dbe0685997..75e915e86c78 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -490,7 +490,7 @@ struct stmmac_ops { #define stmmac_set_arp_offload(__priv, __args...) \ stmmac_do_void_callback(__priv, mac, set_arp_offload, __args) #define stmmac_fpe_map_preemption_class(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, fpe_map_preemption_class, __args) + stmmac_do_callback(__priv, mac, fpe_map_preemption_class, __args) /* PTP and HW Timer helpers */ struct stmmac_hwtimestamp { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 81d4039e1c08..741e3864f509 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -1059,8 +1059,6 @@ static int stmmac_get_ts_info(struct net_device *dev, if (priv->ptp_clock) info->phc_index = ptp_clock_index(priv->ptp_clock); - else - info->phc_index = 0; info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 0119b4b89fc0..49161241d032 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -970,7 +970,7 @@ static int tc_taprio_configure(struct stmmac_priv *priv, struct netlink_ext_ack *extack = qopt->mqprio.extack; struct timespec64 time, current_time, qopt_time; ktime_t current_time_ns; - int i, ret = 0; + int err, i, ret = 0; u64 ctr; if (qopt->base_time < 0) @@ -1120,9 +1120,9 @@ static int tc_taprio_configure(struct stmmac_priv *priv, mutex_unlock(&priv->est_lock); } - stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0); + err = stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0); - return ret; + return qopt->cmd == TAPRIO_CMD_DESTROY ? err : ret; } static void tc_taprio_stats(struct stmmac_priv *priv, @@ -1237,14 +1237,15 @@ static int tc_query_caps(struct stmmac_priv *priv, } } -static void stmmac_reset_tc_mqprio(struct net_device *ndev, - struct netlink_ext_ack *extack) +static int stmmac_reset_tc_mqprio(struct net_device *ndev, + struct netlink_ext_ack *extack) { struct stmmac_priv *priv = netdev_priv(ndev); netdev_reset_tc(ndev); netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use); - stmmac_fpe_map_preemption_class(priv, ndev, extack, 0); + + return stmmac_fpe_map_preemption_class(priv, ndev, extack, 0); } static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv, @@ -1257,10 +1258,8 @@ static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv, u32 num_tc = qopt->num_tc; int err; - if (!num_tc) { - stmmac_reset_tc_mqprio(ndev, extack); - return 0; - } + if (!num_tc) + return stmmac_reset_tc_mqprio(ndev, extack); err = netdev_set_num_tc(ndev, num_tc); if (err) diff --git a/drivers/net/fddi/skfp/skfddi.c b/drivers/net/fddi/skfp/skfddi.c index a273362c9e70..feea7baa4816 100644 --- a/drivers/net/fddi/skfp/skfddi.c +++ b/drivers/net/fddi/skfp/skfddi.c @@ -928,7 +928,8 @@ static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr) dev_addr_set(dev, p_sockaddr->sa_data); spin_lock_irqsave(&bp->DriverLock, Flags); - ResetAdapter(smc); + if (netif_running(dev)) + ResetAdapter(smc); spin_unlock_irqrestore(&bp->DriverLock, Flags); return 0; /* always return zero */ diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c index dfd0f4e439a2..608072fbfde9 100644 --- a/drivers/net/phy/mediatek/mtk-phy-lib.c +++ b/drivers/net/phy/mediatek/mtk-phy-lib.c @@ -156,20 +156,27 @@ int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index, if (!rules) return 0; - if (on & on_set) + /* TRIGGER_NETDEV_LINK must not be reported together with any of the + * per-speed rules, the netdev trigger rejects that combination. + * on_set holds every speed this LED can indicate and is what + * mtk_phy_led_hw_ctrl_set() programs for TRIGGER_NETDEV_LINK, so + * report the speed independent rule only when they are all on. + */ + if ((on & on_set) == on_set) { *rules |= BIT(TRIGGER_NETDEV_LINK); + } else { + if (on & MTK_PHY_LED_ON_LINK10) + *rules |= BIT(TRIGGER_NETDEV_LINK_10); - if (on & MTK_PHY_LED_ON_LINK10) - *rules |= BIT(TRIGGER_NETDEV_LINK_10); + if (on & MTK_PHY_LED_ON_LINK100) + *rules |= BIT(TRIGGER_NETDEV_LINK_100); - if (on & MTK_PHY_LED_ON_LINK100) - *rules |= BIT(TRIGGER_NETDEV_LINK_100); + if (on & MTK_PHY_LED_ON_LINK1000) + *rules |= BIT(TRIGGER_NETDEV_LINK_1000); - if (on & MTK_PHY_LED_ON_LINK1000) - *rules |= BIT(TRIGGER_NETDEV_LINK_1000); - - if (on & MTK_PHY_LED_ON_LINK2500) - *rules |= BIT(TRIGGER_NETDEV_LINK_2500); + if (on & MTK_PHY_LED_ON_LINK2500) + *rules |= BIT(TRIGGER_NETDEV_LINK_2500); + } if (on & MTK_PHY_LED_ON_FDX) *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX); diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 4794caa9f7ea..c97c07a7ef0f 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -873,6 +873,22 @@ static int ath11k_mac_set_kickout(struct ath11k_vif *arvif) return 0; } +static void ath11k_mac_station_cleanup(struct ieee80211_sta *sta) +{ + struct ath11k_sta *arsta; + + if (!sta) + return; + + arsta = ath11k_sta_to_arsta(sta); + + kfree(arsta->tx_stats); + arsta->tx_stats = NULL; + + kfree(arsta->rx_stats); + arsta->rx_stats = NULL; +} + void ath11k_mac_peer_cleanup_all(struct ath11k *ar) { struct ath11k_peer *peer, *tmp; @@ -885,6 +901,7 @@ void ath11k_mac_peer_cleanup_all(struct ath11k *ar) list_for_each_entry_safe(peer, tmp, &ab->peers, list) { ath11k_peer_rx_tid_cleanup(ar, peer); ath11k_peer_rhash_delete(ab, peer); + ath11k_mac_station_cleanup(peer->sta); list_del(&peer->list); kfree(peer); } @@ -9720,7 +9737,6 @@ static int ath11k_mac_station_remove(struct ath11k *ar, { struct ath11k_base *ab = ar->ab; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); - struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); int ret; if (ab->hw_params.vdev_start_delay && @@ -9744,12 +9760,7 @@ static int ath11k_mac_station_remove(struct ath11k *ar, sta->addr, arvif->vdev_id); ath11k_mac_dec_num_stations(arvif, sta); - - kfree(arsta->tx_stats); - arsta->tx_stats = NULL; - - kfree(arsta->rx_stats); - arsta->rx_stats = NULL; + ath11k_mac_station_cleanup(sta); return ret; } diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 0f4df5585fd9..914054aeefd2 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -1055,7 +1055,7 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn) free_irq(wcn->tx_irq, wcn); free_irq(wcn->rx_irq, wcn); - timer_delete(&wcn->tx_ack_timer); + timer_shutdown_sync(&wcn->tx_ack_timer); if (wcn->tx_ack_skb) { ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 169e62b9d773..048b5d500215 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -555,6 +555,8 @@ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success) if (type == ETH_P_PAE) { atomic_dec(&ifp->pend_8021x_cnt); + /* Order the decrement before waitqueue_active() */ + smp_mb__after_atomic(); if (waitqueue_active(&ifp->pend_8021x_wait)) wake_up(&ifp->pend_8021x_wait); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index b7472e19dd60..32a6e9ca2a46 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -201,7 +201,7 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev, { struct brcmf_if *ifp; struct brcmf_pub *drvr; - struct brcmf_auth_req_status_le auth_status; + struct brcmf_auth_req_status_le auth_status = {}; int ret = 0; brcmf_dbg(TRACE, "Enter\n"); @@ -209,6 +209,9 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev, ifp = netdev_priv(dev); drvr = ifp->drvr; if (params->status == WLAN_STATUS_SUCCESS) { + if (params->pmkid) + memcpy(auth_status.pmkid, params->pmkid, + WLAN_PMKID_LEN); auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_SUCCESS); } else { bphy_err(drvr, "External authentication failed: status=%d\n", diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index aadcff1e2b5d..b59decc8a07c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -1571,6 +1571,10 @@ void brcms_free_timer(struct brcms_timer *t) /* delete the timer in case it is active */ brcms_del_timer(t); + /* Ensure the callback has finished before freeing the timer + * structure, since brcms_del_timer() uses non-synchronous cancel. + */ + cancel_delayed_work_sync(&t->dly_wrk); if (wl->timers == t) { wl->timers = wl->timers->next; diff --git a/drivers/net/wireless/intel/ipw2x00/Kconfig b/drivers/net/wireless/intel/ipw2x00/Kconfig index b92df91adb3a..b508f14542d5 100644 --- a/drivers/net/wireless/intel/ipw2x00/Kconfig +++ b/drivers/net/wireless/intel/ipw2x00/Kconfig @@ -154,7 +154,6 @@ config LIBIPW depends on PCI && CFG80211 select WIRELESS_EXT select CRYPTO - select CRYPTO_MICHAEL_MIC select CRYPTO_LIB_ARC4 select CRC32 help diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c index 32288697da4f..695d1d85f822 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include #include "libipw.h" @@ -57,11 +55,6 @@ struct libipw_tkip_data { struct arc4_ctx rx_ctx_arc4; struct arc4_ctx tx_ctx_arc4; - struct crypto_shash *rx_tfm_michael; - struct crypto_shash *tx_tfm_michael; - - /* scratch buffers for virt_to_page() (crypto API) */ - u8 rx_hdr[16], tx_hdr[16]; unsigned long flags; }; @@ -89,41 +82,14 @@ static void *libipw_tkip_init(int key_idx) priv = kzalloc(sizeof(*priv), GFP_ATOMIC); if (priv == NULL) - goto fail; + return priv; priv->key_idx = key_idx; - - priv->tx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0); - if (IS_ERR(priv->tx_tfm_michael)) { - priv->tx_tfm_michael = NULL; - goto fail; - } - - priv->rx_tfm_michael = crypto_alloc_shash("michael_mic", 0, 0); - if (IS_ERR(priv->rx_tfm_michael)) { - priv->rx_tfm_michael = NULL; - goto fail; - } - return priv; - - fail: - if (priv) { - crypto_free_shash(priv->tx_tfm_michael); - crypto_free_shash(priv->rx_tfm_michael); - kfree(priv); - } - - return NULL; } static void libipw_tkip_deinit(void *priv) { - struct libipw_tkip_data *_priv = priv; - if (_priv) { - crypto_free_shash(_priv->tx_tfm_michael); - crypto_free_shash(_priv->rx_tfm_michael); - } kfree_sensitive(priv); } @@ -464,73 +430,6 @@ static int libipw_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) return keyidx; } -static int michael_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *hdr, - u8 *data, size_t data_len, u8 *mic) -{ - SHASH_DESC_ON_STACK(desc, tfm_michael); - int err; - - if (tfm_michael == NULL) { - pr_warn("%s(): tfm_michael == NULL\n", __func__); - return -1; - } - - desc->tfm = tfm_michael; - - if (crypto_shash_setkey(tfm_michael, key, 8)) - return -1; - - err = crypto_shash_init(desc); - if (err) - goto out; - err = crypto_shash_update(desc, hdr, 16); - if (err) - goto out; - err = crypto_shash_update(desc, data, data_len); - if (err) - goto out; - err = crypto_shash_final(desc, mic); - -out: - shash_desc_zero(desc); - return err; -} - -static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) -{ - struct ieee80211_hdr *hdr11; - - hdr11 = (struct ieee80211_hdr *)skb->data; - - switch (le16_to_cpu(hdr11->frame_control) & - (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { - case IEEE80211_FCTL_TODS: - memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ - break; - case IEEE80211_FCTL_FROMDS: - memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ - break; - case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: - memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ - break; - default: - memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ - break; - } - - if (ieee80211_is_data_qos(hdr11->frame_control)) { - hdr[12] = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(hdr11))) - & IEEE80211_QOS_CTL_TID_MASK; - } else - hdr[12] = 0; /* priority */ - - hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ -} - static int libipw_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv) { @@ -544,12 +443,9 @@ static int libipw_michael_mic_add(struct sk_buff *skb, int hdr_len, return -1; } - michael_mic_hdr(skb, tkey->tx_hdr); pos = skb_put(skb, 8); - if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, - skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) - return -1; - + michael_mic(&tkey->key[16], (struct ieee80211_hdr *)skb->data, + skb->data + hdr_len, skb->len - 8 - hdr_len, pos); return 0; } @@ -578,16 +474,16 @@ static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx, int hdr_len, void *priv) { struct libipw_tkip_data *tkey = priv; - u8 mic[8]; + u8 mic[MICHAEL_MIC_LEN]; - if (!tkey->key_set) + if (!tkey->key_set || skb->len < hdr_len + MICHAEL_MIC_LEN) return -1; - michael_mic_hdr(skb, tkey->rx_hdr); - if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, - skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) - return -1; - if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { + michael_mic(&tkey->key[24], (struct ieee80211_hdr *)skb->data, + skb->data + hdr_len, + skb->len - MICHAEL_MIC_LEN - hdr_len, mic); + if (memcmp(mic, skb->data + skb->len - MICHAEL_MIC_LEN, + MICHAEL_MIC_LEN) != 0) { struct ieee80211_hdr *hdr; hdr = (struct ieee80211_hdr *)skb->data; printk(KERN_DEBUG "%s: Michael MIC verification failed for " @@ -605,7 +501,7 @@ static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx, tkey->rx_iv32 = tkey->rx_iv32_new; tkey->rx_iv16 = tkey->rx_iv16_new; - skb_trim(skb, skb->len - 8); + skb_trim(skb, skb->len - MICHAEL_MIC_LEN); return 0; } @@ -614,17 +510,13 @@ static int libipw_tkip_set_key(void *key, int len, u8 * seq, void *priv) { struct libipw_tkip_data *tkey = priv; int keyidx; - struct crypto_shash *tfm = tkey->tx_tfm_michael; struct arc4_ctx *tfm2 = &tkey->tx_ctx_arc4; - struct crypto_shash *tfm3 = tkey->rx_tfm_michael; struct arc4_ctx *tfm4 = &tkey->rx_ctx_arc4; keyidx = tkey->key_idx; memset(tkey, 0, sizeof(*tkey)); tkey->key_idx = keyidx; - tkey->tx_tfm_michael = tfm; tkey->tx_ctx_arc4 = *tfm2; - tkey->rx_tfm_michael = tfm3; tkey->rx_ctx_arc4 = *tfm4; if (len == TKIP_KEY_LEN) { memcpy(tkey->key, key, TKIP_KEY_LEN); diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c index c8841f9b9ad9..424349a6935e 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c @@ -1209,6 +1209,9 @@ static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_as struct libipw_network *network = &network_resp; struct net_device *dev = ieee->dev; + if (stats->len < sizeof(*frame)) + return 1; + network->flags = 0; network->qos_data.active = 0; network->qos_data.supported = 0; @@ -1421,6 +1424,9 @@ static void libipw_process_probe_response(struct libipw_device #endif unsigned long flags; + if (stats->len < sizeof(*beacon)) + return; + LIBIPW_DEBUG_SCAN("'%*pE' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", info_element->len, info_element->data, beacon->header.addr3, diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index b7bd3ec4cc50..a4a2415a0634 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -2327,7 +2327,7 @@ il_dealloc_bcast_stations(struct il_priv *il) if (!(il->stations[i].used & IL_STA_BCAST)) continue; - il->stations[i].used &= ~IL_STA_UCODE_ACTIVE; + il->stations[i].used = 0; il->num_stations--; BUG_ON(il->num_stations < 0); kfree(il->stations[i].lq); diff --git a/drivers/net/wireless/intersil/p54/eeprom.c b/drivers/net/wireless/intersil/p54/eeprom.c index 5bd35c147e19..14646c878322 100644 --- a/drivers/net/wireless/intersil/p54/eeprom.c +++ b/drivers/net/wireless/intersil/p54/eeprom.c @@ -418,17 +418,22 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev) } static int p54_convert_rev0(struct ieee80211_hw *dev, - struct pda_pa_curve_data *curve_data) + struct pda_pa_curve_data *curve_data, size_t len) { struct p54_common *priv = dev->priv; struct p54_pa_curve_data_sample *dst; struct pda_pa_curve_data_sample_rev0 *src; + size_t needed = curve_data->channels * + (sizeof(*src) * curve_data->points_per_channel + 2); size_t cd_len = sizeof(*curve_data) + (curve_data->points_per_channel*sizeof(*dst) + 2) * curve_data->channels; unsigned int i, j; void *source, *target; + if (len < sizeof(*curve_data) + needed) + return -EINVAL; + priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len, GFP_KERNEL); if (!priv->curve_data) @@ -470,17 +475,22 @@ static int p54_convert_rev0(struct ieee80211_hw *dev, } static int p54_convert_rev1(struct ieee80211_hw *dev, - struct pda_pa_curve_data *curve_data) + struct pda_pa_curve_data *curve_data, size_t len) { struct p54_common *priv = dev->priv; struct p54_pa_curve_data_sample *dst; struct pda_pa_curve_data_sample_rev1 *src; + size_t needed = curve_data->channels * + (sizeof(*src) * curve_data->points_per_channel + 3); size_t cd_len = sizeof(*curve_data) + (curve_data->points_per_channel*sizeof(*dst) + 2) * curve_data->channels; unsigned int i, j; void *source, *target; + if (len < sizeof(*curve_data) + needed) + return -EINVAL; + priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data), GFP_KERNEL); if (!priv->curve_data) @@ -767,6 +777,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) case PDR_PRISM_PA_CAL_CURVE_DATA: { struct pda_pa_curve_data *curve_data = (struct pda_pa_curve_data *)entry->data; + if (data_len < sizeof(*curve_data)) { err = -EINVAL; goto err; @@ -774,10 +785,10 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) switch (curve_data->cal_method_rev) { case 0: - err = p54_convert_rev0(dev, curve_data); + err = p54_convert_rev0(dev, curve_data, data_len); break; case 1: - err = p54_convert_rev1(dev, curve_data); + err = p54_convert_rev1(dev, curve_data, data_len); break; default: wiphy_err(dev->wiphy, @@ -805,7 +816,8 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) break; case PDR_INTERFACE_LIST: tmp = entry->data; - while ((u8 *)tmp < entry->data + data_len) { + while ((u8 *)tmp + sizeof(struct exp_if) <= + entry->data + data_len) { struct exp_if *exp_if = tmp; if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000)) synth = le16_to_cpu(exp_if->variant); diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 42be6fa22f9c..411f075b6186 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -173,8 +173,8 @@ static int lbtf_init_adapter(struct lbtf_private *priv) static void lbtf_free_adapter(struct lbtf_private *priv) { lbtf_deb_enter(LBTF_DEB_MAIN); - lbtf_free_cmd_buffer(priv); timer_delete_sync(&priv->command_timer); + lbtf_free_cmd_buffer(priv); lbtf_deb_leave(LBTF_DEB_MAIN); } diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index ce569d35d051..58c35d7557fc 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -4271,6 +4271,7 @@ mwifiex_cfg80211_authenticate(struct wiphy *wiphy, struct mwifiex_adapter *adapter = priv->adapter; struct sk_buff *skb; u16 pkt_len, auth_alg; + size_t frame_len; int ret; struct mwifiex_ieee80211_mgmt *mgmt; struct mwifiex_txinfo *tx_info; @@ -4343,10 +4344,17 @@ mwifiex_cfg80211_authenticate(struct wiphy *wiphy, mwifiex_cancel_scan(adapter); - pkt_len = (u16)req->ie_len + req->auth_data_len + + frame_len = req->ie_len + req->auth_data_len + MWIFIEX_MGMT_HEADER_LEN + MWIFIEX_AUTH_BODY_LEN; if (req->auth_data_len >= 4) - pkt_len -= 4; + frame_len -= 4; + + if (frame_len > U16_MAX) { + mwifiex_dbg(priv->adapter, ERROR, + "auth frame too long: %zu bytes\n", frame_len); + return -EINVAL; + } + pkt_len = frame_len; skb = dev_alloc_skb(MWIFIEX_MIN_DATA_HEADER_LEN + MWIFIEX_MGMT_FRAME_HEADER_SIZE + diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index a760de191fce..a9425e9a94f4 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -3068,7 +3068,7 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) ret); for (j = 0; j < i; j++) free_irq(card->msix_entries[j].vector, - &card->msix_ctx[i]); + &card->msix_ctx[j]); pci_disable_msix(pdev); } else { mwifiex_dbg(adapter, MSG, "MSIx enabled!"); diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index cab889af4c4a..552e66dd0186 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -104,12 +104,24 @@ has_vendor_hdr(struct ieee_types_vendor_specific *ie, u8 key) * a given oui in PTK. */ static u8 -mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui) +mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui, int ie_len) { + const size_t ptk_body_offset = offsetof(struct ie_body, ptk_body); u8 count; + /* ie_len is the number of bytes available at iebody. Keep it signed + * and reject a negative (underflowed) length before the unsigned + * comparisons below, so a small or zero IE length cannot wrap. + */ + if (ie_len < 0 || (size_t)ie_len < ptk_body_offset) + return MWIFIEX_OUI_NOT_PRESENT; + count = iebody->ptk_cnt[0]; + /* Reject an OUI count whose list would run past the element. */ + if (ptk_body_offset + count * sizeof(iebody->ptk_body) > (size_t)ie_len) + return MWIFIEX_OUI_NOT_PRESENT; + /* There could be multiple OUIs for PTK hence 1) Take the length. 2) Check all the OUIs for AES. @@ -143,11 +155,14 @@ mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) u8 ret = MWIFIEX_OUI_NOT_PRESENT; if (has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) { + int ie_len = (int)bss_desc->bcn_rsn_ie->ieee_hdr.len - + RSN_GTK_OUI_OFFSET; + iebody = (struct ie_body *) (((u8 *) bss_desc->bcn_rsn_ie->data) + RSN_GTK_OUI_OFFSET); oui = &mwifiex_rsn_oui[cipher][0]; - ret = mwifiex_search_oui_in_ie(iebody, oui); + ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len); if (ret) return ret; } @@ -169,10 +184,14 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) u8 ret = MWIFIEX_OUI_NOT_PRESENT; if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) { + int ie_len = (int)bss_desc->bcn_wpa_ie->vend_hdr.len - + (int)sizeof(bss_desc->bcn_wpa_ie->vend_hdr.oui) - + WPA_GTK_OUI_OFFSET; + iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data + WPA_GTK_OUI_OFFSET); oui = &mwifiex_wpa_oui[cipher][0]; - ret = mwifiex_search_oui_in_ie(iebody, oui); + ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len); if (ret) return ret; } @@ -2098,6 +2117,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, u32 bytes_left; u32 idx; u32 tlv_buf_size; + size_t fixed_size; struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; struct chan_band_param_set *chan_band; u8 is_bgscan_resp; @@ -2113,6 +2133,14 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, else scan_rsp = &resp->params.scan_resp; + scan_resp_size = le16_to_cpu(resp->size); + fixed_size = scan_rsp->bss_desc_and_tlv_buffer - (u8 *)resp; + if (scan_resp_size < fixed_size) { + mwifiex_dbg(adapter, ERROR, + "SCAN_RESP: response is too short\n"); + ret = -1; + goto check_next_scan; + } if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) { mwifiex_dbg(adapter, ERROR, @@ -2130,8 +2158,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, "info: SCAN_RESP: bss_descript_size %d\n", bytes_left); - scan_resp_size = le16_to_cpu(resp->size); - mwifiex_dbg(adapter, INFO, "info: SCAN_RESP: returned %d APs before parsing\n", scan_rsp->number_of_sets); @@ -2139,15 +2165,17 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, bss_info = scan_rsp->bss_desc_and_tlv_buffer; /* - * The size of the TLV buffer is equal to the entire command response - * size (scan_resp_size) minus the fixed fields (sizeof()'s), the - * BSS Descriptions (bss_descript_size as bytesLef) and the command - * response header (S_DS_GEN) + * The TLV buffer follows the command-specific fixed fields and the BSS + * descriptions. Background-scan responses have an additional fixed + * field before scan_rsp, which is included in fixed_size. */ - tlv_buf_size = scan_resp_size - (bytes_left - + sizeof(scan_rsp->bss_descript_size) - + sizeof(scan_rsp->number_of_sets) - + S_DS_GEN); + if (bytes_left > scan_resp_size - fixed_size) { + mwifiex_dbg(adapter, ERROR, + "SCAN_RESP: BSS data exceeds response\n"); + ret = -1; + goto check_next_scan; + } + tlv_buf_size = scan_resp_size - fixed_size - bytes_left; tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp-> bss_desc_and_tlv_buffer + diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index 6882e90e90b2..6b8561e6725b 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -317,10 +317,16 @@ mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len, switch (stype) { case IEEE80211_STYPE_ACTION: - category = *(payload + sizeof(struct ieee80211_hdr)); + if (len < sizeof(*ieee_hdr) + 1) + return -1; + + category = *(payload + sizeof(*ieee_hdr)); switch (category) { case WLAN_CATEGORY_PUBLIC: - action_code = *(payload + sizeof(struct ieee80211_hdr) + if (len < sizeof(*ieee_hdr) + 2) + return -1; + + action_code = *(payload + sizeof(*ieee_hdr) + 1); if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { addr2 = ieee_hdr->addr2; diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index c39e7f313ea1..0178747d4b2f 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1060,6 +1060,13 @@ void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size) if (!ieee80211_is_public_action((struct ieee80211_hdr *)buff, size)) goto out_rx_mgmt; + /* ieee80211_is_public_action() only validates up to the category + * byte, so reject frames too short for the P2P public action header + * before dereferencing it or computing size - ie_offset. + */ + if (size < ie_offset) + goto out_rx_mgmt; + d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action); if (d->oui_subtype != GO_NEG_REQ && d->oui_subtype != GO_NEG_RSP && d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP) @@ -1208,6 +1215,13 @@ static int mgmt_tx(struct wiphy *wiphy, goto out_set_timeout; } + /* ieee80211_is_public_action() only validates up to the category + * byte, so reject frames too short for the P2P public action header + * before dereferencing it or computing len - ie_offset. + */ + if (len < ie_offset) + goto out_set_timeout; + d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action); if (d->oui_type != WLAN_OUI_TYPE_WFA_P2P || d->oui_subtype != GO_NEG_CONF) { diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 1cc4ee62987d..9843f52fe75a 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -1197,6 +1197,15 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) if (size <= 0) return; + /* A size exceeding the RX buffer is bogus; drop the transfer + * instead of overflowing the buffer. + */ + if (size > WILC_RX_BUFF_SIZE) { + wilc->hif_func->hif_clear_int_ext(wilc, + DATA_INT_CLR | ENABLE_RX_VMM); + return; + } + if (WILC_RX_BUFF_SIZE - offset < size) offset = 0; diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c index 611dade1b1eb..e73c06b268cf 100644 --- a/drivers/net/wireless/realtek/rtw88/tx.c +++ b/drivers/net/wireless/realtek/rtw88/tx.c @@ -426,7 +426,7 @@ void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, pkt_info->mac_id = rtwvif->mac_id; } - if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) + if (ieee80211_is_mgmt(fc) || ieee80211_is_any_nullfunc(fc)) rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb); else if (ieee80211_is_data(fc)) rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 2ddf4d158bfe..c1fc39fafeb7 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -852,8 +852,6 @@ int rsi_hal_load_key(struct rsi_common *common, memcpy(set_key->tx_mic_key, &data[16], 8); memcpy(set_key->rx_mic_key, &data[24], 8); } - } else { - memset(&set_key[FRAME_DESC_SZ], 0, frame_len - FRAME_DESC_SZ); } skb_put(skb, frame_len); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index bdb06584d7e4..fe7c2e70d168 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -3719,10 +3719,8 @@ void wlcore_regdomain_config(struct wl1271 *wl) goto out; ret = wlcore_cmd_regdomain_config_locked(wl); - if (ret < 0) { + if (ret < 0) wl12xx_queue_recovery_work(wl); - goto out; - } pm_runtime_mark_last_busy(wl->dev); pm_runtime_put_autosuspend(wl->dev); diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index 90caa4290dc4..484198766efd 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -2162,7 +2162,12 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw, bool suspend) struct sk_buff *skb; int i; - data->started = false; + /* + * Serialise against wmediumd userspace, so no more frames + * can be handed to mac80211 after this returns. + */ + scoped_guard(mutex, &data->mutex) + data->started = false; for (i = 0; i < ARRAY_SIZE(data->link_data); i++) hrtimer_cancel(&data->link_data[i].beacon_timer); @@ -6136,12 +6141,12 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, if (frame_data_len < sizeof(struct ieee80211_hdr_3addr) || frame_data_len > IEEE80211_MAX_DATA_LEN) - goto err; + goto out; /* Allocate new skb here */ skb = alloc_skb(frame_data_len, GFP_KERNEL); if (skb == NULL) - goto err; + goto out; /* Copy the data */ skb_put_data(skb, frame_data, frame_data_len); @@ -6166,10 +6171,17 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, goto out; } + /* + * Serialise against mac80211_hwsim_stop() - mac80211 doesn't allow + * frames reported while the HW is down, hence the ->started check + * must be under mutex. + */ + mutex_lock(&data2->mutex); + /* check if radio is configured properly */ if ((data2->idle && !data2->tmp_chan) || !data2->started) - goto out; + goto out_unlock; /* A frame is received from user space */ memset(&rx_status, 0, sizeof(rx_status)); @@ -6185,22 +6197,18 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, iter_data.channel = ieee80211_get_channel(data2->hw->wiphy, rx_status.freq); if (!iter_data.channel) - goto out; + goto out_unlock; rx_status.band = iter_data.channel->band; - mutex_lock(&data2->mutex); if (!hwsim_chans_compat(iter_data.channel, channel)) { ieee80211_iterate_active_interfaces_atomic( data2->hw, IEEE80211_IFACE_ITER_NORMAL, mac80211_hwsim_tx_iter, &iter_data); - if (!iter_data.receive) { - mutex_unlock(&data2->mutex); - goto out; - } + if (!iter_data.receive) + goto out_unlock; } - mutex_unlock(&data2->mutex); } else if (!channel) { - goto out; + goto out_unlock; } else { rx_status.freq = channel->center_freq; rx_status.band = channel->band; @@ -6208,7 +6216,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates) - goto out; + goto out_unlock; rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); hdr = (void *)skb->data; @@ -6218,10 +6226,11 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, rx_status.boottime_ns = ktime_get_boottime_ns(); mac80211_hwsim_rx(data2, &rx_status, skb); + mutex_unlock(&data2->mutex); return 0; -err: - pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); +out_unlock: + mutex_unlock(&data2->mutex); out: dev_kfree_skb(skb); return -EINVAL; diff --git a/drivers/net/wireless/virtual/virt_wifi.c b/drivers/net/wireless/virtual/virt_wifi.c index cd6b66242bff..16d1d3cedd98 100644 --- a/drivers/net/wireless/virtual/virt_wifi.c +++ b/drivers/net/wireless/virtual/virt_wifi.c @@ -432,6 +432,7 @@ static netdev_tx_t virt_wifi_start_xmit(struct sk_buff *skb, priv->tx_packets++; if (!priv->is_connected) { priv->tx_failed++; + dev_kfree_skb_any(skb); return NET_XMIT_DROP; } @@ -555,7 +556,6 @@ static int virt_wifi_newlink(struct net_device *dev, } eth_hw_addr_inherit(dev, priv->lowerdev); - netif_stacked_transfer_operstate(priv->lowerdev, dev); dev->ieee80211_ptr = kzalloc(sizeof(*dev->ieee80211_ptr), GFP_KERNEL); @@ -581,6 +581,8 @@ static int virt_wifi_newlink(struct net_device *dev, goto unregister_netdev; } + netif_stacked_transfer_operstate(priv->lowerdev, dev); + dev->priv_destructor = virt_wifi_net_device_destructor; priv->being_deleted = false; priv->is_connected = false; diff --git a/drivers/net/wwan/mhi_wwan_mbim.c b/drivers/net/wwan/mhi_wwan_mbim.c index 1d7e3ad900c1..4995e9836f76 100644 --- a/drivers/net/wwan/mhi_wwan_mbim.c +++ b/drivers/net/wwan/mhi_wwan_mbim.c @@ -252,6 +252,14 @@ static int mbim_rx_verify_ndp16(struct sk_buff *skb, struct usb_cdc_ncm_ndp16 *n return ret; } +static void mhi_mbim_rx_drop(struct mhi_mbim_link *link, struct sk_buff *skb) +{ + dev_kfree_skb_any(skb); + u64_stats_update_begin(&link->rx_syncp); + u64_stats_inc(&link->rx_errors); + u64_stats_update_end(&link->rx_syncp); +} + static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb) { int ndpoffset; @@ -321,7 +329,10 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb) continue; skb_put(skbn, dgram_len); - skb_copy_bits(skb, dgram_offset, skbn->data, dgram_len); + if (skb_copy_bits(skb, dgram_offset, skbn->data, dgram_len)) { + mhi_mbim_rx_drop(link, skbn); + continue; + } switch (skbn->data[0] & 0xf0) { case 0x40: @@ -333,10 +344,7 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb) default: net_err_ratelimited("%s: unknown protocol\n", link->ndev->name); - dev_kfree_skb_any(skbn); - u64_stats_update_begin(&link->rx_syncp); - u64_stats_inc(&link->rx_errors); - u64_stats_update_end(&link->rx_syncp); + mhi_mbim_rx_drop(link, skbn); continue; } @@ -350,9 +358,13 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb) unlock: rcu_read_unlock(); next_ndp: - /* Other NDP to process? */ - ndpoffset = (int)le16_to_cpu(ndp16.wNextNdpIndex); - if (!ndpoffset) + /* Other NDP to process? The offsets must advance, or a + * self-referencing NDP keeps the loop spinning forever. + */ + n = (int)le16_to_cpu(ndp16.wNextNdpIndex); + if (n > ndpoffset) + ndpoffset = n; + else break; } diff --git a/drivers/net/wwan/t7xx/t7xx_netdev.c b/drivers/net/wwan/t7xx/t7xx_netdev.c index fc0a7cb181df..8f32c2d26931 100644 --- a/drivers/net/wwan/t7xx/t7xx_netdev.c +++ b/drivers/net/wwan/t7xx/t7xx_netdev.c @@ -420,6 +420,10 @@ static void t7xx_ccmni_recv_skb(struct t7xx_ccmni_ctrl *ccmni_ctlb, struct sk_bu skb_cb = T7XX_SKB_CB(skb); netif_id = skb_cb->netif_idx; + if (netif_id >= NIC_DEV_MAX) { + dev_kfree_skb(skb); + return; + } ccmni = READ_ONCE(ccmni_ctlb->ccmni_inst[netif_id]); if (!ccmni) { dev_kfree_skb(skb); diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c index 8924f482806b..527a953bf474 100644 --- a/drivers/perf/arm-cmn.c +++ b/drivers/perf/arm-cmn.c @@ -1393,13 +1393,14 @@ static void arm_cmn_claim_wp_idx(struct arm_cmn_dtm *dtm, static u32 arm_cmn_wp_config(struct perf_event *event, int wp_idx) { + struct arm_cmn *cmn = to_cmn(event->pmu); u32 config; u32 dev = CMN_EVENT_WP_DEV_SEL(event); u32 chn = CMN_EVENT_WP_CHN_SEL(event); u32 grp = CMN_EVENT_WP_GRP(event); u32 exc = CMN_EVENT_WP_EXCLUSIVE(event); u32 combine = CMN_EVENT_WP_COMBINE(event); - bool is_cmn600 = to_cmn(event->pmu)->part == PART_CMN600; + bool is_cmn600 = cmn->part == PART_CMN600; /* CMN-600 supports only primary and secondary matching groups */ if (is_cmn600) @@ -1407,8 +1408,11 @@ static u32 arm_cmn_wp_config(struct perf_event *event, int wp_idx) config = FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_DEV_SEL, dev) | FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_CHN_SEL, chn) | - FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_GRP, grp) | - FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_DEV_SEL2, dev >> 1); + FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_GRP, grp); + + if (!cmn->multi_dtm) + config |= FIELD_PREP(CMN_DTM_WPn_CONFIG_WP_DEV_SEL2, dev >> 1); + if (exc) config |= is_cmn600 ? CMN600_WPn_CONFIG_WP_EXCLUSIVE : CMN_DTM_WPn_CONFIG_WP_EXCLUSIVE; diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c index b38f3ae26b3f..2f03c4e66d6f 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c +++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c @@ -36,7 +36,7 @@ mtk_phy_tmds_clk_ratio(struct mtk_hdmi_phy *hdmi_phy, bool enable) * clock bit ratio 1:40, under 3.4Gbps, clock bit ratio 1:10 */ if (enable) - mtk_phy_update_field(regs + HDMI20_CLK_CFG, REG_TXC_DIV, 3); + mtk_phy_update_field(regs + HDMI20_CLK_CFG, REG_TXC_DIV, VAL_TXC_DIV4); else mtk_phy_clear_bits(regs + HDMI20_CLK_CFG, REG_TXC_DIV); } @@ -290,7 +290,7 @@ static int mtk_hdmi_pll_calc(struct mtk_hdmi_phy *hdmi_phy, struct clk_hw *hw, posdiv2 = 1; /* Digital clk divider, max /32 */ - digital_div = div_u64(ns_hdmipll_ck, posdiv1 * posdiv2 * pixel_clk); + digital_div = div64_u64(ns_hdmipll_ck, posdiv1 * posdiv2 * pixel_clk); if (!(digital_div <= 32 && digital_div >= 1)) return -EINVAL; diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h index e26caaf4d104..58800d7659ca 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h +++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h @@ -17,6 +17,9 @@ #define HDMI20_CLK_CFG 0x70 #define REG_TXC_DIV GENMASK(31, 30) +#define VAL_TXC_DIV2 1 +#define VAL_TXC_DIV4 2 +#define VAL_TXC_DIV8 3 #define HDMI_1_CFG_0 0x00 #define RG_HDMITX21_DRV_IBIAS_CLK GENMASK(10, 5) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 4739de1e99fb..e1c94fc890f7 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -26,6 +26,7 @@ #include #include #include +#include #include /******* USB2.0 Host registers (original offset is +0x200) *******/ @@ -105,6 +106,13 @@ /* RZ/G2L specific */ #define USB2_LINECTRL1_USB2_IDMON BIT(0) +/* + * The OTG initialization is expected to finish in 20ms. Choose a large enough + * timeout to avoid waiters exit prematurely the waiting section under heavy + * CPU load. + */ +#define USB2_OTG_INIT_TIMEOUT msecs_to_jiffies(120) + #define NUM_OF_PHYS 4 enum rcar_gen3_phy_index { PHY_INDEX_BOTH_HC, @@ -136,12 +144,20 @@ struct rcar_gen3_chan { struct rcar_gen3_phy rphys[NUM_OF_PHYS]; struct regulator *vbus; struct work_struct work; + wait_queue_head_t otg_init_done; spinlock_t lock; /* protects access to hardware and driver data structure. */ enum usb_dr_mode dr_mode; bool extcon_host; bool is_otg_channel; bool uses_otg_pins; bool otg_internal_reg; + /* + * The OTG can be initialized only once and needs to release the spinlock + * and wait for 20 ms due to hardware constraints. If a thread executes + * PHY configuration code while the OTG PHY is waiting for the 20 ms, the + * thread will have to wait for the OTG PHY initialization to complete. + */ + bool otg_initializing; }; struct rcar_gen3_phy_drv_data { @@ -392,26 +408,58 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, struct rcar_gen3_chan *ch = dev_get_drvdata(dev); bool is_b_device; enum phy_mode cur_mode, new_mode; + int retries = NUM_OF_PHYS; + unsigned long flags; + int ret = -EIO; - guard(spinlock_irqsave)(&ch->lock); + spin_lock_irqsave(&ch->lock, flags); - if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch)) - return -EIO; + if (!ch->is_otg_channel) + goto unlock; + + while (retries-- && ch->otg_initializing) { + spin_unlock_irqrestore(&ch->lock, flags); + + ret = wait_event_timeout(ch->otg_init_done, !ch->otg_initializing, + USB2_OTG_INIT_TIMEOUT); + ret = ret ? 0 : -ETIMEDOUT; + if (ret && !retries) + goto exit; + + spin_lock_irqsave(&ch->lock, flags); + } + + /* If another thread started a new initialization just return -EBUSY. */ + if (ch->otg_initializing) { + ret = -EBUSY; + goto unlock; + } else { + ret = 0; + } + + if (!rcar_gen3_is_any_otg_rphy_initialized(ch)) { + ret = -EIO; + goto unlock; + } - if (sysfs_streq(buf, "host")) + if (sysfs_streq(buf, "host")) { new_mode = PHY_MODE_USB_HOST; - else if (sysfs_streq(buf, "peripheral")) + } else if (sysfs_streq(buf, "peripheral")) { new_mode = PHY_MODE_USB_DEVICE; - else - return -EINVAL; + } else { + ret = -EINVAL; + goto unlock; + } /* is_b_device: true is B-Device. false is A-Device. */ is_b_device = rcar_gen3_check_id(ch); cur_mode = rcar_gen3_get_phy_mode(ch); /* If current and new mode is the same, this returns the error */ - if (cur_mode == new_mode) - return -EINVAL; + if (cur_mode == new_mode) { + ret = -EINVAL; + goto unlock; + } if (new_mode == PHY_MODE_USB_HOST) { /* And is_host must be false */ if (!is_b_device) /* A-Peripheral */ @@ -425,7 +473,10 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, rcar_gen3_init_for_peri(ch); } - return count; +unlock: + spin_unlock_irqrestore(&ch->lock, flags); +exit: + return ret ?: count; } static ssize_t role_show(struct device *dev, struct device_attribute *attr, @@ -441,14 +492,11 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(role); -static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) +static void rcar_gen3_init_otg_phase0(struct rcar_gen3_chan *ch) { void __iomem *usb2_base = ch->base; u32 val; - if (!ch->is_otg_channel || rcar_gen3_is_any_otg_rphy_initialized(ch)) - return; - /* Should not use functions of read-modify-write a register */ val = readl(usb2_base + USB2_LINECTRL1); val = (val & ~USB2_LINECTRL1_DP_RPD) | USB2_LINECTRL1_DPRPD_EN | @@ -471,7 +519,11 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); } } - mdelay(20); +} + +static void rcar_gen3_init_otg_phase1(struct rcar_gen3_chan *ch) +{ + void __iomem *usb2_base = ch->base; writel(0xffffffff, usb2_base + USB2_OBINTSTA); writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTEN); @@ -502,6 +554,7 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) void __iomem *usb2_base = ch->base; struct device *dev = ch->dev; irqreturn_t ret = IRQ_NONE; + unsigned long flags; u32 status; pm_runtime_get_noresume(dev); @@ -509,33 +562,102 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) if (pm_runtime_suspended(dev)) goto rpm_put; - scoped_guard(spinlock, &ch->lock) { - status = readl(usb2_base + USB2_OBINTSTA); - if (status & ch->phy_data->obint_enable_bits) { - dev_vdbg(dev, "%s: %08x\n", __func__, status); - if (ch->phy_data->vblvl_ctrl) - writel(USB2_OBINTSTA_CLEAR, usb2_base + USB2_OBINTSTA); - else - writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA); - rcar_gen3_device_recognition(ch); - rcar_gen3_configure_vblvl_ctrl(ch); - ret = IRQ_HANDLED; - } + spin_lock_irqsave(&ch->lock, flags); + + status = readl(usb2_base + USB2_OBINTSTA); + if (status & ch->phy_data->obint_enable_bits) { + dev_vdbg(dev, "%s: %08x\n", __func__, status); + if (ch->phy_data->vblvl_ctrl) + writel(USB2_OBINTSTA_CLEAR, usb2_base + USB2_OBINTSTA); + else + writel(ch->phy_data->obint_enable_bits, usb2_base + USB2_OBINTSTA); + + ret = IRQ_HANDLED; + + /* This should not happen! */ + if (ch->otg_initializing) + goto unlock; + + rcar_gen3_device_recognition(ch); + rcar_gen3_configure_vblvl_ctrl(ch); } +unlock: + spin_unlock_irqrestore(&ch->lock, flags); rpm_put: pm_runtime_put_noidle(dev); return ret; } +static void rcar_gen3_phy_usb2_irqs_mask_all(struct rcar_gen3_chan *channel, + u32 *masked_irqs_bits) +{ + u32 val, bitmask = USB2_INT_ENABLE_UCOM_INTEN; + void __iomem *usb2_base = channel->base; + + for (unsigned int i = 0; i < NUM_OF_PHYS; i++) + bitmask |= channel->rphys[i].int_enable_bits; + + val = readl(usb2_base + USB2_INT_ENABLE); + *masked_irqs_bits = val & bitmask; + val &= ~bitmask; + writel(val, usb2_base + USB2_INT_ENABLE); + + /* + * Don't report channel->phy_data->obint_enable_bits IRQs. These are + * unmasked anyway in rcar_gen3_init_otg_phase1(). + */ + val = readl(usb2_base + USB2_OBINTEN); + val &= ~channel->phy_data->obint_enable_bits; + writel(val, usb2_base + USB2_OBINTEN); +} + +static void rcar_gen3_phy_usb2_irqs_unmask(struct rcar_gen3_chan *channel, + u32 irqs_bits) +{ + u32 val, bitmask = USB2_INT_ENABLE_UCOM_INTEN; + void __iomem *usb2_base = channel->base; + + for (unsigned int i = 0; i < NUM_OF_PHYS; i++) + bitmask |= channel->rphys[i].int_enable_bits; + + val = readl(usb2_base + USB2_INT_ENABLE); + val &= ~bitmask; + val |= irqs_bits; + writel(val, usb2_base + USB2_INT_ENABLE); +} + static int rcar_gen3_phy_usb2_init(struct phy *p) { struct rcar_gen3_phy *rphy = phy_get_drvdata(p); struct rcar_gen3_chan *channel = rphy->ch; void __iomem *usb2_base = channel->base; + int retries = NUM_OF_PHYS; + unsigned long flags; u32 val; + int ret; - guard(spinlock_irqsave)(&channel->lock); + spin_lock_irqsave(&channel->lock, flags); + + while (retries-- && channel->otg_initializing) { + spin_unlock_irqrestore(&channel->lock, flags); + + ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing, + USB2_OTG_INIT_TIMEOUT); + ret = ret ? 0 : -ETIMEDOUT; + if (ret && !retries) + return ret; + + spin_lock_irqsave(&channel->lock, flags); + } + + /* If another thread started a new initialization just return -EBUSY. */ + if (channel->otg_initializing) { + ret = -EBUSY; + goto unlock; + } else { + ret = 0; + } /* Initialize USB2 part */ val = readl(usb2_base + USB2_INT_ENABLE); @@ -548,8 +670,23 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) } /* Initialize otg part (only if we initialize a PHY with IRQs). */ - if (rphy->int_enable_bits) - rcar_gen3_init_otg(channel); + if (rphy->int_enable_bits && channel->is_otg_channel && + !rcar_gen3_is_any_otg_rphy_initialized(channel)) { + u32 masked_irq_bits = 0; + + rcar_gen3_init_otg_phase0(channel); + rcar_gen3_phy_usb2_irqs_mask_all(channel, &masked_irq_bits); + channel->otg_initializing = true; + spin_unlock_irqrestore(&channel->lock, flags); + + fsleep(20000); + + spin_lock_irqsave(&channel->lock, flags); + rcar_gen3_phy_usb2_irqs_unmask(channel, masked_irq_bits); + rcar_gen3_init_otg_phase1(channel); + channel->otg_initializing = false; + wake_up_all(&channel->otg_init_done); + } if (channel->phy_data->vblvl_ctrl) { /* SIDDQ mode release */ @@ -568,7 +705,10 @@ static int rcar_gen3_phy_usb2_init(struct phy *p) rphy->initialized = true; - return 0; +unlock: + spin_unlock_irqrestore(&channel->lock, flags); + + return ret; } static int rcar_gen3_phy_usb2_exit(struct phy *p) @@ -576,9 +716,32 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) struct rcar_gen3_phy *rphy = phy_get_drvdata(p); struct rcar_gen3_chan *channel = rphy->ch; void __iomem *usb2_base = channel->base; + int retries = NUM_OF_PHYS; + unsigned long flags; u32 val; + int ret; - guard(spinlock_irqsave)(&channel->lock); + spin_lock_irqsave(&channel->lock, flags); + + while (retries-- && channel->otg_initializing) { + spin_unlock_irqrestore(&channel->lock, flags); + + ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing, + USB2_OTG_INIT_TIMEOUT); + ret = ret ? 0 : -ETIMEDOUT; + if (ret && !retries) + return ret; + + spin_lock_irqsave(&channel->lock, flags); + } + + /* If another thread started a new initialization just return -EBUSY. */ + if (channel->otg_initializing) { + ret = -EBUSY; + goto unlock; + } else { + ret = 0; + } rphy->initialized = false; @@ -588,7 +751,9 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p) val &= ~USB2_INT_ENABLE_UCOM_INTEN; writel(val, usb2_base + USB2_INT_ENABLE); - return 0; +unlock: + spin_unlock_irqrestore(&channel->lock, flags); + return ret; } static int rcar_gen3_phy_usb2_power_on(struct phy *p) @@ -596,8 +761,10 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) struct rcar_gen3_phy *rphy = phy_get_drvdata(p); struct rcar_gen3_chan *channel = rphy->ch; void __iomem *usb2_base = channel->base; + int retries = NUM_OF_PHYS; + unsigned long flags; u32 val; - int ret = 0; + int ret; if (channel->vbus && !channel->otg_internal_reg) { ret = regulator_enable(channel->vbus); @@ -605,7 +772,27 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) return ret; } - guard(spinlock_irqsave)(&channel->lock); + spin_lock_irqsave(&channel->lock, flags); + + while (retries-- && channel->otg_initializing) { + spin_unlock_irqrestore(&channel->lock, flags); + + ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing, + USB2_OTG_INIT_TIMEOUT); + ret = ret ? 0 : -ETIMEDOUT; + if (ret && !retries) + goto disable_regulator; + + spin_lock_irqsave(&channel->lock, flags); + } + + /* If another thread started a new initialization just return -EBUSY. */ + if (channel->otg_initializing) { + ret = -EBUSY; + goto unlock; + } else { + ret = 0; + } if (!rcar_gen3_are_all_rphys_power_off(channel)) goto out; @@ -620,27 +807,59 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) /* The powered flag should be set for any other phys anyway */ rphy->powered = true; - return 0; +unlock: + spin_unlock_irqrestore(&channel->lock, flags); + +disable_regulator: + if (ret && channel->vbus && !channel->otg_internal_reg) + regulator_disable(channel->vbus); + + return ret; } static int rcar_gen3_phy_usb2_power_off(struct phy *p) { struct rcar_gen3_phy *rphy = phy_get_drvdata(p); struct rcar_gen3_chan *channel = rphy->ch; - int ret = 0; + int retries = NUM_OF_PHYS; + unsigned long flags; + int ret; - scoped_guard(spinlock_irqsave, &channel->lock) { - rphy->powered = false; + spin_lock_irqsave(&channel->lock, flags); - if (rcar_gen3_are_all_rphys_power_off(channel)) { - u32 val = readl(channel->base + USB2_USBCTR); + while (retries-- && channel->otg_initializing) { + spin_unlock_irqrestore(&channel->lock, flags); - val |= USB2_USBCTR_PLL_RST; - writel(val, channel->base + USB2_USBCTR); - } + ret = wait_event_timeout(channel->otg_init_done, !channel->otg_initializing, + USB2_OTG_INIT_TIMEOUT); + ret = ret ? 0 : -ETIMEDOUT; + if (ret && !retries) + return ret; + + spin_lock_irqsave(&channel->lock, flags); + } + + /* If another thread started a new initialization just return -EBUSY. */ + if (channel->otg_initializing) { + ret = -EBUSY; + goto unlock; + } else { + ret = 0; + } + + rphy->powered = false; + + if (rcar_gen3_are_all_rphys_power_off(channel)) { + u32 val = readl(channel->base + USB2_USBCTR); + + val |= USB2_USBCTR_PLL_RST; + writel(val, channel->base + USB2_USBCTR); } - if (channel->vbus && !channel->otg_internal_reg) +unlock: + spin_unlock_irqrestore(&channel->lock, flags); + + if (!ret && channel->vbus && !channel->otg_internal_reg) ret = regulator_disable(channel->vbus); return ret; @@ -1018,6 +1237,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) } spin_lock_init(&channel->lock); + init_waitqueue_head(&channel->otg_init_done); for (i = 0; i < NUM_OF_PHYS; i++) { channel->rphys[i].phy = devm_phy_create(dev, NULL, channel->phy_data->phy_usb2_ops); diff --git a/drivers/power/sequencing/Kconfig b/drivers/power/sequencing/Kconfig index 280f92beb5d0..a33b705415c4 100644 --- a/drivers/power/sequencing/Kconfig +++ b/drivers/power/sequencing/Kconfig @@ -29,7 +29,8 @@ config POWER_SEQUENCING_QCOM_WCN config POWER_SEQUENCING_TH1520_GPU tristate "T-HEAD TH1520 GPU power sequencing driver" - depends on (ARCH_THEAD && AUXILIARY_BUS) || COMPILE_TEST + depends on ARCH_THEAD || COMPILE_TEST + select AUXILIARY_BUS help Say Y here to enable the power sequencing driver for the TH1520 SoC GPU. This driver handles the complex clock and reset sequence diff --git a/drivers/power/sequencing/core.c b/drivers/power/sequencing/core.c index 0a1bc6c20c11..54fba52df473 100644 --- a/drivers/power/sequencing/core.c +++ b/drivers/power/sequencing/core.c @@ -101,6 +101,7 @@ static struct pwrseq_unit *pwrseq_unit_new(const struct pwrseq_unit_data *data) } kref_init(&unit->ref); + INIT_LIST_HEAD(&unit->list); INIT_LIST_HEAD(&unit->deps); unit->enable = data->enable; unit->disable = data->disable; @@ -504,10 +505,6 @@ pwrseq_device_register(const struct pwrseq_config *config) */ device_initialize(&pwrseq->dev); - ret = dev_set_name(&pwrseq->dev, "pwrseq.%d", pwrseq->id); - if (ret) - goto err_put_pwrseq; - pwrseq->owner = config->owner ?: THIS_MODULE; pwrseq->match = config->match; @@ -516,6 +513,10 @@ pwrseq_device_register(const struct pwrseq_config *config) INIT_LIST_HEAD(&pwrseq->targets); INIT_LIST_HEAD(&pwrseq->units); + ret = dev_set_name(&pwrseq->dev, "pwrseq.%d", pwrseq->id); + if (ret) + goto err_put_pwrseq; + ret = pwrseq_setup_targets(config->targets, pwrseq); if (ret) goto err_put_pwrseq; @@ -913,6 +914,8 @@ int pwrseq_power_on(struct pwrseq_desc *desc) if (!ret) desc->powered_on = true; } + if (ret) + return ret; if (target->post_enable) { ret = target->post_enable(pwrseq); diff --git a/drivers/scsi/fnic/fdls_disc.c b/drivers/scsi/fnic/fdls_disc.c index ae37f85f618b..6ecfbd3c5215 100644 --- a/drivers/scsi/fnic/fdls_disc.c +++ b/drivers/scsi/fnic/fdls_disc.c @@ -104,7 +104,7 @@ uint8_t *fdls_alloc_frame(struct fnic_iport_s *iport) frame = mempool_alloc(fnic->frame_pool, GFP_ATOMIC); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame"); return NULL; } @@ -136,7 +136,7 @@ uint16_t fdls_alloc_oxid(struct fnic_iport_s *iport, int oxid_frame_type, */ idx = find_next_zero_bit(oxid_pool->bitmap, FNIC_OXID_POOL_SZ, oxid_pool->next_idx); if (idx == FNIC_OXID_POOL_SZ) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Alloc oxid: all oxid slots are busy iport state:%d\n", iport->state); return FNIC_UNASSIGNED_OXID; @@ -148,7 +148,7 @@ uint16_t fdls_alloc_oxid(struct fnic_iport_s *iport, int oxid_frame_type, oxid = FNIC_OXID_ENCODE(idx, oxid_frame_type); *active_oxid = oxid; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "alloc oxid: 0x%x, iport state: %d\n", oxid, iport->state); return oxid; @@ -169,7 +169,7 @@ static void fdls_free_oxid_idx(struct fnic_iport_s *iport, uint16_t oxid_idx) lockdep_assert_held(&fnic->fnic_lock); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "free oxid idx: 0x%x\n", oxid_idx); WARN_ON(!test_and_clear_bit(oxid_idx, oxid_pool->bitmap)); @@ -194,7 +194,7 @@ void fdls_reclaim_oxid_handler(struct work_struct *work) struct reclaim_entry_s *reclaim_entry, *next; unsigned long delay_j, cur_jiffies; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Reclaim oxid callback\n"); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); @@ -223,7 +223,7 @@ void fdls_reclaim_oxid_handler(struct work_struct *work) delay_j = reclaim_entry->expires - cur_jiffies; schedule_delayed_work(&oxid_pool->oxid_reclaim_work, delay_j); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Scheduling next callback at:%ld jiffies\n", delay_j); } @@ -266,7 +266,7 @@ void fdls_schedule_oxid_free(struct fnic_iport_s *iport, uint16_t *active_oxid) lockdep_assert_held(&fnic->fnic_lock); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Schedule oxid free. oxid: 0x%x\n", *active_oxid); *active_oxid = FNIC_UNASSIGNED_OXID; @@ -275,7 +275,7 @@ void fdls_schedule_oxid_free(struct fnic_iport_s *iport, uint16_t *active_oxid) kzalloc(sizeof(struct reclaim_entry_s), GFP_ATOMIC); if (!reclaim_entry) { - FNIC_FCS_DBG(KERN_WARNING, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_WARNING, fnic, "Failed to allocate memory for reclaim struct for oxid idx: %d\n", oxid_idx); @@ -313,7 +313,7 @@ void fdls_schedule_oxid_free_retry_work(struct work_struct *work) for_each_set_bit(idx, oxid_pool->pending_schedule_free, FNIC_OXID_POOL_SZ) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Schedule oxid free. oxid idx: %d\n", idx); reclaim_entry = kzalloc(sizeof(*reclaim_entry), GFP_KERNEL); @@ -416,7 +416,7 @@ fdls_start_fabric_timer(struct fnic_iport_s *iport, int timeout) struct fnic *fnic = iport->fnic; if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport fcid: 0x%x: Canceling fabric disc timer\n", iport->fcid); fnic_del_fabric_timer_sync(fnic); @@ -429,7 +429,7 @@ fdls_start_fabric_timer(struct fnic_iport_s *iport, int timeout) fabric_tov = jiffies + msecs_to_jiffies(timeout); mod_timer(&iport->fabric.retry_timer, round_jiffies(fabric_tov)); iport->fabric.timer_pending = 1; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "fabric timer is %d ", timeout); } @@ -441,7 +441,7 @@ fdls_start_tport_timer(struct fnic_iport_s *iport, struct fnic *fnic = iport->fnic; if (tport->timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport fcid 0x%x: Canceling disc timer\n", tport->fcid); fnic_del_tport_timer_sync(fnic, tport); @@ -575,7 +575,7 @@ fdls_send_rscn_resp(struct fnic_iport_s *iport, frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send RSCN response"); return; } @@ -588,7 +588,7 @@ fdls_send_rscn_resp(struct fnic_iport_s *iport, oxid = FNIC_STD_GET_OX_ID(rscn_fchdr); FNIC_STD_SET_OX_ID(pels_acc->fchdr, oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send RSCN response with oxid: 0x%x", iport->fcid, oxid); @@ -608,7 +608,7 @@ fdls_send_logo_resp(struct fnic_iport_s *iport, frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send LOGO response"); return; } @@ -621,7 +621,7 @@ fdls_send_logo_resp(struct fnic_iport_s *iport, oxid = FNIC_STD_GET_OX_ID(req_fchdr); FNIC_STD_SET_OX_ID(plogo_resp->fchdr, oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send LOGO response with oxid: 0x%x", iport->fcid, oxid); @@ -642,7 +642,7 @@ fdls_send_tport_abts(struct fnic_iport_s *iport, frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send tport ABTS"); return; } @@ -665,7 +665,7 @@ fdls_send_tport_abts(struct fnic_iport_s *iport, FNIC_STD_SET_OX_ID(*ptport_abts, tport->active_oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send tport abts: tport->state: %d ", iport->fcid, tport->state); @@ -687,7 +687,7 @@ static void fdls_send_fabric_abts(struct fnic_iport_s *iport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send fabric ABTS"); return; } @@ -750,7 +750,7 @@ static void fdls_send_fabric_abts(struct fnic_iport_s *iport) oxid = iport->active_oxid_fabric_req; FNIC_STD_SET_OX_ID(*pfabric_abts, oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send fabric abts. iport->fabric.state: %d oxid: 0x%x", iport->fcid, iport->fabric.state, oxid); @@ -773,7 +773,7 @@ static uint8_t *fdls_alloc_init_fdmi_abts_frame(struct fnic_iport_s *iport, frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send FDMI ABTS"); return NULL; } @@ -802,7 +802,7 @@ static void fdls_send_fdmi_abts(struct fnic_iport_s *iport) if (frame == NULL) return; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send FDMI PLOGI abts. iport->fabric.state: %d oxid: 0x%x", iport->fcid, iport->fabric.state, iport->active_oxid_fdmi_plogi); fnic_send_fcoe_frame(iport, frame, frame_size); @@ -813,7 +813,7 @@ static void fdls_send_fdmi_abts(struct fnic_iport_s *iport) if (frame == NULL) return; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send FDMI RHBA abts. iport->fabric.state: %d oxid: 0x%x", iport->fcid, iport->fabric.state, iport->active_oxid_fdmi_rhba); fnic_send_fcoe_frame(iport, frame, frame_size); @@ -828,7 +828,7 @@ static void fdls_send_fdmi_abts(struct fnic_iport_s *iport) return; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send FDMI RPA abts. iport->fabric.state: %d oxid: 0x%x", iport->fcid, iport->fabric.state, iport->active_oxid_fdmi_rpa); fnic_send_fcoe_frame(iport, frame, frame_size); @@ -840,7 +840,7 @@ static void fdls_send_fdmi_abts(struct fnic_iport_s *iport) mod_timer(&iport->fabric.fdmi_timer, round_jiffies(fdmi_tov)); iport->fabric.fdmi_pending |= FDLS_FDMI_ABORT_PENDING; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: iport->fabric.fdmi_pending: 0x%x", iport->fcid, iport->fabric.fdmi_pending); } @@ -856,7 +856,7 @@ static void fdls_send_fabric_flogi(struct fnic_iport_s *iport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send FLOGI"); iport->fabric.flags |= FNIC_FDLS_RETRY_FRAME; goto err_out; @@ -885,7 +885,7 @@ static void fdls_send_fabric_flogi(struct fnic_iport_s *iport) &iport->active_oxid_fabric_req); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send FLOGI", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -894,7 +894,7 @@ static void fdls_send_fabric_flogi(struct fnic_iport_s *iport) } FNIC_STD_SET_OX_ID(pflogi->fchdr, oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send fabric FLOGI with oxid: 0x%x", iport->fcid, oxid); @@ -916,7 +916,7 @@ static void fdls_send_fabric_plogi(struct fnic_iport_s *iport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send PLOGI"); iport->fabric.flags |= FNIC_FDLS_RETRY_FRAME; goto err_out; @@ -928,7 +928,7 @@ static void fdls_send_fabric_plogi(struct fnic_iport_s *iport) oxid = fdls_alloc_oxid(iport, FNIC_FRAME_TYPE_FABRIC_PLOGI, &iport->active_oxid_fabric_req); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send fabric PLOGI", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -937,7 +937,7 @@ static void fdls_send_fabric_plogi(struct fnic_iport_s *iport) } FNIC_STD_SET_OX_ID(pplogi->fchdr, oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send fabric PLOGI with oxid: 0x%x", iport->fcid, oxid); @@ -962,7 +962,7 @@ static void fdls_send_fdmi_plogi(struct fnic_iport_s *iport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send FDMI PLOGI"); goto err_out; } @@ -974,7 +974,7 @@ static void fdls_send_fdmi_plogi(struct fnic_iport_s *iport) &iport->active_oxid_fdmi_plogi); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send FDMI PLOGI", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -985,7 +985,7 @@ static void fdls_send_fdmi_plogi(struct fnic_iport_s *iport) hton24(d_id, FC_FID_MGMT_SERV); FNIC_STD_SET_D_ID(pplogi->fchdr, d_id); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send FDMI PLOGI with oxid: 0x%x", iport->fcid, oxid); @@ -1009,7 +1009,7 @@ static void fdls_send_rpn_id(struct fnic_iport_s *iport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send RPN_ID"); iport->fabric.flags |= FNIC_FDLS_RETRY_FRAME; goto err_out; @@ -1036,7 +1036,7 @@ static void fdls_send_rpn_id(struct fnic_iport_s *iport) &iport->active_oxid_fabric_req); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send RPN_ID", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -1045,7 +1045,7 @@ static void fdls_send_rpn_id(struct fnic_iport_s *iport) } FNIC_STD_SET_OX_ID(prpn_id->fchdr, oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send RPN ID with oxid: 0x%x", iport->fcid, oxid); @@ -1068,7 +1068,7 @@ static void fdls_send_scr(struct fnic_iport_s *iport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send SCR"); iport->fabric.flags |= FNIC_FDLS_RETRY_FRAME; goto err_out; @@ -1090,7 +1090,7 @@ static void fdls_send_scr(struct fnic_iport_s *iport) oxid = fdls_alloc_oxid(iport, FNIC_FRAME_TYPE_FABRIC_SCR, &iport->active_oxid_fabric_req); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send SCR", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -1099,7 +1099,7 @@ static void fdls_send_scr(struct fnic_iport_s *iport) } FNIC_STD_SET_OX_ID(pscr->fchdr, oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send SCR with oxid: 0x%x", iport->fcid, oxid); @@ -1123,7 +1123,7 @@ static void fdls_send_gpn_ft(struct fnic_iport_s *iport, int fdls_state) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send GPN FT"); iport->fabric.flags |= FNIC_FDLS_RETRY_FRAME; goto err_out; @@ -1148,7 +1148,7 @@ static void fdls_send_gpn_ft(struct fnic_iport_s *iport, int fdls_state) &iport->active_oxid_fabric_req); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send GPN FT", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -1157,7 +1157,7 @@ static void fdls_send_gpn_ft(struct fnic_iport_s *iport, int fdls_state) } FNIC_STD_SET_OX_ID(pgpn_ft->fchdr, oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send GPN FT with oxid: 0x%x", iport->fcid, oxid); @@ -1183,7 +1183,7 @@ fdls_send_tgt_adisc(struct fnic_iport_s *iport, struct fnic_tport_s *tport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send TGT ADISC"); tport->flags |= FNIC_FDLS_RETRY_FRAME; goto err_out; @@ -1203,7 +1203,7 @@ fdls_send_tgt_adisc(struct fnic_iport_s *iport, struct fnic_tport_s *tport) oxid = fdls_alloc_oxid(iport, FNIC_FRAME_TYPE_TGT_ADISC, &tport->active_oxid); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send TGT ADISC", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -1222,7 +1222,7 @@ fdls_send_tgt_adisc(struct fnic_iport_s *iport, struct fnic_tport_s *tport) padisc->els.adisc_cmd = ELS_ADISC; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send ADISC to tgt fcid: 0x%x", iport->fcid, tport->fcid); @@ -1242,7 +1242,7 @@ bool fdls_delete_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport) if ((tport->state == FDLS_TGT_STATE_OFFLINING) || (tport->state == FDLS_TGT_STATE_OFFLINE)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport fcid 0x%x: tport state is offlining/offline\n", tport->fcid); return false; @@ -1257,7 +1257,7 @@ bool fdls_delete_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport) tport->flags |= FNIC_FDLS_TPORT_TERMINATING; if (tport->timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport fcid 0x%x: Canceling disc timer\n", tport->fcid); fnic_del_tport_timer_sync(fnic, tport); @@ -1272,9 +1272,9 @@ bool fdls_delete_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport) tport_del_evt = kzalloc(sizeof(struct fnic_tport_event_s), GFP_ATOMIC); if (!tport_del_evt) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "Failed to allocate memory for tport fcid: 0x%0x\n", - tport->fcid); + FNIC_FCS_DBG(KERN_INFO, fnic, + "iport: 0x%x tport 0x%x: Failed to allocate memory\n", + iport->fcid, tport->fcid); return false; } tport_del_evt->event = TGT_EV_RPORT_DEL; @@ -1282,9 +1282,9 @@ bool fdls_delete_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport) list_add_tail(&tport_del_evt->links, &fnic->tport_event_list); queue_work(fnic_event_queue, &fnic->tport_work); } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "tport 0x%x not reg with scsi_transport. Freeing locally", - tport->fcid); + FNIC_FCS_DBG(KERN_INFO, fnic, + "tport 0x%x not registered, freeing locally\n", + tport->fcid); list_del(&tport->links); kfree(tport); } @@ -1305,7 +1305,7 @@ fdls_send_tgt_plogi(struct fnic_iport_s *iport, struct fnic_tport_s *tport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send TGT PLOGI"); tport->flags |= FNIC_FDLS_RETRY_FRAME; goto err_out; @@ -1316,7 +1316,7 @@ fdls_send_tgt_plogi(struct fnic_iport_s *iport, struct fnic_tport_s *tport) oxid = fdls_alloc_oxid(iport, FNIC_FRAME_TYPE_TGT_PLOGI, &tport->active_oxid); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate oxid to send PLOGI to fcid: 0x%x", iport->fcid, tport->fcid); mempool_free(frame, fnic->frame_pool); @@ -1330,7 +1330,7 @@ fdls_send_tgt_plogi(struct fnic_iport_s *iport, struct fnic_tport_s *tport) hton24(d_id, tport->fcid); FNIC_STD_SET_D_ID(pplogi->fchdr, d_id); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send tgt PLOGI to tgt: 0x%x with oxid: 0x%x", iport->fcid, tport->fcid, oxid); @@ -1353,7 +1353,7 @@ fnic_fc_plogi_rsp_rdf(struct fnic_iport_s *iport, be16_to_cpu(plogi_rsp->els.fl_cssp[2].cp_rdfs) & FNIC_FC_C3_RDF; struct fnic *fnic = iport->fnic; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "MFS: b2b_rdf_size: 0x%x spc3_rdf_size: 0x%x", b2b_rdf_size, spc3_rdf_size); @@ -1372,7 +1372,7 @@ static void fdls_send_register_fc4_types(struct fnic_iport_s *iport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send RFT"); return; } @@ -1396,7 +1396,7 @@ static void fdls_send_register_fc4_types(struct fnic_iport_s *iport) &iport->active_oxid_fabric_req); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send RFT", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -1404,15 +1404,18 @@ static void fdls_send_register_fc4_types(struct fnic_iport_s *iport) } FNIC_STD_SET_OX_ID(prft_id->fchdr, oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "0x%x: FDLS send RFT with oxid: 0x%x", iport->fcid, - oxid); prft_id->rft_id.fr_fts.ff_type_map[0] = cpu_to_be32(1 << FC_TYPE_FCP); prft_id->rft_id.fr_fts.ff_type_map[1] = cpu_to_be32(1 << (FC_TYPE_CT % FC_NS_BPW)); + FNIC_FCS_DBG(KERN_INFO, fnic, + "0x%x: FDLS send RFT 0x%08x 0x%08x 0x%08x with oxid: 0x%x", + iport->fcid, prft_id->rft_id.fr_fts.ff_type_map[0], + prft_id->rft_id.fr_fts.ff_type_map[1], + prft_id->rft_id.fr_fts.ff_type_map[2], + oxid); fnic_send_fcoe_frame(iport, frame, frame_size); @@ -1432,7 +1435,7 @@ static void fdls_send_register_fc4_features(struct fnic_iport_s *iport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send RFF"); return; } @@ -1458,7 +1461,7 @@ static void fdls_send_register_fc4_features(struct fnic_iport_s *iport) &iport->active_oxid_fabric_req); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send RFF", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -1466,12 +1469,13 @@ static void fdls_send_register_fc4_features(struct fnic_iport_s *iport) } FNIC_STD_SET_OX_ID(prff_id->fchdr, oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "0x%x: FDLS send RFF with oxid: 0x%x", iport->fcid, - oxid); - prff_id->rff_id.fr_type = FC_TYPE_FCP; + FNIC_FCS_DBG(KERN_INFO, fnic, + "0x%x: FDLS send RFF with oxid: 0x%x type 0%x feat 0%x", + iport->fcid, oxid, prff_id->rff_id.fr_type, + prff_id->rff_id.fr_feat); + fnic_send_fcoe_frame(iport, frame, frame_size); /* Even if fnic_send_fcoe_frame() fails we want to retry after timeout */ @@ -1493,7 +1497,7 @@ fdls_send_tgt_prli(struct fnic_iport_s *iport, struct fnic_tport_s *tport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send TGT PRLI"); tport->flags |= FNIC_FDLS_RETRY_FRAME; goto err_out; @@ -1513,7 +1517,7 @@ fdls_send_tgt_prli(struct fnic_iport_s *iport, struct fnic_tport_s *tport) oxid = fdls_alloc_oxid(iport, FNIC_FRAME_TYPE_TGT_PRLI, &tport->active_oxid); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "0x%x: Failed to allocate OXID to send TGT PRLI to 0x%x", iport->fcid, tport->fcid); mempool_free(frame, fnic->frame_pool); @@ -1530,7 +1534,7 @@ fdls_send_tgt_prli(struct fnic_iport_s *iport, struct fnic_tport_s *tport) FNIC_STD_SET_S_ID(pprli->fchdr, s_id); FNIC_STD_SET_D_ID(pprli->fchdr, d_id); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send PRLI to tgt: 0x%x with oxid: 0x%x", iport->fcid, tport->fcid, oxid); @@ -1564,7 +1568,7 @@ void fdls_send_fabric_logo(struct fnic_iport_s *iport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send fabric LOGO"); return; } @@ -1576,7 +1580,7 @@ void fdls_send_fabric_logo(struct fnic_iport_s *iport) &iport->active_oxid_fabric_req); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send fabric LOGO", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -1589,7 +1593,7 @@ void fdls_send_fabric_logo(struct fnic_iport_s *iport) iport->fabric.flags &= ~FNIC_FDLS_FABRIC_ABORT_ISSUED; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send fabric LOGO with oxid: 0x%x", iport->fcid, oxid); @@ -1621,7 +1625,7 @@ void fdls_tgt_logout(struct fnic_iport_s *iport, struct fnic_tport_s *tport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send fabric LOGO"); return; } @@ -1631,7 +1635,7 @@ void fdls_tgt_logout(struct fnic_iport_s *iport, struct fnic_tport_s *tport) oxid = fdls_alloc_oxid(iport, FNIC_FRAME_TYPE_TGT_LOGO, &tport->active_oxid); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send tgt LOGO", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -1642,7 +1646,7 @@ void fdls_tgt_logout(struct fnic_iport_s *iport, struct fnic_tport_s *tport) hton24(d_id, tport->fcid); FNIC_STD_SET_D_ID(plogo->fchdr, d_id); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send tgt LOGO with oxid: 0x%x", iport->fcid, oxid); @@ -1657,7 +1661,7 @@ static void fdls_tgt_discovery_start(struct fnic_iport_s *iport) u32 old_link_down_cnt = iport->fnic->link_down_cnt; struct fnic *fnic = iport->fnic; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Starting FDLS target discovery", iport->fcid); list_for_each_entry_safe(tport, next, &iport->tport_list, links) { @@ -1711,7 +1715,7 @@ static void fdls_target_restart_nexus(struct fnic_tport_s *tport) struct fnic *fnic = iport->fnic; bool retval = true; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport fcid: 0x%x state: %d restart_count: %d", tport->fcid, tport->state, tport->nexus_restart_count); @@ -1721,13 +1725,13 @@ static void fdls_target_restart_nexus(struct fnic_tport_s *tport) retval = fdls_delete_tport(iport, tport); if (retval != true) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Error deleting tport: 0x%x", fcid); return; } if (nexus_restart_count >= FNIC_TPORT_MAX_NEXUS_RESTART) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Exceeded nexus restart retries tport: 0x%x", fcid); return; @@ -1744,7 +1748,7 @@ static void fdls_target_restart_nexus(struct fnic_tport_s *tport) */ new_tport = fdls_create_tport(iport, fcid, wwpn); if (!new_tport) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Error creating new tport: 0x%x", fcid); return; } @@ -1773,12 +1777,12 @@ static struct fnic_tport_s *fdls_create_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport; struct fnic *fnic = iport->fnic; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDLS create tport: fcid: 0x%x wwpn: 0x%llx", fcid, wwpn); tport = kzalloc(sizeof(struct fnic_tport_s), GFP_ATOMIC); if (!tport) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Memory allocation failure while creating tport: 0x%x\n", fcid); return NULL; @@ -1791,12 +1795,12 @@ static struct fnic_tport_s *fdls_create_tport(struct fnic_iport_s *iport, tport->wwpn = wwpn; tport->iport = iport; - FNIC_FCS_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_DEBUG, fnic, "Need to setup tport timer callback"); timer_setup(&tport->retry_timer, fdls_tport_timer_callback, 0); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Added tport 0x%x", tport->fcid); fdls_set_tport_state(tport, FDLS_TGT_STATE_INIT); list_add_tail(&tport->links, &iport->tport_list); @@ -1847,7 +1851,7 @@ static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send FDMI RHBA"); return; } @@ -1875,7 +1879,7 @@ static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) &iport->active_oxid_fdmi_rhba); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send FDMI RHBA", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -1896,14 +1900,14 @@ static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_NODE_NAME, FNIC_FDMI_NN_LEN, data, &attr_off_bytes); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "NN set, off=%d", attr_off_bytes); strscpy_pad(data, FNIC_FDMI_MANUFACTURER, FNIC_FDMI_MANU_LEN); fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_MANUFACTURER, FNIC_FDMI_MANU_LEN, data, &attr_off_bytes); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "MFG set <%s>, off=%d", data, attr_off_bytes); err = vnic_dev_fw_info(fnic->vdev, &fw_info); @@ -1912,7 +1916,7 @@ static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) FNIC_FDMI_SERIAL_LEN); fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_SERIAL_NUMBER, FNIC_FDMI_SERIAL_LEN, data, &attr_off_bytes); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "SERIAL set <%s>, off=%d", data, attr_off_bytes); } @@ -1923,21 +1927,21 @@ static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_MODEL, FNIC_FDMI_MODEL_LEN, data, &attr_off_bytes); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "MODEL set <%s>, off=%d", data, attr_off_bytes); strscpy_pad(data, FNIC_FDMI_MODEL_DESCRIPTION, FNIC_FDMI_MODEL_DES_LEN); fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_MODEL_DES, FNIC_FDMI_MODEL_DES_LEN, data, &attr_off_bytes); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "MODEL_DESC set <%s>, off=%d", data, attr_off_bytes); if (!err) { strscpy_pad(data, fw_info->hw_version, FNIC_FDMI_HW_VER_LEN); fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_HARDWARE_VERSION, FNIC_FDMI_HW_VER_LEN, data, &attr_off_bytes); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "HW_VER set <%s>, off=%d", data, attr_off_bytes); } @@ -1946,14 +1950,14 @@ static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_DRIVER_VERSION, FNIC_FDMI_DR_VER_LEN, data, &attr_off_bytes); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "DRV_VER set <%s>, off=%d", data, attr_off_bytes); strscpy_pad(data, "N/A", FNIC_FDMI_ROM_VER_LEN); fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_ROM_VERSION, FNIC_FDMI_ROM_VER_LEN, data, &attr_off_bytes); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "ROM_VER set <%s>, off=%d", data, attr_off_bytes); if (!err) { @@ -1961,14 +1965,14 @@ static void fdls_fdmi_register_hba(struct fnic_iport_s *iport) fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_FIRMWARE_VERSION, FNIC_FDMI_FW_VER_LEN, data, &attr_off_bytes); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FW_VER set <%s>, off=%d", data, attr_off_bytes); } len = sizeof(struct fc_std_fdmi_rhba) + attr_off_bytes; frame_size += len; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send FDMI RHBA with oxid: 0x%x fs: %d", iport->fcid, oxid, frame_size); @@ -1992,7 +1996,7 @@ static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send FDMI RPA"); return; } @@ -2020,7 +2024,7 @@ static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) &iport->active_oxid_fdmi_rpa); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Failed to allocate OXID to send FDMI RPA", iport->fcid); mempool_free(frame, fnic->frame_pool); @@ -2085,7 +2089,7 @@ static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_OS_NAME, FNIC_FDMI_OS_NAME_LEN, data, &attr_off_bytes); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "OS name set <%s>, off=%d", data, attr_off_bytes); sprintf(fc_host_system_hostname(fnic->host), "%s", utsname()->nodename); @@ -2094,13 +2098,13 @@ static void fdls_fdmi_register_pa(struct fnic_iport_s *iport) fnic_fdmi_attr_set(fdmi_attr, FNIC_FDMI_TYPE_HOST_NAME, FNIC_FDMI_HN_LEN, data, &attr_off_bytes); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Host name set <%s>, off=%d", data, attr_off_bytes); len = sizeof(struct fc_std_fdmi_rpa) + attr_off_bytes; frame_size += len; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send FDMI RPA with oxid: 0x%x fs: %d", iport->fcid, oxid, frame_size); @@ -2117,7 +2121,7 @@ void fdls_fabric_timer_callback(struct timer_list *t) struct fnic *fnic = iport->fnic; unsigned long flags; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tp: %d fab state: %d fab retry counter: %d max_flogi_retries: %d", iport->fabric.timer_pending, iport->fabric.state, iport->fabric.retry_counter, iport->max_flogi_retries); @@ -2132,7 +2136,7 @@ void fdls_fabric_timer_callback(struct timer_list *t) if (iport->fabric.del_timer_inprogress) { iport->fabric.del_timer_inprogress = 0; spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "fabric_del_timer inprogress(%d). Skip timer cb", iport->fabric.del_timer_inprogress); return; @@ -2160,7 +2164,7 @@ void fdls_fabric_timer_callback(struct timer_list *t) iport->fabric.flags &= ~FNIC_FDLS_FABRIC_ABORT_ISSUED; fdls_send_fabric_flogi(iport); } else - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Exceeded max FLOGI retries"); } break; @@ -2182,7 +2186,7 @@ void fdls_fabric_timer_callback(struct timer_list *t) iport->fabric.flags &= ~FNIC_FDLS_FABRIC_ABORT_ISSUED; fdls_send_fabric_plogi(iport); } else - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Exceeded max PLOGI retries"); } break; @@ -2213,7 +2217,7 @@ void fdls_fabric_timer_callback(struct timer_list *t) else { /* ABTS has timed out */ fdls_schedule_oxid_free(iport, &iport->active_oxid_fabric_req); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "ABTS timed out. Starting PLOGI: %p", iport); fnic_fdls_start_plogi(iport); } @@ -2230,7 +2234,7 @@ void fdls_fabric_timer_callback(struct timer_list *t) } else { /* ABTS has timed out */ fdls_schedule_oxid_free(iport, &iport->active_oxid_fabric_req); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "ABTS timed out. Starting PLOGI: %p", iport); fnic_fdls_start_plogi(iport); /* go back to fabric Plogi */ } @@ -2247,7 +2251,7 @@ void fdls_fabric_timer_callback(struct timer_list *t) else { /* ABTS has timed out */ fdls_schedule_oxid_free(iport, &iport->active_oxid_fabric_req); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "ABTS timed out. Starting PLOGI %p", iport); fnic_fdls_start_plogi(iport); /* go back to fabric Plogi */ } @@ -2269,7 +2273,7 @@ void fdls_fabric_timer_callback(struct timer_list *t) if (iport->fabric.retry_counter < FDLS_RETRY_COUNT) { fdls_send_gpn_ft(iport, iport->fabric.state); } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "ABTS timeout for fabric GPN_FT. Check name server: %p", iport); } @@ -2289,7 +2293,7 @@ void fdls_fdmi_retry_plogi(struct fnic_iport_s *iport) /* If max retries not exhausted, start over from fdmi plogi */ if (iport->fabric.fdmi_retry < FDLS_FDMI_MAX_RETRY) { iport->fabric.fdmi_retry++; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Retry FDMI PLOGI. FDMI retry: %d", iport->fabric.fdmi_retry); fdls_send_fdmi_plogi(iport); @@ -2307,7 +2311,7 @@ void fdls_fdmi_timer_callback(struct timer_list *t) spin_lock_irqsave(&fnic->fnic_lock, flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport->fabric.fdmi_pending: 0x%x\n", iport->fabric.fdmi_pending); if (!iport->fabric.fdmi_pending) { @@ -2315,7 +2319,7 @@ void fdls_fdmi_timer_callback(struct timer_list *t) spin_unlock_irqrestore(&fnic->fnic_lock, flags); return; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport->fabric.fdmi_pending: 0x%x\n", iport->fabric.fdmi_pending); /* if not abort pending, send an abort */ @@ -2324,7 +2328,7 @@ void fdls_fdmi_timer_callback(struct timer_list *t) spin_unlock_irqrestore(&fnic->fnic_lock, flags); return; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport->fabric.fdmi_pending: 0x%x\n", iport->fabric.fdmi_pending); /* ABTS pending for an active fdmi request that is pending. @@ -2332,29 +2336,36 @@ void fdls_fdmi_timer_callback(struct timer_list *t) * Schedule to free the OXID after 2*r_a_tov and proceed */ if (iport->fabric.fdmi_pending & FDLS_FDMI_PLOGI_PENDING) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDMI PLOGI ABTS timed out. Schedule oxid free: 0x%x\n", iport->active_oxid_fdmi_plogi); fdls_schedule_oxid_free(iport, &iport->active_oxid_fdmi_plogi); } else { if (iport->fabric.fdmi_pending & FDLS_FDMI_REG_HBA_PENDING) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDMI RHBA ABTS timed out. Schedule oxid free: 0x%x\n", iport->active_oxid_fdmi_rhba); fdls_schedule_oxid_free(iport, &iport->active_oxid_fdmi_rhba); } if (iport->fabric.fdmi_pending & FDLS_FDMI_RPA_PENDING) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDMI RPA ABTS timed out. Schedule oxid free: 0x%x\n", iport->active_oxid_fdmi_rpa); fdls_schedule_oxid_free(iport, &iport->active_oxid_fdmi_rpa); } } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport->fabric.fdmi_pending: 0x%x\n", iport->fabric.fdmi_pending); - fdls_fdmi_retry_plogi(iport); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + iport->fabric.fdmi_pending = 0; + /* If max retries not exhaused, start over from fdmi plogi */ + if (iport->fabric.fdmi_retry < FDLS_FDMI_MAX_RETRY) { + iport->fabric.fdmi_retry++; + FNIC_FCS_DBG(KERN_INFO, fnic, + "retry fdmi timer %d", iport->fabric.fdmi_retry); + fdls_send_fdmi_plogi(iport); + } + FNIC_FCS_DBG(KERN_INFO, fnic, "iport->fabric.fdmi_pending: 0x%x\n", iport->fabric.fdmi_pending); spin_unlock_irqrestore(&fnic->fnic_lock, flags); } @@ -2367,7 +2378,7 @@ static void fdls_send_delete_tport_msg(struct fnic_tport_s *tport) tport_del_evt = kzalloc(sizeof(struct fnic_tport_event_s), GFP_ATOMIC); if (!tport_del_evt) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Failed to allocate memory for tport event fcid: 0x%x", tport->fcid); return; @@ -2400,13 +2411,13 @@ static void fdls_tport_timer_callback(struct timer_list *t) if (tport->del_timer_inprogress) { tport->del_timer_inprogress = 0; spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport_del_timer inprogress. Skip timer cb tport fcid: 0x%x\n", tport->fcid); return; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport fcid: 0x%x timer pending: %d state: %d retry counter: %d", tport->fcid, tport->timer_pending, tport->state, tport->retry_counter); @@ -2467,15 +2478,16 @@ static void fdls_tport_timer_callback(struct timer_list *t) } else { /* exceeded retry count */ fdls_schedule_oxid_free(iport, &tport->active_oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "ADISC not responding. Deleting target port: 0x%x", tport->fcid); fdls_send_delete_tport_msg(tport); } break; default: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "oxid: 0x%x Unknown tport state: 0x%x", oxid, tport->state); + FNIC_FCS_DBG(KERN_INFO, fnic, + "0x%x timeout tport 0x%x oxid 0x%x state %d\n", + iport->fcid, tport->fcid, oxid, tport->state); break; } spin_unlock_irqrestore(&fnic->fnic_lock, flags); @@ -2524,26 +2536,26 @@ fdls_process_tgt_adisc_rsp(struct fnic_iport_s *iport, tport = fnic_find_tport_by_fcid(iport, tgt_fcid); if (!tport) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Tgt ADISC response tport not found: 0x%x", tgt_fcid); return; } if ((iport->state != FNIC_IPORT_STATE_READY) || (tport->state != FDLS_TGT_STATE_ADISC) || (tport->flags & FNIC_FDLS_TGT_ABORT_ISSUED)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Dropping this ADISC response"); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport state: %d tport state: %d Is abort issued on PRLI? %d", iport->state, tport->state, (tport->flags & FNIC_FDLS_TGT_ABORT_ISSUED)); return; } if (FNIC_STD_GET_OX_ID(fchdr) != tport->active_oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Dropping frame from target: 0x%x", tgt_fcid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Reason: Stale ADISC/Aborted ADISC/OOO frame delivery"); return; } @@ -2555,7 +2567,7 @@ fdls_process_tgt_adisc_rsp(struct fnic_iport_s *iport, case ELS_LS_ACC: atomic64_inc(&iport->iport_stats.tport_adisc_ls_accepts); if (tport->timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport 0x%p Canceling fabric disc timer\n", tport); fnic_del_tport_timer_sync(fnic, tport); @@ -2565,12 +2577,12 @@ fdls_process_tgt_adisc_rsp(struct fnic_iport_s *iport, frame_wwnn = get_unaligned_be64(&adisc_rsp->els.adisc_wwnn); frame_wwpn = get_unaligned_be64(&adisc_rsp->els.adisc_wwpn); if ((frame_wwnn == tport->wwnn) && (frame_wwpn == tport->wwpn)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "ADISC accepted from target: 0x%x. Target logged in", tgt_fcid); fdls_set_tport_state(tport, FDLS_TGT_STATE_READY); } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Error mismatch frame: ADISC"); } break; @@ -2580,14 +2592,14 @@ fdls_process_tgt_adisc_rsp(struct fnic_iport_s *iport, if (((els_rjt->rej.er_reason == ELS_RJT_BUSY) || (els_rjt->rej.er_reason == ELS_RJT_UNAB)) && (tport->retry_counter < FDLS_RETRY_COUNT)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "ADISC ret ELS_LS_RJT BUSY. Retry from timer routine: 0x%x", tgt_fcid); /* Retry ADISC again from the timer routine. */ tport->flags |= FNIC_FDLS_RETRY_FRAME; } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "ADISC returned ELS_LS_RJT from target: 0x%x", tgt_fcid); fdls_delete_tport(iport, tport); @@ -2611,33 +2623,33 @@ fdls_process_tgt_plogi_rsp(struct fnic_iport_s *iport, fcid = FNIC_STD_GET_S_ID(fchdr); tgt_fcid = ntoh24(fcid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDLS processing target PLOGI response: tgt_fcid: 0x%x", tgt_fcid); tport = fnic_find_tport_by_fcid(iport, tgt_fcid); if (!tport) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport not found: 0x%x", tgt_fcid); return; } if ((iport->state != FNIC_IPORT_STATE_READY) || (tport->flags & FNIC_FDLS_TGT_ABORT_ISSUED)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Dropping frame! iport state: %d tport state: %d", iport->state, tport->state); return; } if (tport->state != FDLS_TGT_STATE_PLOGI) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PLOGI rsp recvd in wrong state. Drop the frame and restart nexus"); fdls_target_restart_nexus(tport); return; } if (FNIC_STD_GET_OX_ID(fchdr) != tport->active_oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PLOGI response from target: 0x%x. Dropping frame", tgt_fcid); return; @@ -2649,7 +2661,7 @@ fdls_process_tgt_plogi_rsp(struct fnic_iport_s *iport, switch (plogi_rsp->els.fl_cmd) { case ELS_LS_ACC: atomic64_inc(&iport->iport_stats.tport_plogi_ls_accepts); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PLOGI accepted by target: 0x%x", tgt_fcid); break; @@ -2658,14 +2670,14 @@ fdls_process_tgt_plogi_rsp(struct fnic_iport_s *iport, if (((els_rjt->rej.er_reason == ELS_RJT_BUSY) || (els_rjt->rej.er_reason == ELS_RJT_UNAB)) && (tport->retry_counter < iport->max_plogi_retries)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PLOGI ret ELS_LS_RJT BUSY. Retry from timer routine: 0x%x", tgt_fcid); /* Retry plogi again from the timer routine. */ tport->flags |= FNIC_FDLS_RETRY_FRAME; return; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PLOGI returned ELS_LS_RJT from target: 0x%x", tgt_fcid); fdls_delete_tport(iport, tport); @@ -2673,18 +2685,18 @@ fdls_process_tgt_plogi_rsp(struct fnic_iport_s *iport, default: atomic64_inc(&iport->iport_stats.tport_plogi_misc_rejects); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PLOGI not accepted from target fcid: 0x%x", tgt_fcid); return; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Found the PLOGI target: 0x%x and state: %d", (unsigned int) tgt_fcid, tport->state); if (tport->timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport fcid 0x%x: Canceling disc timer\n", tport->fcid); fnic_del_tport_timer_sync(fnic, tport); @@ -2702,13 +2714,13 @@ fdls_process_tgt_plogi_rsp(struct fnic_iport_s *iport, min(max_payload_size, iport->max_payload_size); if (tport->max_payload_size < FNIC_MIN_DATA_FIELD_SIZE) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "MFS: tport max frame size below spec bounds: %d", tport->max_payload_size); tport->max_payload_size = FNIC_MIN_DATA_FIELD_SIZE; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "MAX frame size: %u iport max_payload_size: %d tport mfs: %d", max_payload_size, iport->max_payload_size, tport->max_payload_size); @@ -2736,12 +2748,12 @@ fdls_process_tgt_prli_rsp(struct fnic_iport_s *iport, fcid = FNIC_STD_GET_S_ID(fchdr); tgt_fcid = ntoh24(fcid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDLS process tgt PRLI response: 0x%x", tgt_fcid); tport = fnic_find_tport_by_fcid(iport, tgt_fcid); if (!tport) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport not found: 0x%x", tgt_fcid); /* Handle or just drop? */ return; @@ -2749,24 +2761,24 @@ fdls_process_tgt_prli_rsp(struct fnic_iport_s *iport, if ((iport->state != FNIC_IPORT_STATE_READY) || (tport->flags & FNIC_FDLS_TGT_ABORT_ISSUED)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Dropping frame! iport st: %d tport st: %d tport fcid: 0x%x", iport->state, tport->state, tport->fcid); return; } if (tport->state != FDLS_TGT_STATE_PRLI) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PRLI rsp recvd in wrong state. Drop frame. Restarting nexus"); fdls_target_restart_nexus(tport); return; } if (FNIC_STD_GET_OX_ID(fchdr) != tport->active_oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Dropping PRLI response from target: 0x%x ", tgt_fcid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Reason: Stale PRLI response/Aborted PDISC/OOO frame delivery"); return; } @@ -2777,11 +2789,11 @@ fdls_process_tgt_prli_rsp(struct fnic_iport_s *iport, switch (prli_rsp->els_prli.prli_cmd) { case ELS_LS_ACC: atomic64_inc(&iport->iport_stats.tport_prli_ls_accepts); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PRLI accepted from target: 0x%x", tgt_fcid); if (prli_rsp->sp.spp_type != FC_FC4_TYPE_SCSI) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "mismatched target zoned with FC SCSI initiator: 0x%x", tgt_fcid); mismatched_tgt = true; @@ -2798,7 +2810,7 @@ fdls_process_tgt_prli_rsp(struct fnic_iport_s *iport, || (els_rjt->rej.er_reason == ELS_RJT_UNAB)) && (tport->retry_counter < FDLS_RETRY_COUNT)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PRLI ret ELS_LS_RJT BUSY. Retry from timer routine: 0x%x", tgt_fcid); @@ -2806,7 +2818,7 @@ fdls_process_tgt_prli_rsp(struct fnic_iport_s *iport, tport->flags |= FNIC_FDLS_RETRY_FRAME; return; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PRLI returned ELS_LS_RJT from target: 0x%x", tgt_fcid); @@ -2815,17 +2827,17 @@ fdls_process_tgt_prli_rsp(struct fnic_iport_s *iport, return; default: atomic64_inc(&iport->iport_stats.tport_prli_misc_rejects); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PRLI not accepted from target: 0x%x", tgt_fcid); return; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Found the PRLI target: 0x%x and state: %d", (unsigned int) tgt_fcid, tport->state); if (tport->timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport fcid 0x%x: Canceling disc timer\n", tport->fcid); fnic_del_tport_timer_sync(fnic, tport); @@ -2841,7 +2853,7 @@ fdls_process_tgt_prli_rsp(struct fnic_iport_s *iport, /* Check if the device plays Target Mode Function */ if (!(tport->fcp_csp & FCP_PRLI_FUNC_TARGET)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Remote port(0x%x): no target support. Deleting it\n", tgt_fcid); fdls_tgt_logout(iport, tport); @@ -2854,16 +2866,16 @@ fdls_process_tgt_prli_rsp(struct fnic_iport_s *iport, /* Inform the driver about new target added */ tport_add_evt = kzalloc(sizeof(struct fnic_tport_event_s), GFP_ATOMIC); if (!tport_add_evt) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "tport event memory allocation failure: 0x%0x\n", - tport->fcid); + FNIC_FCS_DBG(KERN_INFO, fnic, + "iport fcid: 0x%x tport event memory allocation failure: 0x%0x\n", + iport->fcid, tport->fcid); return; } tport_add_evt->event = TGT_EV_RPORT_ADD; tport_add_evt->arg1 = (void *) tport; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "iport fcid: 0x%x add tport event fcid: 0x%x\n", - tport->fcid, iport->fcid); + FNIC_FCS_DBG(KERN_INFO, fnic, + "iport fcid: 0x%x add tport event fcid: 0x%x\n", + tport->fcid, iport->fcid); list_add_tail(&tport_add_evt->links, &fnic->tport_event_list); queue_work(fnic_event_queue, &fnic->tport_work); } @@ -2881,21 +2893,21 @@ fdls_process_rff_id_rsp(struct fnic_iport_s *iport, uint16_t oxid = FNIC_STD_GET_OX_ID(fchdr); if (fdls_get_state(fdls) != FDLS_STATE_REGISTER_FC4_FEATURES) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RFF_ID resp recvd in state(%d). Dropping.", fdls_get_state(fdls)); return; } if (iport->active_oxid_fabric_req != oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Incorrect OXID in response. state: %d, oxid recvd: 0x%x, active oxid: 0x%x\n", fdls_get_state(fdls), oxid, iport->active_oxid_fabric_req); return; } rsp = FNIC_STD_GET_FC_CT_CMD((&rff_rsp->fc_std_ct_hdr)); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS process RFF ID response: 0x%04x", iport->fcid, (uint32_t) rsp); @@ -2904,7 +2916,7 @@ fdls_process_rff_id_rsp(struct fnic_iport_s *iport, switch (rsp) { case FC_FS_ACC: if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Canceling fabric disc timer %p\n", iport); fnic_del_fabric_timer_sync(fnic); } @@ -2918,18 +2930,18 @@ fdls_process_rff_id_rsp(struct fnic_iport_s *iport, if (((reason_code == FC_FS_RJT_BSY) || (reason_code == FC_FS_RJT_UNABL)) && (fdls->retry_counter < FDLS_RETRY_COUNT)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RFF_ID ret ELS_LS_RJT BUSY. Retry from timer routine %p", iport); /* Retry again from the timer routine */ fdls->flags |= FNIC_FDLS_RETRY_FRAME; } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RFF_ID returned ELS_LS_RJT. Halting discovery %p", iport); if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Canceling fabric disc timer %p\n", iport); fnic_del_fabric_timer_sync(fnic); } @@ -2954,14 +2966,14 @@ fdls_process_rft_id_rsp(struct fnic_iport_s *iport, uint16_t oxid = FNIC_STD_GET_OX_ID(fchdr); if (fdls_get_state(fdls) != FDLS_STATE_REGISTER_FC4_TYPES) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RFT_ID resp recvd in state(%d). Dropping.", fdls_get_state(fdls)); return; } if (iport->active_oxid_fabric_req != oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Incorrect OXID in response. state: %d, oxid recvd: 0x%x, active oxid: 0x%x\n", fdls_get_state(fdls), oxid, iport->active_oxid_fabric_req); return; @@ -2969,7 +2981,7 @@ fdls_process_rft_id_rsp(struct fnic_iport_s *iport, rsp = FNIC_STD_GET_FC_CT_CMD((&rft_rsp->fc_std_ct_hdr)); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS process RFT ID response: 0x%04x", iport->fcid, (uint32_t) rsp); @@ -2978,7 +2990,7 @@ fdls_process_rft_id_rsp(struct fnic_iport_s *iport, switch (rsp) { case FC_FS_ACC: if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Canceling fabric disc timer %p\n", iport); fnic_del_fabric_timer_sync(fnic); } @@ -2992,19 +3004,19 @@ fdls_process_rft_id_rsp(struct fnic_iport_s *iport, if (((reason_code == FC_FS_RJT_BSY) || (reason_code == FC_FS_RJT_UNABL)) && (fdls->retry_counter < FDLS_RETRY_COUNT)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: RFT_ID ret ELS_LS_RJT BUSY. Retry from timer routine", iport->fcid); /* Retry again from the timer routine */ fdls->flags |= FNIC_FDLS_RETRY_FRAME; } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: RFT_ID REJ. Halting discovery reason %d expl %d", iport->fcid, reason_code, rft_rsp->fc_std_ct_hdr.ct_explan); if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Canceling fabric disc timer %p\n", iport); fnic_del_fabric_timer_sync(fnic); } @@ -3029,20 +3041,20 @@ fdls_process_rpn_id_rsp(struct fnic_iport_s *iport, uint16_t oxid = FNIC_STD_GET_OX_ID(fchdr); if (fdls_get_state(fdls) != FDLS_STATE_RPN_ID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RPN_ID resp recvd in state(%d). Dropping.", fdls_get_state(fdls)); return; } if (iport->active_oxid_fabric_req != oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Incorrect OXID in response. state: %d, oxid recvd: 0x%x, active oxid: 0x%x\n", fdls_get_state(fdls), oxid, iport->active_oxid_fabric_req); return; } rsp = FNIC_STD_GET_FC_CT_CMD((&rpn_rsp->fc_std_ct_hdr)); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS process RPN ID response: 0x%04x", iport->fcid, (uint32_t) rsp); fdls_free_oxid(iport, oxid, &iport->active_oxid_fabric_req); @@ -3050,7 +3062,7 @@ fdls_process_rpn_id_rsp(struct fnic_iport_s *iport, switch (rsp) { case FC_FS_ACC: if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Canceling fabric disc timer %p\n", iport); fnic_del_fabric_timer_sync(fnic); } @@ -3064,17 +3076,17 @@ fdls_process_rpn_id_rsp(struct fnic_iport_s *iport, if (((reason_code == FC_FS_RJT_BSY) || (reason_code == FC_FS_RJT_UNABL)) && (fdls->retry_counter < FDLS_RETRY_COUNT)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RPN_ID returned REJ BUSY. Retry from timer routine %p", iport); /* Retry again from the timer routine */ fdls->flags |= FNIC_FDLS_RETRY_FRAME; } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RPN_ID ELS_LS_RJT. Halting discovery %p", iport); if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Canceling fabric disc timer %p\n", iport); fnic_del_fabric_timer_sync(fnic); } @@ -3097,18 +3109,18 @@ fdls_process_scr_rsp(struct fnic_iport_s *iport, struct fnic *fnic = iport->fnic; uint16_t oxid = FNIC_STD_GET_OX_ID(fchdr); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDLS process SCR response: 0x%04x", (uint32_t) scr_rsp->scr.scr_cmd); if (fdls_get_state(fdls) != FDLS_STATE_SCR) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "SCR resp recvd in state(%d). Dropping.", fdls_get_state(fdls)); return; } if (iport->active_oxid_fabric_req != oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Incorrect OXID in response. state: %d, oxid recvd: 0x%x, active oxid: 0x%x\n", fdls_get_state(fdls), oxid, iport->active_oxid_fabric_req); } @@ -3119,7 +3131,7 @@ fdls_process_scr_rsp(struct fnic_iport_s *iport, case ELS_LS_ACC: atomic64_inc(&iport->iport_stats.fabric_scr_ls_accepts); if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Canceling fabric disc timer %p\n", iport); fnic_del_fabric_timer_sync(fnic); } @@ -3133,17 +3145,17 @@ fdls_process_scr_rsp(struct fnic_iport_s *iport, if (((els_rjt->rej.er_reason == ELS_RJT_BUSY) || (els_rjt->rej.er_reason == ELS_RJT_UNAB)) && (fdls->retry_counter < FDLS_RETRY_COUNT)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "SCR ELS_LS_RJT BUSY. Retry from timer routine %p", iport); /* Retry again from the timer routine */ fdls->flags |= FNIC_FDLS_RETRY_FRAME; } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "SCR returned ELS_LS_RJT. Halting discovery %p", iport); if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Canceling fabric disc timer %p\n", iport); fnic_del_fabric_timer_sync(fnic); @@ -3171,7 +3183,7 @@ fdls_process_gpn_ft_tgt_list(struct fnic_iport_s *iport, u32 old_link_down_cnt = iport->fnic->link_down_cnt; struct fnic *fnic = iport->fnic; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS process GPN_FT tgt list", iport->fcid); gpn_ft_tgt = @@ -3185,7 +3197,7 @@ fdls_process_gpn_ft_tgt_list(struct fnic_iport_s *iport, fcid = ntoh24(gpn_ft_tgt->fcid); wwpn = be64_to_cpu(gpn_ft_tgt->wwpn); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "tport: 0x%x: ctrl:0x%x", fcid, gpn_ft_tgt->ctrl); if (fcid == iport->fcid) { @@ -3232,7 +3244,7 @@ fdls_process_gpn_ft_tgt_list(struct fnic_iport_s *iport, rem_len -= sizeof(struct fc_gpn_ft_rsp_iu); } if (rem_len <= 0) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "GPN_FT response: malformed/corrupt frame rxlen: %d remlen: %d", len, rem_len); } @@ -3242,7 +3254,7 @@ fdls_process_gpn_ft_tgt_list(struct fnic_iport_s *iport, list_for_each_entry_safe(tport, next, &iport->tport_list, links) { if (!(tport->flags & FNIC_FDLS_TPORT_IN_GPN_FT_LIST)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Remove port: 0x%x not found in GPN_FT list", tport->fcid); fdls_delete_tport(iport, tport); @@ -3271,7 +3283,7 @@ fdls_process_gpn_ft_rsp(struct fnic_iport_s *iport, struct fnic *fnic = iport->fnic; uint16_t oxid = FNIC_STD_GET_OX_ID(fchdr); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDLS process GPN_FT response: iport state: %d len: %d", iport->state, len); @@ -3291,14 +3303,14 @@ fdls_process_gpn_ft_rsp(struct fnic_iport_s *iport, && ((fdls_get_state(fdls) == FDLS_STATE_RSCN_GPN_FT) || (fdls_get_state(fdls) == FDLS_STATE_SEND_GPNFT) || (fdls_get_state(fdls) == FDLS_STATE_TGT_DISCOVERY))))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "GPNFT resp recvd in fab state(%d) iport_state(%d). Dropping.", fdls_get_state(fdls), iport->state); return; } if (iport->active_oxid_fabric_req != oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Incorrect OXID in response. state: %d, oxid recvd: 0x%x, active oxid: 0x%x\n", fdls_get_state(fdls), oxid, iport->active_oxid_fabric_req); } @@ -3311,10 +3323,10 @@ fdls_process_gpn_ft_rsp(struct fnic_iport_s *iport, switch (rsp) { case FC_FS_ACC: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: GPNFT_RSP accept", iport->fcid); if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Canceling fabric disc timer\n", iport->fcid); fnic_del_fabric_timer_sync(fnic); @@ -3329,7 +3341,7 @@ fdls_process_gpn_ft_rsp(struct fnic_iport_s *iport, * that will be taken care in next link up event */ if (iport->state != FNIC_IPORT_STATE_READY) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Halting target discovery: fab st: %d iport st: %d ", fdls_get_state(fdls), iport->state); break; @@ -3339,22 +3351,22 @@ fdls_process_gpn_ft_rsp(struct fnic_iport_s *iport, case FC_FS_RJT: reason_code = gpn_ft_rsp->fc_std_ct_hdr.ct_reason; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: GPNFT_RSP Reject reason: %d", iport->fcid, reason_code); if (((reason_code == FC_FS_RJT_BSY) || (reason_code == FC_FS_RJT_UNABL)) && (fdls->retry_counter < FDLS_RETRY_COUNT)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: GPNFT_RSP ret REJ/BSY. Retry from timer routine", iport->fcid); /* Retry again from the timer routine */ fdls->flags |= FNIC_FDLS_RETRY_FRAME; } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: GPNFT_RSP reject", iport->fcid); if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Canceling fabric disc timer\n", iport->fcid); fnic_del_fabric_timer_sync(fnic); @@ -3368,7 +3380,7 @@ fdls_process_gpn_ft_rsp(struct fnic_iport_s *iport, count = 0; list_for_each_entry_safe(tport, next, &iport->tport_list, links) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "GPN_FT_REJECT: Remove port: 0x%x", tport->fcid); fdls_delete_tport(iport, tport); @@ -3378,7 +3390,7 @@ fdls_process_gpn_ft_rsp(struct fnic_iport_s *iport, } count++; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "GPN_FT_REJECT: Removed (0x%x) ports", count); } break; @@ -3403,7 +3415,7 @@ fdls_process_fabric_logo_rsp(struct fnic_iport_s *iport, uint16_t oxid = FNIC_STD_GET_OX_ID(fchdr); if (iport->active_oxid_fabric_req != oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Incorrect OXID in response. state: %d, oxid recvd: 0x%x, active oxid: 0x%x\n", fdls_get_state(fdls), oxid, iport->active_oxid_fabric_req); } @@ -3412,7 +3424,7 @@ fdls_process_fabric_logo_rsp(struct fnic_iport_s *iport, switch (flogo_rsp->els.fl_cmd) { case ELS_LS_ACC: if (iport->fabric.state != FDLS_STATE_FABRIC_LOGO) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Flogo response. Fabric not in LOGO state. Dropping! %p", iport); return; @@ -3422,25 +3434,25 @@ fdls_process_fabric_logo_rsp(struct fnic_iport_s *iport, iport->state = FNIC_IPORT_STATE_LINK_WAIT; if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport 0x%p Canceling fabric disc timer\n", iport); fnic_del_fabric_timer_sync(fnic); } iport->fabric.timer_pending = 0; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Flogo response from Fabric for did: 0x%x", ntoh24(fchdr->fh_d_id)); return; case ELS_LS_RJT: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Flogo response from Fabric for did: 0x%x returned ELS_LS_RJT", ntoh24(fchdr->fh_d_id)); return; default: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FLOGO response not accepted or rejected: 0x%x", flogo_rsp->els.fl_cmd); } @@ -3458,17 +3470,17 @@ fdls_process_flogi_rsp(struct fnic_iport_s *iport, struct fnic *fnic = iport->fnic; uint16_t oxid = FNIC_STD_GET_OX_ID(fchdr); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS processing FLOGI response", iport->fcid); if (fdls_get_state(fabric) != FDLS_STATE_FABRIC_FLOGI) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FLOGI response received in state (%d). Dropping frame", fdls_get_state(fabric)); return; } if (iport->active_oxid_fabric_req != oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Incorrect OXID in response. state: %d, oxid recvd: 0x%x, active oxid: 0x%x\n", fdls_get_state(fabric), oxid, iport->active_oxid_fabric_req); return; @@ -3480,7 +3492,7 @@ fdls_process_flogi_rsp(struct fnic_iport_s *iport, case ELS_LS_ACC: atomic64_inc(&iport->iport_stats.fabric_flogi_ls_accepts); if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport fcid: 0x%x Canceling fabric disc timer\n", iport->fcid); fnic_del_fabric_timer_sync(fnic); @@ -3490,7 +3502,7 @@ fdls_process_flogi_rsp(struct fnic_iport_s *iport, iport->fabric.retry_counter = 0; fcid = FNIC_STD_GET_D_ID(fchdr); iport->fcid = ntoh24(fcid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FLOGI response accepted", iport->fcid); /* Learn the Service Params */ @@ -3500,7 +3512,7 @@ fdls_process_flogi_rsp(struct fnic_iport_s *iport, iport->max_payload_size = min(rdf_size, iport->max_payload_size); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "max_payload_size from fabric: %u set: %d", rdf_size, iport->max_payload_size); @@ -3510,7 +3522,7 @@ fdls_process_flogi_rsp(struct fnic_iport_s *iport, if (FNIC_LOGI_FEATURES(flogi_rsp->els) & FNIC_FC_EDTOV_NSEC) iport->e_d_tov = iport->e_d_tov / FNIC_NSEC_TO_MSEC; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "From fabric: R_A_TOV: %d E_D_TOV: %d", iport->r_a_tov, iport->e_d_tov); @@ -3521,13 +3533,13 @@ fdls_process_flogi_rsp(struct fnic_iport_s *iport, fnic_fdls_learn_fcoe_macs(iport, rx_frame, fcid); if (fnic_fdls_register_portid(iport, iport->fcid, rx_frame) != 0) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FLOGI registration failed", iport->fcid); break; } memcpy(&fcmac[3], fcid, 3); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Adding vNIC device MAC addr: %02x:%02x:%02x:%02x:%02x:%02x", fcmac[0], fcmac[1], fcmac[2], fcmac[3], fcmac[4], fcmac[5]); @@ -3535,7 +3547,7 @@ fdls_process_flogi_rsp(struct fnic_iport_s *iport, if (fdls_get_state(fabric) == FDLS_STATE_FABRIC_FLOGI) { fnic_fdls_start_plogi(iport); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FLOGI response received. Starting PLOGI"); } else { /* From FDLS_STATE_FABRIC_FLOGI state fabric can only go to @@ -3543,7 +3555,7 @@ fdls_process_flogi_rsp(struct fnic_iport_s *iport, * state, hence we don't have to worry about undoing: * the fnic_fdls_register_portid and vnic_dev_add_addr */ - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FLOGI response received in state (%d). Dropping frame", fdls_get_state(fabric)); } @@ -3552,7 +3564,7 @@ fdls_process_flogi_rsp(struct fnic_iport_s *iport, case ELS_LS_RJT: atomic64_inc(&iport->iport_stats.fabric_flogi_ls_rejects); if (fabric->retry_counter < iport->max_flogi_retries) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FLOGI returned ELS_LS_RJT BUSY. Retry from timer routine %p", iport); @@ -3560,11 +3572,11 @@ fdls_process_flogi_rsp(struct fnic_iport_s *iport, fabric->flags |= FNIC_FDLS_RETRY_FRAME; } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FLOGI returned ELS_LS_RJT. Halting discovery %p", iport); if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport 0x%p Canceling fabric disc timer\n", iport); fnic_del_fabric_timer_sync(fnic); @@ -3575,7 +3587,7 @@ fdls_process_flogi_rsp(struct fnic_iport_s *iport, break; default: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FLOGI response not accepted: 0x%x", flogi_rsp->els.fl_cmd); atomic64_inc(&iport->iport_stats.fabric_flogi_misc_rejects); @@ -3594,13 +3606,13 @@ fdls_process_fabric_plogi_rsp(struct fnic_iport_s *iport, uint16_t oxid = FNIC_STD_GET_OX_ID(fchdr); if (fdls_get_state((&iport->fabric)) != FDLS_STATE_FABRIC_PLOGI) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Fabric PLOGI response received in state (%d). Dropping frame", fdls_get_state(&iport->fabric)); return; } if (iport->active_oxid_fabric_req != oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Incorrect OXID in response. state: %d, oxid recvd: 0x%x, active oxid: 0x%x\n", fdls_get_state(fdls), oxid, iport->active_oxid_fabric_req); return; @@ -3611,7 +3623,7 @@ fdls_process_fabric_plogi_rsp(struct fnic_iport_s *iport, case ELS_LS_ACC: atomic64_inc(&iport->iport_stats.fabric_plogi_ls_accepts); if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport fcid: 0x%x fabric PLOGI response: Accepted\n", iport->fcid); fnic_del_fabric_timer_sync(fnic); @@ -3626,15 +3638,15 @@ fdls_process_fabric_plogi_rsp(struct fnic_iport_s *iport, if (((els_rjt->rej.er_reason == ELS_RJT_BUSY) || (els_rjt->rej.er_reason == ELS_RJT_UNAB)) && (iport->fabric.retry_counter < iport->max_plogi_retries)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Fabric PLOGI ELS_LS_RJT BUSY. Retry from timer routine", iport->fcid); } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Fabric PLOGI ELS_LS_RJT. Halting discovery", iport->fcid); if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport fcid: 0x%x Canceling fabric disc timer\n", iport->fcid); fnic_del_fabric_timer_sync(fnic); @@ -3645,7 +3657,7 @@ fdls_process_fabric_plogi_rsp(struct fnic_iport_s *iport, } break; default: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PLOGI response not accepted: 0x%x", plogi_rsp->els.fl_cmd); atomic64_inc(&iport->iport_stats.fabric_plogi_misc_rejects); @@ -3664,7 +3676,7 @@ static void fdls_process_fdmi_plogi_rsp(struct fnic_iport_s *iport, uint16_t oxid = FNIC_STD_GET_OX_ID(fchdr); if (iport->active_oxid_fdmi_plogi != oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Incorrect OXID in response. state: %d, oxid recvd: 0x%x, active oxid: 0x%x\n", fdls_get_state(fdls), oxid, iport->active_oxid_fdmi_plogi); return; @@ -3678,9 +3690,9 @@ static void fdls_process_fdmi_plogi_rsp(struct fnic_iport_s *iport, iport->fabric.fdmi_pending = 0; switch (plogi_rsp->els.fl_cmd) { case ELS_LS_ACC: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDLS process fdmi PLOGI response status: ELS_LS_ACC\n"); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Sending fdmi registration for port 0x%x\n", iport->fcid); @@ -3691,7 +3703,7 @@ static void fdls_process_fdmi_plogi_rsp(struct fnic_iport_s *iport, round_jiffies(fdmi_tov)); break; case ELS_LS_RJT: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Fabric FDMI PLOGI returned ELS_LS_RJT reason: 0x%x", els_rjt->rej.er_reason); @@ -3715,7 +3727,7 @@ static void fdls_process_fdmi_reg_ack(struct fnic_iport_s *iport, uint16_t oxid; if (!iport->fabric.fdmi_pending) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Received FDMI ack while not waiting: 0x%x\n", FNIC_STD_GET_OX_ID(fchdr)); return; @@ -3725,7 +3737,7 @@ static void fdls_process_fdmi_reg_ack(struct fnic_iport_s *iport, if ((iport->active_oxid_fdmi_rhba != oxid) && (iport->active_oxid_fdmi_rpa != oxid)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Incorrect OXID in response. oxid recvd: 0x%x, active oxids(rhba,rpa): 0x%x, 0x%x\n", oxid, iport->active_oxid_fdmi_rhba, iport->active_oxid_fdmi_rpa); return; @@ -3738,13 +3750,13 @@ static void fdls_process_fdmi_reg_ack(struct fnic_iport_s *iport, fdls_free_oxid(iport, oxid, &iport->active_oxid_fdmi_rpa); } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport fcid: 0x%x: Received FDMI registration ack\n", iport->fcid); if (!iport->fabric.fdmi_pending) { timer_delete_sync(&iport->fabric.fdmi_timer); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport fcid: 0x%x: Canceling FDMI timer\n", iport->fcid); } @@ -3760,7 +3772,7 @@ static void fdls_process_fdmi_abts_rsp(struct fnic_iport_s *iport, s_id = ntoh24(FNIC_STD_GET_S_ID(fchdr)); if (!(s_id != FC_FID_MGMT_SERV)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received abts rsp with invalid SID: 0x%x. Dropping frame", s_id); return; @@ -3770,23 +3782,23 @@ static void fdls_process_fdmi_abts_rsp(struct fnic_iport_s *iport, switch (FNIC_FRAME_TYPE(oxid)) { case FNIC_FRAME_TYPE_FDMI_PLOGI: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received FDMI PLOGI ABTS rsp with oxid: 0x%x", oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: iport->fabric.fdmi_pending: 0x%x", iport->fcid, iport->fabric.fdmi_pending); fdls_free_oxid(iport, oxid, &iport->active_oxid_fdmi_plogi); iport->fabric.fdmi_pending &= ~FDLS_FDMI_PLOGI_PENDING; iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: iport->fabric.fdmi_pending: 0x%x", iport->fcid, iport->fabric.fdmi_pending); break; case FNIC_FRAME_TYPE_FDMI_RHBA: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received FDMI RHBA ABTS rsp with oxid: 0x%x", oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: iport->fabric.fdmi_pending: 0x%x", iport->fcid, iport->fabric.fdmi_pending); @@ -3800,14 +3812,14 @@ static void fdls_process_fdmi_abts_rsp(struct fnic_iport_s *iport, iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING; fdls_free_oxid(iport, oxid, &iport->active_oxid_fdmi_rhba); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: iport->fabric.fdmi_pending: 0x%x", iport->fcid, iport->fabric.fdmi_pending); break; case FNIC_FRAME_TYPE_FDMI_RPA: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received FDMI RPA ABTS rsp with oxid: 0x%x", oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: iport->fabric.fdmi_pending: 0x%x", iport->fcid, iport->fabric.fdmi_pending); @@ -3821,12 +3833,12 @@ static void fdls_process_fdmi_abts_rsp(struct fnic_iport_s *iport, iport->fabric.fdmi_pending &= ~FDLS_FDMI_ABORT_PENDING; fdls_free_oxid(iport, oxid, &iport->active_oxid_fdmi_rpa); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: iport->fabric.fdmi_pending: 0x%x", iport->fcid, iport->fabric.fdmi_pending); break; default: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received abts rsp with invalid oxid: 0x%x. Dropping frame", oxid); break; @@ -3861,7 +3873,7 @@ fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, if (!((s_id == FC_FID_DIR_SERV) || (s_id == FC_FID_FLOGI) || (s_id == FC_FID_FCTRL))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received abts rsp with invalid SID: 0x%x. Dropping frame", s_id); return; @@ -3869,14 +3881,14 @@ fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, oxid = FNIC_STD_GET_OX_ID(fchdr); if (iport->active_oxid_fabric_req != oxid) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received abts rsp with invalid oxid: 0x%x. Dropping frame", oxid); return; } if (iport->fabric.timer_pending) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Canceling fabric disc timer %p\n", iport); fnic_del_fabric_timer_sync(fnic); } @@ -3884,11 +3896,11 @@ fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, iport->fabric.flags &= ~FNIC_FDLS_FABRIC_ABORT_ISSUED; if (fchdr->fh_r_ctl == FC_RCTL_BA_ACC) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received abts rsp BA_ACC for fabric_state: %d OX_ID: 0x%x", fabric_state, be16_to_cpu(ba_acc->acc.ba_ox_id)); } else if (fchdr->fh_r_ctl == FC_RCTL_BA_RJT) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "BA_RJT fs: %d OX_ID: 0x%x rc: 0x%x rce: 0x%x", fabric_state, FNIC_STD_GET_OX_ID(&ba_rjt->fchdr), ba_rjt->rjt.br_reason, ba_rjt->rjt.br_explan); @@ -3903,7 +3915,7 @@ fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, if (iport->fabric.retry_counter < iport->max_flogi_retries) fdls_send_fabric_flogi(iport); else - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Exceeded max FLOGI retries"); break; case FNIC_FRAME_TYPE_FABRIC_LOGO: @@ -3914,7 +3926,7 @@ fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, if (iport->fabric.retry_counter < iport->max_plogi_retries) fdls_send_fabric_plogi(iport); else - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Exceeded max PLOGI retries"); break; case FNIC_FRAME_TYPE_FABRIC_RPN: @@ -3928,7 +3940,7 @@ fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, if (iport->fabric.retry_counter < FDLS_RETRY_COUNT) fdls_send_scr(iport); else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "SCR exhausted retries. Start fabric PLOGI %p", iport); fnic_fdls_start_plogi(iport); /* go back to fabric Plogi */ @@ -3938,7 +3950,7 @@ fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, if (iport->fabric.retry_counter < FDLS_RETRY_COUNT) fdls_send_register_fc4_types(iport); else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RFT exhausted retries. Start fabric PLOGI %p", iport); fnic_fdls_start_plogi(iport); /* go back to fabric Plogi */ @@ -3948,7 +3960,7 @@ fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, if (iport->fabric.retry_counter < FDLS_RETRY_COUNT) fdls_send_register_fc4_features(iport); else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RFF exhausted retries. Start fabric PLOGI %p", iport); fnic_fdls_start_plogi(iport); /* go back to fabric Plogi */ @@ -3958,7 +3970,7 @@ fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, if (iport->fabric.retry_counter <= FDLS_RETRY_COUNT) fdls_send_gpn_ft(iport, fabric_state); else - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "GPN FT exhausted retries. Start fabric PLOGI %p", iport); break; @@ -3967,7 +3979,7 @@ fdls_process_fabric_abts_rsp(struct fnic_iport_s *iport, * We should not be here since we already validated rx oxid with * our active_oxid_fabric_req */ - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Invalid OXID/active oxid 0x%x\n", oxid); WARN_ON(true); return; @@ -3987,7 +3999,7 @@ fdls_process_abts_req(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) sizeof(struct fc_std_abts_ba_acc); nport_id = ntoh24(fchdr->fh_s_id); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received abort from SID 0x%8x", nport_id); tport = fnic_find_tport_by_fcid(iport, nport_id); @@ -4000,7 +4012,7 @@ fdls_process_abts_req(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "0x%x: Failed to allocate frame to send response for ABTS req", iport->fcid); return; @@ -4021,7 +4033,7 @@ fdls_process_abts_req(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) pba_acc->acc.ba_rx_id = cpu_to_be16(FNIC_STD_GET_RX_ID(fchdr)); pba_acc->acc.ba_ox_id = cpu_to_be16(FNIC_STD_GET_OX_ID(fchdr)); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS send BA ACC with oxid: 0x%x", iport->fcid, oxid); @@ -4041,7 +4053,7 @@ fdls_process_unsupported_els_req(struct fnic_iport_s *iport, sizeof(struct fc_std_els_rjt_rsp); if (iport->fcid != d_id) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Dropping unsupported ELS with illegal frame bits 0x%x\n", d_id); atomic64_inc(&iport->iport_stats.unsupported_frames_dropped); @@ -4050,7 +4062,7 @@ fdls_process_unsupported_els_req(struct fnic_iport_s *iport, if ((iport->state != FNIC_IPORT_STATE_READY) && (iport->state != FNIC_IPORT_STATE_FABRIC_DISC)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Dropping unsupported ELS request in iport state: %d", iport->state); atomic64_inc(&iport->iport_stats.unsupported_frames_dropped); @@ -4059,7 +4071,7 @@ fdls_process_unsupported_els_req(struct fnic_iport_s *iport, frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send response to unsupported ELS request"); return; } @@ -4067,7 +4079,7 @@ fdls_process_unsupported_els_req(struct fnic_iport_s *iport, pls_rsp = (struct fc_std_els_rjt_rsp *) (frame + FNIC_ETH_FCOE_HDRS_OFFSET); fdls_init_els_rjt_frame(frame, iport); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Process unsupported ELS request from SID: 0x%x", iport->fcid, ntoh24(fchdr->fh_s_id)); @@ -4094,12 +4106,12 @@ fdls_process_rls_req(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) uint16_t frame_size = FNIC_ETH_FCOE_HDRS_OFFSET + sizeof(struct fc_std_rls_acc); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Process RLS request %d", iport->fnic->fnic_num); if ((iport->state != FNIC_IPORT_STATE_READY) && (iport->state != FNIC_IPORT_STATE_FABRIC_DISC)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received RLS req in iport state: %d. Dropping the frame.", iport->state); return; @@ -4107,7 +4119,7 @@ fdls_process_rls_req(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send RLS accept"); return; } @@ -4148,33 +4160,33 @@ fdls_process_els_req(struct fnic_iport_s *iport, struct fc_frame_header *fchdr, if ((iport->state != FNIC_IPORT_STATE_READY) && (iport->state != FNIC_IPORT_STATE_FABRIC_DISC)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Dropping ELS frame type: 0x%x in iport state: %d", type, iport->state); return; } switch (type) { case ELS_ECHO: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "sending LS_ACC for ECHO request %d\n", iport->fnic->fnic_num); break; case ELS_RRQ: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "sending LS_ACC for RRQ request %d\n", iport->fnic->fnic_num); break; default: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "sending LS_ACC for 0x%x ELS frame\n", type); break; } frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send ELS response for 0x%x", type); return; @@ -4220,17 +4232,17 @@ fdls_process_tgt_abts_rsp(struct fnic_iport_s *iport, tport = fnic_find_tport_by_fcid(iport, s_id); if (!tport) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Received tgt abts rsp with invalid SID: 0x%x", s_id); return; } if (tport->timer_pending) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "tport 0x%p Canceling fabric disc timer\n", tport); fnic_del_tport_timer_sync(fnic, tport); } if (iport->state != FNIC_IPORT_STATE_READY) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Received tgt abts rsp in iport state(%d). Dropping.", iport->state); return; @@ -4245,15 +4257,15 @@ fdls_process_tgt_abts_rsp(struct fnic_iport_s *iport, switch (frame_type) { case FNIC_FRAME_TYPE_TGT_ADISC: if (fchdr->fh_r_ctl == FC_RCTL_BA_ACC) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "OX_ID: 0x%x tgt_fcid: 0x%x rcvd tgt adisc abts resp BA_ACC", be16_to_cpu(ba_acc->acc.ba_ox_id), tport->fcid); } else if (fchdr->fh_r_ctl == FC_RCTL_BA_RJT) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "ADISC BA_RJT rcvd tport_fcid: 0x%x tport_state: %d ", tport->fcid, tport_state); - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "reason code: 0x%x reason code explanation:0x%x ", ba_rjt->rjt.br_reason, ba_rjt->rjt.br_explan); @@ -4265,7 +4277,7 @@ fdls_process_tgt_abts_rsp(struct fnic_iport_s *iport, return; } fdls_free_oxid(iport, oxid, &tport->active_oxid); - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "ADISC not responding. Deleting target port: 0x%x", tport->fcid); fdls_delete_tport(iport, tport); @@ -4278,14 +4290,14 @@ fdls_process_tgt_abts_rsp(struct fnic_iport_s *iport, break; case FNIC_FRAME_TYPE_TGT_PLOGI: if (fchdr->fh_r_ctl == FC_RCTL_BA_ACC) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Received tgt PLOGI abts response BA_ACC tgt_fcid: 0x%x", tport->fcid); } else if (fchdr->fh_r_ctl == FC_RCTL_BA_RJT) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PLOGI BA_RJT received for tport_fcid: 0x%x OX_ID: 0x%x", tport->fcid, FNIC_STD_GET_OX_ID(fchdr)); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "reason code: 0x%x reason code explanation: 0x%x", ba_rjt->rjt.br_reason, ba_rjt->rjt.br_explan); @@ -4308,14 +4320,14 @@ fdls_process_tgt_abts_rsp(struct fnic_iport_s *iport, break; case FNIC_FRAME_TYPE_TGT_PRLI: if (fchdr->fh_r_ctl == FC_RCTL_BA_ACC) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Received tgt PRLI abts response BA_ACC", tport->fcid); } else if (fchdr->fh_r_ctl == FC_RCTL_BA_RJT) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PRLI BA_RJT received for tport_fcid: 0x%x OX_ID: 0x%x ", tport->fcid, FNIC_STD_GET_OX_ID(fchdr)); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "reason code: 0x%x reason code explanation: 0x%x", ba_rjt->rjt.br_reason, ba_rjt->rjt.br_explan); @@ -4331,7 +4343,7 @@ fdls_process_tgt_abts_rsp(struct fnic_iport_s *iport, fdls_set_tport_state(tport, FDLS_TGT_STATE_PLOGI); break; default: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received ABTS response for unknown frame %p", iport); break; } @@ -4351,14 +4363,14 @@ fdls_process_plogi_req(struct fnic_iport_s *iport, sizeof(struct fc_std_els_rjt_rsp); if (iport->fcid != d_id) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received PLOGI with illegal frame bits. Dropping frame from 0x%x", d_id); return; } if (iport->state != FNIC_IPORT_STATE_READY) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received PLOGI request in iport state: %d Dropping frame", iport->state); return; @@ -4366,7 +4378,7 @@ fdls_process_plogi_req(struct fnic_iport_s *iport, frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send response to PLOGI request"); return; } @@ -4374,7 +4386,7 @@ fdls_process_plogi_req(struct fnic_iport_s *iport, pplogi_rsp = (struct fc_std_els_rjt_rsp *) (frame + FNIC_ETH_FCOE_HDRS_OFFSET); fdls_init_els_rjt_frame(frame, iport); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: Process PLOGI request from SID: 0x%x", iport->fcid, ntoh24(fchdr->fh_s_id)); @@ -4404,11 +4416,11 @@ fdls_process_logo_req(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) nport_id = ntoh24(logo->els.fl_n_port_id); nport_name = be64_to_cpu(logo->els.fl_n_port_wwn); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Process LOGO request from fcid: 0x%x", nport_id); if (iport->state != FNIC_IPORT_STATE_READY) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Dropping LOGO req from 0x%x in iport state: %d", nport_id, iport->state); return; @@ -4418,19 +4430,19 @@ fdls_process_logo_req(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) if (!tport) { /* We are not logged in with the nport, log and drop... */ - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Received LOGO from an nport not logged in: 0x%x(0x%llx)", nport_id, nport_name); return; } if (tport->fcid != nport_id) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Received LOGO with invalid target port fcid: 0x%x(0x%llx)", nport_id, nport_name); return; } if (tport->timer_pending) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "tport fcid 0x%x: Canceling disc timer\n", tport->fcid); fnic_del_tport_timer_sync(fnic, tport); @@ -4447,7 +4459,7 @@ fdls_process_logo_req(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) if ((iport->state == FNIC_IPORT_STATE_READY) && (fdls_get_state(&iport->fabric) != FDLS_STATE_SEND_GPNFT) && (fdls_get_state(&iport->fabric) != FDLS_STATE_RSCN_GPN_FT)) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Sending GPNFT in response to LOGO from Target:0x%x", nport_id); fdls_send_gpn_ft(iport, FDLS_STATE_SEND_GPNFT); @@ -4460,7 +4472,7 @@ fdls_process_logo_req(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) fdls_send_logo_resp(iport, &logo->fchdr); if ((fdls_get_state(&iport->fabric) != FDLS_STATE_SEND_GPNFT) && (fdls_get_state(&iport->fabric) != FDLS_STATE_RSCN_GPN_FT)) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Sending GPNFT in response to LOGO from Target:0x%x", nport_id); fdls_send_gpn_ft(iport, FDLS_STATE_SEND_GPNFT); @@ -4487,11 +4499,11 @@ fdls_process_rscn(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) atomic64_inc(&iport->iport_stats.num_rscns); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDLS process RSCN %p", iport); if (iport->state != FNIC_IPORT_STATE_READY) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDLS RSCN received in state(%d). Dropping", fdls_get_state(fdls)); return; @@ -4508,18 +4520,18 @@ fdls_process_rscn(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) if ((rscn_payload_len == 0xFFFF) && (sid == FC_FID_FCTRL)) { rscn_type = PC_RSCN; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "pcrscn: PCRSCN received. sid: 0x%x payload len: 0x%x", sid, rscn_payload_len); } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RSCN payload_len: 0x%x page_len: 0x%x", rscn_payload_len, rscn->els.rscn_page_len); /* if this happens then we need to send ADISC to all the tports. */ list_for_each_entry_safe(tport, next, &iport->tport_list, links) { if (tport->state == FDLS_TGT_STATE_READY) tport->flags |= FNIC_FDLS_TPORT_SEND_ADISC; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RSCN for port id: 0x%x", tport->fcid); } } /* end else */ @@ -4527,7 +4539,7 @@ fdls_process_rscn(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) num_ports = (rscn_payload_len - 4) / rscn->els.rscn_page_len; rscn_port = (struct fc_els_rscn_page *)(rscn + 1); } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RSCN received for num_ports: %d payload_len: %d page_len: %d ", num_ports, rscn_payload_len, rscn->els.rscn_page_len); @@ -4551,14 +4563,14 @@ fdls_process_rscn(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) if (tport->state == FDLS_TGT_STATE_READY) tport->flags |= FNIC_FDLS_TPORT_SEND_ADISC; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RSCN for port id: 0x%x", tport->fcid); } break; } tport = fnic_find_tport_by_fcid(iport, nport_id); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "RSCN port id list: 0x%x", nport_id); if (!tport) { @@ -4573,13 +4585,13 @@ fdls_process_rscn(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) rscn_type == PC_RSCN && fnic->role == FNIC_ROLE_FCP_INITIATOR) { if (fnic->pc_rscn_handling_status == PC_RSCN_HANDLING_IN_PROGRESS) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PCRSCN handling already in progress. Skip host reset: %d", iport->fnic->fnic_num); return; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Processing PCRSCN. Queuing fnic for host reset: %d", iport->fnic->fnic_num); fnic->pc_rscn_handling_status = PC_RSCN_HANDLING_IN_PROGRESS; @@ -4595,7 +4607,7 @@ fdls_process_rscn(struct fnic_iport_s *iport, struct fc_frame_header *fchdr) queue_work(reset_fnic_work_queue, &reset_fnic_work); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FDLS process RSCN sending GPN_FT: newports: %d", newports); fdls_send_gpn_ft(iport, FDLS_STATE_RSCN_GPN_FT); fdls_send_rscn_resp(iport, fchdr); @@ -4613,7 +4625,7 @@ void fnic_fdls_disc_start(struct fnic_iport_s *iport) if (!iport->usefip) { if (iport->flags & FNIC_FIRST_LINK_UP) { spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - fnic_scsi_fcpio_reset(iport->fnic); + fnic_fcpio_reset(iport->fnic); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); iport->flags &= ~FNIC_FIRST_LINK_UP; @@ -4644,20 +4656,20 @@ fdls_process_adisc_req(struct fnic_iport_s *iport, uint16_t acc_frame_size = FNIC_ETH_FCOE_HDRS_OFFSET + sizeof(struct fc_std_els_adisc); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Process ADISC request %d", iport->fnic->fnic_num); fcid = FNIC_STD_GET_S_ID(fchdr); tgt_fcid = ntoh24(fcid); tport = fnic_find_tport_by_fcid(iport, tgt_fcid); if (!tport) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "tport for fcid: 0x%x not found. Dropping ADISC req.", tgt_fcid); return; } if (iport->state != FNIC_IPORT_STATE_READY) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Dropping ADISC req from fcid: 0x%x in iport state: %d", tgt_fcid, iport->state); return; @@ -4668,16 +4680,16 @@ fdls_process_adisc_req(struct fnic_iport_s *iport, if ((frame_wwnn != tport->wwnn) || (frame_wwpn != tport->wwpn)) { /* send reject */ - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "ADISC req from fcid: 0x%x mismatch wwpn: 0x%llx wwnn: 0x%llx", tgt_fcid, frame_wwpn, frame_wwnn); - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "local tport wwpn: 0x%llx wwnn: 0x%llx. Sending RJT", tport->wwpn, tport->wwnn); rjt_frame = fdls_alloc_frame(iport); if (rjt_frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate rjt_frame to send response to ADISC request"); return; } @@ -4700,7 +4712,7 @@ fdls_process_adisc_req(struct fnic_iport_s *iport, acc_frame = fdls_alloc_frame(iport); if (acc_frame == NULL) { - FNIC_FCS_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_ERR, fnic, "Failed to allocate frame to send ADISC accept"); return; } @@ -4754,7 +4766,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, /* some common validation */ if (fdls_get_state(fabric) > FDLS_STATE_FABRIC_FLOGI) { if (iport->fcid != d_id || (!FNIC_FC_FRAME_CS_CTL(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "invalid frame received. Dropping frame"); return -1; } @@ -4764,14 +4776,14 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, if ((fchdr->fh_r_ctl == FC_RCTL_BA_ACC) || (fchdr->fh_r_ctl == FC_RCTL_BA_RJT)) { if (!(FNIC_FC_FRAME_TYPE_BLS(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received ABTS invalid frame. Dropping frame"); return -1; } if (fdls_is_oxid_fabric_req(oxid)) { if (!(iport->fabric.flags & FNIC_FDLS_FABRIC_ABORT_ISSUED)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received unexpected ABTS RSP(oxid:0x%x) from 0x%x. Dropping frame", oxid, s_id); return -1; @@ -4782,7 +4794,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, } else if (fdls_is_oxid_tgt_req(oxid)) { return FNIC_TPORT_BLS_ABTS_RSP; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received ABTS rsp with unknown oxid(0x%x) from 0x%x. Dropping frame", oxid, s_id); return -1; @@ -4791,7 +4803,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, /* BLS ABTS Req */ if ((fchdr->fh_r_ctl == FC_RCTL_BA_ABTS) && (FNIC_FC_FRAME_TYPE_BLS(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Receiving Abort Request from s_id: 0x%x", s_id); return FNIC_BLS_ABTS_REQ; } @@ -4803,7 +4815,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, if ((!FNIC_FC_FRAME_FCTL_FIRST_LAST_SEQINIT(fchdr)) || (!FNIC_FC_FRAME_UNSOLICITED(fchdr)) || (!FNIC_FC_FRAME_TYPE_ELS(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received LOGO invalid frame. Dropping frame"); return -1; } @@ -4812,12 +4824,12 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, if ((!FNIC_FC_FRAME_FCTL_FIRST_LAST_SEQINIT(fchdr)) || (!FNIC_FC_FRAME_TYPE_ELS(fchdr)) || (!FNIC_FC_FRAME_UNSOLICITED(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received RSCN invalid FCTL. Dropping frame"); return -1; } if (s_id != FC_FID_FCTRL) - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received RSCN from target FCTL: 0x%x type: 0x%x s_id: 0x%x.", fchdr->fh_f_ctl[0], fchdr->fh_type, s_id); return FNIC_ELS_RSCN_REQ; @@ -4832,7 +4844,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, case ELS_RRQ: return FNIC_ELS_RRQ; default: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Unsupported frame (type:0x%02x) from fcid: 0x%x", type, s_id); return FNIC_ELS_UNSUPPORTED_REQ; @@ -4841,14 +4853,14 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, /* solicited response from fabric or target */ oxid_frame_type = FNIC_FRAME_TYPE(oxid); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "oxid frame code: 0x%x, oxid: 0x%x\n", oxid_frame_type, oxid); switch (oxid_frame_type) { case FNIC_FRAME_TYPE_FABRIC_FLOGI: if (type == ELS_LS_ACC) { if ((s_id != FC_FID_FLOGI) || (!FNIC_FC_FRAME_TYPE_ELS(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received unknown frame. Dropping frame"); return -1; } @@ -4859,7 +4871,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, if (type == ELS_LS_ACC) { if ((s_id != FC_FID_DIR_SERV) || (!FNIC_FC_FRAME_TYPE_ELS(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received unknown frame. Dropping frame"); return -1; } @@ -4870,7 +4882,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, if (type == ELS_LS_ACC) { if ((s_id != FC_FID_FCTRL) || (!FNIC_FC_FRAME_TYPE_ELS(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received unknown frame. Dropping frame"); return -1; } @@ -4879,7 +4891,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, case FNIC_FRAME_TYPE_FABRIC_RPN: if ((s_id != FC_FID_DIR_SERV) || (!FNIC_FC_FRAME_TYPE_FC_GS(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received unknown frame. Dropping frame"); return -1; } @@ -4887,7 +4899,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, case FNIC_FRAME_TYPE_FABRIC_RFT: if ((s_id != FC_FID_DIR_SERV) || (!FNIC_FC_FRAME_TYPE_FC_GS(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received unknown frame. Dropping frame"); return -1; } @@ -4895,7 +4907,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, case FNIC_FRAME_TYPE_FABRIC_RFF: if ((s_id != FC_FID_DIR_SERV) || (!FNIC_FC_FRAME_TYPE_FC_GS(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received unknown frame. Dropping frame"); return -1; } @@ -4903,7 +4915,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, case FNIC_FRAME_TYPE_FABRIC_GPN_FT: if ((s_id != FC_FID_DIR_SERV) || (!FNIC_FC_FRAME_TYPE_FC_GS(fchdr))) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received unknown frame. Dropping frame"); return -1; } @@ -4925,7 +4937,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, return FNIC_TPORT_ADISC_RSP; case FNIC_FRAME_TYPE_TGT_LOGO: if (!FNIC_FC_FRAME_TYPE_ELS(fchdr)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Dropping Unknown frame in tport solicited exchange range type: 0x%x.", fchdr->fh_type); return -1; @@ -4933,7 +4945,7 @@ fnic_fdls_validate_and_get_frame_type(struct fnic_iport_s *iport, return FNIC_TPORT_LOGO_RSP; default: /* Drop the Rx frame and log/stats it */ - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Solicited response: unknown OXID: 0x%x", oxid); return -1; } @@ -5003,7 +5015,7 @@ void fnic_fdls_recv_frame(struct fnic_iport_s *iport, void *rx_frame, break; case FNIC_TPORT_LOGO_RSP: /* Logo response from tgt which we have deleted */ - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Logo response from tgt: 0x%x", ntoh24(fchdr->fh_s_id)); break; @@ -5046,9 +5058,9 @@ void fnic_fdls_recv_frame(struct fnic_iport_s *iport, void *rx_frame, fdls_process_fdmi_reg_ack(iport, fchdr, frame_type); break; default: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "s_id: 0x%x d_did: 0x%x", s_id, d_id); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Received unknown FCoE frame of len: %d. Dropping frame", len); break; } @@ -5065,17 +5077,17 @@ void fnic_fdls_link_down(struct fnic_iport_s *iport) struct fnic_tport_s *tport, *next; struct fnic *fnic = iport->fnic; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS processing link down", iport->fcid); fdls_set_state((&iport->fabric), FDLS_STATE_LINKDOWN); iport->fabric.flags = 0; spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - fnic_scsi_fcpio_reset(iport->fnic); + fnic_fcpio_reset(iport->fnic); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); list_for_each_entry_safe(tport, next, &iport->tport_list, links) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "removing rport: 0x%x", tport->fcid); fdls_delete_tport(iport, tport); } @@ -5088,6 +5100,6 @@ void fnic_fdls_link_down(struct fnic_iport_s *iport) iport->flags &= ~FNIC_FDMI_ACTIVE; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "0x%x: FDLS finish processing link down", iport->fcid); } diff --git a/drivers/scsi/fnic/fip.c b/drivers/scsi/fnic/fip.c index e08a4f5ac217..41a31a173249 100644 --- a/drivers/scsi/fnic/fip.c +++ b/drivers/scsi/fnic/fip.c @@ -27,7 +27,7 @@ void fnic_fcoe_reset_vlans(struct fnic *fnic) } spin_unlock_irqrestore(&fnic->vlans_lock, flags); - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "Reset vlan complete\n"); } @@ -46,7 +46,7 @@ void fnic_fcoe_send_vlan_req(struct fnic *fnic) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FIP_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_ERR, fnic, "Failed to allocate frame to send VLAN req"); return; } @@ -54,10 +54,10 @@ void fnic_fcoe_send_vlan_req(struct fnic *fnic) fnic_fcoe_reset_vlans(fnic); fnic->set_vlan(fnic, 0); - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "set vlan done\n"); - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "got MAC 0x%x:%x:%x:%x:%x:%x\n", iport->hwmac[0], iport->hwmac[1], iport->hwmac[2], iport->hwmac[3], iport->hwmac[4], iport->hwmac[5]); @@ -81,13 +81,13 @@ void fnic_fcoe_send_vlan_req(struct fnic *fnic) iport->fip.state = FDLS_FIP_VLAN_DISCOVERY_STARTED; - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "Send VLAN req\n"); fnic_send_fip_frame(iport, frame, frame_size); vlan_tov = jiffies + msecs_to_jiffies(FCOE_CTLR_FIPVLAN_TOV); mod_timer(&fnic->retry_fip_timer, round_jiffies(vlan_tov)); - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fip timer set\n"); } @@ -111,11 +111,11 @@ void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct fip_header *fiph) struct fip_vlan_desc *vlan_desc; unsigned long flags; - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic 0x%p got vlan resp\n", fnic); desc_len = be16_to_cpu(vlan_notif->fip.fip_dl_len); - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "desc_len %d\n", desc_len); spin_lock_irqsave(&fnic->vlans_lock, flags); @@ -128,23 +128,20 @@ void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct fip_header *fiph) if (vlan_desc->fd_desc.fip_dtype == FIP_DT_VLAN) { if (vlan_desc->fd_desc.fip_dlen != 1) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "Invalid descriptor length(%x) in VLan response\n", vlan_desc->fd_desc.fip_dlen); } num_vlan++; vid = be16_to_cpu(vlan_desc->fd_vlan); - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "process_vlan_resp: FIP VLAN %d\n", vid); vlan = kzalloc(sizeof(*vlan), GFP_ATOMIC); if (!vlan) { /* retry from timer */ - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "Mem Alloc failure\n"); spin_unlock_irqrestore(&fnic->vlans_lock, flags); @@ -155,14 +152,14 @@ void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct fip_header *fiph) list_add_tail(&vlan->list, &fnic->vlan_list); break; } - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, - "Invalid descriptor type(%x) in VLan response\n", - vlan_desc->fd_desc.fip_dtype); /* - * Note : received a type=2 descriptor here i.e. FIP - * MAC Address Descriptor + * Note : skip any type=2 descriptor here + * (i.e. FIP MAC Address Descriptor) */ + if (vlan_desc->fd_desc.fip_dtype != FIP_DT_MAC) + FNIC_FIP_DBG(KERN_INFO, fnic, + "Invalid descriptor type(0x%x) in vlan response\n", + vlan_desc->fd_desc.fip_dtype); cur_desc += vlan_desc->fd_desc.fip_dlen; desc_len -= vlan_desc->fd_desc.fip_dlen; } @@ -170,7 +167,7 @@ void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct fip_header *fiph) /* any VLAN descriptors present ? */ if (num_vlan == 0) { atomic64_inc(&fnic_stats->vlan_stats.resp_withno_vlanID); - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic 0x%p No VLAN descriptors in FIP VLAN response\n", fnic); } @@ -195,7 +192,7 @@ void fnic_fcoe_start_fcf_discovery(struct fnic *fnic) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FIP_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_ERR, fnic, "Failed to allocate frame to start FCF discovery"); return; } @@ -222,7 +219,7 @@ void fnic_fcoe_start_fcf_discovery(struct fnic *fnic) FNIC_STD_SET_NODE_NAME(&pdisc_sol->name_desc.fd_wwn, iport->wwnn); - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "Start FCF discovery\n"); fnic_send_fip_frame(iport, frame, frame_size); @@ -257,16 +254,14 @@ void fnic_fcoe_fip_discovery_resp(struct fnic *fnic, struct fip_header *fiph) switch (iport->fip.state) { case FDLS_FIP_FCF_DISCOVERY_STARTED: if (be16_to_cpu(disc_adv->fip.fip_flags) & FIP_FL_SOL) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic 0x%p Solicited adv\n", fnic); if ((disc_adv->prio_desc.fd_pri < iport->selected_fcf.fcf_priority) && (be16_to_cpu(disc_adv->fip.fip_flags) & FIP_FL_AVAIL)) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic 0x%p FCF Available\n", fnic); memcpy(iport->selected_fcf.fcf_mac, disc_adv->mac_desc.fd_mac, ETH_ALEN); @@ -274,8 +269,8 @@ void fnic_fcoe_fip_discovery_resp(struct fnic *fnic, struct fip_header *fiph) disc_adv->prio_desc.fd_pri; iport->selected_fcf.fka_adv_period = be32_to_cpu(disc_adv->fka_adv_desc.fd_fka_period); - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, "adv time %d", + FNIC_FIP_DBG(KERN_INFO, fnic, + "adv time %d", iport->selected_fcf.fka_adv_period); iport->selected_fcf.ka_disabled = (disc_adv->fka_adv_desc.fd_flags & 1); @@ -294,8 +289,7 @@ void fnic_fcoe_fip_discovery_resp(struct fnic *fnic, struct fip_header *fiph) iport->selected_fcf.fka_adv_period = be32_to_cpu(disc_adv->fka_adv_desc.fd_fka_period); FNIC_FIP_DBG(KERN_INFO, - fnic->host, - fnic->fnic_num, + fnic, "change fka to %d", iport->selected_fcf.fka_adv_period); } @@ -362,7 +356,7 @@ void fnic_fcoe_start_flogi(struct fnic *fnic) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FIP_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_ERR, fnic, "Failed to allocate frame to start FIP FLOGI"); return; } @@ -415,7 +409,7 @@ void fnic_fcoe_start_flogi(struct fnic *fnic) oxid = fdls_alloc_oxid(iport, FNIC_FRAME_TYPE_FABRIC_FLOGI, &iport->active_oxid_fabric_req); if (oxid == FNIC_UNASSIGNED_OXID) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Failed to allocate OXID to send FIP FLOGI"); mempool_free(frame, fnic->frame_pool); return; @@ -427,7 +421,7 @@ void fnic_fcoe_start_flogi(struct fnic *fnic) FNIC_STD_SET_NODE_NAME(&pflogi_req->flogi_desc.flogi.els.fl_wwnn, iport->wwnn); - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "FIP start FLOGI\n"); fnic_send_fip_frame(iport, frame, frame_size); iport->fip.flogi_retry++; @@ -457,11 +451,11 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph) struct fnic_stats *fnic_stats = &fnic->fnic_stats; struct fc_frame_header *fchdr = &flogi_rsp->rsp_desc.flogi.fchdr; - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic 0x%p FIP FLOGI rsp\n", fnic); desc_len = be16_to_cpu(flogi_rsp->fip.fip_dl_len); if (desc_len != 38) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "Invalid Descriptor List len (%x). Dropping frame\n", desc_len); return; @@ -471,7 +465,7 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph) && (flogi_rsp->rsp_desc.fd_desc.fip_dlen == 36)) || !((flogi_rsp->mac_desc.fd_desc.fip_dtype == 2) && (flogi_rsp->mac_desc.fd_desc.fip_dlen == 2))) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "Dropping frame invalid type and len mix\n"); return; } @@ -484,7 +478,7 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph) || (s_id != FC_FID_FLOGI) || (frame_type != FNIC_FABRIC_FLOGI_RSP) || (fchdr->fh_type != 0x01)) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "Dropping invalid frame: s_id %x F %x R %x t %x OX_ID %x\n", s_id, fchdr->fh_f_ctl[0], fchdr->fh_r_ctl, fchdr->fh_type, FNIC_STD_GET_OX_ID(fchdr)); @@ -492,7 +486,7 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph) } if (iport->fip.state == FDLS_FIP_FLOGI_STARTED) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic 0x%p rsp for pending FLOGI\n", fnic); oxid = FNIC_STD_GET_OX_ID(fchdr); @@ -502,8 +496,7 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph) if ((be16_to_cpu(flogi_rsp->fip.fip_dl_len) == FIP_FLOGI_LEN) && (flogi_rsp->rsp_desc.flogi.els.fl_cmd == ELS_LS_ACC)) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic 0x%p FLOGI success\n", fnic); memcpy(iport->fpma, flogi_rsp->mac_desc.fd_mac, ETH_ALEN); iport->fcid = @@ -519,8 +512,7 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph) if (fnic_fdls_register_portid(iport, iport->fcid, NULL) != 0) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic 0x%p flogi registration failed\n", fnic); return; @@ -528,8 +520,8 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph) iport->fip.state = FDLS_FIP_FLOGI_COMPLETE; iport->state = FNIC_IPORT_STATE_FABRIC_DISC; - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, "iport->state:%d\n", + FNIC_FIP_DBG(KERN_INFO, fnic, + "iport->state:%d\n", iport->state); fnic_fdls_disc_start(iport); if (!((iport->selected_fcf.ka_disabled) @@ -575,7 +567,7 @@ void fnic_common_fip_cleanup(struct fnic *fnic) if (!iport->usefip) return; - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic 0x%p fip cleanup\n", fnic); iport->fip.state = FDLS_FIP_INIT; @@ -617,7 +609,7 @@ void fnic_fcoe_process_cvl(struct fnic *fnic, struct fip_header *fiph) int found = false; int max_count = 0; - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic 0x%p clear virtual link handler\n", fnic); if (!((cvl_msg->fcf_mac_desc.fd_desc.fip_dtype == 2) @@ -625,7 +617,7 @@ void fnic_fcoe_process_cvl(struct fnic *fnic, struct fip_header *fiph) || !((cvl_msg->name_desc.fd_desc.fip_dtype == 4) && (cvl_msg->name_desc.fd_desc.fip_dlen == 3))) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "invalid mix: ft %x fl %x ndt %x ndl %x", cvl_msg->fcf_mac_desc.fd_desc.fip_dtype, cvl_msg->fcf_mac_desc.fd_desc.fip_dlen, @@ -640,8 +632,7 @@ void fnic_fcoe_process_cvl(struct fnic *fnic, struct fip_header *fiph) if (!((cvl_msg->vn_ports_desc[i].fd_desc.fip_dtype == 11) && (cvl_msg->vn_ports_desc[i].fd_desc.fip_dlen == 5))) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "Invalid type and len mix type: %d len: %d\n", cvl_msg->vn_ports_desc[i].fd_desc.fip_dtype, cvl_msg->vn_ports_desc[i].fd_desc.fip_dlen); @@ -664,12 +655,12 @@ void fnic_fcoe_process_cvl(struct fnic *fnic, struct fip_header *fiph) spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); max_count++; if (max_count >= FIP_FNIC_RESET_WAIT_COUNT) { - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "Rthr waited too long. Skipping handle link event %p\n", fnic); return; } - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic reset in progress. Link event needs to wait %p", fnic); } @@ -714,7 +705,7 @@ int fdls_fip_recv_frame(struct fnic *fnic, void *frame) return true; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Not a FIP Frame"); return false; } @@ -724,7 +715,7 @@ void fnic_work_on_fip_timer(struct work_struct *work) struct fnic *fnic = container_of(work, struct fnic, fip_timer_work); struct fnic_iport_s *iport = &fnic->iport; - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "FIP timeout\n"); if (iport->fip.state == FDLS_FIP_VLAN_DISCOVERY_STARTED) { @@ -732,12 +723,12 @@ void fnic_work_on_fip_timer(struct work_struct *work) } else if (iport->fip.state == FDLS_FIP_FCF_DISCOVERY_STARTED) { u8 zmac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "FCF Discovery timeout\n"); if (memcmp(iport->selected_fcf.fcf_mac, zmac, ETH_ALEN) != 0) { if (iport->flags & FNIC_FIRST_LINK_UP) { - fnic_scsi_fcpio_reset(iport->fnic); + fnic_fcpio_reset(iport->fnic); iport->flags &= ~FNIC_FIRST_LINK_UP; } @@ -754,13 +745,13 @@ void fnic_work_on_fip_timer(struct work_struct *work) round_jiffies(fcf_tov)); } } else { - FNIC_FIP_DBG(KERN_INFO, fnic->host, - fnic->fnic_num, "FCF Discovery timeout\n"); + FNIC_FIP_DBG(KERN_INFO, fnic, + "FCF Discovery timeout\n"); fnic_vlan_discovery_timeout(fnic); } } else if (iport->fip.state == FDLS_FIP_FLOGI_STARTED) { fdls_schedule_oxid_free(iport, &iport->active_oxid_fabric_req); - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "FLOGI timeout\n"); if (iport->fip.flogi_retry < fnic->config.flogi_retries) fnic_fcoe_start_flogi(fnic); @@ -807,7 +798,7 @@ void fnic_handle_enode_ka_timer(struct timer_list *t) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FIP_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_ERR, fnic, "Failed to allocate frame to send enode ka"); return; } @@ -828,7 +819,7 @@ void fnic_handle_enode_ka_timer(struct timer_list *t) memcpy(penode_ka->eth.h_dest, iport->selected_fcf.fcf_mac, ETH_ALEN); memcpy(penode_ka->mac_desc.fd_mac, iport->hwmac, ETH_ALEN); - FNIC_FIP_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_DEBUG, fnic, "Handle enode KA timer\n"); fnic_send_fip_frame(iport, frame, frame_size); enode_ka_tov = jiffies @@ -861,7 +852,7 @@ void fnic_handle_vn_ka_timer(struct timer_list *t) frame = fdls_alloc_frame(iport); if (frame == NULL) { - FNIC_FIP_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_ERR, fnic, "Failed to allocate frame to send vn ka"); return; } @@ -887,7 +878,7 @@ void fnic_handle_vn_ka_timer(struct timer_list *t) memcpy(pvn_port_ka->vn_port_desc.fd_fc_id, fcid, 3); FNIC_STD_SET_NPORT_NAME(&pvn_port_ka->vn_port_desc.fd_wwpn, iport->wwpn); - FNIC_FIP_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_DEBUG, fnic, "Handle vnport KA timer\n"); fnic_send_fip_frame(iport, frame, frame_size); vn_ka_tov = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); @@ -977,7 +968,7 @@ void fnic_work_on_fcs_ka_timer(struct work_struct *work) *fnic = container_of(work, struct fnic, fip_timer_work); struct fnic_iport_s *iport = &fnic->iport; - FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FIP_DBG(KERN_INFO, fnic, "fnic 0x%p fcs ka timeout\n", fnic); fnic_common_fip_cleanup(fnic); diff --git a/drivers/scsi/fnic/fip.h b/drivers/scsi/fnic/fip.h index 79fee7628870..4866152a32df 100644 --- a/drivers/scsi/fnic/fip.h +++ b/drivers/scsi/fnic/fip.h @@ -142,7 +142,7 @@ fnic_debug_dump_fip_frame(struct fnic *fnic, struct ethhdr *eth, u16 op = be16_to_cpu(fiph->fip_op); u8 sub = fiph->fip_subcode; - FNIC_FCS_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_DEBUG, fnic, "FIP %s packet contents: op: 0x%x sub: 0x%x (len = %d)", pfx, op, sub, len); diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 1199d701c3f5..3a3e8d0d9fc5 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -30,7 +30,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.8.0.2" +#define DRV_VERSION "1.9.0.1" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " @@ -144,6 +144,9 @@ #define PCI_SUBDEVICE_ID_CISCO_HELSINKI 0x02e4 /* VIC 15235 */ #define PCI_SUBDEVICE_ID_CISCO_GOTHENBURG 0x02f2 /* VIC 15425 */ +#define IS_FNIC_FCP_INITIATOR(fnic) (fnic->role == FNIC_ROLE_FCP_INITIATOR) +#define IS_FNIC_NVME_INITIATOR(fnic) (fnic->role == FNIC_ROLE_NVME_INITIATOR) + struct fnic_pcie_device { u32 device; u8 *desc; @@ -240,6 +243,9 @@ extern struct work_struct reset_fnic_work; #define FNIC_FCS_LOGGING 0x02 #define FNIC_SCSI_LOGGING 0x04 #define FNIC_ISR_LOGGING 0x08 +#define FNIC_FDLS_LOGGING 0x10 +#define FNIC_NVME_LOGGING 0x20 +#define FNIC_FIP_LOGGING 0x40 #define FNIC_CHECK_LOGGING(LEVEL, CMD) \ do { \ @@ -249,38 +255,39 @@ do { \ } while (0); \ } while (0) -#define FNIC_MAIN_DBG(kern_level, host, fnic_num, fmt, args...) \ - FNIC_CHECK_LOGGING(FNIC_MAIN_LOGGING, \ - shost_printk(kern_level, host, \ - "fnic<%d>: %s: %d: " fmt, fnic_num,\ - __func__, __LINE__, ##args);) - -#define FNIC_FCS_DBG(kern_level, host, fnic_num, fmt, args...) \ - FNIC_CHECK_LOGGING(FNIC_FCS_LOGGING, \ - shost_printk(kern_level, host, \ - "fnic<%d>: %s: %d: " fmt, fnic_num,\ - __func__, __LINE__, ##args);) - -#define FNIC_FIP_DBG(kern_level, host, fnic_num, fmt, args...) \ - FNIC_CHECK_LOGGING(FNIC_FCS_LOGGING, \ - shost_printk(kern_level, host, \ - "fnic<%d>: %s: %d: " fmt, fnic_num,\ - __func__, __LINE__, ##args);) - -#define FNIC_SCSI_DBG(kern_level, host, fnic_num, fmt, args...) \ - FNIC_CHECK_LOGGING(FNIC_SCSI_LOGGING, \ - shost_printk(kern_level, host, \ - "fnic<%d>: %s: %d: " fmt, fnic_num,\ - __func__, __LINE__, ##args);) - -#define FNIC_ISR_DBG(kern_level, host, fnic_num, fmt, args...) \ - FNIC_CHECK_LOGGING(FNIC_ISR_LOGGING, \ - shost_printk(kern_level, host, \ - "fnic<%d>: %s: %d: " fmt, fnic_num,\ - __func__, __LINE__, ##args);) - -#define FNIC_MAIN_NOTE(kern_level, host, fmt, args...) \ - shost_printk(kern_level, host, fmt, ##args) +#define fnic_printk(kern_level, fnic, fmt, ...) \ + (IS_FNIC_FCP_INITIATOR(fnic) ? \ + shost_printk(kern_level, fnic->host, "fnic<%d>: %s: %d: " fmt, \ + fnic->fnic_num, __func__, __LINE__, ##__VA_ARGS__) : \ + printk(kern_level "fnic<%d>: %s: %d: " fmt, fnic->fnic_num, \ + __func__, __LINE__, ##__VA_ARGS__)) + +#define FNIC_MAIN_DBG(kern_level, fnic, fmt, args...) \ + FNIC_CHECK_LOGGING(FNIC_MAIN_LOGGING, \ + fnic_printk(kern_level, fnic, fmt, ##args);) + +#define FNIC_FCS_DBG(kern_level, fnic, fmt, args...) \ + FNIC_CHECK_LOGGING(FNIC_FCS_LOGGING, \ + fnic_printk(kern_level, fnic, fmt, ##args);) + +#define FNIC_FIP_DBG(kern_level, fnic, fmt, args...) \ + FNIC_CHECK_LOGGING(FNIC_FIP_LOGGING, \ + fnic_printk(kern_level, fnic, fmt, ##args);) + +#define FNIC_SCSI_DBG(kern_level, fnic, fmt, args...) \ + FNIC_CHECK_LOGGING(FNIC_SCSI_LOGGING, \ + fnic_printk(kern_level, fnic, fmt, ##args);) + +#define FNIC_ISR_DBG(kern_level, fnic, fmt, args...) \ + FNIC_CHECK_LOGGING(FNIC_ISR_LOGGING, \ + fnic_printk(kern_level, fnic, fmt, ##args);) + +#define FNIC_NVME_DBG(kern_level, fnic, fmt, args...) \ + FNIC_CHECK_LOGGING(FNIC_NVME_LOGGING, \ + fnic_printk(kern_level, fnic, fmt, ##args);) + +#define FNIC_MAIN_NOTE(kern_level, fnic, fmt, args...) \ + fnic_printk(kern_level, fnic, fmt, ##args) #define FNIC_WQ_COPY_MAX 64 #define FNIC_WQ_MAX 1 @@ -325,6 +332,7 @@ enum fnic_state { enum fnic_role_e { FNIC_ROLE_FCP_INITIATOR = 0, + FNIC_ROLE_NVME_INITIATOR, }; enum fnic_evt { @@ -511,7 +519,6 @@ int fnic_host_reset(struct Scsi_Host *shost); void fnic_reset(struct Scsi_Host *shost); int fnic_issue_fc_host_lip(struct Scsi_Host *shost); void fnic_get_host_port_state(struct Scsi_Host *shost); -void fnic_scsi_fcpio_reset(struct fnic *fnic); int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do, unsigned int cq_index); int fnic_wq_cmpl_handler(struct fnic *fnic, int); int fnic_flogi_reg_handler(struct fnic *fnic, u32); @@ -596,7 +603,7 @@ fnic_debug_dump(struct fnic *fnic, uint8_t *u8arr, int len) int i; for (i = 0; i < len; i = i+8) { - FNIC_FCS_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "%d: %02x %02x %02x %02x %02x %02x %02x %02x", i / 8, u8arr[i + 0], u8arr[i + 1], u8arr[i + 2], u8arr[i + 3], u8arr[i + 4], u8arr[i + 5], u8arr[i + 6], u8arr[i + 7]); @@ -611,7 +618,7 @@ fnic_debug_dump_fc_frame(struct fnic *fnic, struct fc_frame_header *fchdr, s_id = ntoh24(fchdr->fh_s_id); d_id = ntoh24(fchdr->fh_d_id); - FNIC_FCS_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "%s packet contents: sid/did/type/oxid = 0x%x/0x%x/0x%x/0x%x (len = %d)\n", pfx, s_id, d_id, fchdr->fh_type, FNIC_STD_GET_OX_ID(fchdr), len); diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 103ab6f1f7cd..11562cae801f 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -39,7 +39,7 @@ static uint8_t FCOE_ALL_FCF_MAC[6] = FC_FCOE_FLOGI_MAC; static inline void fnic_fdls_set_fcoe_srcmac(struct fnic *fnic, uint8_t *src_mac) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Setting src mac: %02x:%02x:%02x:%02x:%02x:%02x", src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5]); @@ -54,7 +54,7 @@ static inline void fnic_fdls_set_fcoe_srcmac(struct fnic *fnic, static inline void fnic_fdls_set_fcoe_dstmac(struct fnic *fnic, uint8_t *dst_mac) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Setting dst mac: %02x:%02x:%02x:%02x:%02x:%02x", dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5]); @@ -82,7 +82,7 @@ void fnic_fdls_link_status_change(struct fnic *fnic, int linkup) { struct fnic_iport_s *iport = &fnic->iport; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "link up: %d, usefip: %d", linkup, iport->usefip); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); @@ -90,12 +90,12 @@ void fnic_fdls_link_status_change(struct fnic *fnic, int linkup) if (linkup) { if (iport->usefip) { iport->state = FNIC_IPORT_STATE_FIP; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "link up: %d, usefip: %d", linkup, iport->usefip); fnic_fcoe_send_vlan_req(fnic); } else { iport->state = FNIC_IPORT_STATE_FABRIC_DISC; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iport->state: %d", iport->state); fnic_fdls_disc_start(iport); } @@ -125,13 +125,13 @@ void fnic_fdls_learn_fcoe_macs(struct fnic_iport_s *iport, void *rx_frame, memcpy(&fcmac[3], fcid, 3); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "learn fcoe: dst_mac: %02x:%02x:%02x:%02x:%02x:%02x", ethhdr->h_dest[0], ethhdr->h_dest[1], ethhdr->h_dest[2], ethhdr->h_dest[3], ethhdr->h_dest[4], ethhdr->h_dest[5]); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "learn fcoe: fc_mac: %02x:%02x:%02x:%02x:%02x:%02x", fcmac[0], fcmac[1], fcmac[2], fcmac[3], fcmac[4], fcmac[5]); @@ -149,7 +149,7 @@ void fnic_fdls_init(struct fnic *fnic, int usefip) iport->fnic = fnic; iport->usefip = usefip; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "iportsrcmac: %02x:%02x:%02x:%02x:%02x:%02x", iport->hwmac[0], iport->hwmac[1], iport->hwmac[2], iport->hwmac[3], iport->hwmac[4], iport->hwmac[5]); @@ -168,14 +168,14 @@ void fnic_handle_link(struct work_struct *work) int max_count = 0; if (vnic_dev_get_intr_mode(fnic->vdev) != VNIC_DEV_INTR_MODE_MSI) - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Interrupt mode is not MSI\n"); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); if (fnic->stop_rx_link_events) { spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Stop link rx events\n"); return; } @@ -184,10 +184,10 @@ void fnic_handle_link(struct work_struct *work) if ((fnic->state != FNIC_IN_ETH_MODE) && (fnic->state != FNIC_IN_FC_MODE)) { spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "fnic in transitional state: %d. link up: %d ignored", fnic->state, vnic_dev_link_status(fnic->vdev)); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Current link status: %d iport state: %d\n", fnic->link_status, fnic->iport.state); return; @@ -199,36 +199,36 @@ void fnic_handle_link(struct work_struct *work) fnic->link_down_cnt = vnic_dev_link_down_cnt(fnic->vdev); while (fnic->reset_in_progress == IN_PROGRESS) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "fnic reset in progress. Link event needs to wait\n"); spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "waiting for reset completion\n"); wait_for_completion_timeout(&fnic->reset_completion_wait, msecs_to_jiffies(5000)); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "woken up from reset completion wait\n"); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); max_count++; if (max_count >= MAX_RESET_WAIT_COUNT) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Rstth waited for too long. Skipping handle link event\n"); spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); return; } } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Marking fnic reset in progress\n"); fnic->reset_in_progress = IN_PROGRESS; if ((vnic_dev_get_intr_mode(fnic->vdev) != VNIC_DEV_INTR_MODE_MSI) || (fnic->link_status != old_link_status)) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "old link status: %d link status: %d\n", old_link_status, (int) fnic->link_status); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "old down count %d down count: %d\n", old_link_down_cnt, (int) fnic->link_down_cnt); } @@ -237,36 +237,36 @@ void fnic_handle_link(struct work_struct *work) if (!fnic->link_status) { /* DOWN -> DOWN */ spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "down->down\n"); } else { if (old_link_down_cnt != fnic->link_down_cnt) { /* UP -> DOWN -> UP */ spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "up->down. Link down\n"); fnic_fdls_link_status_change(fnic, 0); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "down->up. Link up\n"); fnic_fdls_link_status_change(fnic, 1); } else { /* UP -> UP */ spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "up->up\n"); } } } else if (fnic->link_status) { /* DOWN -> UP */ spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "down->up. Link up\n"); fnic_fdls_link_status_change(fnic, 1); } else { /* UP -> DOWN */ spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "up->down. Link down\n"); fnic_fdls_link_status_change(fnic, 0); } @@ -275,7 +275,7 @@ void fnic_handle_link(struct work_struct *work) fnic->reset_in_progress = NOT_IN_PROGRESS; complete(&fnic->reset_completion_wait); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Marking fnic reset completion\n"); spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); } @@ -302,7 +302,7 @@ void fnic_handle_frame(struct work_struct *work) */ if (fnic->state != FNIC_IN_FC_MODE && fnic->state != FNIC_IN_ETH_MODE) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Cannot process frame in transitional state\n"); spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags); return; @@ -328,7 +328,7 @@ void fnic_handle_fip_frame(struct work_struct *work) struct fnic_frame_list *cur_frame, *next; struct fnic *fnic = container_of(work, struct fnic, fip_frame_work); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Processing FIP frame\n"); spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags); @@ -407,7 +407,7 @@ void fnic_update_mac_locked(struct fnic *fnic, u8 *new) if (ether_addr_equal(data, new)) return; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Update MAC: %u\n", *new); if (!is_zero_ether_addr(data) && !ether_addr_equal(data, ctl)) @@ -477,7 +477,7 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc if (!fcs_ok) { atomic64_inc(&fnic_stats->misc_stats.frame_errors); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "fnic 0x%p fcs error. Dropping packet.\n", fnic); goto drop; } @@ -487,21 +487,21 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc if (fnic_import_rq_eth_pkt(fnic, fp)) return; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Dropping h_proto 0x%x", be16_to_cpu(eh->h_proto)); goto drop; } } else { /* wrong CQ type */ - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "fnic rq_cmpl wrong cq type x%x\n", type); goto drop; } if (!fcs_ok || packet_error || !fcoe_fnic_crc_ok || fcoe_enc_error) { atomic64_inc(&fnic_stats->misc_stats.frame_errors); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "fcoe %x fcsok %x pkterr %x ffco %x fee %x\n", fcoe, fcs_ok, packet_error, fcoe_fnic_crc_ok, fcoe_enc_error); @@ -511,7 +511,7 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc spin_lock_irqsave(&fnic->fnic_lock, flags); if (fnic->stop_rx_link_events) { spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "fnic->stop_rx_link_events: %d\n", fnic->stop_rx_link_events); goto drop; @@ -522,7 +522,7 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc frame_elem = mempool_alloc(fnic->frame_elem_pool, GFP_ATOMIC | __GFP_ZERO); if (!frame_elem) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Failed to allocate memory for frame elem"); goto drop; } @@ -567,7 +567,7 @@ int fnic_rq_cmpl_handler(struct fnic *fnic, int rq_work_to_do) if (cur_work_done && fnic->stop_rx_link_events != 1) { err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame); if (err) - shost_printk(KERN_ERR, fnic->host, + fnic_printk(KERN_ERR, fnic, "fnic_alloc_rq_frame can't alloc" " frame\n"); } @@ -593,7 +593,7 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) len = FNIC_FRAME_HT_ROOM; buf = kmalloc(len, GFP_ATOMIC); if (!buf) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Unable to allocate RQ buffer of size: %d\n", len); return -ENOMEM; } @@ -601,7 +601,7 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) pa = dma_map_single(&fnic->pdev->dev, buf, len, DMA_FROM_DEVICE); if (dma_mapping_error(&fnic->pdev->dev, pa)) { ret = -ENOMEM; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "PCI mapping failed with error %d\n", ret); goto free_buf; } @@ -642,7 +642,7 @@ static int fnic_send_frame(struct fnic *fnic, void *frame, int frame_len) if ((fnic_fc_trace_set_data(fnic->fnic_num, FNIC_FC_SEND | 0x80, (char *) frame, frame_len)) != 0) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "fnic ctlr frame trace error"); } @@ -650,7 +650,7 @@ static int fnic_send_frame(struct fnic *fnic, void *frame, int frame_len) if (!vnic_wq_desc_avail(wq)) { dma_unmap_single(&fnic->pdev->dev, pa, frame_len, DMA_TO_DEVICE); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "vnic work queue descriptor is not available"); ret = -1; goto fnic_send_frame_end; @@ -707,12 +707,12 @@ fdls_send_fcoe_frame(struct fnic *fnic, void *frame, int frame_size, frame_elem = mempool_alloc(fnic->frame_elem_pool, GFP_ATOMIC | __GFP_ZERO); if (!frame_elem) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Failed to allocate memory for frame elem"); return -ENOMEM; } - FNIC_FCS_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Queueing FC frame: sid/did/type/oxid = 0x%x/0x%x/0x%x/0x%x\n", ntoh24(fchdr->fh_s_id), ntoh24(fchdr->fh_d_id), fchdr->fh_type, FNIC_STD_GET_OX_ID(fchdr)); @@ -778,7 +778,7 @@ void fnic_flush_tx(struct work_struct *work) struct fc_frame *fp; struct fnic_frame_list *cur_frame, *next; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Flush queued frames"); list_for_each_entry_safe(cur_frame, next, &fnic->tx_queue, links) { @@ -797,7 +797,7 @@ fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id, struct ethhdr *ethhdr; int ret; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Setting port id: 0x%x fp: 0x%p fnic state: %d", port_id, fp, fnic->state); @@ -810,7 +810,7 @@ fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id, if (fnic->state == FNIC_IN_ETH_MODE || fnic->state == FNIC_IN_FC_MODE) fnic->state = FNIC_IN_ETH_TRANS_FC_MODE; else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Unexpected fnic state while processing FLOGI response\n"); return -1; } @@ -821,7 +821,7 @@ fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id, */ ret = fnic_flogi_reg_handler(fnic, port_id); if (ret < 0) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FLOGI registration error ret: %d fnic state: %d\n", ret, fnic->state); if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE) @@ -831,7 +831,7 @@ fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id, } iport->fabric.flags |= FNIC_FDLS_FPMA_LEARNT; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "FLOGI registration success\n"); return 0; } @@ -911,7 +911,7 @@ fnic_fdls_add_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport, struct fc_rport_identifiers ids; struct rport_dd_data_s *rdd_data; - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Adding rport fcid: 0x%x", tport->fcid); ids.node_name = tport->wwnn; @@ -923,12 +923,12 @@ fnic_fdls_add_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport, rport = fc_remote_port_add(fnic->host, 0, &ids); spin_lock_irqsave(&fnic->fnic_lock, flags); if (!rport) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Failed to add rport for tport: 0x%x", tport->fcid); return; } - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Added rport fcid: 0x%x", tport->fcid); /* Mimic these assignments in queuecommand to avoid timing issues */ @@ -967,7 +967,7 @@ fnic_fdls_remove_tport(struct fnic_iport_s *iport, fc_remote_port_delete(rport); spin_lock_irqsave(&fnic->fnic_lock, flags); - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Deregistered and freed tport fcid: 0x%x from scsi transport fc", tport->fcid); @@ -994,7 +994,7 @@ void fnic_delete_fcp_tports(struct fnic *fnic) spin_lock_irqsave(&fnic->fnic_lock, flags); list_for_each_entry_safe(tport, next, &fnic->iport.tport_list, links) { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "removing fcp rport fcid: 0x%x", tport->fcid); fdls_set_tport_state(tport, FDLS_TGT_STATE_OFFLINING); fnic_del_tport_timer_sync(fnic, tport); @@ -1021,36 +1021,36 @@ void fnic_tport_event_handler(struct work_struct *work) tport = cur_evt->arg1; switch (cur_evt->event) { case TGT_EV_RPORT_ADD: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Add rport event"); if (tport->state == FDLS_TGT_STATE_READY) { fnic_fdls_add_tport(&fnic->iport, (struct fnic_tport_s *) cur_evt->arg1, flags); } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Target not ready. Add rport event dropped: 0x%x", tport->fcid); } break; case TGT_EV_RPORT_DEL: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Remove rport event"); if (tport->state == FDLS_TGT_STATE_OFFLINING) { fnic_fdls_remove_tport(&fnic->iport, (struct fnic_tport_s *) cur_evt->arg1, flags); } else { - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "remove rport event dropped tport fcid: 0x%x", tport->fcid); } break; case TGT_EV_TPORT_DELETE: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Delete tport event"); fdls_delete_tport(tport->iport, tport); break; default: - FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_FCS_DBG(KERN_INFO, fnic, "Unknown tport event"); break; } @@ -1108,3 +1108,53 @@ void fnic_reset_work_handler(struct work_struct *work) spin_unlock_irqrestore(&reset_fnic_list_lock, reset_fnic_list_lock_flags); } + +void fnic_fcpio_reset(struct fnic *fnic) +{ + unsigned long flags; + enum fnic_state old_state; + struct fnic_iport_s *iport = &fnic->iport; + DECLARE_COMPLETION_ONSTACK(fw_reset_done); + int time_remain; + + /* issue fw reset */ + spin_lock_irqsave(&fnic->fnic_lock, flags); + if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE)) { + /* fw reset is in progress, poll for its completion */ + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + FNIC_FCS_DBG(KERN_INFO, fnic, + "fnic is in unexpected state: %d for fw_reset\n", + fnic->state); + return; + } + + old_state = fnic->state; + fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; + + fnic_update_mac_locked(fnic, iport->hwmac); + fnic->fw_reset_done = &fw_reset_done; + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + + FNIC_FCS_DBG(KERN_INFO, fnic, + "Issuing fw reset\n"); + if (fnic_fw_reset_handler(fnic)) { + spin_lock_irqsave(&fnic->fnic_lock, flags); + if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) + fnic->state = old_state; + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + } else { + FNIC_FCS_DBG(KERN_INFO, fnic, + "Waiting for fw completion\n"); + time_remain = wait_for_completion_timeout(&fw_reset_done, + msecs_to_jiffies(FNIC_FW_RESET_TIMEOUT)); + FNIC_FCS_DBG(KERN_INFO, fnic, + "Woken up after fw completion timeout\n"); + if (time_remain == 0) { + FNIC_FCS_DBG(KERN_INFO, fnic, + "FW reset completion timed out after %d ms\n", + FNIC_FW_RESET_TIMEOUT); + } + atomic64_inc(&fnic->fnic_stats.reset_stats.fw_reset_timeouts); + } + fnic->fw_reset_done = NULL; +} diff --git a/drivers/scsi/fnic/fnic_fdls.h b/drivers/scsi/fnic/fnic_fdls.h index 531d0b37e450..e2959120c4f9 100644 --- a/drivers/scsi/fnic/fnic_fdls.h +++ b/drivers/scsi/fnic/fnic_fdls.h @@ -410,6 +410,7 @@ void fnic_fdls_add_tport(struct fnic_iport_s *iport, void fnic_fdls_remove_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport, unsigned long flags); +void fnic_fcpio_reset(struct fnic *fnic); /* fip.c */ void fnic_fcoe_send_vlan_req(struct fnic *fnic); @@ -422,7 +423,6 @@ void fnic_handle_fip_timer(struct timer_list *t); extern void fdls_fabric_timer_callback(struct timer_list *t); /* fnic_scsi.c */ -void fnic_scsi_fcpio_reset(struct fnic *fnic); extern void fdls_fabric_timer_callback(struct timer_list *t); void fnic_rport_exch_reset(struct fnic *fnic, u32 fcid); int fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id, diff --git a/drivers/scsi/fnic/fnic_isr.c b/drivers/scsi/fnic/fnic_isr.c index 7ed50b11afa6..43149d8312ec 100644 --- a/drivers/scsi/fnic/fnic_isr.c +++ b/drivers/scsi/fnic/fnic_isr.c @@ -222,7 +222,7 @@ int fnic_request_intr(struct fnic *fnic) fnic->msix[i].devname, fnic->msix[i].devid); if (err) { - FNIC_ISR_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_ISR_DBG(KERN_ERR, fnic, "request_irq failed with error: %d\n", err); fnic_free_intr(fnic); @@ -245,15 +245,22 @@ int fnic_set_intr_mode_msix(struct fnic *fnic) unsigned int m = ARRAY_SIZE(fnic->wq); unsigned int o = ARRAY_SIZE(fnic->hw_copy_wq); unsigned int min_irqs = n + m + 1 + 1; /*rq, raw wq, wq, err*/ - + /* + * Make driver critical vectors unmanaged, or else it can get tied + * to an offline CPU. This can happen when hyper-threading is off. + */ + struct irq_affinity affd = { + .pre_vectors = n + m + 1, /* rq, raw wq, 1 ioq */ + .post_vectors = 1, /* err */ + }; /* * We need n RQs, m WQs, o Copy WQs, n+m+o CQs, and n+m+o+1 INTRs * (last INTR is used for WQ/RQ errors and notification area) */ - FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_ISR_DBG(KERN_INFO, fnic, "rq-array size: %d wq-array size: %d copy-wq array size: %d\n", n, m, o); - FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_ISR_DBG(KERN_INFO, fnic, "rq_count: %d raw_wq_count: %d wq_copy_count: %d cq_count: %d\n", fnic->rq_count, fnic->raw_wq_count, fnic->wq_copy_count, fnic->cq_count); @@ -263,19 +270,19 @@ int fnic_set_intr_mode_msix(struct fnic *fnic) int vec_count = 0; int vecs = fnic->rq_count + fnic->raw_wq_count + fnic->wq_copy_count + 1; - vec_count = pci_alloc_irq_vectors(fnic->pdev, min_irqs, vecs, - PCI_IRQ_MSIX | PCI_IRQ_AFFINITY); - FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + vec_count = pci_alloc_irq_vectors_affinity(fnic->pdev, min_irqs, + vecs, PCI_IRQ_MSIX|PCI_IRQ_AFFINITY, &affd); + FNIC_ISR_DBG(KERN_INFO, fnic, "allocated %d MSI-X vectors\n", vec_count); if (vec_count > 0) { if (vec_count < vecs) { - FNIC_ISR_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_ISR_DBG(KERN_ERR, fnic, "interrupts number mismatch: vec_count: %d vecs: %d\n", vec_count, vecs); if (vec_count < min_irqs) { - FNIC_ISR_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_ISR_DBG(KERN_ERR, fnic, "no interrupts for copy wq\n"); return 1; } @@ -287,7 +294,7 @@ int fnic_set_intr_mode_msix(struct fnic *fnic) fnic->wq_copy_count = vec_count - n - m - 1; fnic->wq_count = fnic->raw_wq_count + fnic->wq_copy_count; if (fnic->cq_count != vec_count - 1) { - FNIC_ISR_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_ISR_DBG(KERN_ERR, fnic, "CQ count: %d does not match MSI-X vector count: %d\n", fnic->cq_count, vec_count); fnic->cq_count = vec_count - 1; @@ -295,23 +302,23 @@ int fnic_set_intr_mode_msix(struct fnic *fnic) fnic->intr_count = vec_count; fnic->err_intr_offset = fnic->rq_count + fnic->wq_count; - FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_ISR_DBG(KERN_INFO, fnic, "rq_count: %d raw_wq_count: %d copy_wq_base: %d\n", fnic->rq_count, fnic->raw_wq_count, fnic->copy_wq_base); - FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_ISR_DBG(KERN_INFO, fnic, "wq_copy_count: %d wq_count: %d cq_count: %d\n", fnic->wq_copy_count, fnic->wq_count, fnic->cq_count); - FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "intr_count: %d err_intr_offset: %u", + FNIC_ISR_DBG(KERN_INFO, fnic, + "intr_count: %d err_intr_offset: %u\n", fnic->intr_count, fnic->err_intr_offset); vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSIX); - FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_ISR_DBG(KERN_INFO, fnic, "fnic using MSI-X\n"); return 0; } @@ -351,7 +358,7 @@ int fnic_set_intr_mode(struct fnic *fnic) fnic->intr_count = 1; fnic->err_intr_offset = 0; - FNIC_ISR_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_ISR_DBG(KERN_DEBUG, fnic, "Using MSI Interrupts\n"); vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSI); @@ -377,7 +384,7 @@ int fnic_set_intr_mode(struct fnic *fnic) fnic->cq_count = 3; fnic->intr_count = 3; - FNIC_ISR_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_ISR_DBG(KERN_DEBUG, fnic, "Using Legacy Interrupts\n"); vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX); diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 4cc4077ea53c..dc117e7fb053 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -184,7 +184,7 @@ static void fnic_get_host_speed(struct Scsi_Host *shost) u32 port_speed = vnic_dev_port_speed(fnic->vdev); struct fnic_stats *fnic_stats = &fnic->fnic_stats; - FNIC_MAIN_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_MAIN_DBG(KERN_INFO, fnic, "port_speed: %d Mbps", port_speed); atomic64_set(&fnic_stats->misc_stats.port_speed_in_mbps, port_speed); @@ -234,7 +234,7 @@ static void fnic_get_host_speed(struct Scsi_Host *shost) fc_host_speed(shost) = FC_PORTSPEED_128GBIT; break; default: - FNIC_MAIN_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_MAIN_DBG(KERN_INFO, fnic, "Unknown FC speed: %d Mbps", port_speed); fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; break; @@ -260,7 +260,7 @@ static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *host) spin_unlock_irqrestore(&fnic->fnic_lock, flags); if (ret) { - FNIC_MAIN_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_MAIN_DBG(KERN_DEBUG, fnic, "fnic: Get vnic stats failed: 0x%x", ret); return stats; } @@ -286,64 +286,66 @@ static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *host) void fnic_dump_fchost_stats(struct Scsi_Host *host, struct fc_host_statistics *stats) { - FNIC_MAIN_NOTE(KERN_NOTICE, host, + struct fnic *fnic = *((struct fnic **) shost_priv(host)); + + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: seconds since last reset = %llu\n", stats->seconds_since_last_reset); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: tx frames = %llu\n", stats->tx_frames); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: tx words = %llu\n", stats->tx_words); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: rx frames = %llu\n", stats->rx_frames); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: rx words = %llu\n", stats->rx_words); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: lip count = %llu\n", stats->lip_count); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: nos count = %llu\n", stats->nos_count); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: error frames = %llu\n", stats->error_frames); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: dumped frames = %llu\n", stats->dumped_frames); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: link failure count = %llu\n", stats->link_failure_count); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: loss of sync count = %llu\n", stats->loss_of_sync_count); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: loss of signal count = %llu\n", stats->loss_of_signal_count); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: prim seq protocol err count = %llu\n", stats->prim_seq_protocol_err_count); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: invalid tx word count= %llu\n", stats->invalid_tx_word_count); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: invalid crc count = %llu\n", stats->invalid_crc_count); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: fcp input requests = %llu\n", stats->fcp_input_requests); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: fcp output requests = %llu\n", stats->fcp_output_requests); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: fcp control requests = %llu\n", stats->fcp_control_requests); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: fcp input megabytes = %llu\n", stats->fcp_input_megabytes); - FNIC_MAIN_NOTE(KERN_NOTICE, host, + FNIC_MAIN_NOTE(KERN_NOTICE, fnic, "fnic: fcp output megabytes = %llu\n", stats->fcp_output_megabytes); return; @@ -369,7 +371,7 @@ static void fnic_reset_host_stats(struct Scsi_Host *host) spin_unlock_irqrestore(&fnic->fnic_lock, flags); if (ret) { - FNIC_MAIN_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_MAIN_DBG(KERN_DEBUG, fnic, "fnic: Reset vnic stats failed" " 0x%x", ret); return; @@ -676,27 +678,58 @@ static int fnic_scsi_drv_init(struct fnic *fnic) void fnic_mq_map_queues_cpus(struct Scsi_Host *host) { + const struct cpumask *mask; + unsigned int queue, cpu; struct fnic *fnic = *((struct fnic **) shost_priv(host)); struct pci_dev *l_pdev = fnic->pdev; int intr_mode = fnic->config.intr_mode; struct blk_mq_queue_map *qmap = &host->tag_set.map[HCTX_TYPE_DEFAULT]; if (intr_mode == VNIC_DEV_INTR_MODE_MSI || intr_mode == VNIC_DEV_INTR_MODE_INTX) { - FNIC_MAIN_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_MAIN_DBG(KERN_ERR, fnic, "intr_mode is not msix\n"); return; } - FNIC_MAIN_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_MAIN_DBG(KERN_INFO, fnic, "qmap->nr_queues: %d\n", qmap->nr_queues); if (l_pdev == NULL) { - FNIC_MAIN_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_MAIN_DBG(KERN_ERR, fnic, "l_pdev is null\n"); return; } - blk_mq_map_hw_queues(qmap, &l_pdev->dev, FNIC_PCI_OFFSET); + for_each_possible_cpu(cpu) + qmap->mq_map[cpu] = 0; + + /* + * Setup CPU to Queue mapping for all managed MSI-X IRQs. + * Q0 is driver critical and non-managed, hence start from Q1. + */ + for (queue = 1; queue < qmap->nr_queues; queue++) { + int irq_num = pci_irq_vector(fnic->pdev, + queue + FNIC_PCI_OFFSET); + + if (irq_num < 0) + continue; + + mask = pci_irq_get_affinity(fnic->pdev, + queue + FNIC_PCI_OFFSET); + if (!mask) { + shost_printk(KERN_ERR, host, + "failed to get irq_affinity map for queue:%d\n", irq_num); + continue; + } + FNIC_MAIN_DBG(KERN_INFO, fnic, + "got irq_affinity map for %d:\n", irq_num); + for_each_cpu(cpu, mask) { + qmap->mq_map[cpu] = qmap->queue_offset + queue; + FNIC_MAIN_DBG(KERN_INFO, fnic, + "[Q%d] cpu:%d <=> irq:%d\n", + queue, cpu, irq_num); + } + } } static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 75b29a018d1f..57fa0a6d36c2 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -148,7 +148,7 @@ unsigned int fnic_count_ioreqs(struct fnic *fnic, u32 portid) fnic_scsi_io_iter(fnic, fnic_count_portid_ioreqs_iter, &portid, &count); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "portid = 0x%x count = %u\n", portid, count); return count; } @@ -180,7 +180,7 @@ fnic_count_lun_ioreqs(struct fnic *fnic, struct scsi_device *scsi_device) fnic_scsi_io_iter(fnic, fnic_count_lun_ioreqs_iter, scsi_device, &count); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "lun = %p count = %u\n", scsi_device, count); return count; } @@ -268,7 +268,7 @@ int fnic_fw_reset_handler(struct fnic *fnic) if (!vnic_wq_copy_desc_avail(wq)) ret = -EAGAIN; else { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "ioreq_count: %u\n", ioreq_count); fnic_queue_wq_copy_desc_fw_reset(wq, SCSI_NO_TAG); atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); @@ -283,11 +283,11 @@ int fnic_fw_reset_handler(struct fnic *fnic) if (!ret) { atomic64_inc(&fnic->fnic_stats.reset_stats.fw_resets); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "Issued fw reset\n"); } else { fnic_clear_state_flags(fnic, FNIC_FLAGS_FWRESET); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "Failed to issue fw reset\n"); } @@ -326,13 +326,13 @@ int fnic_flogi_reg_handler(struct fnic *fnic, u32 fc_id) fc_id, gw_mac, fnic->iport.fpma, iport->r_a_tov, iport->e_d_tov); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "FLOGI FIP reg issued fcid: 0x%x src %p dest %p\n", fc_id, fnic->iport.fpma, gw_mac); } else { fnic_queue_wq_copy_desc_flogi_reg(wq, SCSI_NO_TAG, format, fc_id, gw_mac); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "FLOGI reg issued fcid 0x%x dest %p\n", fc_id, gw_mac); } @@ -413,7 +413,7 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, free_wq_copy_descs(fnic, wq, hwq); if (unlikely(!vnic_wq_copy_desc_avail(wq))) { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "fnic_queue_wq_copy_desc failure - no descriptors\n"); atomic64_inc(&misc_stats->io_cpwq_alloc_failures); return SCSI_MLQUEUE_HOST_BUSY; @@ -478,7 +478,7 @@ int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) rport = starget_to_rport(scsi_target(sc->device)); if (!rport) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "returning DID_NO_CONNECT for IO as rport is NULL\n"); sc->result = DID_NO_CONNECT << 16; done(sc); @@ -487,7 +487,7 @@ int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) ret = fc_remote_port_chkready(rport); if (ret) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "rport is not ready\n"); atomic64_inc(&fnic_stats->misc_stats.tport_not_ready); sc->result = ret; @@ -501,7 +501,7 @@ int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) if (iport->state != FNIC_IPORT_STATE_READY) { spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "returning DID_NO_CONNECT for IO as iport state: %d\n", iport->state); sc->result = DID_NO_CONNECT << 16; @@ -515,13 +515,13 @@ int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) rdd_data = rport->dd_data; tport = rdd_data->tport; if (!tport || (rdd_data->iport != iport)) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "dd_data not yet set in SCSI for rport portid: 0x%x\n", rport->port_id); tport = fnic_find_tport_by_fcid(iport, rport->port_id); if (!tport) { spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "returning DID_BUS_BUSY for IO as tport not found for: 0x%x\n", rport->port_id); sc->result = DID_BUS_BUSY << 16; @@ -544,7 +544,7 @@ int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) if ((tport->state != FDLS_TGT_STATE_READY) && (tport->state != FDLS_TGT_STATE_ADISC)) { spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "returning DID_NO_CONNECT for IO as tport state: %d\n", tport->state); sc->result = DID_NO_CONNECT << 16; @@ -564,7 +564,7 @@ int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_FWRESET))) { spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "fnic flags FW reset: 0x%lx. Returning SCSI_MLQUEUE_HOST_BUSY\n", fnic->state_flags); return SCSI_MLQUEUE_HOST_BUSY; @@ -706,7 +706,7 @@ int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) atomic_dec(&tport->in_flight); if (lun0_delay) { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "LUN0 delay\n"); mdelay(LUN0_DELAY_TIME); } @@ -746,12 +746,12 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic, if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) { /* Check status of reset completion */ if (!hdr_status) { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "reset cmpl success\n"); /* Ready to send flogi out */ fnic->state = FNIC_IN_ETH_MODE; } else { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "reset failed with header status: %s\n", fnic_fcpio_status_to_str(hdr_status)); @@ -760,7 +760,7 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic, ret = -1; } } else { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "Unexpected state while processing reset completion: %s\n", fnic_state_to_str(fnic->state)); atomic64_inc(&reset_stats->fw_reset_failures); @@ -812,19 +812,18 @@ static int fnic_fcpio_flogi_reg_cmpl_handler(struct fnic *fnic, /* Check flogi registration completion status */ if (!hdr_status) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "FLOGI reg succeeded\n"); fnic->state = FNIC_IN_FC_MODE; } else { - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "fnic flogi reg failed: %s\n", fnic_fcpio_status_to_str(hdr_status)); fnic->state = FNIC_IN_ETH_MODE; ret = -1; } } else { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "Unexpected fnic state %s while" " processing flogi reg completion\n", fnic_state_to_str(fnic->state)); @@ -935,19 +934,19 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind hwq = blk_mq_unique_tag_to_hwq(mqtag); if (hwq != cq_index) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ", hwq, mqtag, tag, cq_index); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hdr status: %s icmnd completion on the wrong queue\n", fnic_fcpio_status_to_str(hdr_status)); } if (tag >= fnic->fnic_max_tag_id) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ", hwq, mqtag, tag, cq_index); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hdr status: %s Out of range tag\n", fnic_fcpio_status_to_str(hdr_status)); return; @@ -959,7 +958,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind if (!sc) { atomic64_inc(&fnic_stats->io_stats.sc_null); spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); - shost_printk(KERN_ERR, fnic->host, + fnic_printk(KERN_ERR, fnic, "icmnd_cmpl sc is null - " "hdr status = %s tag = 0x%x desc = 0x%p\n", fnic_fcpio_status_to_str(hdr_status), id, desc); @@ -987,7 +986,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind atomic64_inc(&fnic_stats->io_stats.ioreq_null); fnic_priv(sc)->flags |= FNIC_IO_REQ_NULL; spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); - shost_printk(KERN_ERR, fnic->host, + fnic_printk(KERN_ERR, fnic, "icmnd_cmpl io_req is null - " "hdr status = %s tag = 0x%x sc 0x%p\n", fnic_fcpio_status_to_str(hdr_status), id, sc); @@ -1014,7 +1013,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind if(FCPIO_ABORTED == hdr_status) fnic_priv(sc)->flags |= FNIC_IO_ABORTED; - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "icmnd_cmpl abts pending " "hdr status = %s tag = 0x%x sc = 0x%p " "scsi_status = %x residual = %d\n", @@ -1046,7 +1045,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind if (icmnd_cmpl->scsi_status == SAM_STAT_TASK_SET_FULL) atomic64_inc(&fnic_stats->misc_stats.queue_fulls); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "xfer_len: %llu", xfer_len); break; @@ -1109,7 +1108,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind if (hdr_status != FCPIO_SUCCESS) { atomic64_inc(&fnic_stats->io_stats.io_failures); - shost_printk(KERN_ERR, fnic->host, "hdr status = %s\n", + fnic_printk(KERN_ERR, fnic, "hdr status = %s\n", fnic_fcpio_status_to_str(hdr_status)); } @@ -1202,27 +1201,27 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde hwq = blk_mq_unique_tag_to_hwq(id & FNIC_TAG_MASK); if (hwq != cq_index) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ", hwq, mqtag, tag, cq_index); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hdr status: %s ITMF completion on the wrong queue\n", fnic_fcpio_status_to_str(hdr_status)); } if (tag > fnic->fnic_max_tag_id) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ", hwq, mqtag, tag, cq_index); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hdr status: %s Tag out of range\n", fnic_fcpio_status_to_str(hdr_status)); return; } else if ((tag == fnic->fnic_max_tag_id) && !(id & FNIC_TAG_DEV_RST)) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ", hwq, mqtag, tag, cq_index); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hdr status: %s Tag out of range\n", fnic_fcpio_status_to_str(hdr_status)); return; @@ -1245,7 +1244,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde if (!sc) { atomic64_inc(&fnic_stats->io_stats.sc_null); spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); - shost_printk(KERN_ERR, fnic->host, + fnic_printk(KERN_ERR, fnic, "itmf_cmpl sc is null - hdr status = %s tag = 0x%x\n", fnic_fcpio_status_to_str(hdr_status), tag); return; @@ -1257,7 +1256,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde atomic64_inc(&fnic_stats->io_stats.ioreq_null); spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_REQ_NULL; - shost_printk(KERN_ERR, fnic->host, + fnic_printk(KERN_ERR, fnic, "itmf_cmpl io_req is null - " "hdr status = %s tag = 0x%x sc 0x%p\n", fnic_fcpio_status_to_str(hdr_status), tag, sc); @@ -1268,7 +1267,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde if ((id & FNIC_TAG_ABORT) && (id & FNIC_TAG_DEV_RST)) { /* Abort and terminate completion of device reset req */ /* REVISIT : Add asserts about various flags */ - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x hst: %s Abt/term completion received\n", hwq, mqtag, tag, fnic_fcpio_status_to_str(hdr_status)); @@ -1280,7 +1279,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); } else if (id & FNIC_TAG_ABORT) { /* Completion of abort cmd */ - shost_printk(KERN_DEBUG, fnic->host, + fnic_printk(KERN_DEBUG, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x Abort header status: %s\n", hwq, mqtag, tag, fnic_fcpio_status_to_str(hdr_status)); @@ -1295,7 +1294,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde &term_stats->terminate_fw_timeouts); break; case FCPIO_ITMF_REJECTED: - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "abort reject recd. id %d\n", (int)(id & FNIC_TAG_MASK)); break; @@ -1330,7 +1329,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde if (!(fnic_priv(sc)->flags & (FNIC_IO_ABORTED | FNIC_IO_DONE))) atomic64_inc(&misc_stats->no_icmnd_itmf_cmpls); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "abts cmpl recd. id %d status %s\n", (int)(id & FNIC_TAG_MASK), fnic_fcpio_status_to_str(hdr_status)); @@ -1343,11 +1342,11 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde if (io_req->abts_done) { complete(io_req->abts_done); spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); - shost_printk(KERN_INFO, fnic->host, + fnic_printk(KERN_INFO, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x Waking up abort thread\n", hwq, mqtag, tag); } else { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x hst: %s Completing IO\n", hwq, mqtag, tag, fnic_fcpio_status_to_str(hdr_status)); @@ -1378,7 +1377,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde } } else if (id & FNIC_TAG_DEV_RST) { /* Completion of device reset */ - shost_printk(KERN_INFO, fnic->host, + fnic_printk(KERN_INFO, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x DR hst: %s\n", hwq, mqtag, tag, fnic_fcpio_status_to_str(hdr_status)); @@ -1390,7 +1389,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde sc->device->host->host_no, id, sc, jiffies_to_msecs(jiffies - start_time), desc, 0, fnic_flags_and_state(sc)); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x hst: %s Terminate pending\n", hwq, mqtag, tag, fnic_fcpio_status_to_str(hdr_status)); @@ -1403,7 +1402,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde sc->device->host->host_no, id, sc, jiffies_to_msecs(jiffies - start_time), desc, 0, fnic_flags_and_state(sc)); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "dev reset cmpl recd after time out. " "id %d status %s\n", (int)(id & FNIC_TAG_MASK), @@ -1412,7 +1411,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde } fnic_priv(sc)->state = FNIC_IOREQ_CMD_COMPLETE; fnic_priv(sc)->flags |= FNIC_DEV_RST_DONE; - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x hst: %s DR completion received\n", hwq, mqtag, tag, fnic_fcpio_status_to_str(hdr_status)); @@ -1421,7 +1420,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); } else { - shost_printk(KERN_ERR, fnic->host, + fnic_printk(KERN_ERR, fnic, "%s: Unexpected itmf io state: hwq: %d tag 0x%x %s\n", __func__, hwq, id, fnic_ioreq_state_to_str(fnic_priv(sc)->state)); spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); @@ -1476,7 +1475,7 @@ static int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev, break; default: - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "firmware completion type %d\n", desc->hdr.type); break; @@ -1537,7 +1536,7 @@ static bool fnic_cleanup_io_iter(struct scsi_cmnd *sc, void *data) io_req = fnic_priv(sc)->io_req; if (!io_req) { spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hwq: %d mqtag: 0x%x tag: 0x%x flags: 0x%x No ioreq. Returning\n", hwq, mqtag, tag, fnic_priv(sc)->flags); return true; @@ -1575,7 +1574,7 @@ static bool fnic_cleanup_io_iter(struct scsi_cmnd *sc, void *data) mempool_free(io_req, fnic->io_req_pool); sc->result = DID_TRANSPORT_DISRUPTED << 16; - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "mqtag: 0x%x tag: 0x%x sc: 0x%p duration = %lu DID_TRANSPORT_DISRUPTED\n", mqtag, tag, sc, (jiffies - start_time)); @@ -1607,7 +1606,7 @@ static void fnic_cleanup_io(struct fnic *fnic, int exclude_id) struct scsi_cmnd *sc = NULL; io_count = fnic_count_all_ioreqs(fnic); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "Outstanding ioreq count: %d active io count: %lld Waiting\n", io_count, atomic64_read(&fnic->fnic_stats.io_stats.active_ios)); @@ -1632,7 +1631,7 @@ static void fnic_cleanup_io(struct fnic *fnic, int exclude_id) spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); while ((io_count = fnic_count_all_ioreqs(fnic))) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "Outstanding ioreq count: %d active io count: %lld Waiting\n", io_count, atomic64_read(&fnic->fnic_stats.io_stats.active_ios)); @@ -1688,7 +1687,7 @@ void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, wq_copy_cleanup_scsi_cmd: sc->result = DID_NO_CONNECT << 16; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, "wq_copy_cleanup_handler:" + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "wq_copy_cleanup_handler:" " DID_NO_CONNECT\n"); FNIC_TRACE(fnic_wq_copy_cleanup_handler, @@ -1732,7 +1731,7 @@ static inline int fnic_queue_abort_io_req(struct fnic *fnic, int tag, spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); atomic_dec(&fnic->in_flight); atomic_dec(&tport->in_flight); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "fnic_queue_abort_io_req: failure: no descriptors\n"); atomic64_inc(&misc_stats->abts_cpwq_alloc_failures); return 1; @@ -1777,7 +1776,7 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data) hwq = blk_mq_unique_tag_to_hwq(abt_tag); if (!sc) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "sc is NULL abt_tag: 0x%x hwq: %d\n", abt_tag, hwq); return true; } @@ -1791,7 +1790,7 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data) if ((fnic_priv(sc)->flags & FNIC_DEVICE_RESET) && !(fnic_priv(sc)->flags & FNIC_DEV_RST_ISSUED)) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hwq: %d abt_tag: 0x%x flags: 0x%x Device reset is not pending\n", hwq, abt_tag, fnic_priv(sc)->flags); spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); @@ -1808,16 +1807,16 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data) } if (io_req->abts_done) { - shost_printk(KERN_ERR, fnic->host, + fnic_printk(KERN_ERR, fnic, "fnic_rport_exch_reset: io_req->abts_done is set state is %s\n", fnic_ioreq_state_to_str(fnic_priv(sc)->state)); } if (!(fnic_priv(sc)->flags & FNIC_IO_ISSUED)) { - shost_printk(KERN_ERR, fnic->host, + fnic_printk(KERN_ERR, fnic, "rport_exch_reset IO not yet issued %p abt_tag 0x%x", sc, abt_tag); - shost_printk(KERN_ERR, fnic->host, + fnic_printk(KERN_ERR, fnic, "flags %x state %d\n", fnic_priv(sc)->flags, fnic_priv(sc)->state); } @@ -1828,13 +1827,13 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data) if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) { atomic64_inc(&reset_stats->device_reset_terminates); abt_tag |= FNIC_TAG_DEV_RST; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "dev reset sc 0x%p\n", sc); } - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "fnic_rport_exch_reset: dev rst sc 0x%p\n", sc); WARN_ON_ONCE(io_req->abts_done); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "fnic_rport_reset_exch: Issuing abts\n"); spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); @@ -1852,7 +1851,7 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data) * lun reset */ spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hwq: %d abt_tag: 0x%x flags: 0x%x Queuing abort failed\n", hwq, abt_tag, fnic_priv(sc)->flags); if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) @@ -1883,7 +1882,7 @@ void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id) .term_cnt = 0, }; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "fnic rport exchange reset for tport: 0x%06x\n", port_id); @@ -1891,7 +1890,7 @@ void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id) return; io_count = fnic_count_ioreqs(fnic, port_id); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "Starting terminates: rport:0x%x portid-io-count: %d active-io-count: %lld\n", port_id, io_count, atomic64_read(&fnic->fnic_stats.io_stats.active_ios)); @@ -1917,7 +1916,7 @@ void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id) while ((io_count = fnic_count_ioreqs(fnic, port_id))) schedule_timeout(msecs_to_jiffies(1000)); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "rport: 0x%x remaining portid-io-count: %d ", port_id, io_count); } @@ -1974,8 +1973,7 @@ void fnic_scsi_unload(struct fnic *fnic) spin_unlock_irqrestore(&fnic->fnic_lock, flags); if (fdls_get_state(&fnic->iport.fabric) != FDLS_STATE_INIT) - fnic_scsi_fcpio_reset(fnic); - + fnic_fcpio_reset(fnic); spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->in_remove = 1; spin_unlock_irqrestore(&fnic->fnic_lock, flags); @@ -2046,10 +2044,10 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) tport = rdd_data->tport; if (!tport) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "Abort cmd called after tport delete! rport fcid: 0x%x", rport->port_id); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "lun: %llu hwq: 0x%x mqtag: 0x%x Op: 0x%x flags: 0x%x\n", sc->device->lun, hwq, mqtag, sc->cmnd[0], fnic_priv(sc)->flags); @@ -2058,18 +2056,18 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) goto fnic_abort_cmd_end; } - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "Abort cmd called rport fcid: 0x%x lun: %llu hwq: 0x%x mqtag: 0x%x", rport->port_id, sc->device->lun, hwq, mqtag); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "Op: 0x%x flags: 0x%x\n", sc->cmnd[0], fnic_priv(sc)->flags); if (iport->state != FNIC_IPORT_STATE_READY) { atomic64_inc(&fnic_stats->misc_stats.iport_not_ready); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "iport NOT in READY state"); ret = FAILED; spin_unlock_irqrestore(&fnic->fnic_lock, flags); @@ -2078,7 +2076,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) if ((tport->state != FDLS_TGT_STATE_READY) && (tport->state != FDLS_TGT_STATE_ADISC)) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "tport state: %d\n", tport->state); ret = FAILED; spin_unlock_irqrestore(&fnic->fnic_lock, flags); @@ -2129,7 +2127,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) else atomic64_inc(&abts_stats->abort_issued_greater_than_60_sec); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "CDB Opcode: 0x%02x Abort issued time: %lu msec\n", sc->cmnd[0], abt_issued_time); /* @@ -2220,7 +2218,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) if (!(fnic_priv(sc)->flags & (FNIC_IO_ABORTED | FNIC_IO_DONE))) { spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "Issuing host reset due to out of order IO\n"); ret = FAILED; @@ -2268,7 +2266,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), fnic_flags_and_state(sc)); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "Returning from abort cmd type %x %s\n", task_req, (ret == SUCCESS) ? "SUCCESS" : "FAILED"); @@ -2309,7 +2307,7 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic, free_wq_copy_descs(fnic, wq, hwq); if (!vnic_wq_copy_desc_avail(wq)) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "queue_dr_io_req failure - no descriptors\n"); atomic64_inc(&misc_stats->devrst_cpwq_alloc_failures); ret = -EAGAIN; @@ -2377,7 +2375,7 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) * Found IO that is still pending with firmware and * belongs to the LUN that we are resetting */ - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "Found IO in %s on lun\n", fnic_ioreq_state_to_str(fnic_priv(sc)->state)); @@ -2387,14 +2385,14 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) } if ((fnic_priv(sc)->flags & FNIC_DEVICE_RESET) && (!(fnic_priv(sc)->flags & FNIC_DEV_RST_ISSUED))) { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "dev rst not pending sc 0x%p\n", sc); spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); return true; } if (io_req->abts_done) - shost_printk(KERN_ERR, fnic->host, + fnic_printk(KERN_ERR, fnic, "%s: io_req->abts_done is set state is %s\n", __func__, fnic_ioreq_state_to_str(fnic_priv(sc)->state)); old_ioreq_state = fnic_priv(sc)->state; @@ -2410,7 +2408,7 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) BUG_ON(io_req->abts_done); if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "dev rst sc 0x%p\n", sc); } @@ -2432,7 +2430,7 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) fnic_priv(sc)->state = old_ioreq_state; spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); iter_data->ret = FAILED; - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "hwq: %d abt_tag: 0x%lx Abort could not be queued\n", hwq, abt_tag); return false; @@ -2524,7 +2522,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, ret = 1; clean_pending_aborts_end: - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "exit status: %d\n", ret); return ret; } @@ -2574,7 +2572,7 @@ int fnic_device_reset(struct scsi_cmnd *sc) rport = starget_to_rport(scsi_target(sc->device)); spin_lock_irqsave(&fnic->fnic_lock, flags); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "fcid: 0x%x lun: %llu hwq: %d mqtag: 0x%x flags: 0x%x Device reset\n", rport->port_id, sc->device->lun, hwq, mqtag, fnic_priv(sc)->flags); @@ -2582,7 +2580,7 @@ int fnic_device_reset(struct scsi_cmnd *sc) rdd_data = rport->dd_data; tport = rdd_data->tport; if (!tport) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "Dev rst called after tport delete! rport fcid: 0x%x lun: %llu\n", rport->port_id, sc->device->lun); spin_unlock_irqrestore(&fnic->fnic_lock, flags); @@ -2591,7 +2589,7 @@ int fnic_device_reset(struct scsi_cmnd *sc) if (iport->state != FNIC_IPORT_STATE_READY) { atomic64_inc(&fnic_stats->misc_stats.iport_not_ready); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "iport NOT in READY state"); spin_unlock_irqrestore(&fnic->fnic_lock, flags); goto fnic_device_reset_end; @@ -2599,7 +2597,7 @@ int fnic_device_reset(struct scsi_cmnd *sc) if ((tport->state != FDLS_TGT_STATE_READY) && (tport->state != FDLS_TGT_STATE_ADISC)) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "tport state: %d\n", tport->state); spin_unlock_irqrestore(&fnic->fnic_lock, flags); goto fnic_device_reset_end; @@ -2662,7 +2660,7 @@ int fnic_device_reset(struct scsi_cmnd *sc) fnic_priv(sc)->lr_status = FCPIO_INVALID_CODE; spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, "TAG %x\n", mqtag); + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "TAG %x\n", mqtag); /* * issue the device reset, if enqueue failed, clean up the ioreq @@ -2713,13 +2711,13 @@ int fnic_device_reset(struct scsi_cmnd *sc) io_req = fnic_priv(sc)->io_req; if (!io_req) { spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "io_req is null mqtag 0x%x sc 0x%p\n", mqtag, sc); goto fnic_device_reset_end; } if (exit_dr) { - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "Host reset called for fnic. Exit device reset\n"); io_req->dr_done = NULL; goto fnic_device_reset_clean; @@ -2734,7 +2732,7 @@ int fnic_device_reset(struct scsi_cmnd *sc) */ if (status == FCPIO_INVALID_CODE) { atomic64_inc(&reset_stats->device_reset_timeouts); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "Device reset timed out\n"); fnic_priv(sc)->flags |= FNIC_DEV_RST_TIMED_OUT; int_to_scsilun(sc->device->lun, &fc_lun); @@ -2746,8 +2744,7 @@ int fnic_device_reset(struct scsi_cmnd *sc) /* Completed, but not successful, clean up the io_req, return fail */ if (status != FCPIO_SUCCESS) { spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "Device reset completed - failed\n"); io_req = fnic_priv(sc)->io_req; goto fnic_device_reset_clean; @@ -2763,7 +2760,7 @@ int fnic_device_reset(struct scsi_cmnd *sc) if (fnic_clean_pending_aborts(fnic, sc, new_sc)) { spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "Device reset failed: Cannot abort all IOs\n"); goto fnic_device_reset_clean; } @@ -2817,13 +2814,13 @@ int fnic_device_reset(struct scsi_cmnd *sc) ret = FAILED; break; } - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "Cannot clean up all IOs for the LUN\n"); schedule_timeout(msecs_to_jiffies(1000)); count++; } - FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_DEBUG, fnic, "Returning from device reset %s\n", (ret == SUCCESS) ? "SUCCESS" : "FAILED"); @@ -2858,13 +2855,13 @@ void fnic_reset(struct Scsi_Host *shost) fnic = *((struct fnic **) shost_priv(shost)); reset_stats = &fnic->fnic_stats.reset_stats; - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "Issuing fnic reset\n"); atomic64_inc(&reset_stats->fnic_resets); fnic_post_flogo_linkflap(fnic); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "Returning from fnic reset"); atomic64_inc(&reset_stats->fnic_reset_completions); @@ -2875,7 +2872,7 @@ int fnic_issue_fc_host_lip(struct Scsi_Host *shost) int ret = 0; struct fnic *fnic = *((struct fnic **) shost_priv(shost)); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "FC host lip issued"); ret = fnic_host_reset(shost); @@ -2901,7 +2898,7 @@ int fnic_host_reset(struct Scsi_Host *shost) spin_lock_irqsave(&fnic->fnic_lock, flags); if (fnic->reset_in_progress == IN_PROGRESS) { spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_SCSI_DBG(KERN_WARNING, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_WARNING, fnic, "Firmware reset in progress. Skipping another host reset\n"); return SUCCESS; } @@ -2939,7 +2936,7 @@ int fnic_host_reset(struct Scsi_Host *shost) } spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "host reset return status: %d\n", ret); return ret; } @@ -2979,7 +2976,7 @@ static bool fnic_abts_pending_iter(struct scsi_cmnd *sc, void *data) * Found IO that is still pending with firmware and * belongs to the LUN that we are resetting */ - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_INFO, fnic, "hwq: %d tag: 0x%x Found IO in state: %s on lun\n", hwq, tag, fnic_ioreq_state_to_str(fnic_priv(sc)->state)); @@ -3033,60 +3030,9 @@ int fnic_eh_host_reset_handler(struct scsi_cmnd *sc) struct Scsi_Host *shost = sc->device->host; struct fnic *fnic = *((struct fnic **) shost_priv(shost)); - FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num, + FNIC_SCSI_DBG(KERN_ERR, fnic, "SCSI error handling: fnic host reset"); ret = fnic_host_reset(shost); return ret; } - - -void fnic_scsi_fcpio_reset(struct fnic *fnic) -{ - unsigned long flags; - enum fnic_state old_state; - struct fnic_iport_s *iport = &fnic->iport; - DECLARE_COMPLETION_ONSTACK(fw_reset_done); - int time_remain; - - /* issue fw reset */ - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE)) { - /* fw reset is in progress, poll for its completion */ - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "fnic is in unexpected state: %d for fw_reset\n", - fnic->state); - return; - } - - old_state = fnic->state; - fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; - - fnic_update_mac_locked(fnic, iport->hwmac); - fnic->fw_reset_done = &fw_reset_done; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "Issuing fw reset\n"); - if (fnic_fw_reset_handler(fnic)) { - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) - fnic->state = old_state; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - } else { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "Waiting for fw completion\n"); - time_remain = wait_for_completion_timeout(&fw_reset_done, - msecs_to_jiffies(FNIC_FW_RESET_TIMEOUT)); - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "Woken up after fw completion timeout\n"); - if (time_remain == 0) { - FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num, - "FW reset completion timed out after %d ms)\n", - FNIC_FW_RESET_TIMEOUT); - } - atomic64_inc(&fnic->fnic_stats.reset_stats.fw_reset_timeouts); - } - fnic->fw_reset_done = NULL; -} diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3e148e4e9459..07ccfe0226c5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -351,7 +351,7 @@ MODULE_PARM_DESC(ql2xnvme_queues, int ql2xfc2target = 1; module_param(ql2xfc2target, int, 0444); -MODULE_PARM_DESC(qla2xfc2target, +MODULE_PARM_DESC(ql2xfc2target, "Enables FC2 Target support. " "0 - FC2 Target support is disabled. " "1 - FC2 Target support is enabled (default)."); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 9a0f467264b3..c122a78afccf 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -722,6 +722,7 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable) struct scsi_mode_data data; struct scsi_sense_hdr sshdr; char *buf_data; + size_t avail, offset; int len; ret = scsi_mode_sense(sdev, 0x08, 0x0a, 0xf2, buf, sizeof(buf), @@ -730,11 +731,24 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable) return -EINVAL; /* Enable or disable CDL using the ATA feature page */ - len = min_t(size_t, sizeof(buf), - data.length - data.header_length - - data.block_descriptor_length); - buf_data = buf + data.header_length + - data.block_descriptor_length; + avail = min_t(size_t, data.length, sizeof(buf)); + if (data.header_length > avail) + return -EINVAL; + + offset = data.header_length; + avail -= data.header_length; + + if (data.block_descriptor_length > avail) + return -EINVAL; + + offset += data.block_descriptor_length; + avail -= data.block_descriptor_length; + + if (avail < 5) + return -EINVAL; + + buf_data = buf + offset; + len = avail; /* * If we want to enable CDL and CDL is already enabled on the diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c index d91049973113..0fcbc08633f6 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -540,13 +540,12 @@ static struct notifier_block exynos_cpupm_reboot_nb = { static int setup_cpuhp_and_cpuidle(struct device *dev) { - struct device_node *intr_gen_node; + struct device_node *intr_gen_node __free(device_node) = + of_parse_phandle(dev->of_node, "google,pmu-intr-gen-syscon", 0); struct resource intrgen_res; void __iomem *virt_addr; int ret, cpu; - intr_gen_node = of_parse_phandle(dev->of_node, - "google,pmu-intr-gen-syscon", 0); if (!intr_gen_node) { /* * To maintain support for older DTs that didn't specify syscon @@ -562,8 +561,6 @@ static int setup_cpuhp_and_cpuidle(struct device *dev) * syscon provided regmap. */ ret = of_address_to_resource(intr_gen_node, 0, &intrgen_res); - of_node_put(intr_gen_node); - virt_addr = devm_ioremap(dev, intrgen_res.start, resource_size(&intrgen_res)); if (!virt_addr) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index d7a0a14ad962..9c7296afd711 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1702,6 +1702,13 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) return 0; } + /* + * wait for any in-flight peripheral event handling to complete before stopping the clock. + * No need to disable peripheral interrupts before canceling the work, as the peripheral + * interrupts are already masked before the work is scheduled. + */ + cancel_work_sync(&cdns->work); + /* * Before entering clock stop we mask the Slave * interrupts. This helps avoid having to deal with e.g. a diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c index 3904d64ed433..cfcf2bc796a1 100644 --- a/drivers/spi/spi-fsl-qspi.c +++ b/drivers/spi/spi-fsl-qspi.c @@ -271,6 +271,7 @@ struct fsl_qspi { struct pm_qos_request pm_qos_req; struct device *dev; int selected; + u32 selected_freq; u32 memmap_phy; }; @@ -528,7 +529,8 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi, unsigned long rate = op->max_freq; int ret; - if (q->selected == spi_get_chipselect(spi, 0)) + if (q->selected == spi_get_chipselect(spi, 0) && + q->selected_freq == op->max_freq) return; if (needs_4x_clock(q)) @@ -545,6 +547,7 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi, return; q->selected = spi_get_chipselect(spi, 0); + q->selected_freq = op->max_freq; fsl_qspi_invalidate(q); } diff --git a/drivers/spi/spi-qpic-snand.c b/drivers/spi/spi-qpic-snand.c index 42f8fb272fa6..222e4aa7ee48 100644 --- a/drivers/spi/spi-qpic-snand.c +++ b/drivers/spi/spi-qpic-snand.c @@ -740,8 +740,6 @@ static int qcom_spi_read_cw_raw(struct qcom_nand_controller *snandc, u8 *data_bu qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); - qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, 1, 0); - qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_clr, NAND_ERASED_CW_DETECT_CFG, 1, 0); qcom_write_reg_dma(snandc, &snandc->regs->erased_cw_detect_cfg_set, @@ -1012,8 +1010,6 @@ static void qcom_spi_config_page_write(struct qcom_nand_controller *snandc) { qcom_write_reg_dma(snandc, &snandc->regs->addr0, NAND_ADDR0, 2, 0); qcom_write_reg_dma(snandc, &snandc->regs->cfg0, NAND_DEV0_CFG0, 3, 0); - qcom_write_reg_dma(snandc, &snandc->regs->ecc_buf_cfg, NAND_EBI2_ECC_BUF_CFG, - 1, NAND_BAM_NEXT_SGL); } static void qcom_spi_config_cw_write(struct qcom_nand_controller *snandc) diff --git a/drivers/spi/spi-virtio.c b/drivers/spi/spi-virtio.c index fb30c9207a4b..06845bd3fe83 100644 --- a/drivers/spi/spi-virtio.c +++ b/drivers/spi/spi-virtio.c @@ -169,7 +169,7 @@ static int virtio_spi_transfer_one(struct spi_controller *ctrl, /* Fill struct spi_transfer_head */ th->chip_select_id = spi_get_chipselect(spi, 0); - th->bits_per_word = spi->bits_per_word; + th->bits_per_word = xfer->bits_per_word; th->cs_change = xfer->cs_change; th->tx_nbits = xfer->tx_nbits; th->rx_nbits = xfer->rx_nbits; diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index f9a1427dabad..5e23b10d82a7 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1374,11 +1374,45 @@ static void zynqmp_qspi_remove(struct platform_device *pdev) clk_disable_unprepare(xqspi->pclk); } +static void zynqmp_qspi_shutdown(struct platform_device *pdev) +{ + struct zynqmp_qspi *xqspi = platform_get_drvdata(pdev); + int ret; + + /* + * Stop the queue and reject any later transfer first, so the write + * below cannot cut into a message that is still being executed. + * Unlike ->suspend this cannot abort on error: a controller left + * mastering the bus is worse than a truncated transfer. + */ + ret = spi_controller_suspend(xqspi->ctlr); + if (ret) + dev_warn(&pdev->dev, "could not stop the queue: %d\n", ret); + + /* + * Only a runtime suspended controller can be left alone: its clocks + * are gated, so it cannot be mastering the bus, and its registers + * must not be accessed either. Any other answer means it may be + * running and has to be stopped. In particular, on a kernel built + * without runtime PM this returns -EINVAL, and there the clocks + * enabled in probe() are never gated at all. + */ + ret = pm_runtime_get_if_in_use(&pdev->dev); + if (!ret) + return; + + zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); + + if (ret > 0) + pm_runtime_put_noidle(&pdev->dev); +} + MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match); static struct platform_driver zynqmp_qspi_driver = { .probe = zynqmp_qspi_probe, .remove = zynqmp_qspi_remove, + .shutdown = zynqmp_qspi_shutdown, .driver = { .name = "zynqmp-qspi", .of_match_table = zynqmp_qspi_of_match, diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c index 426962547df1..4d558652e9e7 100644 --- a/drivers/watchdog/da9062_wdt.c +++ b/drivers/watchdog/da9062_wdt.c @@ -256,7 +256,7 @@ static int __maybe_unused da9062_wdt_suspend(struct device *dev) if (!wdt->use_sw_pm) return 0; - if (watchdog_active(wdd)) + if (watchdog_active(wdd) || watchdog_hw_running(wdd)) return da9062_wdt_stop(wdd); return 0; @@ -270,7 +270,7 @@ static int __maybe_unused da9062_wdt_resume(struct device *dev) if (!wdt->use_sw_pm) return 0; - if (watchdog_active(wdd)) + if (watchdog_active(wdd) || watchdog_hw_running(wdd)) return da9062_wdt_start(wdd); return 0; diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index 92e1b78ff481..3703110e82fc 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c @@ -271,7 +271,7 @@ static int da9063_wdt_suspend(struct device *dev) if (!da9063->use_sw_pm) return 0; - if (watchdog_active(wdd)) + if (watchdog_active(wdd) || watchdog_hw_running(wdd)) return da9063_wdt_stop(wdd); return 0; @@ -285,7 +285,7 @@ static int da9063_wdt_resume(struct device *dev) if (!da9063->use_sw_pm) return 0; - if (watchdog_active(wdd)) + if (watchdog_active(wdd) || watchdog_hw_running(wdd)) return da9063_wdt_start(wdd); return 0; diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c index 073d37867f47..de1a3267a972 100644 --- a/drivers/watchdog/digicolor_wdt.c +++ b/drivers/watchdog/digicolor_wdt.c @@ -25,6 +25,7 @@ struct dc_wdt { void __iomem *base; struct clk *clk; spinlock_t lock; + unsigned long rate; }; static unsigned timeout; @@ -61,7 +62,7 @@ static int dc_wdt_start(struct watchdog_device *wdog) { struct dc_wdt *wdt = watchdog_get_drvdata(wdog); - dc_wdt_set(wdt, wdog->timeout * clk_get_rate(wdt->clk)); + dc_wdt_set(wdt, wdog->timeout * wdt->rate); return 0; } @@ -79,7 +80,7 @@ static int dc_wdt_set_timeout(struct watchdog_device *wdog, unsigned int t) { struct dc_wdt *wdt = watchdog_get_drvdata(wdog); - dc_wdt_set(wdt, t * clk_get_rate(wdt->clk)); + dc_wdt_set(wdt, t * wdt->rate); wdog->timeout = t; return 0; @@ -90,7 +91,7 @@ static unsigned int dc_wdt_get_timeleft(struct watchdog_device *wdog) struct dc_wdt *wdt = watchdog_get_drvdata(wdog); uint32_t count = readl_relaxed(wdt->base + TIMER_A_COUNT); - return count / clk_get_rate(wdt->clk); + return count / wdt->rate; } static const struct watchdog_ops dc_wdt_ops = { @@ -130,7 +131,11 @@ static int dc_wdt_probe(struct platform_device *pdev) wdt->clk = devm_clk_get(dev, NULL); if (IS_ERR(wdt->clk)) return PTR_ERR(wdt->clk); - dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk); + + wdt->rate = clk_get_rate(wdt->clk); + if (!wdt->rate) + return -EINVAL; + dc_wdt_wdd.max_timeout = U32_MAX / wdt->rate; dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout; dc_wdt_wdd.parent = dev; diff --git a/drivers/watchdog/msc313e_wdt.c b/drivers/watchdog/msc313e_wdt.c index eea26c6c95d8..8aba7de823b5 100644 --- a/drivers/watchdog/msc313e_wdt.c +++ b/drivers/watchdog/msc313e_wdt.c @@ -47,6 +47,9 @@ static void msc313e_wdt_set_hw_timeout(struct msc313e_wdt_priv *priv, { u32 t = timeout * clk_get_rate(priv->clk); + /* Clear before to prevent premature reset during non-atomic updates. */ + writew(1, priv->base + REG_WDT_CLR); + writew(t & 0xffff, priv->base + REG_WDT_MAX_PRD_L); writew((t >> 16) & 0xffff, priv->base + REG_WDT_MAX_PRD_H); writew(1, priv->base + REG_WDT_CLR); @@ -77,6 +80,9 @@ static int msc313e_wdt_stop(struct watchdog_device *wdev) { struct msc313e_wdt_priv *priv = watchdog_get_drvdata(wdev); + /* Clear before to prevent premature reset during non-atomic updates. */ + writew(1, priv->base + REG_WDT_CLR); + writew(0, priv->base + REG_WDT_MAX_PRD_L); writew(0, priv->base + REG_WDT_MAX_PRD_H); writew(0, priv->base + REG_WDT_CLR); @@ -192,11 +198,15 @@ static int __maybe_unused msc313e_wdt_suspend(struct device *dev) static int __maybe_unused msc313e_wdt_resume(struct device *dev) { struct msc313e_wdt_priv *priv = dev_get_drvdata(dev); + int ret = 0; - if (watchdog_active(&priv->wdev) || watchdog_hw_running(&priv->wdev)) - msc313e_wdt_start(&priv->wdev); + if (watchdog_active(&priv->wdev) || watchdog_hw_running(&priv->wdev)) { + ret = msc313e_wdt_start(&priv->wdev); + if (ret) + dev_err(dev, "Failed to restart watchdog (err=%d)\n", ret); + } - return 0; + return ret; } static SIMPLE_DEV_PM_OPS(msc313e_wdt_pm_ops, msc313e_wdt_suspend, msc313e_wdt_resume); diff --git a/drivers/watchdog/rtd119x_wdt.c b/drivers/watchdog/rtd119x_wdt.c index 984905695dde..0bfadb58917b 100644 --- a/drivers/watchdog/rtd119x_wdt.c +++ b/drivers/watchdog/rtd119x_wdt.c @@ -98,6 +98,7 @@ static int rtd119x_wdt_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rtd119x_watchdog_device *data; + unsigned long rate; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -111,10 +112,14 @@ static int rtd119x_wdt_probe(struct platform_device *pdev) if (IS_ERR(data->clk)) return PTR_ERR(data->clk); + rate = clk_get_rate(data->clk); + if (!rate) + return -EINVAL; + data->wdt_dev.info = &rtd119x_wdt_info; data->wdt_dev.ops = &rtd119x_wdt_ops; data->wdt_dev.timeout = 120; - data->wdt_dev.max_timeout = 0xffffffff / clk_get_rate(data->clk); + data->wdt_dev.max_timeout = 0xffffffff / rate; data->wdt_dev.min_timeout = 1; data->wdt_dev.parent = dev; diff --git a/drivers/watchdog/rzv2h_wdt.c b/drivers/watchdog/rzv2h_wdt.c index f9bb4ef3d327..a1698dc50acd 100644 --- a/drivers/watchdog/rzv2h_wdt.c +++ b/drivers/watchdog/rzv2h_wdt.c @@ -280,6 +280,7 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct rzv2h_wdt_priv *priv; struct clk *count_clk; + unsigned long rate; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -316,8 +317,12 @@ static int rzv2h_wdt_probe(struct platform_device *pdev) return dev_err_probe(dev, -EINVAL, "Invalid count source\n"); } + rate = clk_get_rate(count_clk); + if (!rate) + return dev_err_probe(dev, -EINVAL, "Invalid clock rate\n"); + priv->wdev.max_hw_heartbeat_ms = (MILLI * priv->of_data->timeout_cycles * - priv->of_data->cks_div) / clk_get_rate(count_clk); + priv->of_data->cks_div) / rate; dev_dbg(dev, "max hw timeout of %dms\n", priv->wdev.max_hw_heartbeat_ms); ret = devm_pm_runtime_enable(dev); diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c index 7e99c3b1f367..72ad59649ccc 100644 --- a/drivers/watchdog/sp5100_tco.c +++ b/drivers/watchdog/sp5100_tco.c @@ -605,8 +605,10 @@ static int __init sp5100_tco_init(void) pr_info("SP5100/SB800 TCO WatchDog Timer Driver\n"); err = platform_driver_register(&sp5100_tco_driver); - if (err) + if (err) { + pci_dev_put(sp5100_tco_pci); return err; + } sp5100_tco_platform_device = platform_device_register_simple(TCO_DRIVER_NAME, -1, NULL, 0); @@ -619,6 +621,7 @@ static int __init sp5100_tco_init(void) unreg_platform_driver: platform_driver_unregister(&sp5100_tco_driver); + pci_dev_put(sp5100_tco_pci); return err; } @@ -626,6 +629,7 @@ static void __exit sp5100_tco_exit(void) { platform_device_unregister(sp5100_tco_platform_device); platform_driver_unregister(&sp5100_tco_driver); + pci_dev_put(sp5100_tco_pci); } module_init(sp5100_tco_init); diff --git a/drivers/watchdog/starfive-wdt.c b/drivers/watchdog/starfive-wdt.c index af55adc4a3c6..5a3254c83d3b 100644 --- a/drivers/watchdog/starfive-wdt.c +++ b/drivers/watchdog/starfive-wdt.c @@ -371,7 +371,7 @@ static void starfive_wdt_stop(struct starfive_wdt *wdt) static int starfive_wdt_pm_start(struct watchdog_device *wdd) { struct starfive_wdt *wdt = watchdog_get_drvdata(wdd); - int ret = pm_runtime_get_sync(wdd->parent); + int ret = pm_runtime_resume_and_get(wdd->parent); if (ret < 0) return ret; diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index 862164181bac..6bf5973445b6 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c @@ -54,11 +54,38 @@ static void v9fs_begin_writeback(struct netfs_io_request *wreq) static void v9fs_issue_write(struct netfs_io_subrequest *subreq) { struct p9_fid *fid = subreq->rreq->netfs_priv; + struct inode *inode = subreq->rreq->inode; + struct netfs_inode *ictx = netfs_inode(inode); int err, len; len = p9_client_write(fid, subreq->start, &subreq->io_iter, &err); - if (len > 0) + if (len > 0) { + unsigned long long end = subreq->start + len, i_size, remote; + bool set = false; + + spin_lock(&inode->i_lock); + + /* We can read the sizes directly as we hold i_lock. */ + i_size = inode->i_size; + remote = ictx->remote_i_size; + + if (end > i_size) { + i_size = end; + set = true; + } + if (end > remote) { + remote = end; + set = true; + } + + if (set) { + i_size_write(inode, i_size); + ictx->remote_i_size = remote; + } + spin_unlock(&inode->i_lock); + __set_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags); + } netfs_write_subrequest_terminated(subreq, len ?: err); } diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index b6c7da8e1bc8..8800918bf9f1 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -491,6 +491,7 @@ static int mark_block_group_to_copy(struct btrfs_fs_info *fs_info, path->reada = READA_FORWARD; path->search_commit_root = true; path->skip_locking = true; + path->need_commit_sem = true; key.objectid = src_dev->devid; key.type = BTRFS_DEV_EXTENT_KEY; diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 8863479a19d3..5396f900d5f1 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -2338,6 +2338,10 @@ static int validate_sys_chunk_array(const struct btrfs_fs_info *fs_info, key.type, cur); return -EUCLEAN; } + + if (unlikely(cur + sizeof(*chunk) > sys_array_size)) + goto short_read; + chunk = (struct btrfs_chunk *)(sb->sys_chunk_array + cur); num_stripes = btrfs_stack_chunk_num_stripes(chunk); if (unlikely(cur + btrfs_chunk_item_size(num_stripes) > sys_array_size)) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index a15062f976ba..19f0f9df038c 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2498,8 +2498,10 @@ int btrfs_replace_file_extents(struct btrfs_inode *inode, inode_set_ctime_current(&inode->vfs_inode)); ret = btrfs_update_inode(trans, inode); - if (ret) + if (unlikely(ret)) { + btrfs_abort_transaction(trans, ret); break; + } btrfs_end_transaction(trans); btrfs_btree_balance_dirty(fs_info); diff --git a/fs/btrfs/free-space-tree.c b/fs/btrfs/free-space-tree.c index fa8fbb19ff65..c1c7c793f291 100644 --- a/fs/btrfs/free-space-tree.c +++ b/fs/btrfs/free-space-tree.c @@ -1346,7 +1346,7 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info) if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); btrfs_end_transaction(trans); - return ret; + goto out_clear; } node = rb_first_cached(&fs_info->block_group_cache_tree); @@ -1364,14 +1364,16 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info) if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); btrfs_end_transaction(trans); - return ret; + goto out_clear; } next: if (btrfs_should_end_transaction(trans)) { btrfs_end_transaction(trans); trans = btrfs_start_transaction(free_space_root, 1); - if (IS_ERR(trans)) - return PTR_ERR(trans); + if (IS_ERR(trans)) { + ret = PTR_ERR(trans); + goto out_clear; + } } node = rb_next(node); } @@ -1383,6 +1385,10 @@ int btrfs_rebuild_free_space_tree(struct btrfs_fs_info *fs_info) ret = btrfs_commit_transaction(trans); clear_bit(BTRFS_FS_FREE_SPACE_TREE_UNTRUSTED, &fs_info->flags); return ret; + +out_clear: + clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags); + return ret; } static int __add_block_group_free_space(struct btrfs_trans_handle *trans, diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3023e1b504b9..6ab593b89319 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3789,7 +3789,8 @@ int btrfs_orphan_cleanup(struct btrfs_root *root) if (ret) goto out; } - trans = btrfs_start_transaction(root, 1); + /* Only deletes the orphan. */ + trans = btrfs_start_transaction_fallback_global_rsv(root, 1); if (IS_ERR(trans)) { ret = PTR_ERR(trans); goto out; diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c index 79f297d9ebc4..baaca330e5db 100644 --- a/fs/btrfs/tree-checker.c +++ b/fs/btrfs/tree-checker.c @@ -1925,7 +1925,7 @@ static int check_dev_extent_item(const struct extent_buffer *leaf, sectorsize))) { generic_err(leaf, slot, "invalid dev extent chunk offset, has %llu not aligned to %u", - btrfs_dev_extent_chunk_objectid(leaf, de), + btrfs_dev_extent_chunk_offset(leaf, de), sectorsize); return -EUCLEAN; } diff --git a/fs/btrfs/uuid-tree.c b/fs/btrfs/uuid-tree.c index 146d78fac8f8..a3c244ff3a0c 100644 --- a/fs/btrfs/uuid-tree.c +++ b/fs/btrfs/uuid-tree.c @@ -27,32 +27,26 @@ static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, const u8 *uuid, u8 type, u64 subid) { int ret; - struct btrfs_path *path = NULL; + BTRFS_PATH_AUTO_FREE(path); struct extent_buffer *eb; int slot; u32 item_size; unsigned long offset; struct btrfs_key key; - if (WARN_ON_ONCE(!uuid_root)) { - ret = -ENOENT; - goto out; - } + if (WARN_ON_ONCE(!uuid_root)) + return -ENOENT; path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } + if (!path) + return -ENOMEM; btrfs_uuid_to_key(uuid, type, &key); ret = btrfs_search_slot(NULL, uuid_root, &key, path, 0, 0); - if (ret < 0) { - goto out; - } else if (ret > 0) { - ret = -ENOENT; - goto out; - } + if (ret < 0) + return ret; + if (ret > 0) + return -ENOENT; eb = path->nodes[0]; slot = path->slots[0]; @@ -64,7 +58,7 @@ static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, const u8 *uuid, btrfs_warn(uuid_root->fs_info, "uuid item with illegal size %lu!", (unsigned long)item_size); - goto out; + return ret; } while (item_size) { __le64 data; @@ -78,8 +72,6 @@ static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, const u8 *uuid, item_size -= sizeof(data); } -out: - btrfs_free_path(path); return ret; } @@ -89,7 +81,7 @@ int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, const u8 *uuid, u8 typ struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *uuid_root = fs_info->uuid_root; int ret; - struct btrfs_path *path = NULL; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_key key; struct extent_buffer *eb; int slot; @@ -100,18 +92,14 @@ int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, const u8 *uuid, u8 typ if (ret != -ENOENT) return ret; - if (WARN_ON_ONCE(!uuid_root)) { - ret = -EINVAL; - goto out; - } + if (WARN_ON_ONCE(!uuid_root)) + return -EINVAL; btrfs_uuid_to_key(uuid, type, &key); path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } + if (!path) + return -ENOMEM; ret = btrfs_insert_empty_item(trans, uuid_root, path, &key, sizeof(subid_le)); @@ -134,15 +122,12 @@ int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, const u8 *uuid, u8 typ btrfs_warn(fs_info, "insert uuid item failed %d (0x%016llx, 0x%016llx) type %u!", ret, key.objectid, key.offset, type); - goto out; + return ret; } - ret = 0; subid_le = cpu_to_le64(subid_cpu); write_extent_buffer(eb, &subid_le, offset, sizeof(subid_le)); -out: - btrfs_free_path(path); - return ret; + return 0; } int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, const u8 *uuid, u8 type, @@ -151,7 +136,7 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, const u8 *uuid, u8 struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *uuid_root = fs_info->uuid_root; int ret; - struct btrfs_path *path = NULL; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_key key; struct extent_buffer *eb; int slot; @@ -161,29 +146,23 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, const u8 *uuid, u8 unsigned long move_src; unsigned long move_len; - if (WARN_ON_ONCE(!uuid_root)) { - ret = -EINVAL; - goto out; - } + if (WARN_ON_ONCE(!uuid_root)) + return -EINVAL; btrfs_uuid_to_key(uuid, type, &key); path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } + if (!path) + return -ENOMEM; ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1); if (ret < 0) { btrfs_warn(fs_info, "error %d while searching for uuid item!", ret); - goto out; - } - if (ret > 0) { - ret = -ENOENT; - goto out; + return ret; } + if (ret > 0) + return -ENOENT; eb = path->nodes[0]; slot = path->slots[0]; @@ -192,8 +171,7 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, const u8 *uuid, u8 if (!IS_ALIGNED(item_size, sizeof(u64))) { btrfs_warn(fs_info, "uuid item with illegal size %lu!", (unsigned long)item_size); - ret = -ENOENT; - goto out; + return -ENOENT; } while (item_size) { __le64 read_subid; @@ -205,16 +183,12 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, const u8 *uuid, u8 item_size -= sizeof(read_subid); } - if (!item_size) { - ret = -ENOENT; - goto out; - } + if (!item_size) + return -ENOENT; item_size = btrfs_item_size(eb, slot); - if (item_size == sizeof(subid)) { - ret = btrfs_del_item(trans, uuid_root, path); - goto out; - } + if (item_size == sizeof(subid)) + return btrfs_del_item(trans, uuid_root, path); move_dst = offset; move_src = offset + sizeof(subid); @@ -222,9 +196,7 @@ int btrfs_uuid_tree_remove(struct btrfs_trans_handle *trans, const u8 *uuid, u8 memmove_extent_buffer(eb, move_dst, move_src, move_len); btrfs_truncate_item(trans, path, item_size - sizeof(subid), 1); -out: - btrfs_free_path(path); - return ret; + return 0; } /* @@ -331,7 +303,7 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info) { struct btrfs_root *root = fs_info->uuid_root; struct btrfs_key key; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); int ret = 0; struct extent_buffer *leaf; int slot; @@ -339,10 +311,8 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info) unsigned long offset; path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } + if (!path) + return -ENOMEM; key.objectid = 0; key.type = 0; @@ -350,17 +320,15 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info) again_search_slot: ret = btrfs_search_forward(root, &key, path, BTRFS_OLDEST_GENERATION); - if (ret) { - if (ret > 0) - ret = 0; - goto out; - } + if (ret < 0) + return ret; + if (ret > 0) + return 0; while (1) { - if (btrfs_fs_closing(fs_info)) { - ret = -EINTR; - goto out; - } + if (btrfs_fs_closing(fs_info)) + return -EINTR; + cond_resched(); leaf = path->nodes[0]; slot = path->slots[0]; @@ -391,7 +359,7 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info) ret = btrfs_check_uuid_tree_entry(fs_info, uuid, key.type, subid_cpu); if (ret < 0) - goto out; + return ret; if (ret > 0) { btrfs_release_path(path); ret = btrfs_uuid_iter_rem(root, uuid, key.type, @@ -407,7 +375,7 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info) goto again_search_slot; } if (ret < 0 && ret != -ENOENT) - goto out; + return ret; key.offset++; goto again_search_slot; } @@ -424,8 +392,6 @@ int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info) break; } -out: - btrfs_free_path(path); return ret; } diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c index 7fc30a58d8d9..43433577076b 100644 --- a/fs/btrfs/verity.c +++ b/fs/btrfs/verity.c @@ -93,6 +93,20 @@ static loff_t merkle_file_pos(const struct inode *inode) return rounded; } +/* + * Start a transaction for removing verity items or the verity orphan. + * + * Like unlink, this only deletes items and frees space in the end, so the + * reservation may come from the global reserve when the filesystem is full + * (-ENOSPC) and is not subject to the qgroup limit (-EDQUOT). Otherwise a + * failed enable could never be cleaned up in either situation. + */ +static struct btrfs_trans_handle *start_verity_cleanup_trans(struct btrfs_root *root, + unsigned int num_items) +{ + return btrfs_start_transaction_fallback_global_rsv(root, num_items); +} + /* * Drop all the items for this inode with this key_type. * @@ -109,7 +123,7 @@ static int drop_verity_items(struct btrfs_inode *inode, u8 key_type) { struct btrfs_trans_handle *trans; struct btrfs_root *root = inode->root; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_key key; int count = 0; int ret; @@ -120,11 +134,9 @@ static int drop_verity_items(struct btrfs_inode *inode, u8 key_type) while (1) { /* 1 for the item being dropped */ - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } + trans = start_verity_cleanup_trans(root, 1); + if (IS_ERR(trans)) + return PTR_ERR(trans); /* * Walk backwards through all the items until we find one that @@ -143,7 +155,7 @@ static int drop_verity_items(struct btrfs_inode *inode, u8 key_type) path->slots[0]--; } else if (ret < 0) { btrfs_end_transaction(trans); - goto out; + return ret; } btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); @@ -161,17 +173,14 @@ static int drop_verity_items(struct btrfs_inode *inode, u8 key_type) ret = btrfs_del_items(trans, root, path, path->slots[0], 1); if (ret) { btrfs_end_transaction(trans); - goto out; + return ret; } count++; btrfs_release_path(path); btrfs_end_transaction(trans); } - ret = count; btrfs_end_transaction(trans); -out: - btrfs_free_path(path); - return ret; + return count; } /* @@ -217,7 +226,7 @@ static int write_key_bytes(struct btrfs_inode *inode, u8 key_type, u64 offset, const char *src, u64 len) { struct btrfs_trans_handle *trans; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_root *root = inode->root; struct extent_buffer *leaf; struct btrfs_key key; @@ -233,10 +242,8 @@ static int write_key_bytes(struct btrfs_inode *inode, u8 key_type, u64 offset, while (len > 0) { /* 1 for the new item being inserted */ trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - break; - } + if (IS_ERR(trans)) + return PTR_ERR(trans); key.objectid = btrfs_ino(inode); key.type = key_type; @@ -267,7 +274,6 @@ static int write_key_bytes(struct btrfs_inode *inode, u8 key_type, u64 offset, btrfs_end_transaction(trans); } - btrfs_free_path(path); return ret; } @@ -296,7 +302,7 @@ static int write_key_bytes(struct btrfs_inode *inode, u8 key_type, u64 offset, static int read_key_bytes(struct btrfs_inode *inode, u8 key_type, u64 offset, char *dest, u64 len, struct folio *dest_folio) { - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_root *root = inode->root; struct extent_buffer *leaf; struct btrfs_key key; @@ -404,7 +410,6 @@ static int read_key_bytes(struct btrfs_inode *inode, u8 key_type, u64 offset, } } out: - btrfs_free_path(path); if (!ret) ret = copied; return ret; @@ -475,7 +480,7 @@ static int rollback_verity(struct btrfs_inode *inode) * 1 for updating the inode flag * 1 for deleting the orphan */ - trans = btrfs_start_transaction(root, 2); + trans = start_verity_cleanup_trans(root, 2); if (IS_ERR(trans)) { ret = PTR_ERR(trans); trans = NULL; diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 792818b66dc4..b4404d09a489 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -1809,7 +1809,7 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, struct btrfs_root *root = fs_info->dev_root; struct btrfs_key key; struct btrfs_dev_extent *dev_extent; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); u64 search_start; u64 hole_size; u64 max_hole_start; @@ -1936,7 +1936,6 @@ static int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, "max_hole_start=%llu max_hole_size=%llu search_end=%llu", max_hole_start, max_hole_size, search_end); out: - btrfs_free_path(path); *start = max_hole_start; if (len) *len = max_hole_size; @@ -1950,7 +1949,7 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans, struct btrfs_fs_info *fs_info = device->fs_info; struct btrfs_root *root = fs_info->dev_root; int ret; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_key key; struct btrfs_key found_key; struct extent_buffer *leaf = NULL; @@ -1969,7 +1968,7 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans, ret = btrfs_previous_item(root, path, key.objectid, BTRFS_DEV_EXTENT_KEY); if (ret) - goto out; + return ret; leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); extent = btrfs_item_ptr(leaf, path->slots[0], @@ -1984,7 +1983,7 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans, extent = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_extent); } else { - goto out; + return ret; } *dev_extent_len = btrfs_dev_extent_length(leaf, extent); @@ -1992,8 +1991,6 @@ static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans, ret = btrfs_del_item(trans, root, path); if (ret == 0) set_bit(BTRFS_TRANS_HAVE_FREE_BGS, &trans->transaction->flags); -out: - btrfs_free_path(path); return ret; } @@ -2021,7 +2018,7 @@ static noinline int find_next_devid(struct btrfs_fs_info *fs_info, int ret; struct btrfs_key key; struct btrfs_key found_key; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); path = btrfs_alloc_path(); if (!path) @@ -2033,13 +2030,12 @@ static noinline int find_next_devid(struct btrfs_fs_info *fs_info, ret = btrfs_search_slot(NULL, fs_info->chunk_root, &key, path, 0, 0); if (ret < 0) - goto error; + return ret; if (unlikely(ret == 0)) { /* Corruption */ btrfs_err(fs_info, "corrupted chunk tree devid -1 matched"); - ret = -EUCLEAN; - goto error; + return -EUCLEAN; } ret = btrfs_previous_item(fs_info->chunk_root, path, @@ -2052,10 +2048,7 @@ static noinline int find_next_devid(struct btrfs_fs_info *fs_info, path->slots[0]); *devid_ret = found_key.offset + 1; } - ret = 0; -error: - btrfs_free_path(path); - return ret; + return 0; } /* @@ -2066,7 +2059,7 @@ static int btrfs_add_dev_item(struct btrfs_trans_handle *trans, struct btrfs_device *device) { int ret; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_dev_item *dev_item; struct extent_buffer *leaf; struct btrfs_key key; @@ -2085,7 +2078,7 @@ static int btrfs_add_dev_item(struct btrfs_trans_handle *trans, &key, sizeof(*dev_item)); btrfs_trans_release_chunk_metadata(trans); if (ret) - goto out; + return ret; leaf = path->nodes[0]; dev_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_item); @@ -2111,10 +2104,7 @@ static int btrfs_add_dev_item(struct btrfs_trans_handle *trans, write_extent_buffer(leaf, trans->fs_info->fs_devices->metadata_uuid, ptr, BTRFS_FSID_SIZE); - ret = 0; -out: - btrfs_free_path(path); - return ret; + return 0; } /* @@ -2141,7 +2131,7 @@ static int btrfs_rm_dev_item(struct btrfs_trans_handle *trans, { struct btrfs_root *root = device->fs_info->chunk_root; int ret; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_key key; path = btrfs_alloc_path(); @@ -2155,16 +2145,12 @@ static int btrfs_rm_dev_item(struct btrfs_trans_handle *trans, btrfs_reserve_chunk_metadata(trans, false); ret = btrfs_search_slot(trans, root, &key, path, -1, 1); btrfs_trans_release_chunk_metadata(trans); - if (ret) { - if (ret > 0) - ret = -ENOENT; - goto out; - } + if (ret > 0) + return -ENOENT; + if (ret < 0) + return ret; - ret = btrfs_del_item(trans, root, path); -out: - btrfs_free_path(path); - return ret; + return btrfs_del_item(trans, root, path); } /* @@ -2748,7 +2734,7 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans) BTRFS_DEV_LOOKUP_ARGS(args); struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *root = fs_info->chunk_root; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct extent_buffer *leaf; struct btrfs_dev_item *dev_item; struct btrfs_device *device; @@ -2770,7 +2756,7 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans) ret = btrfs_search_slot(trans, root, &key, path, 0, 1); btrfs_trans_release_chunk_metadata(trans); if (ret < 0) - goto error; + return ret; leaf = path->nodes[0]; next_slot: @@ -2779,7 +2765,7 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans) if (ret > 0) break; if (ret < 0) - goto error; + return ret; leaf = path->nodes[0]; btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); btrfs_release_path(path); @@ -2810,10 +2796,7 @@ static int btrfs_finish_sprout(struct btrfs_trans_handle *trans) path->slots[0]++; goto next_slot; } - ret = 0; -error: - btrfs_free_path(path); - return ret; + return 0; } int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path) @@ -3072,7 +3055,7 @@ static noinline int btrfs_update_device(struct btrfs_trans_handle *trans, struct btrfs_device *device) { int ret; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_root *root = device->fs_info->chunk_root; struct btrfs_dev_item *dev_item; struct extent_buffer *leaf; @@ -3088,12 +3071,10 @@ static noinline int btrfs_update_device(struct btrfs_trans_handle *trans, ret = btrfs_search_slot(trans, root, &key, path, 0, 1); if (ret < 0) - goto out; + return ret; - if (ret > 0) { - ret = -ENOENT; - goto out; - } + if (ret > 0) + return -ENOENT; leaf = path->nodes[0]; dev_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_item); @@ -3107,8 +3088,6 @@ static noinline int btrfs_update_device(struct btrfs_trans_handle *trans, btrfs_device_get_disk_total_bytes(device)); btrfs_set_device_bytes_used(leaf, dev_item, btrfs_device_get_bytes_used(device)); -out: - btrfs_free_path(path); return ret; } @@ -3161,7 +3140,7 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset) struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *root = fs_info->chunk_root; int ret; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_key key; path = btrfs_alloc_path(); @@ -3174,23 +3153,21 @@ static int btrfs_free_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset) ret = btrfs_search_slot(trans, root, &key, path, -1, 1); if (ret < 0) - goto out; - else if (unlikely(ret > 0)) { /* Logic error or corruption */ + return ret; + if (unlikely(ret > 0)) { + /* Logic error or corruption */ btrfs_err(fs_info, "failed to lookup chunk %llu when freeing", chunk_offset); btrfs_abort_transaction(trans, -ENOENT); - ret = -EUCLEAN; - goto out; + return -EUCLEAN; } ret = btrfs_del_item(trans, root, path); if (unlikely(ret < 0)) { btrfs_err(fs_info, "failed to delete chunk %llu item", chunk_offset); btrfs_abort_transaction(trans, ret); - goto out; + return ret; } -out: - btrfs_free_path(path); return ret; } @@ -3627,7 +3604,7 @@ int btrfs_relocate_chunk(struct btrfs_fs_info *fs_info, u64 chunk_offset, static int btrfs_relocate_sys_chunks(struct btrfs_fs_info *fs_info) { struct btrfs_root *chunk_root = fs_info->chunk_root; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct extent_buffer *leaf; struct btrfs_chunk *chunk; struct btrfs_key key; @@ -3651,7 +3628,7 @@ static int btrfs_relocate_sys_chunks(struct btrfs_fs_info *fs_info) ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); if (ret < 0) { mutex_unlock(&fs_info->reclaim_bgs_lock); - goto error; + return ret; } if (unlikely(ret == 0)) { /* @@ -3661,9 +3638,8 @@ static int btrfs_relocate_sys_chunks(struct btrfs_fs_info *fs_info) * offset (one less than the previous one, wrong * alignment and size). */ - ret = -EUCLEAN; mutex_unlock(&fs_info->reclaim_bgs_lock); - goto error; + return -EUCLEAN; } ret = btrfs_previous_item(chunk_root, path, key.objectid, @@ -3671,7 +3647,7 @@ static int btrfs_relocate_sys_chunks(struct btrfs_fs_info *fs_info) if (ret) mutex_unlock(&fs_info->reclaim_bgs_lock); if (ret < 0) - goto error; + return ret; if (ret > 0) break; @@ -3705,8 +3681,6 @@ static int btrfs_relocate_sys_chunks(struct btrfs_fs_info *fs_info) } else if (WARN_ON(failed && retried)) { ret = -ENOSPC; } -error: - btrfs_free_path(path); return ret; } @@ -4844,7 +4818,7 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info) struct btrfs_balance_control *bctl; struct btrfs_balance_item *item; struct btrfs_disk_balance_args disk_bargs; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct extent_buffer *leaf; struct btrfs_key key; int ret; @@ -4859,17 +4833,14 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info) ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, path, 0, 0); if (ret < 0) - goto out; + return ret; if (ret > 0) { /* ret = -ENOENT; */ - ret = 0; - goto out; + return 0; } bctl = kzalloc(sizeof(*bctl), GFP_NOFS); - if (!bctl) { - ret = -ENOMEM; - goto out; - } + if (!bctl) + return -ENOMEM; leaf = path->nodes[0]; item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_balance_item); @@ -4906,8 +4877,6 @@ int btrfs_recover_balance(struct btrfs_fs_info *fs_info) fs_info->balance_ctl = bctl; spin_unlock(&fs_info->balance_lock); mutex_unlock(&fs_info->balance_mutex); -out: - btrfs_free_path(path); return ret; } @@ -7593,7 +7562,7 @@ static void readahead_tree_node_children(struct extent_buffer *node) int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info) { struct btrfs_root *root = fs_info->chunk_root; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct extent_buffer *leaf; struct btrfs_key key; struct btrfs_key found_key; @@ -7710,8 +7679,6 @@ int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info) ret = 0; error: mutex_unlock(&uuid_mutex); - - btrfs_free_path(path); return ret; } @@ -7811,7 +7778,7 @@ int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info) { struct btrfs_fs_devices *fs_devices = fs_info->fs_devices, *seed_devs; struct btrfs_device *device; - struct btrfs_path *path = NULL; + BTRFS_PATH_AUTO_FREE(path); int ret = 0; path = btrfs_alloc_path(); @@ -7833,8 +7800,6 @@ int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info) } out: mutex_unlock(&fs_devices->device_list_mutex); - - btrfs_free_path(path); return ret; } @@ -7843,7 +7808,7 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans, { struct btrfs_fs_info *fs_info = trans->fs_info; struct btrfs_root *dev_root = fs_info->dev_root; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_key key; struct extent_buffer *eb; struct btrfs_dev_stats_item *ptr; @@ -7862,7 +7827,7 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans, btrfs_warn(fs_info, "error %d while searching for dev_stats item for device %s", ret, btrfs_dev_name(device)); - goto out; + return ret; } if (ret == 0 && @@ -7873,7 +7838,7 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans, btrfs_warn(fs_info, "delete too small dev_stats item for device %s failed %d", btrfs_dev_name(device), ret); - goto out; + return ret; } ret = 1; } @@ -7887,7 +7852,7 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans, btrfs_warn(fs_info, "insert dev_stats item for device %s failed %d", btrfs_dev_name(device), ret); - goto out; + return ret; } } @@ -7896,8 +7861,6 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans, for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) btrfs_set_dev_stats_value(eb, ptr, i, btrfs_dev_stat_read(device, i)); -out: - btrfs_free_path(path); return ret; } @@ -8188,7 +8151,7 @@ static int verify_chunk_dev_extent_mapping(struct btrfs_fs_info *fs_info) */ int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info) { - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct btrfs_root *root = fs_info->dev_root; struct btrfs_key key; u64 prev_devid = 0; @@ -8219,17 +8182,15 @@ int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info) path->reada = READA_FORWARD; ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); if (ret < 0) - goto out; + return ret; if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { ret = btrfs_next_leaf(root, path); if (ret < 0) - goto out; + return ret; /* No dev extents at all? Not good */ - if (unlikely(ret > 0)) { - ret = -EUCLEAN; - goto out; - } + if (unlikely(ret > 0)) + return -EUCLEAN; } while (1) { struct extent_buffer *leaf = path->nodes[0]; @@ -8255,20 +8216,19 @@ int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info) btrfs_err(fs_info, "dev extent devid %llu physical offset %llu overlap with previous dev extent end %llu", devid, physical_offset, prev_dev_ext_end); - ret = -EUCLEAN; - goto out; + return -EUCLEAN; } ret = verify_one_dev_extent(fs_info, chunk_offset, devid, physical_offset, physical_len); if (ret < 0) - goto out; + return ret; prev_devid = devid; prev_dev_ext_end = physical_offset + physical_len; ret = btrfs_next_item(root, path); if (ret < 0) - goto out; + return ret; if (ret > 0) { ret = 0; break; @@ -8276,10 +8236,7 @@ int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info) } /* Ensure all chunks have corresponding dev extents */ - ret = verify_chunk_dev_extent_mapping(fs_info); -out: - btrfs_free_path(path); - return ret; + return verify_chunk_dev_extent_mapping(fs_info); } /* diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c index b6e91e8fb7e3..ab55d10bd71f 100644 --- a/fs/btrfs/xattr.c +++ b/fs/btrfs/xattr.c @@ -29,9 +29,8 @@ int btrfs_getxattr(const struct inode *inode, const char *name, { struct btrfs_dir_item *di; struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); struct extent_buffer *leaf; - int ret = 0; unsigned long data_ptr; path = btrfs_alloc_path(); @@ -41,26 +40,19 @@ int btrfs_getxattr(const struct inode *inode, const char *name, /* lookup the xattr by name */ di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(BTRFS_I(inode)), name, strlen(name), 0); - if (!di) { - ret = -ENODATA; - goto out; - } else if (IS_ERR(di)) { - ret = PTR_ERR(di); - goto out; - } + if (!di) + return -ENODATA; + if (IS_ERR(di)) + return PTR_ERR(di); leaf = path->nodes[0]; /* if size is 0, that means we want the size of the attr */ - if (!size) { - ret = btrfs_dir_data_len(leaf, di); - goto out; - } + if (!size) + return btrfs_dir_data_len(leaf, di); /* now get the data out of our dir_item */ - if (btrfs_dir_data_len(leaf, di) > size) { - ret = -ERANGE; - goto out; - } + if (btrfs_dir_data_len(leaf, di) > size) + return -ERANGE; /* * The way things are packed into the leaf is like this @@ -73,11 +65,7 @@ int btrfs_getxattr(const struct inode *inode, const char *name, btrfs_dir_name_len(leaf, di)); read_extent_buffer(leaf, buffer, data_ptr, btrfs_dir_data_len(leaf, di)); - ret = btrfs_dir_data_len(leaf, di); - -out: - btrfs_free_path(path); - return ret; + return btrfs_dir_data_len(leaf, di); } int btrfs_setxattr(struct btrfs_trans_handle *trans, struct inode *inode, @@ -277,7 +265,7 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) struct btrfs_key key; struct inode *inode = d_inode(dentry); struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_path *path; + BTRFS_PATH_AUTO_FREE(path); int iter_ret = 0; int ret = 0; size_t total_size = 0, size_left = size; @@ -353,8 +341,6 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) else ret = total_size; - btrfs_free_path(path); - return ret; } diff --git a/fs/dax.c b/fs/dax.c index 516f995a988c..69ac2562cec3 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -443,11 +443,12 @@ static void dax_associate_entry(void *entry, struct address_space *mapping, unsigned long address, bool shared) { unsigned long size = dax_entry_size(entry), index; - struct folio *folio = dax_to_folio(entry); + struct folio *folio; if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry)) return; + folio = dax_to_folio(entry); index = linear_page_index(vma, address & ~(size - 1)); if (shared && (folio->mapping || dax_folio_is_shared(folio))) { if (folio->mapping) @@ -468,21 +469,23 @@ static void dax_associate_entry(void *entry, struct address_space *mapping, static void dax_disassociate_entry(void *entry, struct address_space *mapping, bool trunc) { - struct folio *folio = dax_to_folio(entry); + struct folio *folio; if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry)) return; + folio = dax_to_folio(entry); dax_folio_put(folio); } static struct page *dax_busy_page(void *entry) { - struct folio *folio = dax_to_folio(entry); + struct folio *folio; if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry)) return NULL; + folio = dax_to_folio(entry); if (folio_ref_count(folio) - folio_mapcount(folio)) return &folio->page; else diff --git a/fs/exec.c b/fs/exec.c index c0eab916a3e0..4aa690525959 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1094,6 +1094,17 @@ void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec) perf_event_comm(tsk, exec); } +static void posixtimer_exec(struct task_struct *me) +{ +#ifdef CONFIG_POSIX_TIMERS + spin_lock_irq(&me->sighand->siglock); + posix_cpu_timers_exit(me); + spin_unlock_irq(&me->sighand->siglock); + exit_itimers(me); + flush_itimer_signals(); +#endif +} + /* * Calling this is the point of no return. None of the failures will be * seen by userspace since either the process is already taking a fatal @@ -1127,6 +1138,16 @@ int begin_new_exec(struct linux_binprm * bprm) retval = de_thread(me); if (retval) goto out; + + /* + * This must be done here to ensure that POSIX CPU timers which were + * armed on the current task are dequeued from me::posix_cputimers. + * Otherwise in case of a TID switch the deletion of the related POSIX + * timer would not remove an enqueued timer because the TID lookup + * of the old TID fails. + */ + posixtimer_exec(me); + /* see the comment in check_unsafe_exec() */ current->fs->in_exec = 0; /* @@ -1181,14 +1202,6 @@ int begin_new_exec(struct linux_binprm * bprm) if (retval) goto out_unlock; -#ifdef CONFIG_POSIX_TIMERS - spin_lock_irq(&me->sighand->siglock); - posix_cpu_timers_exit(me); - spin_unlock_irq(&me->sighand->siglock); - exit_itimers(me); - flush_itimer_signals(); -#endif - /* * Make the signal table private. */ diff --git a/fs/smb/client/cifs_fs_sb.h b/fs/smb/client/cifs_fs_sb.h index fc75999ffdc4..87191ec7ddf5 100644 --- a/fs/smb/client/cifs_fs_sb.h +++ b/fs/smb/client/cifs_fs_sb.h @@ -57,6 +57,7 @@ struct cifs_sb_info { struct smb3_fs_context *ctx; atomic_t active; atomic_t mnt_cifs_flags; + atomic_t outstanding_rreq; /* nr of rreqs not yet fully deinitialized */ struct delayed_work prune_tlinks; struct rcu_head rcu; diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index 7bd950b28deb..6d35f3872266 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -342,6 +342,18 @@ static void cifs_kill_sb(struct super_block *sb) /* Wait for all opened files to release */ flush_workqueue(deferredclose_wq); + /* + * Wait for all in-flight netfs I/O requests to finish their + * cleanup_work so that any cifsFileInfo final puts they queue + * to fileinfo_put_wq/serverclose_wq have been queued, then + * drain the workqueue so the cfile dentry refs are dropped to + * avoid the busy dentry warning. + */ + wait_var_event(&cifs_sb->outstanding_rreq, + !atomic_read(&cifs_sb->outstanding_rreq)); + flush_workqueue(serverclose_wq); + flush_workqueue(fileinfo_put_wq); + /* finally release root dentry */ dput(cifs_sb->root); cifs_sb->root = NULL; diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 5956d6657383..0a5b580e5227 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -3015,7 +3015,7 @@ int cifs_query_reparse_point(const unsigned int xid, end = 2 + get_bcc(&io_rsp->hdr) + (__u8 *)&io_rsp->ByteCount; start = (__u8 *)&io_rsp->hdr.Protocol + data_offset; - if (start >= end) { + if (start >= end || (size_t)(end - start) < sizeof(*buf)) { rc = -EIO; goto error; } diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index ae4d3f740065..f589b188ccfc 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -171,6 +171,8 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server, nserver = ses->chans[i].server; if (!nserver) continue; + if (!list_empty(&nserver->rlist)) + continue; nserver->srv_count++; list_add(&nserver->rlist, &reco); } @@ -179,11 +181,15 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server, } } + spin_lock(&cifs_tcp_ses_lock); list_for_each_entry_safe(server, nserver, &reco, rlist) { list_del_init(&server->rlist); set_need_reco(server); + spin_unlock(&cifs_tcp_ses_lock); cifs_put_tcp_session(server, 0); + spin_lock(&cifs_tcp_ses_lock); } + spin_unlock(&cifs_tcp_ses_lock); } /* @@ -1064,6 +1070,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server) spin_unlock(&server->srv_lock); cancel_delayed_work_sync(&server->echo); + cancel_delayed_work_sync(&server->reconnect); spin_lock(&server->srv_lock); server->tcpStatus = CifsExiting; @@ -1822,6 +1829,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, spin_lock_init(&tcp_ses->mid_counter_lock); INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); INIT_LIST_HEAD(&tcp_ses->smb_ses_list); + INIT_LIST_HEAD(&tcp_ses->rlist); INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server); mutex_init(&tcp_ses->reconnect_mutex); @@ -1925,6 +1933,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, kfree(tcp_ses->leaf_fullpath); if (tcp_ses->ssocket) sock_release(tcp_ses->ssocket); + smbd_destroy(tcp_ses); kfree(tcp_ses); } return ERR_PTR(rc); @@ -3588,6 +3597,7 @@ int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb) spin_lock_init(&cifs_sb->tlink_tree_lock); cifs_sb->tlink_tree = RB_ROOT; + atomic_set(&cifs_sb->outstanding_rreq, 0); cifs_dbg(FYI, "file mode: %04ho dir mode: %04ho\n", ctx->file_mode, ctx->dir_mode); diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 235e365f6093..1e557601804f 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -289,6 +289,7 @@ static int cifs_init_request(struct netfs_io_request *rreq, struct file *file) return -EIO; } + atomic_inc(&cifs_sb->outstanding_rreq); return 0; } @@ -310,9 +311,13 @@ static void cifs_rreq_done(struct netfs_io_request *rreq) static void cifs_free_request(struct netfs_io_request *rreq) { struct cifs_io_request *req = container_of(rreq, struct cifs_io_request, rreq); + struct cifs_sb_info *cifs_sb = CIFS_SB(rreq->inode->i_sb); if (req->cfile) cifsFileInfo_put(req->cfile); + + if (atomic_dec_and_test(&cifs_sb->outstanding_rreq)) + wake_up_var(&cifs_sb->outstanding_rreq); } static void cifs_free_subrequest(struct netfs_io_subrequest *subreq) @@ -1462,11 +1467,18 @@ int cifs_close(struct inode *inode, struct file *file) cifsFileInfo_get(cfile); } else { /* Deferred close for files */ - queue_delayed_work(deferredclose_wq, - &cfile->deferred, cifs_sb->ctx->closetimeo); - cfile->deferred_close_scheduled = true; - spin_unlock(&cinode->deferred_lock); - return 0; + /* + * Each queued execution owns one reference. + * If nothing was queued, the reference of + * the closing file is dropped below. + */ + if (queue_delayed_work(deferredclose_wq, + &cfile->deferred, + cifs_sb->ctx->closetimeo)) { + cfile->deferred_close_scheduled = true; + spin_unlock(&cinode->deferred_lock); + return 0; + } } spin_unlock(&cinode->deferred_lock); _cifsFileInfo_put(cfile, true, false); @@ -3136,8 +3148,6 @@ void cifs_oplock_break(struct work_struct *work) struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo, oplock_break); struct inode *inode = d_inode(cfile->dentry); - struct super_block *sb = inode->i_sb; - struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifsInodeInfo *cinode = CIFS_I(inode); struct cifs_tcon *tcon; struct TCP_Server_Info *server; @@ -3150,8 +3160,8 @@ void cifs_oplock_break(struct work_struct *work) wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS, TASK_UNINTERRUPTIBLE); - tlink = cifs_sb_tlink(cifs_sb); - if (IS_ERR(tlink)) { + tlink = cifs_get_tlink(cfile->tlink); + if (IS_ERR_OR_NULL(tlink)) { /* drop the reference taken when the break was queued */ _cifsFileInfo_put(cfile, false /* do not wait for ourself */, false); goto out; diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c index 25e29b1e554e..9c32213e9379 100644 --- a/fs/smb/client/misc.c +++ b/fs/smb/client/misc.c @@ -1050,7 +1050,11 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); /* copy DfsPath */ - if (le16_to_cpu(ref->DfsPathOffset) > data_end - (char *)ref) { + if (le16_to_cpu(ref->DfsPathOffset) < sizeof(*ref) || + le16_to_cpu(ref->DfsPathOffset) > data_end - (char *)ref) { + cifs_dbg(VFS, "%s: DfsPathOffset %u out of range [%zu, %td]\n", + __func__, le16_to_cpu(ref->DfsPathOffset), + sizeof(*ref), data_end - (char *)ref); rc = -EINVAL; goto parse_DFS_referrals_exit; } @@ -1064,7 +1068,11 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, } /* copy link target UNC */ - if (le16_to_cpu(ref->NetworkAddressOffset) > data_end - (char *)ref) { + if (le16_to_cpu(ref->NetworkAddressOffset) < sizeof(*ref) || + le16_to_cpu(ref->NetworkAddressOffset) > data_end - (char *)ref) { + cifs_dbg(VFS, "%s: NetworkAddressOffset %u out of range [%zu, %td]\n", + __func__, le16_to_cpu(ref->NetworkAddressOffset), + sizeof(*ref), data_end - (char *)ref); rc = -EINVAL; goto parse_DFS_referrals_exit; } diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c index 6ec6b8c46ba2..2e773a1a6714 100644 --- a/fs/smb/client/reparse.c +++ b/fs/smb/client/reparse.c @@ -1156,9 +1156,9 @@ static bool wsl_to_fattr(struct cifs_open_info_data *data, fattr->cf_gid = wsl_make_kgid(cifs_sb, v); else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen)) { /* File type in reparse point tag and in xattr mode must match. */ - if (S_DT(fattr->cf_mode) != S_DT(le32_to_cpu(*(__le32 *)v))) + if (S_DT(fattr->cf_mode) != S_DT(get_unaligned_le32(v))) return false; - fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v); + fattr->cf_mode = (umode_t)get_unaligned_le32(v); } else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen)) { fattr->cf_rdev = reparse_mkdev(v); have_xattr_dev = true; diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h index d7d205cde868..701969e018d2 100644 --- a/fs/smb/client/reparse.h +++ b/fs/smb/client/reparse.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "fs_context.h" #include "cifsglob.h" @@ -22,7 +23,7 @@ static inline dev_t reparse_mkdev(void *ptr) { - u64 v = le64_to_cpu(*(__le64 *)ptr); + u64 v = get_unaligned_le64(ptr); return MKDEV(v & 0xffffffff, v >> 32); } @@ -30,7 +31,7 @@ static inline dev_t reparse_mkdev(void *ptr) static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb, void *ptr) { - u32 uid = le32_to_cpu(*(__le32 *)ptr); + u32 uid = get_unaligned_le32(ptr); if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_OVERR_UID) return cifs_sb->ctx->linux_uid; @@ -40,7 +41,7 @@ static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb, static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb, void *ptr) { - u32 gid = le32_to_cpu(*(__le32 *)ptr); + u32 gid = get_unaligned_le32(ptr); if (cifs_sb_flags(cifs_sb) & CIFS_MOUNT_OVERR_GID) return cifs_sb->ctx->linux_gid; diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index ca0ac52522e5..6f4194811ba7 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -150,9 +150,9 @@ int cifs_try_adding_channels(struct cifs_ses *ses) int old_chan_count, new_chan_count; int left; int rc = 0; - int tries = 0; + int tries = 0, attempts; size_t iface_weight = 0, iface_min_speed = 0; - struct cifs_server_iface *iface = NULL, *niface = NULL; + struct cifs_server_iface *iface = NULL, *candidate = NULL; struct cifs_server_iface *last_iface = NULL; spin_lock(&ses->chan_lock); @@ -198,67 +198,89 @@ int cifs_try_adding_channels(struct cifs_ses *ses) break; } - if (!iface) - iface = list_first_entry(&ses->iface_list, struct cifs_server_iface, - iface_head); last_iface = list_last_entry(&ses->iface_list, struct cifs_server_iface, iface_head); iface_min_speed = last_iface->speed; + spin_unlock(&ses->iface_lock); - list_for_each_entry_safe_from(iface, niface, &ses->iface_list, - iface_head) { - /* do not mix rdma and non-rdma interfaces */ - if (iface->rdma_capable != ses->server->rdma) - continue; - - /* skip ifaces that are unusable */ - if (!iface->is_active || - (is_ses_using_iface(ses, iface) && - !iface->rss_capable)) - continue; + attempts = 0; + while (left > 0) { + spin_lock(&ses->iface_lock); - /* check if we already allocated enough channels */ - iface_weight = iface->speed / iface_min_speed; + /* + * iface_lock must be dropped while opening a channel, + * and a concurrent interface refresh may remove and + * free entries during that window, so no list entry + * may be kept across it without a reference. Scan + * the list from the beginning each time and only pass + * a referenced candidate to cifs_ses_add_channel(); + * weight_fulfilled tracks the progress so that no + * iface is selected beyond its weight. + */ + candidate = NULL; + list_for_each_entry(iface, &ses->iface_list, iface_head) { + /* do not mix rdma and non-rdma interfaces */ + if (iface->rdma_capable != ses->server->rdma) + continue; + + /* skip ifaces that are unusable */ + if (!iface->is_active || + (is_ses_using_iface(ses, iface) && + !iface->rss_capable)) + continue; + + /* check if we already allocated enough channels */ + iface_weight = iface->speed / iface_min_speed; + + if (iface->weight_fulfilled >= iface_weight) + continue; + + /* take ref before unlock */ + kref_get(&iface->refcount); + candidate = iface; + break; + } - if (iface->weight_fulfilled >= iface_weight) - continue; + if (!candidate) { + /* no usable iface. reset weight_fulfilled and start over */ + list_for_each_entry(iface, &ses->iface_list, iface_head) + iface->weight_fulfilled = 0; + spin_unlock(&ses->iface_lock); + break; + } - /* take ref before unlock */ - kref_get(&iface->refcount); + attempts++; + if (attempts > 3 * ses->chan_max) { + kref_put(&candidate->refcount, release_iface); + spin_unlock(&ses->iface_lock); + break; + } spin_unlock(&ses->iface_lock); - rc = cifs_ses_add_channel(ses, iface); + rc = cifs_ses_add_channel(ses, candidate); spin_lock(&ses->iface_lock); if (rc) { cifs_dbg(VFS, "failed to open extra channel on iface:%pIS rc=%d\n", - &iface->sockaddr, + &candidate->sockaddr, rc); /* failure to add chan should increase weight */ - iface->weight_fulfilled++; - kref_put(&iface->refcount, release_iface); + candidate->weight_fulfilled++; + kref_put(&candidate->refcount, release_iface); + spin_unlock(&ses->iface_lock); continue; } - iface->num_channels++; - iface->weight_fulfilled++; + candidate->num_channels++; + candidate->weight_fulfilled++; cifs_info("successfully opened new channel on iface:%pIS\n", - &iface->sockaddr); - break; - } - - /* reached end of list. reset weight_fulfilled and start over */ - if (list_entry_is_head(iface, &ses->iface_list, iface_head)) { - list_for_each_entry(iface, &ses->iface_list, iface_head) - iface->weight_fulfilled = 0; + &candidate->sockaddr); spin_unlock(&ses->iface_lock); - iface = NULL; - continue; - } - spin_unlock(&ses->iface_lock); - left--; - new_chan_count++; + left--; + new_chan_count++; + break; + } } return new_chan_count - old_chan_count; diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index b5351b620a57..2e28a965a25d 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -70,6 +70,17 @@ static int parse_posix_sids(struct cifs_open_info_data *data, sidsbuf = (u8 *)qi + le16_to_cpu(qi->OutputBufferOffset) + qi_len; sidsbuf_end = sidsbuf + out_len - qi_len; + if (sidsbuf_end < sidsbuf) { + cifs_dbg(VFS, "%s: server-supplied out_len %u caused pointer wraparound\n", + __func__, out_len); + return -EINVAL; + } + if (sidsbuf_end > (u8 *)rsp_iov->iov_base + rsp_iov->iov_len) { + cifs_dbg(VFS, "%s: server-supplied out_len %u overruns iov by %td bytes\n", + __func__, out_len, + sidsbuf_end - ((u8 *)rsp_iov->iov_base + rsp_iov->iov_len)); + return -EINVAL; + } owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end); if (owner_len == -1) diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 67a7f0c4beac..dcf0a9b9647c 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -786,9 +786,9 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf, break; } /* Validate that Next doesn't point beyond the buffer */ - if (next > bytes_left) { - cifs_dbg(VFS, "%s: invalid Next pointer %zu > %zd\n", - __func__, next, bytes_left); + if (next < sizeof(*p) || next > bytes_left) { + cifs_dbg(VFS, "%s: invalid Next pointer %zu out of range [%zu, %zd]\n", + __func__, next, sizeof(*p), bytes_left); rc = -EINVAL; goto out; } @@ -1054,8 +1054,9 @@ move_smb2_ea_to_cifs(char *dst, size_t dst_size, char *name, *value; size_t buf_size = dst_size; size_t name_len, value_len, user_name_len; + u32 next_off; - while (src_size > 0) { + while (src_size >= sizeof(*src)) { name_len = (size_t)src->ea_name_length; value_len = (size_t)le16_to_cpu(src->ea_value_length); @@ -1110,14 +1111,22 @@ move_smb2_ea_to_cifs(char *dst, size_t dst_size, if (!src->next_entry_offset) break; - if (src_size < le32_to_cpu(src->next_entry_offset)) { - /* stop before overrun buffer */ - rc = -ERANGE; - break; + next_off = le32_to_cpu(src->next_entry_offset); + if (next_off < sizeof(*src) || src_size < next_off) { + cifs_dbg(FYI, "EA next_entry_offset %u out of range [%zu, %zu]\n", + next_off, sizeof(*src), src_size); + rc = smb_EIO2(smb_eio_trace_ea_next_offset, + next_off, src_size); + goto out; + } + src_size -= next_off; + src = (void *)((char *)src + next_off); + if (src_size > 0 && src_size < sizeof(*src)) { + cifs_dbg(FYI, "EA next_entry_offset %u left truncated entry (%zu bytes)\n", + next_off, src_size); + rc = smb_EIO2(smb_eio_trace_ea_next_offset, next_off, src_size); + goto out; } - src_size -= le32_to_cpu(src->next_entry_offset); - src = (void *)((char *)src + - le32_to_cpu(src->next_entry_offset)); } /* didn't find the named attribute */ @@ -2406,8 +2415,14 @@ smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon, * and retry the ioctl again with larger array size sufficient * to hold all of the snapshot GMT tokens on the second try. */ - if (snapshot_in.snapshot_array_size < GMT_TOKEN_SIZE) + if (snapshot_in.snapshot_array_size < GMT_TOKEN_SIZE) { + if (ret_data_len < sizeof(struct smb_snapshot_array)) { + rc = -EIO; + kfree(retbuf); + return rc; + } ret_data_len = sizeof(struct smb_snapshot_array); + } /* * We return struct SRV_SNAPSHOT_ARRAY, followed by @@ -5280,11 +5295,13 @@ receive_encrypted_standard(struct TCP_Server_Info *server, length = decrypt_raw_data(server, buf, buf_size, NULL, false); if (length) return length; + pdu_length = buf_size; next_is_large = server->large_buf; one_more: shdr = (struct smb2_hdr *)buf; next_cmd = le32_to_cpu(shdr->NextCommand); + server->total_read = next_cmd ? next_cmd : pdu_length; if (*num_mids >= MAX_COMPOUND) { cifs_server_dbg(VFS, "too many PDUs in compound\n"); @@ -5292,8 +5309,15 @@ receive_encrypted_standard(struct TCP_Server_Info *server, } if (next_cmd) { - if (WARN_ON_ONCE(next_cmd > pdu_length)) + if (next_cmd < MID_HEADER_SIZE(server) || + next_cmd > pdu_length || + pdu_length - next_cmd < MID_HEADER_SIZE(server)) { + unsigned int max_next = pdu_length > (unsigned int)MID_HEADER_SIZE(server) ? + pdu_length - (unsigned int)MID_HEADER_SIZE(server) : 0; + cifs_server_dbg(VFS, "invalid NextCommand offset %u out of range [%zu, %u]\n", + next_cmd, MID_HEADER_SIZE(server), max_next); return -1; + } if (next_is_large) next_buffer = (char *)cifs_buf_get(); else @@ -5329,6 +5353,7 @@ receive_encrypted_standard(struct TCP_Server_Info *server, server->bigbuf = buf = next_buffer; else server->smallbuf = buf = next_buffer; + next_buffer = NULL; goto one_more; } else if (ret != 0) { /* diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index e4f18766f0a1..c07c5bb32140 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -190,18 +190,19 @@ cifs_chan_skip_or_disable(struct cifs_ses *ses, spin_unlock(&ses->chan_lock); /* - * the above reference of server by channel - * needs to be dropped without holding chan_lock - * as cifs_put_tcp_session takes a higher lock - * i.e. cifs_tcp_ses_lock + * signal the channel and its primary server to + * reconnect before dropping the above reference of + * server by channel, which is done without holding + * chan_lock as cifs_put_tcp_session takes a higher + * lock i.e. cifs_tcp_ses_lock */ - cifs_put_tcp_session(server, from_reconnect); - cifs_signal_cifsd_for_reconnect(server, false); /* mark primary server as needing reconnect */ pserver = server->primary_server; cifs_signal_cifsd_for_reconnect(pserver, false); + + cifs_put_tcp_session(server, from_reconnect); skip_terminate: return -EHOSTDOWN; } diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index 90fd665ff8dd..a56fbacf28d1 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -27,6 +27,7 @@ EM(smb_eio_trace_copychunk_overcopy_c, "copychunk_overcopy_c") \ EM(smb_eio_trace_create_rsp_too_small, "create_rsp_too_small") \ EM(smb_eio_trace_dfsref_no_rsp, "dfsref_no_rsp") \ + EM(smb_eio_trace_ea_next_offset, "ea_next_offset") \ EM(smb_eio_trace_ea_overrun, "ea_overrun") \ EM(smb_eio_trace_extract_will_pin, "extract_will_pin") \ EM(smb_eio_trace_forced_shutdown, "forced_shutdown") \ diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c index f2bc73a7ee82..e7af6353a641 100644 --- a/fs/smb/server/server.c +++ b/fs/smb/server/server.c @@ -95,7 +95,7 @@ static inline int check_conn_state(struct ksmbd_work *work) if (ksmbd_conn_exiting(work->conn) || ksmbd_conn_need_reconnect(work->conn)) { - rsp_hdr = smb_get_msg(work->response_buf); + rsp_hdr = work->response_buf; rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED; return 1; } diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index cd7bfc73cf08..9cc6110fbcf9 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -4633,26 +4633,31 @@ int smb2_query_dir(struct ksmbd_work *work) /** * buffer_check_err() - helper function to check buffer errors * @reqOutputBufferLength: max buffer length expected in command response + * @fixed_len: minimum fixed response length * @rsp: query info response buffer contains output buffer length - * @rsp_org: base response buffer pointer in case of chained response * * Return: 0 on success, otherwise error */ static int buffer_check_err(int reqOutputBufferLength, - struct smb2_query_info_rsp *rsp, - void *rsp_org) + unsigned int fixed_len, + struct smb2_query_info_rsp *rsp) { - if (reqOutputBufferLength < le32_to_cpu(rsp->OutputBufferLength)) { + unsigned int output_len = le32_to_cpu(rsp->OutputBufferLength); + + if (reqOutputBufferLength < fixed_len) { pr_err("Invalid Buffer Size Requested\n"); rsp->hdr.Status = STATUS_INFO_LENGTH_MISMATCH; - *(__be32 *)rsp_org = cpu_to_be32(sizeof(struct smb2_hdr)); return -EINVAL; } + + if (reqOutputBufferLength < output_len) { + rsp->hdr.Status = STATUS_BUFFER_OVERFLOW; + rsp->OutputBufferLength = cpu_to_le32(reqOutputBufferLength); + } return 0; } -static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp, - void *rsp_org) +static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp) { struct smb2_file_standard_info *sinfo; @@ -4667,8 +4672,7 @@ static void get_standard_info_pipe(struct smb2_query_info_rsp *rsp, cpu_to_le32(sizeof(struct smb2_file_standard_info)); } -static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num, - void *rsp_org) +static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num) { struct smb2_file_internal_info *file_info; @@ -4682,8 +4686,7 @@ static void get_internal_info_pipe(struct smb2_query_info_rsp *rsp, u64 num, static int smb2_get_info_file_pipe(struct ksmbd_session *sess, struct smb2_query_info_req *req, - struct smb2_query_info_rsp *rsp, - void *rsp_org) + struct smb2_query_info_rsp *rsp) { u64 id; int rc; @@ -4708,14 +4711,16 @@ static int smb2_get_info_file_pipe(struct ksmbd_session *sess, switch (req->FileInfoClass) { case FILE_STANDARD_INFORMATION: - get_standard_info_pipe(rsp, rsp_org); + get_standard_info_pipe(rsp); rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), - rsp, rsp_org); + le32_to_cpu(rsp->OutputBufferLength), + rsp); break; case FILE_INTERNAL_INFORMATION: - get_internal_info_pipe(rsp, id, rsp_org); + get_internal_info_pipe(rsp, id); rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), - rsp, rsp_org); + le32_to_cpu(rsp->OutputBufferLength), + rsp); break; default: ksmbd_debug(SMB, "smb2_info_file_pipe for %u not supported\n", @@ -4998,7 +5003,6 @@ static int get_file_all_info(struct ksmbd_work *work, char *filename; u64 time; int ret, buf_free_len, filename_len; - struct smb2_query_info_req *req = ksmbd_req_buf_next(work); if (!(fp->daccess & FILE_READ_ATTRIBUTES_LE)) { ksmbd_debug(SMB, "no right to read the attributes : 0x%x\n", @@ -5011,10 +5015,9 @@ static int get_file_all_info(struct ksmbd_work *work, return PTR_ERR(filename); filename_len = strlen(filename); - buf_free_len = smb2_calc_max_out_buf_len(work, + buf_free_len = smb2_resp_buf_len(work, offsetof(struct smb2_query_info_rsp, Buffer) + - offsetof(struct smb2_file_all_info, FileName), - le32_to_cpu(req->OutputBufferLength)); + offsetof(struct smb2_file_all_info, FileName)); if (buf_free_len < (filename_len + 1) * 2) { kfree(filename); return -EINVAL; @@ -5107,7 +5110,6 @@ static int get_file_stream_info(struct ksmbd_work *work, ssize_t xattr_list_len; int nbytes = 0, streamlen, stream_name_len, next, idx = 0; int buf_free_len; - struct smb2_query_info_req *req = ksmbd_req_buf_next(work); int ret; ret = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, @@ -5117,10 +5119,8 @@ static int get_file_stream_info(struct ksmbd_work *work, file_info = (struct smb2_file_stream_info *)rsp->Buffer; - buf_free_len = - smb2_calc_max_out_buf_len(work, - offsetof(struct smb2_query_info_rsp, Buffer), - le32_to_cpu(req->OutputBufferLength)); + buf_free_len = smb2_resp_buf_len(work, + offsetof(struct smb2_query_info_rsp, Buffer)); if (buf_free_len < 0) goto out; @@ -5430,13 +5430,13 @@ static int smb2_get_info_file(struct ksmbd_work *work, struct ksmbd_file *fp; int fileinfoclass = 0; int rc = 0; + unsigned int fixed_len; unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_PIPE)) { /* smb2 info file called for pipe */ - rc = smb2_get_info_file_pipe(work->sess, req, rsp, - work->response_buf); + rc = smb2_get_info_file_pipe(work->sess, req, rsp); goto iov_pin_out; } @@ -5533,9 +5533,26 @@ static int smb2_get_info_file(struct ksmbd_work *work, fileinfoclass); rc = -EOPNOTSUPP; } - if (!rc) + if (!rc) { + fixed_len = le32_to_cpu(rsp->OutputBufferLength); + switch (fileinfoclass) { + case FILE_ALL_INFORMATION: + fixed_len = FILE_ALL_INFORMATION_SIZE; + break; + case FILE_ALTERNATE_NAME_INFORMATION: + fixed_len = FILE_ALTERNATE_NAME_INFORMATION_SIZE; + break; + case FILE_NORMALIZED_NAME_INFORMATION: + fixed_len = FILE_NORMALIZED_NAME_INFORMATION_SIZE; + break; + case FILE_STREAM_INFORMATION: + fixed_len = FILE_STREAM_INFORMATION_SIZE; + break; + } rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), - rsp, work->response_buf); + fixed_len, + rsp); + } ksmbd_fd_put(work, fp); iov_pin_out: @@ -5556,6 +5573,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, struct kstatfs stfs; struct path path; int rc = 0, len; + unsigned int fixed_len = 0; if (!share->path) return -EIO; @@ -5590,6 +5608,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, info->DeviceCharacteristics |= cpu_to_le32(FILE_READ_ONLY_DEVICE); rsp->OutputBufferLength = cpu_to_le32(8); + fixed_len = 8; break; } case FS_ATTRIBUTE_INFORMATION: @@ -5618,6 +5637,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, info->FileSystemNameLen = cpu_to_le32(len); sz = sizeof(struct filesystem_attribute_info) + len; rsp->OutputBufferLength = cpu_to_le32(sz); + fixed_len = 16; break; } case FS_VOLUME_INFORMATION: @@ -5644,6 +5664,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, info->Reserved = 0; sz = sizeof(struct filesystem_vol_info) + len; rsp->OutputBufferLength = cpu_to_le32(sz); + fixed_len = 24; break; } case FS_SIZE_INFORMATION: @@ -5656,6 +5677,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, info->SectorsPerAllocationUnit = cpu_to_le32(1); info->BytesPerSector = cpu_to_le32(stfs.f_bsize); rsp->OutputBufferLength = cpu_to_le32(24); + fixed_len = 24; break; } case FS_FULL_SIZE_INFORMATION: @@ -5671,6 +5693,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, info->SectorsPerAllocationUnit = cpu_to_le32(1); info->BytesPerSector = cpu_to_le32(stfs.f_bsize); rsp->OutputBufferLength = cpu_to_le32(32); + fixed_len = 32; break; } case FS_OBJECT_ID_INFORMATION: @@ -5691,6 +5714,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, info->extended_info.rel_date = 0; memcpy(info->extended_info.version_string, "1.1.0", strlen("1.1.0")); rsp->OutputBufferLength = cpu_to_le32(64); + fixed_len = 64; break; } case FS_SECTOR_SIZE_INFORMATION: @@ -5712,6 +5736,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, info->ByteOffsetForSectorAlignment = 0; info->ByteOffsetForPartitionAlignment = 0; rsp->OutputBufferLength = cpu_to_le32(28); + fixed_len = 28; break; } case FS_CONTROL_INFORMATION: @@ -5732,6 +5757,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, info->DefaultQuotaLimit = cpu_to_le64(SMB2_NO_FID); info->Padding = 0; rsp->OutputBufferLength = cpu_to_le32(48); + fixed_len = 48; break; } case FS_POSIX_INFORMATION: @@ -5752,6 +5778,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, info->TotalFileNodes = cpu_to_le64(stfs.f_files); info->FreeFileNodes = cpu_to_le64(stfs.f_ffree); rsp->OutputBufferLength = cpu_to_le32(56); + fixed_len = 56; } break; } @@ -5760,7 +5787,8 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, return -EOPNOTSUPP; } rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), - rsp, work->response_buf); + fixed_len, + rsp); path_put(&path); if (!rc) @@ -5874,7 +5902,8 @@ static int smb2_get_info_sec(struct ksmbd_work *work, iov_pin: rsp->OutputBufferLength = cpu_to_le32(secdesclen); rc = buffer_check_err(le32_to_cpu(req->OutputBufferLength), - rsp, work->response_buf); + le32_to_cpu(rsp->OutputBufferLength), + rsp); if (rc) goto err_out; diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h index 10591d757f2c..683334240701 100644 --- a/fs/smb/server/smb2pdu.h +++ b/fs/smb/server/smb2pdu.h @@ -213,6 +213,7 @@ struct file_sparse { #define FILE_ALLOCATION_INFORMATION_SIZE 19 #define FILE_END_OF_FILE_INFORMATION_SIZE 20 #define FILE_ALTERNATE_NAME_INFORMATION_SIZE 8 +#define FILE_NORMALIZED_NAME_INFORMATION_SIZE 8 #define FILE_STREAM_INFORMATION_SIZE 32 #define FILE_PIPE_INFORMATION_SIZE 23 #define FILE_PIPE_LOCAL_INFORMATION_SIZE 24 diff --git a/fs/smb/server/smb_common.c b/fs/smb/server/smb_common.c index 3e3758f5ed42..2f08c667e5ef 100644 --- a/fs/smb/server/smb_common.c +++ b/fs/smb/server/smb_common.c @@ -140,7 +140,7 @@ int ksmbd_verify_smb_message(struct ksmbd_work *work) if (smb2_hdr->ProtocolId == SMB2_PROTO_NUMBER) return ksmbd_smb2_check_message(work); - hdr = smb_get_msg(work->request_buf); + hdr = work->request_buf; if (*(__le32 *)hdr->Protocol == SMB1_PROTO_NUMBER && hdr->Command == SMB_COM_NEGOTIATE) { work->conn->outstanding_credits++; @@ -278,14 +278,15 @@ static int ksmbd_negotiate_smb_dialect(void *buf) req->DialectCount); } + proto = *(__le32 *)((struct smb_hdr *)buf)->Protocol; if (proto == SMB1_PROTO_NUMBER) { struct smb_negotiate_req *req; - req = (struct smb_negotiate_req *)smb_get_msg(buf); + req = (struct smb_negotiate_req *)buf; if (le16_to_cpu(req->ByteCount) < 2) goto err_out; - if (offsetof(struct smb_negotiate_req, DialectsArray) + + if (offsetof(struct smb_negotiate_req, DialectsArray) - 4 + le16_to_cpu(req->ByteCount) > smb_buf_length) { goto err_out; } @@ -319,8 +320,8 @@ static u16 get_smb1_cmd_val(struct ksmbd_work *work) */ static int init_smb1_rsp_hdr(struct ksmbd_work *work) { - struct smb_hdr *rsp_hdr = (struct smb_hdr *)smb_get_msg(work->response_buf); - struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb_get_msg(work->request_buf); + struct smb_hdr *rsp_hdr = (struct smb_hdr *)work->response_buf; + struct smb_hdr *rcv_hdr = (struct smb_hdr *)work->request_buf; rsp_hdr->Command = SMB_COM_NEGOTIATE; *(__le32 *)rsp_hdr->Protocol = SMB1_PROTO_NUMBER; @@ -411,10 +412,9 @@ static int init_smb1_server(struct ksmbd_conn *conn) int ksmbd_init_smb_server(struct ksmbd_conn *conn) { - struct smb_hdr *rcv_hdr = (struct smb_hdr *)smb_get_msg(conn->request_buf); __le32 proto; - proto = *(__le32 *)rcv_hdr->Protocol; + proto = *(__le32 *)((struct smb_hdr *)conn->request_buf)->Protocol; if (conn->need_neg == false) { if (proto == SMB1_PROTO_NUMBER) return -EINVAL; @@ -572,12 +572,12 @@ static int __smb2_negotiate(struct ksmbd_conn *conn) static int smb_handle_negotiate(struct ksmbd_work *work) { - struct smb_negotiate_rsp *neg_rsp = smb_get_msg(work->response_buf); + struct smb_negotiate_rsp *neg_rsp = work->response_buf; ksmbd_debug(SMB, "Unsupported SMB1 protocol\n"); - if (ksmbd_iov_pin_rsp(work, (void *)neg_rsp, - sizeof(struct smb_negotiate_rsp))) + if (ksmbd_iov_pin_rsp(work, (void *)neg_rsp + 4, + sizeof(struct smb_negotiate_rsp) - 4)) return -ENOMEM; neg_rsp->hdr.Status.CifsError = STATUS_SUCCESS; diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index 53ef4b7e504d..bdffade9848f 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c @@ -820,7 +820,7 @@ xfs_bmap_local_to_extents( args.mp = ip->i_mount; args.total = total; args.minlen = args.maxlen = args.prod = 1; - xfs_rmap_ino_owner(&args.oinfo, ip->i_ino, whichfork, 0); + xfs_rmap_inode_owner(&args.oinfo, ip, whichfork, 0); /* * Allocate a block. We know we need only one, since the diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c index 90f7fc219fcc..90fbdef23def 100644 --- a/fs/xfs/libxfs/xfs_da_btree.c +++ b/fs/xfs/libxfs/xfs_da_btree.c @@ -130,7 +130,7 @@ xfs_da_state_reset( state->mp = state->args->dp->i_mount; } -static inline int xfs_dabuf_nfsb(struct xfs_mount *mp, int whichfork) +inline int xfs_dabuf_nfsb(struct xfs_mount *mp, int whichfork) { if (whichfork == XFS_DATA_FORK) return mp->m_dir_geo->fsbcount; diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h index 354d5d65043e..cd2e213f5e74 100644 --- a/fs/xfs/libxfs/xfs_da_btree.h +++ b/fs/xfs/libxfs/xfs_da_btree.h @@ -242,4 +242,6 @@ xfs_failaddr_t xfs_da3_node_header_check(struct xfs_buf *bp, xfs_ino_t owner); extern struct kmem_cache *xfs_da_state_cache; +int xfs_dabuf_nfsb(struct xfs_mount *mp, int whichfork); + #endif /* __XFS_DA_BTREE_H__ */ diff --git a/fs/xfs/libxfs/xfs_rmap.h b/fs/xfs/libxfs/xfs_rmap.h index 5f39f6e53cd1..3670a33fc927 100644 --- a/fs/xfs/libxfs/xfs_rmap.h +++ b/fs/xfs/libxfs/xfs_rmap.h @@ -35,6 +35,8 @@ xfs_rmap_ino_owner( if (whichfork == XFS_ATTR_FORK) oi->oi_flags |= XFS_OWNER_INFO_ATTR_FORK; } +#define xfs_rmap_inode_owner(oi, ip, whichfork, offset) \ + xfs_rmap_ino_owner(oi, (ip)->i_ino, whichfork, offset) static inline bool xfs_rmap_should_skip_owner_update( diff --git a/fs/xfs/scrub/attr_repair.c b/fs/xfs/scrub/attr_repair.c index fa68ecabd983..6f668ddea819 100644 --- a/fs/xfs/scrub/attr_repair.c +++ b/fs/xfs/scrub/attr_repair.c @@ -1294,8 +1294,8 @@ xrep_xattr_swap_prep( .geo = sc->mp->m_attr_geo, .whichfork = XFS_ATTR_FORK, .trans = sc->tp, - .total = 1, - .owner = sc->ip->i_ino, + .total = xfs_dabuf_nfsb(sc->mp, XFS_ATTR_FORK), + .owner = I_INO(sc->ip), }; error = xfs_attr_shortform_to_leaf(&args); diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c index 47b5902431d0..687f2cd8a47f 100644 --- a/fs/xfs/scrub/bmap.c +++ b/fs/xfs/scrub/bmap.c @@ -352,7 +352,7 @@ xchk_bmap_rt_iextent_xref( case XFS_DATA_FORK: xchk_bmap_xref_rmap(info, irec, rgbno); if (!xfs_is_reflink_inode(info->sc->ip)) { - xfs_rmap_ino_owner(&oinfo, info->sc->ip->i_ino, + xfs_rmap_inode_owner(&oinfo, info->sc->ip, info->whichfork, irec->br_startoff); xchk_xref_is_only_rt_owned_by(info->sc, rgbno, irec->br_blockcount, &oinfo); @@ -407,7 +407,7 @@ xchk_bmap_iextent_xref( case XFS_DATA_FORK: xchk_bmap_xref_rmap(info, irec, agbno); if (!xfs_is_reflink_inode(info->sc->ip)) { - xfs_rmap_ino_owner(&oinfo, info->sc->ip->i_ino, + xfs_rmap_inode_owner(&oinfo, info->sc->ip, info->whichfork, irec->br_startoff); xchk_xref_is_only_owned_by(info->sc, agbno, irec->br_blockcount, &oinfo); @@ -419,7 +419,7 @@ xchk_bmap_iextent_xref( break; case XFS_ATTR_FORK: xchk_bmap_xref_rmap(info, irec, agbno); - xfs_rmap_ino_owner(&oinfo, info->sc->ip->i_ino, + xfs_rmap_inode_owner(&oinfo, info->sc->ip, info->whichfork, irec->br_startoff); xchk_xref_is_only_owned_by(info->sc, agbno, irec->br_blockcount, &oinfo); diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c index 58f2ed19ef5a..ecbf965ad689 100644 --- a/fs/xfs/scrub/common.c +++ b/fs/xfs/scrub/common.c @@ -309,12 +309,12 @@ xchk_ino_set_corrupt( /* Record a corruption while cross-referencing with an inode. */ void -xchk_ino_xref_set_corrupt( +xchk_ip_xref_set_corrupt( struct xfs_scrub *sc, - xfs_ino_t ino) + struct xfs_inode *ip) { sc->sm->sm_flags |= XFS_SCRUB_OFLAG_XCORRUPT; - trace_xchk_ino_error(sc, ino, __return_address); + trace_xchk_ino_error(sc, ip->i_ino, __return_address); } /* Record corruption in a block indexed by a file fork. */ diff --git a/fs/xfs/scrub/common.h b/fs/xfs/scrub/common.h index ae998501f8aa..5f854d3c7e8e 100644 --- a/fs/xfs/scrub/common.h +++ b/fs/xfs/scrub/common.h @@ -41,8 +41,8 @@ void xchk_qcheck_set_corrupt(struct xfs_scrub *sc, unsigned int dqtype, void xchk_block_xref_set_corrupt(struct xfs_scrub *sc, struct xfs_buf *bp); -void xchk_ino_xref_set_corrupt(struct xfs_scrub *sc, - xfs_ino_t ino); +void xchk_ip_xref_set_corrupt(struct xfs_scrub *sc, + struct xfs_inode *ip); void xchk_fblock_xref_set_corrupt(struct xfs_scrub *sc, int whichfork, xfs_fileoff_t offset); diff --git a/fs/xfs/scrub/dir_repair.c b/fs/xfs/scrub/dir_repair.c index b43ea86db074..36432705c44a 100644 --- a/fs/xfs/scrub/dir_repair.c +++ b/fs/xfs/scrub/dir_repair.c @@ -1473,8 +1473,8 @@ xrep_dir_swap_prep( .geo = sc->mp->m_dir_geo, .whichfork = XFS_DATA_FORK, .trans = sc->tp, - .total = 1, - .owner = sc->ip->i_ino, + .total = xfs_dabuf_nfsb(sc->mp, XFS_DATA_FORK), + .owner = I_INO(sc->ip), }; error = xfs_dir2_sf_to_block(&args); diff --git a/fs/xfs/scrub/dirtree.c b/fs/xfs/scrub/dirtree.c index 2b5c5fa72339..686437ce10e5 100644 --- a/fs/xfs/scrub/dirtree.c +++ b/fs/xfs/scrub/dirtree.c @@ -981,7 +981,7 @@ xchk_dirtree( * parent pointers are corrupt; this scan cannot be completed * without full information. */ - xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino); + xchk_ip_xref_set_corrupt(sc, sc->ip); error = 0; goto out_scanlock; } @@ -1011,7 +1011,7 @@ xchk_dirtree( if (oc.bad || oc.good + oc.suspect != 1) xchk_ip_set_corrupt(sc, sc->ip); if (oc.suspect) - xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino); + xchk_ip_xref_set_corrupt(sc, sc->ip); } out_scanlock: diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c index bb3f475b6353..0d30d65f336a 100644 --- a/fs/xfs/scrub/inode.c +++ b/fs/xfs/scrub/inode.c @@ -710,17 +710,17 @@ xchk_inode_xref_bmap( if (!xchk_should_check_xref(sc, &error, NULL)) return; if (nextents < xfs_dfork_data_extents(dip)) - xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino); + xchk_ip_xref_set_corrupt(sc, sc->ip); error = xchk_inode_count_blocks(sc, XFS_ATTR_FORK, &nextents, &acount); if (!xchk_should_check_xref(sc, &error, NULL)) return; if (nextents != xfs_dfork_attr_extents(dip)) - xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino); + xchk_ip_xref_set_corrupt(sc, sc->ip); /* Check nblocks against the inode. */ if (count + acount != be64_to_cpu(dip->di_nblocks)) - xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino); + xchk_ip_xref_set_corrupt(sc, sc->ip); } /* Cross-reference with the other btrees. */ diff --git a/fs/xfs/scrub/nlinks.c b/fs/xfs/scrub/nlinks.c index 988262fc9953..d783b32a0b28 100644 --- a/fs/xfs/scrub/nlinks.c +++ b/fs/xfs/scrub/nlinks.c @@ -741,7 +741,7 @@ xchk_nlinks_compare_inode( * number of subdirectory entries in the directory. */ if (obs.children != obs.backrefs) - xchk_ino_xref_set_corrupt(sc, ip->i_ino); + xchk_ip_xref_set_corrupt(sc, ip); } else { /* * Non-directories and unlinked directories should not have diff --git a/fs/xfs/scrub/reap.c b/fs/xfs/scrub/reap.c index db32356e517d..116afa89b1b3 100644 --- a/fs/xfs/scrub/reap.c +++ b/fs/xfs/scrub/reap.c @@ -1249,8 +1249,7 @@ xreap_bmapi_select( cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, sc->sa.agf_bp, sc->sa.pag); - xfs_rmap_ino_owner(&oinfo, rs->ip->i_ino, rs->whichfork, - imap->br_startoff); + xfs_rmap_inode_owner(&oinfo, rs->ip, rs->whichfork, imap->br_startoff); error = xfs_rmap_has_other_keys(cur, agbno, 1, &oinfo, crosslinked); if (error) goto out_cur; diff --git a/fs/xfs/scrub/rtbitmap.c b/fs/xfs/scrub/rtbitmap.c index 68b833870760..639e1328c199 100644 --- a/fs/xfs/scrub/rtbitmap.c +++ b/fs/xfs/scrub/rtbitmap.c @@ -284,7 +284,7 @@ xchk_xref_is_used_rt_space( if (xfs_has_zoned(sc->mp)) { if (!xfs_zone_rgbno_is_valid(rtg, xfs_rtb_to_rgbno(sc->mp, rtbno) + len - 1)) - xchk_ino_xref_set_corrupt(sc, rtg_rmap(rtg)->i_ino); + xchk_ip_xref_set_corrupt(sc, rtg_rmap(rtg)); return; } @@ -295,5 +295,5 @@ xchk_xref_is_used_rt_space( if (!xchk_should_check_xref(sc, &error, NULL)) return; if (is_free) - xchk_ino_xref_set_corrupt(sc, rtg_bitmap(rtg)->i_ino); + xchk_ip_xref_set_corrupt(sc, rtg_bitmap(rtg)); } diff --git a/fs/xfs/scrub/rtsummary.c b/fs/xfs/scrub/rtsummary.c index dbbbafe8b92d..8fb06ce4a200 100644 --- a/fs/xfs/scrub/rtsummary.c +++ b/fs/xfs/scrub/rtsummary.c @@ -190,7 +190,7 @@ xchk_rtsum_record_free( rtlen = xfs_rtxlen_to_extlen(mp, rec->ar_extcount); if (!xfs_verify_rtbext(mp, rtbno, rtlen)) { - xchk_ino_xref_set_corrupt(sc, rtg_bitmap(rtg)->i_ino); + xchk_ip_xref_set_corrupt(sc, rtg_bitmap(rtg)); return -EFSCORRUPTED; } @@ -359,7 +359,7 @@ xchk_rtsummary( * EFSCORRUPTED means the rtbitmap is corrupt, which is an xref * error since we're checking the summary file. */ - xchk_ino_xref_set_corrupt(sc, rbmip->i_ino); + xchk_ip_xref_set_corrupt(sc, rbmip); return 0; } if (error) diff --git a/fs/xfs/scrub/tempfile.c b/fs/xfs/scrub/tempfile.c index fabf6ae2e512..d9741a566fc6 100644 --- a/fs/xfs/scrub/tempfile.c +++ b/fs/xfs/scrub/tempfile.c @@ -649,6 +649,19 @@ xrep_tempexch_prep_request( return 0; } +static inline unsigned int +xrep_tempexch_estimate_sf_resblks( + struct xfs_scrub *sc, + int whichfork) +{ + /* repairing a symlink target */ + if (S_ISLNK(VFS_I(sc->ip)->i_mode) && whichfork == XFS_DATA_FORK) + return 1; + + /* everything else is a directory or an xattr structure */ + return xfs_dabuf_nfsb(sc->mp, whichfork); +} + /* * Fill out the mapping exchange resource estimation structures in preparation * for exchanging the contents of a metadata file that we've rebuilt in the @@ -663,6 +676,8 @@ xrep_tempexch_estimate( struct xfs_ifork *ifp; struct xfs_ifork *tifp; int whichfork = xfs_exchmaps_reqfork(req); + unsigned int sf_resblks = + xrep_tempexch_estimate_sf_resblks(sc, whichfork); int state = 0; /* @@ -693,9 +708,9 @@ xrep_tempexch_estimate( * plus the block we converted. */ req->ip1_bcount = sc->tempip->i_nblocks; - req->ip2_bcount = 1; + req->ip2_bcount = sf_resblks; req->nr_exchanges = 1 + tifp->if_nextents; - req->resblks = 1; + req->resblks = sf_resblks; break; case 2: /* @@ -707,10 +722,10 @@ xrep_tempexch_estimate( * is (worst case) the extent count of the file being repaired * plus the block we converted. */ - req->ip1_bcount = 1; + req->ip1_bcount = sf_resblks; req->ip2_bcount = sc->ip->i_nblocks; req->nr_exchanges = 1 + ifp->if_nextents; - req->resblks = 1; + req->resblks = sf_resblks; break; case 3: /* @@ -722,10 +737,10 @@ xrep_tempexch_estimate( * fileoff 0. Presumably, the caller could not exchange the * two inode fork areas directly. */ - req->ip1_bcount = 1; - req->ip2_bcount = 1; + req->ip1_bcount = sf_resblks; + req->ip2_bcount = sf_resblks; req->nr_exchanges = 1; - req->resblks = 2; + req->resblks = 2 * sf_resblks; break; } diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index bd6d33557194..11598ee7c179 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -184,6 +184,9 @@ static inline const struct inode *VFS_IC(const struct xfs_inode *ip) return &ip->i_vnode; } +/* The VFS inode number is only unsigned long on this stable branch. */ +#define I_INO(ip) ((ip)->i_ino) + /* * For regular files we only update the on-disk filesize when actually * writing data back to disk. Until then only the copy in the VFS inode diff --git a/include/keys/request_key_auth-type.h b/include/keys/request_key_auth-type.h index 01e42ee5f409..464636278c4f 100644 --- a/include/keys/request_key_auth-type.h +++ b/include/keys/request_key_auth-type.h @@ -22,7 +22,7 @@ struct request_key_auth { const struct cred *cred; void *callout_info; size_t callout_len; - pid_t pid; + struct pid *pid; char op[8]; } __randomize_layout; diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 2526ccd8a4a0..2cf3ae4b940a 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -2249,6 +2249,11 @@ enum ieee80211_radio_measurement_actioncode { #define PMK_MAX_LEN 64 #define SAE_PASSWORD_MAX_LEN 128 +#define MICHAEL_MIC_LEN 8 + +void michael_mic(const u8 *key, struct ieee80211_hdr *hdr, + const u8 *data, size_t data_len, u8 *mic); + /* Public action codes (IEEE Std 802.11-2016, 9.6.8.1, Table 9-307) */ enum ieee80211_pub_actioncode { WLAN_PUB_ACTION_20_40_BSS_COEX = 0, diff --git a/include/linux/mm.h b/include/linux/mm.h index 50710a5d4a05..2c0503bbcc19 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2516,7 +2516,7 @@ struct zap_details { void sched_mm_cid_before_execve(struct task_struct *t); void sched_mm_cid_after_execve(struct task_struct *t); void sched_mm_cid_fork(struct task_struct *t); -void sched_mm_cid_exit_signals(struct task_struct *t); +void sched_mm_cid_exit(struct task_struct *t); static inline int task_mm_cid(struct task_struct *t) { return t->mm_cid; @@ -2525,7 +2525,7 @@ static inline int task_mm_cid(struct task_struct *t) static inline void sched_mm_cid_before_execve(struct task_struct *t) { } static inline void sched_mm_cid_after_execve(struct task_struct *t) { } static inline void sched_mm_cid_fork(struct task_struct *t) { } -static inline void sched_mm_cid_exit_signals(struct task_struct *t) { } +static inline void sched_mm_cid_exit(struct task_struct *t) { } static inline int task_mm_cid(struct task_struct *t) { /* diff --git a/include/net/bluetooth/coredump.h b/include/net/bluetooth/coredump.h index 72f51b587a04..00c12c7ac042 100644 --- a/include/net/bluetooth/coredump.h +++ b/include/net/bluetooth/coredump.h @@ -61,6 +61,7 @@ struct hci_devcoredump { #ifdef CONFIG_DEV_COREDUMP void hci_devcd_reset(struct hci_dev *hdev); +void hci_devcd_shutdown(struct hci_dev *hdev); void hci_devcd_rx(struct work_struct *work); void hci_devcd_timeout(struct work_struct *work); @@ -75,6 +76,7 @@ int hci_devcd_abort(struct hci_dev *hdev); #else static inline void hci_devcd_reset(struct hci_dev *hdev) {} +static inline void hci_devcd_shutdown(struct hci_dev *hdev) {} static inline void hci_devcd_rx(struct work_struct *work) {} static inline void hci_devcd_timeout(struct work_struct *work) {} diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ac2546b12138..d19b95d3c3a4 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -7309,11 +7309,14 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw, * * @skb: packet injected by userspace * @dev: the &struct device of this 802.11 device + * @chandef: the channel definition the frame will be transmitted on, or + * %NULL to skip the bandwidth checks * * Return: %true if the radiotap header was parsed, %false otherwise */ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, - struct net_device *dev); + struct net_device *dev, + const struct cfg80211_chan_def *chandef); /** * struct ieee80211_noa_data - holds temporary data for tracking P2P NoA state diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h index 23dd647fe024..b73983a17e08 100644 --- a/include/net/netns/xfrm.h +++ b/include/net/netns/xfrm.h @@ -59,7 +59,7 @@ struct netns_xfrm { struct list_head inexact_bins; - struct sock *nlsk; + struct sock __rcu *nlsk; struct sock *nlsk_stash; u32 sysctl_aevent_etime; diff --git a/include/net/sock.h b/include/net/sock.h index 9e13e1233e41..fb91d72a955d 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -2260,6 +2260,8 @@ static inline void sk_gso_disable(struct sock *sk) sk->sk_route_caps &= ~NETIF_F_GSO_MASK; } +bool sk_has_decrypt_user(const struct sock *sk); + static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb, struct iov_iter *from, char *to, int copy, int offset) diff --git a/include/sound/soc.h b/include/sound/soc.h index 33968935d00a..bfe8cd7cc338 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -682,7 +682,8 @@ struct snd_soc_dai_link_component { struct snd_soc_dai_link_ch_map { unsigned int cpu; unsigned int codec; - unsigned int ch_mask; + unsigned int cpu_ch_mask; + unsigned int codec_ch_mask; }; struct snd_soc_dai_link { diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h index 3c5e9b2af7f1..ea8b8adf33b7 100644 --- a/include/sound/soc_sdw_utils.h +++ b/include/sound/soc_sdw_utils.h @@ -13,6 +13,7 @@ #include #define SOC_SDW_MAX_DAI_NUM 8 +#define SOC_SDW_MAX_AUX_NUM 2 #define SOC_SDW_MAX_NO_PROPS 2 #define SOC_SDW_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0)) @@ -43,6 +44,18 @@ struct asoc_sdw_codec_info; +struct asoc_sdw_mc_private { + struct snd_soc_card card; + struct snd_soc_jack sdw_headset; + struct device *headset_codec_dev; /* only one headset per card */ + struct device *amp_dev1, *amp_dev2; + bool append_dai_type; + bool ignore_internal_dmic; + void *private; + unsigned long mc_quirk; + int codec_info_list_count; +}; + struct asoc_sdw_dai_info { const bool direction[2]; /* playback & capture support */ const char *dai_name; @@ -64,6 +77,10 @@ struct asoc_sdw_dai_info { bool quirk_exclude; }; +struct asoc_sdw_aux_info { + const char *codec_name; +}; + struct asoc_sdw_codec_info { const int part_id; const int version_id; @@ -74,28 +91,18 @@ struct asoc_sdw_codec_info { const struct snd_soc_ops *ops; struct asoc_sdw_dai_info dais[SOC_SDW_MAX_DAI_NUM]; const int dai_num; + struct asoc_sdw_aux_info auxs[SOC_SDW_MAX_AUX_NUM]; + const int aux_num; int (*codec_card_late_probe)(struct snd_soc_card *card); - int (*count_sidecar)(struct snd_soc_card *card, + int (*count_sidecar)(struct asoc_sdw_mc_private *ctx, int *num_dais, int *num_devs); int (*add_sidecar)(struct snd_soc_card *card, struct snd_soc_dai_link **dai_links, struct snd_soc_codec_conf **codec_conf); }; -struct asoc_sdw_mc_private { - struct snd_soc_card card; - struct snd_soc_jack sdw_headset; - struct device *headset_codec_dev; /* only one headset per card */ - struct device *amp_dev1, *amp_dev2; - bool append_dai_type; - bool ignore_internal_dmic; - void *private; - unsigned long mc_quirk; - int codec_info_list_count; -}; - struct asoc_sdw_endpoint { struct list_head list; @@ -164,12 +171,15 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d int no_pcm, int (*init)(struct snd_soc_pcm_runtime *rtd), const struct snd_soc_ops *ops); -int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends); +int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, + int *num_devs, int *num_ends, int *num_aux); struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, const struct snd_soc_acpi_endpoint *new); -int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, +int asoc_sdw_parse_sdw_endpoints(struct device *dev, + struct asoc_sdw_mc_private *ctx, + struct snd_soc_aux_dev *soc_aux, struct asoc_sdw_dailink *soc_dais, struct asoc_sdw_endpoint *soc_ends, int *num_devs); @@ -210,7 +220,7 @@ int asoc_sdw_cs42l43_spk_init(struct snd_soc_card *card, bool playback); /* CS AMP support */ -int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card, +int asoc_sdw_bridge_cs35l56_count_sidecar(struct asoc_sdw_mc_private *ctx, int *num_dais, int *num_devs); int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card, struct snd_soc_dai_link **dai_links, diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c index 77c8d9487a9a..87f2f02e921a 100644 --- a/kernel/dma/coherent.c +++ b/kernel/dma/coherent.c @@ -351,8 +351,7 @@ static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev) min_not_zero(dev->coherent_dma_mask, dev->bus_dma_limit)) dev_warn(dev, "reserved memory is beyond device's set DMA address range\n"); - dma_assign_coherent_memory(dev, mem); - return 0; + return dma_assign_coherent_memory(dev, mem); } static void rmem_dma_device_release(struct reserved_mem *rmem, diff --git a/kernel/dma/swiotlb.c b/kernel/dma/swiotlb.c index 294543316622..4593064c2ada 100644 --- a/kernel/dma/swiotlb.c +++ b/kernel/dma/swiotlb.c @@ -869,7 +869,6 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size int index = (tlb_addr - mem->start) >> IO_TLB_SHIFT; phys_addr_t orig_addr = mem->slots[index].orig_addr; size_t alloc_size = mem->slots[index].alloc_size; - unsigned long pfn = PFN_DOWN(orig_addr); unsigned char *vaddr = mem->vaddr + tlb_addr - mem->start; int tlb_offset; @@ -899,7 +898,8 @@ static void swiotlb_bounce(struct device *dev, phys_addr_t tlb_addr, size_t size size = alloc_size; } - if (PageHighMem(pfn_to_page(pfn))) { + if (PhysHighMem(orig_addr)) { + unsigned long pfn = PFN_DOWN(orig_addr); unsigned int offset = orig_addr & ~PAGE_MASK; struct page *page; unsigned int sz = 0; diff --git a/kernel/exit.c b/kernel/exit.c index d60c1241923a..e38b2bb85097 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -304,12 +304,13 @@ void release_task(struct task_struct *p) free_pids(post.pids); release_thread(p); /* - * This task was already removed from the process/thread/pid lists - * and lock_task_sighand(p) can't succeed. Nobody else can touch - * ->pending or, if group dead, signal->shared_pending. We can call - * flush_sigqueue() lockless. + * This task was already removed from the process/thread/pid lists and + * lock_task_sighand(p) can't succeed. If it's the group leader then + * flush tsk->signal->shared_pending. tsk->pending has been flushed + * already in exit_signals(). Nothing else can touch + * signal->shared_pending anymore, so flush_sigqueue() can be invoked + * lockless. */ - flush_sigqueue(&p->pending); if (thread_group_leader(p)) flush_sigqueue(&p->signal->shared_pending); @@ -924,6 +925,7 @@ void __noreturn do_exit(long code) user_events_exit(tsk); io_uring_files_cancel(); + sched_mm_cid_exit(tsk); exit_signals(tsk); /* sets PF_EXITING */ seccomp_filter_release(tsk); diff --git a/kernel/fork.c b/kernel/fork.c index 295cf8cf719e..7be5736d44c7 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1918,9 +1918,9 @@ static bool need_futex_hash_allocate_default(u64 clone_flags) { /* * Allocate a default futex hash for any sibling that will - * share the parent's mm, except vfork. + * share the parent's mm. */ - return (clone_flags & (CLONE_VM | CLONE_VFORK)) == CLONE_VM; + return clone_flags & CLONE_VM; } /* diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 43f3ac16b0e8..aad9813bd617 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -10545,7 +10545,7 @@ int __sched_mm_cid_migrate_from_try_steal_cid(struct rq *src_rq, * * The implicit barrier after cmpxchg per-mm/cpu cid before loading * rq->curr->mm_cid_active matches the barrier in - * sched_mm_cid_exit_signals(), sched_mm_cid_before_execve(), and + * sched_mm_cid_exit(), sched_mm_cid_before_execve(), and * sched_mm_cid_after_execve() between store to t->mm_cid_active and * load of per-mm/cpu cid. */ @@ -10665,7 +10665,7 @@ static void sched_mm_cid_remote_clear(struct mm_struct *mm, struct mm_cid *pcpu_ * * The implicit barrier after cmpxchg per-mm/cpu cid before loading * rq->curr->mm_cid_active matches the barrier in - * sched_mm_cid_exit_signals(), sched_mm_cid_before_execve(), and + * sched_mm_cid_exit(), sched_mm_cid_before_execve(), and * sched_mm_cid_after_execve() between store to t->mm_cid_active and * load of per-mm/cpu cid. */ @@ -10810,7 +10810,7 @@ void task_tick_mm_cid(struct rq *rq, struct task_struct *curr) task_work_add(curr, work, TWA_RESUME); } -void sched_mm_cid_exit_signals(struct task_struct *t) +void sched_mm_cid_exit(struct task_struct *t) { struct mm_struct *mm = t->mm; struct rq *rq; diff --git a/kernel/signal.c b/kernel/signal.c index b18f07a5b62d..0d2fcf9d3023 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -475,18 +475,42 @@ static void __sigqueue_free(struct sigqueue *q) kmem_cache_free(sigqueue_cachep, q); } -void flush_sigqueue(struct sigpending *queue) +/* + * flush_sigqueue_list() can only be invoked without holding sighand::siglock in + * the following cases: + * + * 1) When flushing task::pending _after_ setting task::flags PF_EXITING + * + * All functions which try to send a signal to @task will observe PF_EXITING + * and drop the signal. + * + * 2) When flushing task::signal::shared_pending _after_ the last task in a + * thread group was unhashed and task::sighand is NULL. + * + * Nothing can queue a signal anymore because sighand is NULL. + */ +static void flush_sigqueue_list(struct list_head *head) { - struct sigqueue *q; + struct sigqueue *q, *tmp; - sigemptyset(&queue->signal); - while (!list_empty(&queue->list)) { - q = list_entry(queue->list.next, struct sigqueue , list); + list_for_each_entry_safe(q, tmp, head, list) { list_del_init(&q->list); __sigqueue_free(q); } } +void flush_sigqueue(struct sigpending *queue) +{ + sigemptyset(&queue->signal); + flush_sigqueue_list(&queue->list); +} + +static void sigqueue_dequeue_pending(struct sigpending *queue, struct list_head *head) +{ + sigemptyset(&queue->signal); + list_splice_init(&queue->list, head); +} + /* * Flush all pending signals for this kthread. */ @@ -1039,6 +1063,21 @@ static inline bool legacy_queue(struct sigpending *signals, int sig) return (sig < SIGRTMIN) && sigismember(&signals->signal, sig); } +/* + * When PF_EXITING is set the task is on the way out and has t::pending + * flushed already. Prevent queueing of PIDTYPE_PID signals as they would + * be leaked. + */ +static inline bool task_can_queue_signal(struct task_struct *t, enum pid_type type) +{ + lockdep_assert_held(&t->sighand->siglock); + + if (!(t->flags & PF_EXITING)) + return true; + + return type != PIDTYPE_PID; +} + static int __send_signal_locked(int sig, struct kernel_siginfo *info, struct task_struct *t, enum pid_type type, bool force) { @@ -1050,6 +1089,10 @@ static int __send_signal_locked(int sig, struct kernel_siginfo *info, lockdep_assert_held(&t->sighand->siglock); result = TRACE_SIGNAL_IGNORED; + + if (!task_can_queue_signal(t, type)) + goto ret; + if (!prepare_signal(sig, t, force)) goto ret; @@ -1993,11 +2036,25 @@ static inline struct task_struct *posixtimer_get_target(struct k_itimer *tmr) struct task_struct *t = pid_task(tmr->it_pid, tmr->it_pid_type); if (t && tmr->it_pid_type != PIDTYPE_PID && - same_thread_group(t, current) && !current->exit_state) + same_thread_group(t, current) && !(current->flags & PF_EXITING)) t = current; return t; } +/* + * Find the target task for the POSIX timer signal and prevent that a + * PIDTYPE_PID signal is queued on a task which has PF_EXITING set. + */ +static inline struct task_struct *posixtimer_get_unignore_target(struct k_itimer *tmr) +{ + struct task_struct *t = posixtimer_get_target(tmr); + + if (t && task_can_queue_signal(t, tmr->it_pid_type)) + return t; + + return NULL; +} + void posixtimer_send_sigqueue(struct k_itimer *tmr) { struct sigqueue *q = &tmr->sigq; @@ -2015,6 +2072,9 @@ void posixtimer_send_sigqueue(struct k_itimer *tmr) if (!likely(lock_task_sighand(t, &flags))) return; + if (!task_can_queue_signal(t, tmr->it_pid_type)) + goto unlock; + /* * Update @tmr::sigqueue_seq for posix timer signals with sighand * locked to prevent a race against dequeue_signal(). @@ -2106,6 +2166,7 @@ void posixtimer_send_sigqueue(struct k_itimer *tmr) result = TRACE_SIGNAL_DELIVERED; out: trace_signal_generate(sig, &q->info, t, tmr->it_pid_type != PIDTYPE_PID, result); +unlock: unlock_task_sighand(t, &flags); } @@ -2161,7 +2222,7 @@ static void posixtimer_sig_unignore(struct task_struct *tsk, int sig) * has exited by now, drop the reference count. */ guard(rcu)(); - target = posixtimer_get_target(tmr); + target = posixtimer_get_unignore_target(tmr); if (target) posixtimer_queue_sigqueue(&tmr->sigq, target, tmr->it_pid_type); else @@ -3140,44 +3201,36 @@ static void retarget_shared_pending(struct task_struct *tsk, sigset_t *which) void exit_signals(struct task_struct *tsk) { + LIST_HEAD(sigq_list); int group_stop = 0; - sigset_t unblocked; /* * @tsk is about to have PF_EXITING set - lock out users which - * expect stable threadgroup. + * expect a stable threadgroup. */ cgroup_threadgroup_change_begin(tsk); - if (thread_group_empty(tsk) || (tsk->signal->flags & SIGNAL_GROUP_EXIT)) { - sched_mm_cid_exit_signals(tsk); + scoped_guard(spinlock_irq, &tsk->sighand->siglock) { tsk->flags |= PF_EXITING; - cgroup_threadgroup_change_end(tsk); - return; - } - spin_lock_irq(&tsk->sighand->siglock); - /* - * From now this task is not visible for group-wide signals, - * see wants_signal(), do_signal_stop(). - */ - sched_mm_cid_exit_signals(tsk); - tsk->flags |= PF_EXITING; + sigqueue_dequeue_pending(&tsk->pending, &sigq_list); - cgroup_threadgroup_change_end(tsk); + if (task_sigpending(tsk) && !thread_group_empty(tsk) && + !(tsk->signal->flags & SIGNAL_GROUP_EXIT)) { + sigset_t unblocked = tsk->blocked; - if (!task_sigpending(tsk)) - goto out; + signotset(&unblocked); + retarget_shared_pending(tsk, &unblocked); - unblocked = tsk->blocked; - signotset(&unblocked); - retarget_shared_pending(tsk, &unblocked); + if (unlikely(tsk->jobctl & JOBCTL_STOP_PENDING) && + task_participate_group_stop(tsk)) + group_stop = CLD_STOPPED; + } + } - if (unlikely(tsk->jobctl & JOBCTL_STOP_PENDING) && - task_participate_group_stop(tsk)) - group_stop = CLD_STOPPED; -out: - spin_unlock_irq(&tsk->sighand->siglock); + cgroup_threadgroup_change_end(tsk); + + flush_sigqueue_list(&sigq_list); /* * If group stop has completed, deliver the notification. This diff --git a/kernel/time/namespace.c b/kernel/time/namespace.c index 51d2fcba7b5f..99dcdb3315db 100644 --- a/kernel/time/namespace.c +++ b/kernel/time/namespace.c @@ -57,6 +57,7 @@ ktime_t do_timens_ktime_to_host(clockid_t clockid, ktime_t tim, return tim; } +EXPORT_SYMBOL_GPL(do_timens_ktime_to_host); static struct ucounts *inc_time_namespaces(struct user_namespace *ns) { @@ -364,6 +365,7 @@ struct time_namespace init_time_ns = { .ns.ops = &timens_operations, .frozen_offsets = true, }; +EXPORT_SYMBOL_GPL(init_time_ns); void __init time_ns_init(void) { diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index 2d64972fd080..b3d4bae9ee3e 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -408,6 +408,7 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer) new_timer->kclock = &clock_posix_cpu; timerqueue_init(&new_timer->it.cpu.node); + INIT_LIST_HEAD(&new_timer->it.cpu.elist); new_timer->it.cpu.pid = get_pid(pid); rcu_read_unlock(); return 0; @@ -565,6 +566,24 @@ static struct task_struct *timer_lock_sighand(struct k_itimer *timer, unsigned l return NULL; } +/* + * If the timer is queued on the expiry list, then it cannot be dequeued because + * the firing list is not protected by sighand->lock. The delivery path is + * waiting for the timer lock. So go back, unlock and retry. + */ +static bool posix_cpu_timer_on_expiry_list(struct k_itimer *timer) +{ + if (list_empty(&timer->it.cpu.elist)) + return false; + + /* + * Prevent signal delivery as there is no point in delivering a signal + * which is made obsolete right away. + */ + timer->it.cpu.firing = false; + return true; +} + /* * Clean up a CPU-clock timer that is about to be destroyed. * This is called from timer deletion with the timer already locked. @@ -580,18 +599,10 @@ static int posix_cpu_timer_del(struct k_itimer *timer) p = timer_lock_sighand(timer, &flags); if (likely(p)) { - if (timer->it.cpu.firing) { - /* - * Prevent signal delivery. The timer cannot be dequeued - * because it is on the firing list which is not protected - * by sighand->lock. The delivery path is waiting for - * the timer lock. So go back, unlock and retry. - */ - timer->it.cpu.firing = false; + if (posix_cpu_timer_on_expiry_list(timer)) ret = TIMER_RETRY; - } else { + else disarm_timer(timer, p); - } unlock_task_sighand(p, &flags); } @@ -731,14 +742,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, /* Retrieve the current expiry time before disarming the timer */ old_expires = cpu_timer_getexpires(ctmr); - if (unlikely(timer->it.cpu.firing)) { - /* - * Prevent signal delivery. The timer cannot be dequeued - * because it is on the firing list which is not protected - * by sighand->lock. The delivery path is waiting for - * the timer lock. So go back, unlock and retry. - */ - timer->it.cpu.firing = false; + if (posix_cpu_timer_on_expiry_list(timer)) { ret = TIMER_RETRY; } else { cpu_timer_dequeue(ctmr); diff --git a/mm/filemap.c b/mm/filemap.c index 2d7533e965e6..1a0358810609 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1624,7 +1624,7 @@ static void filemap_end_dropbehind(struct folio *folio) return; if (!folio_test_clear_dropbehind(folio)) return; - if (mapping) + if (mapping && !folio_mapped(folio)) folio_unmap_invalidate(mapping, folio, 0); } diff --git a/mm/huge_memory.c b/mm/huge_memory.c index bedd9ba223fb..e0c7b7efd38a 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -84,7 +84,7 @@ unsigned long huge_anon_orders_madvise __read_mostly; unsigned long huge_anon_orders_inherit __read_mostly; static bool anon_orders_configured __initdata; -static inline bool file_thp_enabled(struct vm_area_struct *vma) +static inline bool file_thp_enabled(const struct vm_area_struct *vma) { struct inode *inode; @@ -102,6 +102,67 @@ static inline bool file_thp_enabled(struct vm_area_struct *vma) return !inode_is_open_for_write(inode) && S_ISREG(inode->i_mode); } +static bool vma_file_bypass_thp_tuneables(const struct vm_area_struct *vma, + enum tva_type type) +{ + const bool has_huge_fault = vma->vm_ops->huge_fault; + + /* MADV_COLLAPSE ignores tuneables. */ + if (type == TVA_FORCED_COLLAPSE) + return true; + /* Huge PFN mappings are uncompactable so the policy doesn't apply. */ + if ((vma->vm_flags & VM_PFNMAP) && has_huge_fault) + return true; + return false; +} + +static bool vma_file_allow_thp_tuneables(vm_flags_t vm_flags) +{ + /* THP=always? */ + if (hugepage_global_always()) + return true; + /* THP=madvise and marked MADV_HUGEPAGE? */ + if (hugepage_global_enabled() && (vm_flags & VM_HUGEPAGE)) + return true; + return false; +} + +static bool vma_file_check_thp_tuneables(const struct vm_area_struct *vma, + vm_flags_t vm_flags, enum tva_type type) +{ + return vma_file_bypass_thp_tuneables(vma, type) || + vma_file_allow_thp_tuneables(vm_flags); +} + +static bool vma_can_map_huge_file(const struct vm_area_struct *vma, + vm_flags_t vm_flags, enum tva_type type) +{ + const bool has_huge_fault = vma->vm_ops->huge_fault; + + /* + * Enforce THP collapse requirements as necessary. Anonymous vmas + * were already handled in thp_vma_allowable_orders(). + */ + if (!vma_file_check_thp_tuneables(vma, vm_flags, type)) + return false; + + switch (type) { + case TVA_PAGEFAULT: + /* + * Trust that ->huge_fault() handlers know what they are doing + * in fault path. + */ + return has_huge_fault; + case TVA_SMAPS: + if (has_huge_fault) + return true; + fallthrough; + default: + /* Only regular file is valid in collapse path. */ + return file_thp_enabled(vma); + } +} + unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma, vm_flags_t vm_flags, enum tva_type type, @@ -174,27 +235,8 @@ unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma, vma, vma->vm_pgoff, 0, forced_collapse); - if (!vma_is_anonymous(vma)) { - /* - * Enforce THP collapse requirements as necessary. Anonymous vmas - * were already handled in thp_vma_allowable_orders(). - */ - if (!forced_collapse && - (!hugepage_global_enabled() || (!(vm_flags & VM_HUGEPAGE) && - !hugepage_global_always()))) - return 0; - - /* - * Trust that ->huge_fault() handlers know what they are doing - * in fault path. - */ - if (((in_pf || smaps)) && vma->vm_ops->huge_fault) - return orders; - /* Only regular file is valid in collapse path */ - if (((!in_pf || smaps)) && file_thp_enabled(vma)) - return orders; - return 0; - } + if (!vma_is_anonymous(vma)) + return vma_can_map_huge_file(vma, vm_flags, type) ? orders : 0; if (vma_is_temporary_stack(vma)) return 0; diff --git a/mm/memblock.c b/mm/memblock.c index 757258d68425..e2f15bbc274b 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -2727,14 +2727,18 @@ static int memblock_debug_show(struct seq_file *m, void *private) else seq_printf(m, "%4c ", 'x'); if (reg->flags) { - for (j = 0; j < count; j++) { - if (reg->flags & (1U << j)) { - seq_printf(m, "%s\n", flagname[j]); - break; - } + unsigned int flags = reg->flags; + bool first = true; + + for (j = 0; flags; j++, flags >>= 1) { + if (!(flags & 1)) + continue; + if (!first) + seq_putc(m, '|'); + seq_puts(m, j < count ? flagname[j] : "UNKNOWN"); + first = false; } - if (j == count) - seq_printf(m, "%s\n", "UNKNOWN"); + seq_putc(m, '\n'); } else { seq_printf(m, "%s\n", "NONE"); } diff --git a/mm/memcontrol.c b/mm/memcontrol.c index a4a3da6f241c..82ad23d689c7 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2812,7 +2812,7 @@ static int obj_cgroup_charge_pages(struct obj_cgroup *objcg, gfp_t gfp, memcg = get_mem_cgroup_from_objcg(objcg); - ret = try_charge_memcg(memcg, gfp, nr_pages); + ret = try_charge(memcg, gfp, nr_pages); if (ret) goto out; diff --git a/mm/mlock.c b/mm/mlock.c index 73551c71cebf..31045f17766a 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -141,7 +141,7 @@ static struct lruvec *__munlock_folio(struct folio *folio, struct lruvec *lruvec munlock: if (folio_test_clear_mlocked(folio)) { - __zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages); + zone_stat_mod_folio(folio, NR_MLOCK, -nr_pages); if (isolated || !folio_test_unevictable(folio)) __count_vm_events(UNEVICTABLE_PGMUNLOCKED, nr_pages); else diff --git a/mm/mremap.c b/mm/mremap.c index bdf63ffaad3d..e60a63a36ea0 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -1270,12 +1270,11 @@ static void dontunmap_complete(struct vma_remap_struct *vrm, if (vma_is_anonymous(vma) && !vma->vm_file) vma->vm_pgoff = pgoff_unfaulted; } - - /* Because we won't unmap we don't need to touch locked_vm. */ } static unsigned long move_vma(struct vma_remap_struct *vrm) { + const bool is_dontunmap = vrm->flags & MREMAP_DONTUNMAP; struct mm_struct *mm = current->mm; struct vm_area_struct *new_vma; unsigned long hiwater_vm; @@ -1316,10 +1315,10 @@ static unsigned long move_vma(struct vma_remap_struct *vrm) */ hiwater_vm = mm->hiwater_vm; - vrm_stat_account(vrm, vrm->new_len); - if (unlikely(!err && (vrm->flags & MREMAP_DONTUNMAP))) + if (unlikely(is_dontunmap && !err)) dontunmap_complete(vrm, new_vma); - else + vrm_stat_account(vrm, vrm->new_len); + if (!is_dontunmap || err) unmap_source_vma(vrm); mm->hiwater_vm = hiwater_vm; diff --git a/mm/swapfile.c b/mm/swapfile.c index cf33c3b2c31f..3ffa258de79e 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -162,7 +162,7 @@ static inline unsigned char swap_count(unsigned char ent) * This bit will be set if the device is not on the plist and not * usable, will be cleared if the device is on the plist. */ -#define SWAP_USAGE_OFFLIST_BIT (1UL << (BITS_PER_TYPE(atomic_t) - 2)) +#define SWAP_USAGE_OFFLIST_BIT (1UL << (BITS_PER_TYPE(atomic_long_t) - 2)) #define SWAP_USAGE_COUNTER_MASK (~SWAP_USAGE_OFFLIST_BIT) static long swap_usage_in_pages(struct swap_info_struct *si) { diff --git a/mm/vma.c b/mm/vma.c index 30148e6af775..dcaa2d8998bf 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -2693,10 +2693,12 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr, map.check_ksm_early = can_set_ksm_flags_early(&map); error = __mmap_prepare(&map, uf); - if (!error && have_mmap_prepare) - error = call_mmap_prepare(&map); if (error) goto abort_munmap; + if (have_mmap_prepare) + error = call_mmap_prepare(&map); + if (error) + goto unacct_error; if (map.check_ksm_early) update_ksm_flags(&map); diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index 3e4f17d335fe..b668a30b67a8 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c @@ -292,10 +292,13 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) struct atm_vcc *vcc; int ret; + if (!pskb_may_pull(skb, 1)) { + kfree_skb(skb); + return DROP_PACKET; + } + ATM_SKB(skb)->vcc = pvcc->atmvcc; pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc); - if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) - (void) skb_pull(skb, 1); vcc = ATM_SKB(skb)->vcc; bh_lock_sock(sk_atm(vcc)); @@ -318,23 +321,13 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) switch (pvcc->encaps) { /* LLC encapsulation needed */ case e_llc: - if (skb_headroom(skb) < LLC_LEN) { - struct sk_buff *n; - n = skb_realloc_headroom(skb, LLC_LEN); - if (n != NULL && - !pppoatm_may_send(pvcc, n->truesize)) { - kfree_skb(n); - goto nospace; - } - consume_skb(skb); - skb = n; - if (skb == NULL) { - bh_unlock_sock(sk_atm(vcc)); - return DROP_PACKET; - } - } else if (!pppoatm_may_send(pvcc, skb->truesize)) + if (skb_cow_head(skb, LLC_LEN)) { + bh_unlock_sock(sk_atm(vcc)); + kfree_skb(skb); + return DROP_PACKET; + } + if (!pppoatm_may_send(pvcc, skb->truesize)) goto nospace; - memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN); break; case e_vc: if (!pppoatm_may_send(pvcc, skb->truesize)) @@ -347,6 +340,12 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) return 1; } + if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT)) + skb_pull(skb, 1); + + if (pvcc->encaps == e_llc) + memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN); + atm_account_tx(vcc, skb); pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); @@ -356,13 +355,6 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb) return ret; nospace: bh_unlock_sock(sk_atm(vcc)); - /* - * We don't have space to send this SKB now, but we might have - * already applied SC_COMP_PROT compression, so may need to undo - */ - if ((pvcc->flags & SC_COMP_PROT) && skb_headroom(skb) > 0 && - skb->data[-1] == '\0') - (void) skb_push(skb, 1); return 0; } diff --git a/net/bluetooth/coredump.c b/net/bluetooth/coredump.c index 720cb79adf96..b15971ad78a8 100644 --- a/net/bluetooth/coredump.c +++ b/net/bluetooth/coredump.c @@ -105,6 +105,22 @@ static void hci_devcd_free(struct hci_dev *hdev) hci_devcd_reset(hdev); } +void hci_devcd_shutdown(struct hci_dev *hdev) +{ + unsigned long flags; + + spin_lock_irqsave(&hdev->dump.dump_q.lock, flags); + hdev->dump.supported = false; + spin_unlock_irqrestore(&hdev->dump.dump_q.lock, flags); + + disable_work_sync(&hdev->dump.dump_rx); + disable_delayed_work_sync(&hdev->dump.dump_timeout); + + hci_dev_lock(hdev); + hci_devcd_free(hdev); + hci_dev_unlock(hdev); +} + /* Call with hci_dev_lock only. */ static int hci_devcd_alloc(struct hci_dev *hdev, u32 size) { @@ -444,7 +460,29 @@ EXPORT_SYMBOL(hci_devcd_register); static inline bool hci_devcd_enabled(struct hci_dev *hdev) { - return hdev->dump.supported; + return READ_ONCE(hdev->dump.supported); +} + +static int hci_devcd_queue(struct hci_dev *hdev, struct sk_buff *skb) +{ + unsigned long flags; + int err = 0; + + spin_lock_irqsave(&hdev->dump.dump_q.lock, flags); + if (!hdev->dump.supported) + err = -EOPNOTSUPP; + else + __skb_queue_tail(&hdev->dump.dump_q, skb); + spin_unlock_irqrestore(&hdev->dump.dump_q.lock, flags); + + if (err) { + kfree_skb(skb); + return err; + } + + queue_work(hdev->workqueue, &hdev->dump.dump_rx); + + return 0; } int hci_devcd_init(struct hci_dev *hdev, u32 dump_size) @@ -461,10 +499,7 @@ int hci_devcd_init(struct hci_dev *hdev, u32 dump_size) hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_INIT; put_unaligned_le32(dump_size, skb_put(skb, 4)); - skb_queue_tail(&hdev->dump.dump_q, skb); - queue_work(hdev->workqueue, &hdev->dump.dump_rx); - - return 0; + return hci_devcd_queue(hdev, skb); } EXPORT_SYMBOL(hci_devcd_init); @@ -480,10 +515,7 @@ int hci_devcd_append(struct hci_dev *hdev, struct sk_buff *skb) hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_SKB; - skb_queue_tail(&hdev->dump.dump_q, skb); - queue_work(hdev->workqueue, &hdev->dump.dump_rx); - - return 0; + return hci_devcd_queue(hdev, skb); } EXPORT_SYMBOL(hci_devcd_append); @@ -505,10 +537,7 @@ int hci_devcd_append_pattern(struct hci_dev *hdev, u8 pattern, u32 len) hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_PATTERN; skb_put_data(skb, &p, sizeof(p)); - skb_queue_tail(&hdev->dump.dump_q, skb); - queue_work(hdev->workqueue, &hdev->dump.dump_rx); - - return 0; + return hci_devcd_queue(hdev, skb); } EXPORT_SYMBOL(hci_devcd_append_pattern); @@ -525,10 +554,7 @@ int hci_devcd_complete(struct hci_dev *hdev) hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_COMPLETE; - skb_queue_tail(&hdev->dump.dump_q, skb); - queue_work(hdev->workqueue, &hdev->dump.dump_rx); - - return 0; + return hci_devcd_queue(hdev, skb); } EXPORT_SYMBOL(hci_devcd_complete); @@ -545,9 +571,6 @@ int hci_devcd_abort(struct hci_dev *hdev) hci_dmp_cb(skb)->pkt_type = HCI_DEVCOREDUMP_PKT_ABORT; - skb_queue_tail(&hdev->dump.dump_q, skb); - queue_work(hdev->workqueue, &hdev->dump.dump_rx); - - return 0; + return hci_devcd_queue(hdev, skb); } EXPORT_SYMBOL(hci_devcd_abort); diff --git a/net/bluetooth/eir.c b/net/bluetooth/eir.c index a55696820b22..ee0136bfae40 100644 --- a/net/bluetooth/eir.c +++ b/net/bluetooth/eir.c @@ -373,7 +373,15 @@ void *eir_get_service_data(u8 *eir, size_t eir_len, u16 uuid, size_t *len) size_t dlen; while ((eir = eir_get_data(eir, eir_len, EIR_SERVICE_DATA, &dlen))) { - u16 value = get_unaligned_le16(eir); + u16 value; + + if (dlen < sizeof(value)) { + eir += dlen; + eir_len = eir_end - eir; + continue; + } + + value = get_unaligned_le16(eir); if (uuid == value) { if (len) diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c index 5bc5003c387c..7a7e813dcdda 100644 --- a/net/bluetooth/hci_codec.c +++ b/net/bluetooth/hci_codec.c @@ -145,11 +145,12 @@ void hci_read_supported_codecs(struct hci_dev *hdev) skb_pull(skb, sizeof(rp->status)); - std_codecs = (void *)skb->data; + std_codecs = skb_pull_data(skb, sizeof(*std_codecs)); + if (!std_codecs) + goto error; /* validate codecs length before accessing */ - if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num) - + sizeof(std_codecs->num)) + if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)) goto error; /* enumerate codec capabilities of standard codecs */ @@ -161,15 +162,14 @@ void hci_read_supported_codecs(struct hci_dev *hdev) LOCAL_CODEC_ACL_MASK | LOCAL_CODEC_SCO_MASK, &caps); } - skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num) - + sizeof(std_codecs->num)); + skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)); - vnd_codecs = (void *)skb->data; + vnd_codecs = skb_pull_data(skb, sizeof(*vnd_codecs)); + if (!vnd_codecs) + goto error; /* validate vendor codecs length before accessing */ - if (skb->len < - flex_array_size(vnd_codecs, codec, vnd_codecs->num) - + sizeof(vnd_codecs->num)) + if (skb->len < flex_array_size(vnd_codecs, codec, vnd_codecs->num)) goto error; /* enumerate vendor codec capabilities */ @@ -214,11 +214,12 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev) skb_pull(skb, sizeof(rp->status)); - std_codecs = (void *)skb->data; + std_codecs = skb_pull_data(skb, sizeof(*std_codecs)); + if (!std_codecs) + goto error; /* check for payload data length before accessing */ - if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num) - + sizeof(std_codecs->num)) + if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)) goto error; memset(&caps, 0, sizeof(caps)); @@ -229,15 +230,14 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev) &caps); } - skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num) - + sizeof(std_codecs->num)); + skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)); - vnd_codecs = (void *)skb->data; + vnd_codecs = skb_pull_data(skb, sizeof(*vnd_codecs)); + if (!vnd_codecs) + goto error; /* check for payload data length before accessing */ - if (skb->len < - flex_array_size(vnd_codecs, codec, vnd_codecs->num) - + sizeof(vnd_codecs->num)) + if (skb->len < flex_array_size(vnd_codecs, codec, vnd_codecs->num)) goto error; for (i = 0; i < vnd_codecs->num; i++) { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 447a7ebcdf62..c0a8bd7af781 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2709,6 +2709,7 @@ void hci_unregister_dev(struct hci_dev *hdev) disable_work_sync(&hdev->error_reset); disable_delayed_work_sync(&hdev->cmd_timer); disable_delayed_work_sync(&hdev->ncmd_timer); + hci_devcd_shutdown(hdev); hci_cmd_sync_clear(hdev); @@ -3273,6 +3274,17 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue, bt_dev_dbg(hdev, "chan %p queued %d", chan, skb_queue_len(queue)); } +/* Queue hdev->tx_work, unless hdev->workqueue is being drained by + * hci_dev_close_sync(), which would otherwise WARN and drop the work. + */ +static void hci_sched_tx(struct hci_dev *hdev) +{ + rcu_read_lock(); + if (!hci_dev_test_flag(hdev, HCI_CMD_DRAIN_WORKQUEUE)) + queue_work(hdev->workqueue, &hdev->tx_work); + rcu_read_unlock(); +} + void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) { struct hci_dev *hdev = chan->conn->hdev; @@ -3281,7 +3293,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) hci_queue_acl(chan, &chan->data_q, skb, flags); - queue_work(hdev->workqueue, &hdev->tx_work); + hci_sched_tx(hdev); } /* Send SCO data */ @@ -3306,7 +3318,7 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) bt_dev_dbg(hdev, "hcon %p queued %d", conn, skb_queue_len(&conn->data_q)); - queue_work(hdev->workqueue, &hdev->tx_work); + hci_sched_tx(hdev); } /* Send ISO data */ @@ -3377,7 +3389,7 @@ void hci_send_iso(struct hci_conn *conn, struct sk_buff *skb) hci_queue_iso(conn, &conn->data_q, skb); - queue_work(hdev->workqueue, &hdev->tx_work); + hci_sched_tx(hdev); } /* ---- HCI TX task (outgoing data) ---- */ diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index be5886a7424f..969ad4317d4b 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -5508,7 +5508,9 @@ int hci_dev_close_sync(struct hci_dev *hdev) memset(hdev->eir, 0, sizeof(hdev->eir)); memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); bacpy(&hdev->random_addr, BDADDR_ANY); + hci_dev_lock(hdev); hci_codec_list_clear(&hdev->local_codecs); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; diff --git a/net/bluetooth/iso.c b/net/bluetooth/iso.c index c30bf48d3858..14f821aa8ac4 100644 --- a/net/bluetooth/iso.c +++ b/net/bluetooth/iso.c @@ -764,19 +764,24 @@ static void iso_sock_destruct(struct sock *sk) skb_queue_purge(&sk->sk_error_queue); } -static void iso_sock_cleanup_listen(struct sock *parent) +/* Close not yet accepted channels */ +static void iso_sock_flush_accept_q(struct sock *parent) { struct sock *sk; - BT_DBG("parent %p", parent); - - /* Close not yet accepted channels */ while ((sk = bt_accept_dequeue(parent, NULL))) { iso_sock_close(sk); iso_sock_kill(sk); /* Drop the reference handed back by bt_accept_dequeue(). */ sock_put(sk); } +} + +static void iso_sock_cleanup_listen(struct sock *parent) +{ + BT_DBG("parent %p", parent); + + iso_sock_flush_accept_q(parent); /* If listening socket has a hcon, properly disconnect it */ if (iso_pi(parent)->conn && iso_pi(parent)->conn->hcon) { @@ -1616,6 +1621,13 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, switch (sk->sk_state) { case BT_CONNECT2: if (test_bit(BT_SK_PA_SYNC, &pi->flags)) { + /* Move to BT_LISTEN before requesting the BIG + * sync: the BIS connections are matched to a + * parent socket in BT_LISTEN state, and they + * may be notified before the request returns. + */ + sk->sk_state = BT_LISTEN; + release_sock(sk); err = iso_conn_big_sync(sk); lock_sock(sk); @@ -1624,12 +1636,20 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, * connection may have been torn down * meanwhile and iso_chan_del() may have * already moved the socket to BT_CLOSED. - * Only move on to BT_LISTEN if the BIG sync - * was actually started and nothing else has - * changed the state. + * Only move back if the BIG sync could not be + * started and nothing else has changed the + * state. */ - if (!err && sk->sk_state == BT_CONNECT2) - sk->sk_state = BT_LISTEN; + if (err && sk->sk_state == BT_LISTEN) { + /* Discard any child socket that may + * have been queued while the socket + * was in BT_LISTEN, as the cleanup of + * BT_CONNECT2 doesn't drain the + * accept queue. + */ + iso_sock_flush_accept_q(sk); + sk->sk_state = BT_CONNECT2; + } } else { iso_conn_defer_accept(pi->conn->hcon); sk->sk_state = BT_CONFIG; @@ -1639,12 +1659,22 @@ static int iso_sock_recvmsg(struct socket *sock, struct msghdr *msg, break; case BT_CONNECTED: if (test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) { + /* As above, the BIS connections may be + * notified before the request returns. + */ + sk->sk_state = BT_LISTEN; + release_sock(sk); err = iso_conn_big_sync(sk); lock_sock(sk); - if (!err && sk->sk_state == BT_CONNECTED) - sk->sk_state = BT_LISTEN; + if (err && sk->sk_state == BT_LISTEN) { + /* As above, don't leave any child + * socket behind in the accept queue. + */ + iso_sock_flush_accept_q(sk); + sk->sk_state = BT_CONNECTED; + } early_ret = true; } @@ -2160,6 +2190,7 @@ static void iso_conn_ready(struct iso_conn *conn) BTPROTO_ISO, GFP_ATOMIC, 0); if (!sk) { release_sock(parent); + sock_put(parent); return; } diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 2286efef62f5..037a7fcab302 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -243,9 +243,7 @@ static void __rfcomm_sock_close(struct sock *sk) */ static void rfcomm_sock_close(struct sock *sk) { - lock_sock(sk); __rfcomm_sock_close(sk); - release_sock(sk); } static void rfcomm_sock_init(struct sock *sk, struct sock *parent) @@ -902,6 +900,7 @@ static int rfcomm_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsig static int rfcomm_sock_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; + bool cleanup_listen = false; int err = 0; BT_DBG("sock %p, sk %p", sock, sk); @@ -912,9 +911,17 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how) lock_sock(sk); if (!sk->sk_shutdown) { sk->sk_shutdown = SHUTDOWN_MASK; + if (sk->sk_state == BT_LISTEN) { + /* Block new children before cleaning up without sk lock. */ + sk->sk_state = BT_CLOSED; + cleanup_listen = true; + } release_sock(sk); - __rfcomm_sock_close(sk); + if (cleanup_listen) + rfcomm_sock_cleanup_listen(sk); + else + __rfcomm_sock_close(sk); lock_sock(sk); if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime && diff --git a/net/bridge/br_mst.c b/net/bridge/br_mst.c index 43a300ae6bfa..1654efd3045b 100644 --- a/net/bridge/br_mst.c +++ b/net/bridge/br_mst.c @@ -107,21 +107,24 @@ int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state, struct net_bridge_vlan *v; int err = 0; - rcu_read_lock(); - vg = nbp_vlan_group_rcu(p); - if (!vg) - goto out; - /* MSTI 0 (CST) state changes are notified via the regular - * SWITCHDEV_ATTR_ID_PORT_STP_STATE. + * SWITCHDEV_ATTR_ID_PORT_STP_STATE. All other MSTIs are handled via + * netlink with RTNL held */ if (msti) { + ASSERT_RTNL(); + err = switchdev_port_attr_set(p->dev, &attr, extack); if (err && err != -EOPNOTSUPP) goto out; + err = 0; } - err = 0; + rcu_read_lock(); + vg = nbp_vlan_group_rcu(p); + if (!vg) + goto out_rcu_unlock; + list_for_each_entry_rcu(v, &vg->vlan_list, vlist) { if (v->brvlan->msti != msti) continue; @@ -129,8 +132,9 @@ int br_mst_set_state(struct net_bridge_port *p, u16 msti, u8 state, br_mst_vlan_set_state(vg, v, state); } -out: +out_rcu_unlock: rcu_read_unlock(); +out: return err; } diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c index a5e75cd04d6c..996ae451af62 100644 --- a/net/core/drop_monitor.c +++ b/net/core/drop_monitor.c @@ -141,9 +141,8 @@ static struct sk_buff *reset_per_cpu_data(struct per_cpu_dm_data *data) al = sizeof(struct net_dm_alert_msg); al += dm_hit_limit * sizeof(struct net_dm_drop_point); - al += sizeof(struct nlattr); - skb = genlmsg_new(al, GFP_KERNEL); + skb = genlmsg_new(nla_total_size(al), GFP_KERNEL); if (!skb) goto err; @@ -1084,7 +1083,7 @@ static int net_dm_hw_monitor_start(struct netlink_ext_ack *extack) struct per_cpu_dm_data *hw_data = &per_cpu(dm_hw_cpu_data, cpu); struct sk_buff *skb; - timer_delete_sync(&hw_data->send_timer); + timer_shutdown_sync(&hw_data->send_timer); cancel_work_sync(&hw_data->dm_alert_work); while ((skb = __skb_dequeue(&hw_data->drop_queue))) { struct devlink_trap_metadata *hw_metadata; @@ -1118,7 +1117,7 @@ static void net_dm_hw_monitor_stop(struct netlink_ext_ack *extack) struct per_cpu_dm_data *hw_data = &per_cpu(dm_hw_cpu_data, cpu); struct sk_buff *skb; - timer_delete_sync(&hw_data->send_timer); + timer_shutdown_sync(&hw_data->send_timer); cancel_work_sync(&hw_data->dm_alert_work); while ((skb = __skb_dequeue(&hw_data->drop_queue))) { struct devlink_trap_metadata *hw_metadata; @@ -1174,12 +1173,13 @@ static int net_dm_trace_on_set(struct netlink_ext_ack *extack) err_unregister_trace: unregister_trace_kfree_skb(ops->kfree_skb_probe, NULL); + tracepoint_synchronize_unregister(); err_module_put: for_each_possible_cpu(cpu) { struct per_cpu_dm_data *data = &per_cpu(dm_cpu_data, cpu); struct sk_buff *skb; - timer_delete_sync(&data->send_timer); + timer_shutdown_sync(&data->send_timer); cancel_work_sync(&data->dm_alert_work); while ((skb = __skb_dequeue(&data->drop_queue))) consume_skb(skb); @@ -1207,7 +1207,7 @@ static void net_dm_trace_off_set(void) struct per_cpu_dm_data *data = &per_cpu(dm_cpu_data, cpu); struct sk_buff *skb; - timer_delete_sync(&data->send_timer); + timer_shutdown_sync(&data->send_timer); cancel_work_sync(&data->dm_alert_work); while ((skb = __skb_dequeue(&data->drop_queue))) consume_skb(skb); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index dabd368eaa4e..862867874e12 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2180,7 +2180,7 @@ static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) return -ENOBUFS; if ((parms->dev && - nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) || + nla_put_u32(skb, NDTPA_IFINDEX, READ_ONCE(parms->dev->ifindex))) || nla_put_u32(skb, NDTPA_REFCNT, refcount_read(&parms->refcnt)) || nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, NEIGH_VAR(parms, QUEUE_LEN_BYTES)) || @@ -2232,8 +2232,6 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, return -EMSGSIZE; ndtmsg = nlmsg_data(nlh); - - read_lock_bh(&tbl->lock); ndtmsg->ndtm_family = tbl->family; ndtmsg->ndtm_pad1 = 0; ndtmsg->ndtm_pad2 = 0; @@ -2259,11 +2257,9 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, .ndtc_proxy_qlen = READ_ONCE(tbl->proxy_queue.qlen), }; - rcu_read_lock(); nht = rcu_dereference(tbl->nht); ndc.ndtc_hash_rnd = nht->hash_rnd[0]; ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1); - rcu_read_unlock(); if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc)) goto nla_put_failure; @@ -2301,12 +2297,10 @@ static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, if (neightbl_fill_parms(skb, &tbl->parms) < 0) goto nla_put_failure; - read_unlock_bh(&tbl->lock); nlmsg_end(skb, nlh); return 0; nla_put_failure: - read_unlock_bh(&tbl->lock); nlmsg_cancel(skb, nlh); return -EMSGSIZE; } @@ -2325,8 +2319,6 @@ static int neightbl_fill_param_info(struct sk_buff *skb, return -EMSGSIZE; ndtmsg = nlmsg_data(nlh); - - read_lock_bh(&tbl->lock); ndtmsg->ndtm_family = tbl->family; ndtmsg->ndtm_pad1 = 0; ndtmsg->ndtm_pad2 = 0; @@ -2335,11 +2327,9 @@ static int neightbl_fill_param_info(struct sk_buff *skb, neightbl_fill_parms(skb, parms) < 0) goto errout; - read_unlock_bh(&tbl->lock); nlmsg_end(skb, nlh); return 0; errout: - read_unlock_bh(&tbl->lock); nlmsg_cancel(skb, nlh); return -EMSGSIZE; } @@ -2353,6 +2343,13 @@ static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = { [NDTA_PARMS] = { .type = NLA_NESTED }, }; +#define NTBL_PARM_MS_MAX (24 * 60 * 60 * MSEC_PER_SEC) + +static const struct netlink_range_validation nl_ntbl_parm_ms_range = { + .min = 1, + .max = NTBL_PARM_MS_MAX, +}; + static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = { [NDTPA_IFINDEX] = { .type = NLA_U32 }, [NDTPA_QUEUE_LEN] = { .type = NLA_U32 }, @@ -2369,7 +2366,8 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = { [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 }, [NDTPA_PROXY_DELAY] = { .type = NLA_U64 }, [NDTPA_LOCKTIME] = { .type = NLA_U64 }, - [NDTPA_INTERVAL_PROBE_TIME_MS] = { .type = NLA_U64, .min = 1 }, + [NDTPA_INTERVAL_PROBE_TIME_MS] = NLA_POLICY_FULL_RANGE(NLA_U64, + &nl_ntbl_parm_ms_range), }; static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -2566,9 +2564,10 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) { const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); + int default_skip = cb->args[2]; + int neigh_skip = cb->args[1]; int family, tidx, nidx = 0; int tbl_skip = cb->args[0]; - int neigh_skip = cb->args[1]; struct neigh_table *tbl; if (cb->strict_check) { @@ -2580,27 +2579,33 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family; + rcu_read_lock(); + for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { struct neigh_parms *p; - tbl = rcu_dereference_rtnl(neigh_tables[tidx]); + tbl = rcu_dereference(neigh_tables[tidx]); if (!tbl) continue; if (tidx < tbl_skip || (family && tbl->family != family)) continue; - if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid, + if (!default_skip && + neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid, nlh->nlmsg_seq, RTM_NEWNEIGHTBL, NLM_F_MULTI) < 0) break; - nidx = 0; - p = list_next_entry(&tbl->parms, list); - list_for_each_entry_from(p, &tbl->parms_list, list) { + default_skip = 1; + + list_for_each_entry_rcu(p, &tbl->parms_list, list) { if (!net_eq(neigh_parms_net(p), net)) continue; + if (!p->dev) + continue; + if (nidx < neigh_skip) goto next; @@ -2615,10 +2620,15 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) } neigh_skip = 0; + nidx = 0; + default_skip = 0; } out: + rcu_read_unlock(); + cb->args[0] = tidx; cb->args[1] = nidx; + cb->args[2] = default_skip; return skb->len; } @@ -3641,12 +3651,13 @@ static int neigh_proc_dointvec_ms_jiffies_positive(const struct ctl_table *ctl, void *buffer, size_t *lenp, loff_t *ppos) { struct ctl_table tmp = *ctl; - int ret; + int ret, min, max; - int min = msecs_to_jiffies(1); + min = msecs_to_jiffies(1); + max = msecs_to_jiffies(NTBL_PARM_MS_MAX); tmp.extra1 = &min; - tmp.extra2 = NULL; + tmp.extra2 = &max; ret = proc_dointvec_ms_jiffies_minmax(&tmp, write, buffer, lenp, ppos); neigh_proc_update(ctl, write); @@ -3919,7 +3930,8 @@ static const struct rtnl_msg_handler neigh_rtnl_msg_handlers[] __initconst = { {.msgtype = RTM_DELNEIGH, .doit = neigh_delete}, {.msgtype = RTM_GETNEIGH, .doit = neigh_get, .dumpit = neigh_dump_info, .flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED}, - {.msgtype = RTM_GETNEIGHTBL, .dumpit = neightbl_dump_info}, + {.msgtype = RTM_GETNEIGHTBL, .dumpit = neightbl_dump_info, + .flags = RTNL_FLAG_DUMP_UNLOCKED}, {.msgtype = RTM_SETNEIGHTBL, .doit = neightbl_set}, }; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 032429230992..594764eab40d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -6766,6 +6766,34 @@ struct sk_buff *alloc_skb_with_frags(unsigned long header_len, } EXPORT_SYMBOL(alloc_skb_with_frags); +/* pskb_carve_inside_header() and pskb_carve_inside_nonlinear() + * remove the first bytes of a packet and reallocate skb->head. + * + * Whatever headers were present before the operation are gone, + * we must not leave stale offsets, otherwise users of this skb + * (skb_dump(), drop_monitor, taps, ...) would read or pull garbage. + */ +static void skb_carve_reset_headers(struct sk_buff *skb) +{ + skb_unset_mac_header(skb); + skb_unset_transport_header(skb); + skb_reset_network_header(skb); + skb->mac_len = 0; + + /* Inner offsets have no "unset" marker, zero them so that + * skb_inner_network_header_was_set() becomes false and no + * consumer mistakes them for a real (and long gone) header. + */ + skb->inner_mac_header = 0; + skb->inner_network_header = 0; + skb->inner_transport_header = 0; + skb->inner_protocol = 0; + skb->encapsulation = 0; + + if (skb->ip_summed == CHECKSUM_PARTIAL) + skb->ip_summed = CHECKSUM_NONE; +} + /* carve out the first off bytes from skb when off < headlen */ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, const int headlen, gfp_t gfp_mask) @@ -6821,7 +6849,7 @@ static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, skb->head_frag = 0; skb_set_end_offset(skb, size); skb_set_tail_pointer(skb, skb_headlen(skb)); - skb_headers_offset_update(skb, 0); + skb_carve_reset_headers(skb); skb->cloned = 0; skb->hdr_len = 0; skb->nohdr = 0; @@ -6961,7 +6989,7 @@ static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, skb->data = data; skb_set_end_offset(skb, size); skb_reset_tail_pointer(skb); - skb_headers_offset_update(skb, 0); + skb_carve_reset_headers(skb); skb->cloned = 0; skb->hdr_len = 0; skb->nohdr = 0; diff --git a/net/core/sock.c b/net/core/sock.c index 1b64ac35073d..0d5f167e6ce6 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -142,6 +142,7 @@ #include +#include #include #include #include @@ -2635,6 +2636,12 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst) } EXPORT_SYMBOL_GPL(sk_setup_caps); +bool sk_has_decrypt_user(const struct sock *sk) +{ + return psp_sk_assoc(sk) || + (sk_is_inet(sk) && inet_csk_has_ulp(sk)); /* for tls */ +} + /* * Simple resource managers for sockets. */ @@ -3783,7 +3790,14 @@ int sock_gettstamp(struct socket *sock, void __user *userstamp, struct sock *sk = sock->sk; struct timespec64 ts; - sock_enable_timestamp(sk, SOCK_TIMESTAMP); + /* sk->sk_flags must only be changed under the socket lock, + * because sock_set_flag() uses non atomic operations. + */ + if (!sock_flag(sk, SOCK_TIMESTAMP)) { + lock_sock(sk); + sock_enable_timestamp(sk, SOCK_TIMESTAMP); + release_sock(sk); + } ts = ktime_to_timespec64(sock_read_timestamp(sk)); if (ts.tv_sec == -1) return -ENOENT; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 513c8215c947..346e78c23af0 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -438,6 +438,12 @@ int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info * esp->inplace = false; + /* Take real page refs and clear SKBFL_MANAGED_FRAG_REFS before + * we mutate the frag array, so the per-frag unref stays balanced + * for zerocopy managed frags (see __ip_append_data()). + */ + skb_zcopy_downgrade_managed(skb); + allocsize = ALIGN(tailen, L1_CACHE_BYTES); spin_lock_bh(&x->lock); diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index a66e1a7175e9..c59a32160ee6 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -572,16 +572,19 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4, skb_dstref_restore(skb_in, orefdst); /* - * At this point, fl4_dec.daddr should NOT be local (we - * checked fl4_dec.saddr above). However, a race condition - * may occur if the address is added to the interface - * concurrently. In that case, ip_route_input() returns a - * LOCAL route with dst.output=ip_rt_bug, which must not - * be used for output. + * fl4_dec.daddr is not expected to be local here, but it can be + * added to an interface concurrently, in which case + * ip_route_input() returns a LOCAL route. It can also fail to + * build a forwarding route towards fl4_dec.daddr, for example, + * when forwarding is disabled, and return an UNREACHABLE route. + * Both cases will result in a route with dst.output=ip_rt_bug, + * which must not be used for output. */ - if (!err && rt2 && rt2->rt_type == RTN_LOCAL) { + if (!err && rt2 && rt2->rt_type == RTN_LOCAL) net_warn_ratelimited("detected local route for %pI4 during ICMP sending, src %pI4\n", &fl4_dec.daddr, &fl4_dec.saddr); + if (!err && rt2 && + (rt2->rt_type == RTN_LOCAL || rt2->rt_type == RTN_UNREACHABLE)) { dst_release(&rt2->dst); err = -EINVAL; } diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 011db59ff61f..ee181fe9995f 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -680,8 +680,14 @@ static int ip_tun_get_optlen(struct nlattr *attr, } static int ip_tun_set_opts(struct nlattr *attr, struct ip_tunnel_info *info, - struct netlink_ext_ack *extack) + int opts_len, struct netlink_ext_ack *extack) { + /* `options_len` is the __counted_by() annotation of the `options` + * flexible array, it must be initialized before parsing writes + * into it. + */ + info->options_len = opts_len; + return ip_tun_parse_opts(attr, info, extack); } @@ -712,7 +718,8 @@ static int ip_tun_build_state(struct net *net, struct nlattr *attr, tun_info = lwt_tun_info(new_state); - err = ip_tun_set_opts(tb[LWTUNNEL_IP_OPTS], tun_info, extack); + err = ip_tun_set_opts(tb[LWTUNNEL_IP_OPTS], tun_info, opt_len, + extack); if (err < 0) { lwtstate_free(new_state); return err; @@ -753,7 +760,6 @@ static int ip_tun_build_state(struct net *net, struct nlattr *attr, } tun_info->mode = IP_TUNNEL_INFO_TX; - tun_info->options_len = opt_len; *ts = new_state; @@ -1006,7 +1012,8 @@ static int ip6_tun_build_state(struct net *net, struct nlattr *attr, tun_info = lwt_tun_info(new_state); - err = ip_tun_set_opts(tb[LWTUNNEL_IP6_OPTS], tun_info, extack); + err = ip_tun_set_opts(tb[LWTUNNEL_IP6_OPTS], tun_info, opt_len, + extack); if (err < 0) { lwtstate_free(new_state); return err; @@ -1040,7 +1047,6 @@ static int ip6_tun_build_state(struct net *net, struct nlattr *attr, } tun_info->mode = IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6; - tun_info->options_len = opt_len; *ts = new_state; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index afcbb9d48cfa..34a8a932402d 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -49,6 +49,8 @@ static int tcp_plb_max_cong_thresh = 256; static unsigned int tcp_tw_reuse_delay_max = TCP_PAWS_MSL * MSEC_PER_SEC; static int tcp_ecn_mode_max = 2; +static int tcp_min_rcvbuf = 4096; + /* obsolete */ static int sysctl_tcp_low_latency __read_mostly; @@ -1435,7 +1437,7 @@ static struct ctl_table ipv4_net_table[] = { .maxlen = sizeof(init_net.ipv4.sysctl_tcp_rmem), .mode = 0644, .proc_handler = proc_dointvec_minmax, - .extra1 = SYSCTL_ONE, + .extra1 = &tcp_min_rcvbuf, }, { .procname = "tcp_comp_sack_delay_ns", diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 05521a3509a9..d9b07a3b9390 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6283,6 +6283,7 @@ static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, * or pure receivers (this means either the sequence number or the ack * value must stay constant) * - Unexpected TCP option. + * - ACK sequence number is outside [SND.UNA, SND.NXT]. * * When these conditions are not satisfied it drops into a standard * receive procedure patterned after RFC793 to handle all cases. @@ -6332,7 +6333,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb) if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt && - !after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) { + between(TCP_SKB_CB(skb)->ack_seq, tp->snd_una, tp->snd_nxt)) { int tcp_header_len = tp->tcp_header_len; s32 delta = 0; int flag = 0; diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c index 2aa442128630..b58045df101e 100644 --- a/net/ipv4/tcp_ulp.c +++ b/net/ipv4/tcp_ulp.c @@ -136,6 +136,10 @@ static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops) if (icsk->icsk_ulp_ops) goto out_err; + err = -EINVAL; + if (sk_has_decrypt_user(sk)) + goto out_err; + if (sk->sk_socket) clear_bit(SOCK_SUPPORT_ZC, &sk->sk_socket->flags); diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index c2eac844bcdb..f6f2a8ef3f88 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -76,8 +76,6 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async) NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, dev_net(dev), NULL, skb, dev, NULL, xfrm4_rcv_encap_finish); - if (async) - dev_put(dev); return 0; } diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 57481e423e59..b26b85afb92e 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -467,6 +467,12 @@ int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info esp->inplace = false; + /* Take real page refs and clear SKBFL_MANAGED_FRAG_REFS before + * we mutate the frag array, so the per-frag unref stays balanced + * for zerocopy managed frags (see __ip_append_data()). + */ + skb_zcopy_downgrade_managed(skb); + allocsize = ALIGN(tailen, L1_CACHE_BYTES); spin_lock_bh(&x->lock); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ddaf51eacc2d..71a38034f5ca 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -819,9 +819,11 @@ static int rt6_nh_find_match(struct fib6_nh *nh, void *_arg) { struct fib6_nh_frl_arg *arg = _arg; - arg->nh = nh; - return find_match(nh, arg->flags, arg->oif, arg->strict, - arg->mpri, arg->do_rr); + if (find_match(nh, arg->flags, arg->oif, arg->strict, arg->mpri, + arg->do_rr)) + arg->nh = nh; + + return 0; } static void __find_rr_leaf(struct fib6_info *f6i_start, @@ -861,11 +863,10 @@ static void __find_rr_leaf(struct fib6_info *f6i_start, res->nh = nexthop_fib6_nh(f6i->nh); return; } - if (nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_find_match, - &arg)) { - matched = true; - nh = arg.nh; - } + nexthop_for_each_fib6_nh(f6i->nh, rt6_nh_find_match, + &arg); + matched = !!arg.nh; + nh = arg.nh; } else { nh = f6i->fib6_nh; if (find_match(nh, f6i->fib6_flags, oif, strict, @@ -2271,6 +2272,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, { struct fib6_result res = {}; struct rt6_info *rt = NULL; + bool have_oif_match; int strict = 0; WARN_ON_ONCE((flags & RT6_LOOKUP_F_DST_NOREF) && @@ -2287,7 +2289,9 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, if (res.f6i == net->ipv6.fib6_null_entry) goto out; - fib6_select_path(net, &res, fl6, oif, false, skb, strict); + have_oif_match = fl6->flowi6_iif == LOOPBACK_IFINDEX && + oif == res.nh->fib_nh_dev->ifindex; + fib6_select_path(net, &res, fl6, oif, have_oif_match, skb, strict); /*Search through exception table */ rt = rt6_find_cached_rt(&res, &fl6->daddr, &fl6->saddr); diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c index 7b5212220185..d1070aec7b72 100644 --- a/net/ipv6/seg6_local.c +++ b/net/ipv6/seg6_local.c @@ -257,10 +257,13 @@ static bool decap_and_validate(struct sk_buff *skb, int proto) return false; if (proto == IPPROTO_IPIP) { + bool l3slave = ipv6_l3mdev_skb(IP6CB(skb)->flags); int iif = IP6CB(skb)->iif; memset(IPCB(skb), 0, sizeof(*IPCB(skb))); IPCB(skb)->iif = iif; + if (l3slave) + IPCB(skb)->flags |= IPSKB_L3SLAVE; } else if (proto == IPPROTO_IPV6) { bool l3slave = ipv6_l3mdev_skb(IP6CB(skb)->flags); int iif = IP6CB(skb)->iif; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index aca71fbb6c29..761cafdc8d2e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1618,7 +1618,8 @@ int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) by tcp. Feel free to propose better solution. --ANK (980728) */ - if (np->rxopt.all && sk->sk_state != TCP_LISTEN) + if (np->rxopt.all && + !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE))) opt_skb = skb_clone_and_charge_r(skb, sk); if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index c9e208c57a6b..07edef258984 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -71,8 +71,6 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async) NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, dev_net(dev), NULL, skb, dev, NULL, xfrm6_transport_finish2); - if (async) - dev_put(dev); return 0; } diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 512bdaf13699..44b221a09a0c 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -19,7 +19,10 @@ void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu) { struct flowi6 fl6; - struct sock *sk = skb->sk; + struct sock *sk = skb_to_full_sk(skb); + + if (!sk) + return; fl6.flowi6_oif = sk->sk_bound_dev_if; fl6.daddr = ipv6_hdr(skb)->daddr; @@ -31,7 +34,10 @@ void xfrm6_local_error(struct sk_buff *skb, u32 mtu) { struct flowi6 fl6; const struct ipv6hdr *hdr; - struct sock *sk = skb->sk; + struct sock *sk = skb_to_full_sk(skb); + + if (!sk) + return; hdr = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb); fl6.fl6_dport = inet_sk(sk)->inet_dport; diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index a33884967f21..85eaf72ba803 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -18,7 +18,6 @@ mac80211-y := \ iface.o \ link.o \ rate.o \ - michael.o \ tkip.o \ aes_cmac.o \ aes_gmac.o \ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 72c9d5aceae5..395479c6b296 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -63,12 +63,14 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata, memcpy(sdata->vif.bss_conf.mu_group.position, params->vht_mumimo_groups + WLAN_MEMBERSHIP_LEN, WLAN_USER_POSITION_LEN); - ieee80211_link_info_change_notify(sdata, &sdata->deflink, - BSS_CHANGED_MU_GROUPS); + /* don't care about endianness - just check for 0 */ memcpy(&membership, params->vht_mumimo_groups, WLAN_MEMBERSHIP_LEN); mu_mimo_groups = membership != 0; + + /* Unset following if configured explicitly */ + eth_broadcast_addr(sdata->u.mntr.mu_follow_addr); } if (params->vht_mumimo_follow_addr) { @@ -76,16 +78,26 @@ static void ieee80211_set_mu_mimo_follow(struct ieee80211_sub_if_data *sdata, is_valid_ether_addr(params->vht_mumimo_follow_addr); ether_addr_copy(sdata->u.mntr.mu_follow_addr, params->vht_mumimo_follow_addr); + + /* Unset current membership until a management frame is RXed */ + memset(sdata->vif.bss_conf.mu_group.membership, 0, + WLAN_MEMBERSHIP_LEN); } sdata->vif.bss_conf.mu_mimo_owner = mu_mimo_groups || mu_mimo_follow; + + /* Notify only after setting mu_mimo_owner */ + if (sdata->vif.bss_conf.mu_mimo_owner && + sdata->flags & IEEE80211_SDATA_IN_DRIVER) + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_MU_GROUPS); } static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata, struct vif_params *params) { struct ieee80211_local *local = sdata->local; - struct ieee80211_sub_if_data *monitor_sdata; + struct ieee80211_sub_if_data *monitor_sdata = NULL; /* check flags first */ if (params->flags && ieee80211_sdata_running(sdata)) { @@ -103,23 +115,32 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata, return -EBUSY; } - /* also validate MU-MIMO change */ - if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) - monitor_sdata = sdata; - else - monitor_sdata = wiphy_dereference(local->hw.wiphy, - local->monitor_sdata); + /* TXQs are reserved in ieee80211_if_add() and cannot be added later */ + if ((params->flags & MONITOR_FLAG_ACTIVE) && !sdata->vif.txq) + return -EOPNOTSUPP; - if (!monitor_sdata && + /* validate whether MU-MIMO can be configured */ + if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) && + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) && (params->vht_mumimo_groups || params->vht_mumimo_follow_addr)) return -EOPNOTSUPP; + /* Also update dependent monitor_sdata if required */ + if (test_bit(SDATA_STATE_RUNNING, &sdata->state) && + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) + monitor_sdata = wiphy_dereference(local->hw.wiphy, + local->monitor_sdata); + /* apply all changes now - no failures allowed */ - if (monitor_sdata && - (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) || - ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))) - ieee80211_set_mu_mimo_follow(monitor_sdata, params); + if (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) || + ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) { + /* This is copied in when the VIF is activated */ + ieee80211_set_mu_mimo_follow(sdata, params); + + if (monitor_sdata) + ieee80211_set_mu_mimo_follow(monitor_sdata, params); + } if (params->flags) { if (ieee80211_sdata_running(sdata)) { @@ -1717,6 +1738,9 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, return 0; error: + link_conf->enable_beacon = false; + link_conf->beacon_int = prev_beacon_int; + sdata->vif.cfg.ssid_len = 0; ieee80211_link_release_channel(link); return err; @@ -2938,7 +2962,11 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev, if (err) return err; - return ieee80211_start_mesh(sdata); + err = ieee80211_start_mesh(sdata); + if (err) + ieee80211_link_release_channel(&sdata->deflink); + + return err; } static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev) @@ -3094,7 +3122,7 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, static int ieee80211_suspend(struct wiphy *wiphy, struct cfg80211_wowlan *wowlan) { - return __ieee80211_suspend(wiphy_priv(wiphy), wowlan); + return __ieee80211_suspend(wiphy_priv(wiphy), wowlan, false); } static int ieee80211_resume(struct wiphy *wiphy) @@ -3731,6 +3759,9 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, if (!ieee80211_sdata_running(sdata)) return -ENETDOWN; + if (!(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) + return -ENETDOWN; + /* * If active validate the setting and reject it if it doesn't leave * at least one basic rate usable, since we really have to be able diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 687a66cd4943..14ce2ea10593 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -409,7 +409,7 @@ static ssize_t reset_write(struct file *file, const char __user *user_buf, rtnl_lock(); wiphy_lock(local->hw.wiphy); - __ieee80211_suspend(&local->hw, NULL); + __ieee80211_suspend(&local->hw, NULL, true); ret = __ieee80211_resume(&local->hw); wiphy_unlock(local->hw.wiphy); diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 30a5a978a678..a7045787cb22 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -656,6 +656,9 @@ static ssize_t ieee80211_if_fmt_tsf( struct ieee80211_local *local = sdata->local; u64 tsf; + if (!ieee80211_sdata_running((struct ieee80211_sub_if_data *)sdata)) + return -ENETDOWN; + tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata); return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf); @@ -669,6 +672,9 @@ static ssize_t ieee80211_if_parse_tsf( int ret; int tsf_is_delta = 0; + if (!ieee80211_sdata_running(sdata)) + return -ENETDOWN; + if (strncmp(buf, "reset", 5) == 0) { if (local->ops->reset_tsf) { drv_reset_tsf(local, sdata); @@ -728,6 +734,9 @@ static ssize_t ieee80211_if_parse_active_links(struct ieee80211_sub_if_data *sda if (kstrtou16(buf, 0, &active_links) || !active_links) return -EINVAL; + if (!ieee80211_sdata_running(sdata)) + return -ENETDOWN; + return ieee80211_set_active_links(&sdata->vif, active_links) ?: buflen; } IEEE80211_IF_FILE_RW(active_links); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b0e64cf346e2..a942986797fa 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2114,7 +2114,8 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, const int offset); int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up); void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata); -int ieee80211_add_virtual_monitor(struct ieee80211_local *local); +int ieee80211_add_virtual_monitor(struct ieee80211_local *local, + struct ieee80211_sub_if_data *creator_sdata); void ieee80211_del_virtual_monitor(struct ieee80211_local *local); bool __ieee80211_recalc_txpower(struct ieee80211_link_data *link); @@ -2365,7 +2366,7 @@ int ieee80211_reconfig(struct ieee80211_local *local); void ieee80211_stop_device(struct ieee80211_local *local, bool suspend); int __ieee80211_suspend(struct ieee80211_hw *hw, - struct cfg80211_wowlan *wowlan); + struct cfg80211_wowlan *wowlan, bool reset); static inline int __ieee80211_resume(struct ieee80211_hw *hw) { diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 499126317a91..bdbf41def36c 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -609,6 +609,8 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do RCU_INIT_POINTER(sdata->vif.bss_conf.chanctx_conf, NULL); /* see comment in the default case below */ ieee80211_free_keys(sdata, true); + /* increased by AP value on ifup, so reset on ifdown */ + sdata->crypto_tx_tailroom_needed_cnt = 0; /* no need to tell driver */ break; case NL80211_IFTYPE_MONITOR: @@ -751,8 +753,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do ieee80211_configure_filter(local); ieee80211_hw_config(local, -1, hw_reconf_flags); + /* Passing NULL means an interface is picked for configuration */ if (local->virt_monitors == local->open_count) - ieee80211_add_virtual_monitor(local); + ieee80211_add_virtual_monitor(local, NULL); } void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata) @@ -885,9 +888,33 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata) ieee80211_link_stop(&sdata->deflink); } +/* + * The netdev can be unregistered without mac80211 doing it, e.g. by the netdev + * core when cfg80211 couldn't move it out of a network namespace that's being + * destroyed. Drop it from the interface list either way. + */ +static void ieee80211_unlist_sdata(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_sub_if_data *iter; + + ASSERT_RTNL(); + + list_for_each_entry(iter, &local->interfaces, list) { + if (iter != sdata) + continue; + guard(mutex)(&local->iflist_mtx); + list_del_rcu(&sdata->list); + return; + } +} + static void ieee80211_uninit(struct net_device *dev) { - ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev)); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + ieee80211_unlist_sdata(sdata); + ieee80211_teardown_sdata(sdata); } static int ieee80211_netdev_setup_tc(struct net_device *dev, @@ -896,6 +923,9 @@ static int ieee80211_netdev_setup_tc(struct net_device *dev, struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + return -EOPNOTSUPP; + return drv_net_setup_tc(local, sdata, dev, type, type_data); } @@ -925,7 +955,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev, /* reset flags and info before parsing radiotap header */ memset(info, 0, sizeof(*info)); - if (!ieee80211_parse_tx_radiotap(skb, dev)) + if (!ieee80211_parse_tx_radiotap(skb, dev, NULL)) return 0; /* doesn't matter, frame will be dropped */ len_rthdr = ieee80211_get_radiotap_len(skb->data); @@ -1186,7 +1216,8 @@ static void ieee80211_sdata_init(struct ieee80211_local *local, ieee80211_link_init(sdata, -1, &sdata->deflink, &sdata->vif.bss_conf); } -int ieee80211_add_virtual_monitor(struct ieee80211_local *local) +int ieee80211_add_virtual_monitor(struct ieee80211_local *local, + struct ieee80211_sub_if_data *creator_sdata) { struct ieee80211_sub_if_data *sdata; int ret; @@ -1194,10 +1225,14 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) ASSERT_RTNL(); lockdep_assert_wiphy(local->hw.wiphy); - if (local->monitor_sdata || - ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) + if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) return 0; + /* Already have a monitor set up, configure it */ + sdata = wiphy_dereference(local->hw.wiphy, local->monitor_sdata); + if (sdata) + goto configure_monitor; + sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); if (!sdata) return -ENOMEM; @@ -1250,6 +1285,32 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) skb_queue_head_init(&sdata->status_queue); wiphy_work_init(&sdata->work, ieee80211_iface_work); +configure_monitor: + /* Copy in the MU-MIMO configuration if set */ + if (!creator_sdata) { + struct ieee80211_sub_if_data *other; + + list_for_each_entry_rcu(other, &local->mon_list, u.mntr.list) { + if (!other->vif.bss_conf.mu_mimo_owner) + continue; + + creator_sdata = other; + break; + } + } + + if (creator_sdata && creator_sdata->vif.bss_conf.mu_mimo_owner) { + sdata->vif.bss_conf.mu_mimo_owner = true; + memcpy(&sdata->vif.bss_conf.mu_group, + &creator_sdata->vif.bss_conf.mu_group, + sizeof(sdata->vif.bss_conf.mu_group)); + memcpy(&sdata->u.mntr.mu_follow_addr, + creator_sdata->u.mntr.mu_follow_addr, ETH_ALEN); + + ieee80211_link_info_change_notify(sdata, &sdata->deflink, + BSS_CHANGED_MU_GROUPS); + } + return 0; } @@ -1406,11 +1467,13 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up) if (res) goto err_stop; } else { - if (local->virt_monitors == 0 && local->open_count == 0) { - res = ieee80211_add_virtual_monitor(local); + /* add/configure if there is no non-monitor interface */ + if (local->virt_monitors == local->open_count) { + res = ieee80211_add_virtual_monitor(local, sdata); if (res) goto err_stop; } + local->virt_monitors++; /* must be before the call to ieee80211_configure_filter */ diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 655a8aec7738..cf1d4a031af3 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1431,6 +1431,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) sizeof(struct ieee80211_he_mcs_nss_supp) + IEEE80211_HE_PPE_THRES_MAX_LEN; + if (local->hw.wiphy->bands[NL80211_BAND_6GHZ]) + local->scan_ies_len += + 3 + sizeof(struct ieee80211_he_6ghz_capa); + if (supp_eht) local->scan_ies_len += 3 + sizeof(struct ieee80211_eht_cap_elem) + diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 4b0eebd5c7cf..a18b8b226001 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -1215,6 +1215,21 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) return 0; } +static void ieee80211_mesh_reset_csa(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + struct mesh_csa_settings *csa; + + /* Reset the TTL value and Initiator flag */ + ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; + ifmsh->chsw_ttl = 0; + + /* Remove the CSA and MCSP elements from the beacon */ + csa = sdata_dereference(ifmsh->csa, sdata); + RCU_INIT_POINTER(ifmsh->csa, NULL); + kfree_rcu(csa, rcu_head); +} + void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; @@ -1223,6 +1238,11 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) netif_carrier_off(sdata->dev); + /* abort any running channel switch */ + sdata->vif.bss_conf.csa_active = false; + ieee80211_mesh_reset_csa(sdata); + ieee80211_vif_unblock_queues_csa(sdata); + /* flush STAs and mpaths on this iface */ sta_info_flush(sdata, -1); ieee80211_free_keys(sdata, true); @@ -1525,19 +1545,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, int ieee80211_mesh_finish_csa(struct ieee80211_sub_if_data *sdata, u64 *changed) { - struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - struct mesh_csa_settings *tmp_csa_settings; - int ret = 0; + int ret; - /* Reset the TTL value and Initiator flag */ - ifmsh->csa_role = IEEE80211_MESH_CSA_ROLE_NONE; - ifmsh->chsw_ttl = 0; + ieee80211_mesh_reset_csa(sdata); - /* Remove the CSA and MCSP elements from the beacon */ - tmp_csa_settings = sdata_dereference(ifmsh->csa, sdata); - RCU_INIT_POINTER(ifmsh->csa, NULL); - if (tmp_csa_settings) - kfree_rcu(tmp_csa_settings, rcu_head); ret = ieee80211_mesh_rebuild_beacon(sdata); if (ret) return -EINVAL; @@ -1571,7 +1582,6 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata, ret = ieee80211_mesh_rebuild_beacon(sdata); if (ret) { - tmp_csa_settings = rcu_dereference(ifmsh->csa); RCU_INIT_POINTER(ifmsh->csa, NULL); kfree_rcu(tmp_csa_settings, rcu_head); return ret; diff --git a/net/mac80211/michael.c b/net/mac80211/michael.c deleted file mode 100644 index 8a1afc93e749..000000000000 --- a/net/mac80211/michael.c +++ /dev/null @@ -1,83 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Michael MIC implementation - optimized for TKIP MIC operations - * Copyright 2002-2003, Instant802 Networks, Inc. - */ -#include -#include -#include -#include - -#include "michael.h" - -static void michael_block(struct michael_mic_ctx *mctx, u32 val) -{ - mctx->l ^= val; - mctx->r ^= rol32(mctx->l, 17); - mctx->l += mctx->r; - mctx->r ^= ((mctx->l & 0xff00ff00) >> 8) | - ((mctx->l & 0x00ff00ff) << 8); - mctx->l += mctx->r; - mctx->r ^= rol32(mctx->l, 3); - mctx->l += mctx->r; - mctx->r ^= ror32(mctx->l, 2); - mctx->l += mctx->r; -} - -static void michael_mic_hdr(struct michael_mic_ctx *mctx, const u8 *key, - struct ieee80211_hdr *hdr) -{ - u8 *da, *sa, tid; - - da = ieee80211_get_DA(hdr); - sa = ieee80211_get_SA(hdr); - if (ieee80211_is_data_qos(hdr->frame_control)) - tid = ieee80211_get_tid(hdr); - else - tid = 0; - - mctx->l = get_unaligned_le32(key); - mctx->r = get_unaligned_le32(key + 4); - - /* - * A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC - * calculation, but it is _not_ transmitted - */ - michael_block(mctx, get_unaligned_le32(da)); - michael_block(mctx, get_unaligned_le16(&da[4]) | - (get_unaligned_le16(sa) << 16)); - michael_block(mctx, get_unaligned_le32(&sa[2])); - michael_block(mctx, tid); -} - -void michael_mic(const u8 *key, struct ieee80211_hdr *hdr, - const u8 *data, size_t data_len, u8 *mic) -{ - u32 val; - size_t block, blocks, left; - struct michael_mic_ctx mctx; - - michael_mic_hdr(&mctx, key, hdr); - - /* Real data */ - blocks = data_len / 4; - left = data_len % 4; - - for (block = 0; block < blocks; block++) - michael_block(&mctx, get_unaligned_le32(&data[block * 4])); - - /* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make - * total length a multiple of 4. */ - val = 0x5a; - while (left > 0) { - val <<= 8; - left--; - val |= data[blocks * 4 + left]; - } - - michael_block(&mctx, val); - michael_block(&mctx, 0); - - put_unaligned_le32(mctx.l, mic); - put_unaligned_le32(mctx.r, mic + 4); -} diff --git a/net/mac80211/michael.h b/net/mac80211/michael.h deleted file mode 100644 index a7fdb8e84615..000000000000 --- a/net/mac80211/michael.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Michael MIC implementation - optimized for TKIP MIC operations - * Copyright 2002-2003, Instant802 Networks, Inc. - */ - -#ifndef MICHAEL_H -#define MICHAEL_H - -#include -#include - -#define MICHAEL_MIC_LEN 8 - -struct michael_mic_ctx { - u32 l, r; -}; - -void michael_mic(const u8 *key, struct ieee80211_hdr *hdr, - const u8 *data, size_t data_len, u8 *mic); - -#endif /* MICHAEL_H */ diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index ae82533e3c02..0c98bdcd54ab 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -462,6 +462,13 @@ static void __ieee80211_roc_work(struct ieee80211_local *local) return; if (!roc->started) { + /* + * The work can be started by a previous ROC work, but a scan + * can get between things; scan finish will retrigger us. + */ + if (local->scanning) + return; + WARN_ON(!local->emulate_chanctx); _ieee80211_start_next_roc(local); } else { diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 5a508d99e84f..f63676c44853 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -18,7 +18,8 @@ static void ieee80211_sched_scan_cancel(struct ieee80211_local *local) cfg80211_sched_scan_stopped_locked(local->hw.wiphy, 0); } -int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) +int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan, + bool reset) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; @@ -166,9 +167,10 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) /* * We disconnected on all interfaces before suspend, all channel - * contexts should be released. + * contexts should be released, but on 'reset' debugfs that's + * not true so don't check there. */ - WARN_ON(!list_empty(&local->chanctx_list)); + WARN_ON(!reset && !list_empty(&local->chanctx_list)); /* stop hardware - this must stop RX */ ieee80211_stop_device(local, true); diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 1e06a465b49e..1101e98f186d 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -1238,7 +1238,7 @@ int ieee80211_request_ibss_scan(struct ieee80211_sub_if_data *sdata, } } - if (WARN_ON_ONCE(n_ch == 0)) + if (n_ch == 0) return -EINVAL; local->int_scan_req->n_channels = n_ch; diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 1536cd71878c..1dde37ad8bb2 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1285,6 +1285,24 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, peer_capability, initiator, extra_ies, extra_ies_len); break; + case WLAN_TDLS_SETUP_CONFIRM: { + struct sta_info *sta; + + sta = sta_info_get(sdata, peer); + if (!sta || !sta->sta.tdls) { + ret = -ENOLINK; + break; + } + + ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, + link_id, action_code, + dialog_token, + status_code, + peer_capability, + initiator, extra_ies, + extra_ies_len, 0, NULL); + break; + } case WLAN_TDLS_DISCOVERY_REQUEST: /* * Protect the discovery so we can hear the TDLS discovery @@ -1293,7 +1311,6 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, */ drv_mgd_protect_tdls_discover(sdata->local, sdata, link_id); fallthrough; - case WLAN_TDLS_SETUP_CONFIRM: case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: /* no special handling */ ret = ieee80211_tdls_prep_mgmt_packet(wiphy, dev, peer, diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index e7df1a0c8591..931846f45c2e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2084,8 +2084,29 @@ static bool ieee80211_validate_radiotap_len(struct sk_buff *skb) return true; } +static bool ieee80211_rate_bw_usable(u16 rate_flags, + const struct cfg80211_chan_def *chandef) +{ + int width; + + if (!chandef) + return true; + + if (rate_flags & IEEE80211_TX_RC_160_MHZ_WIDTH) + width = 160; + else if (rate_flags & IEEE80211_TX_RC_80_MHZ_WIDTH) + width = 80; + else if (rate_flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + width = 40; + else + return true; + + return width <= cfg80211_chandef_get_width(chandef); +} + bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, - struct net_device *dev) + struct net_device *dev, + const struct cfg80211_chan_def *chandef) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_radiotap_iterator iterator; @@ -2259,6 +2280,9 @@ bool ieee80211_parse_tx_radiotap(struct sk_buff *skb, struct ieee80211_supported_band *sband = local->hw.wiphy->bands[info->band]; + if (!ieee80211_rate_bw_usable(rate_flags, chandef)) + return false; + info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT; for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { @@ -2448,7 +2472,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb, * selected chandef above to accurately set injection rates and * retransmissions. */ - if (!ieee80211_parse_tx_radiotap(skb, dev)) + if (!ieee80211_parse_tx_radiotap(skb, dev, chandef)) goto fail_rcu; /* remove the injection radiotap header */ @@ -2902,10 +2926,23 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, */ skb = skb_share_check(skb, GFP_ATOMIC); if (unlikely(!skb)) { - ret = -ENOMEM; - goto free; + /* skb_share_check() already freed the skb */ + if (info_id) + ieee80211_remove_ack_skb(local, info_id); + return ERR_PTR(-ENOMEM); } + /* set this up so failure paths can clean up ack skb */ + info = IEEE80211_SKB_CB(skb); + memset(info, 0, sizeof(*info)); + + info->flags = info_flags; + if (info_id) { + info->status_data = info_id; + info->status_data_idr = 1; + } + info->band = band; + hdr.frame_control = fc; hdr.duration_id = 0; hdr.seq_ctrl = 0; @@ -2944,10 +2981,8 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, head_need += local->tx_headroom; head_need = max_t(int, 0, head_need); if (ieee80211_skb_resize(sdata, skb, head_need, ENCRYPT_DATA)) { - ieee80211_free_txskb(&local->hw, skb); - skb = NULL; ret = -ENOMEM; - goto free; + goto free_txskb; } } @@ -2974,16 +3009,6 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, skb_reset_mac_header(skb); - info = IEEE80211_SKB_CB(skb); - memset(info, 0, sizeof(*info)); - - info->flags = info_flags; - if (info_id) { - info->status_data = info_id; - info->status_data_idr = 1; - } - info->band = band; - if (likely(!cookie)) { ctrl_flags |= u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK); @@ -3007,16 +3032,17 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, pre_conf_link_id, link_id); #endif ret = -EINVAL; - goto free; + goto free_txskb; } } info->control.flags = ctrl_flags; return skb; + free_txskb: + ieee80211_free_txskb(&local->hw, skb); + return ERR_PTR(ret); free: - if (info_id) - ieee80211_remove_ack_skb(local, info_id); kfree_skb(skb); return ERR_PTR(ret); } @@ -4954,10 +4980,18 @@ static void ieee80211_beacon_add_tim_pvb(struct ps_data *ps, */ static void ieee80211_s1g_beacon_add_tim_pvb(struct ps_data *ps, struct sk_buff *skb, - bool mcast_traffic) + bool mcast_traffic, + bool ucast_traffic) { int blk; + /* + * if no unicast and multicast traffic don't emit a bitmap control + * or pvb + */ + if (!mcast_traffic && !ucast_traffic) + return; + /* * Emit a bitmap control block with a page slice number of 31 and a * page index of 0 which indicates as per IEEE80211-2024 9.4.2.5.1 @@ -4966,6 +5000,10 @@ static void ieee80211_s1g_beacon_add_tim_pvb(struct ps_data *ps, */ skb_put_u8(skb, mcast_traffic | (31 << 1)); + /* If there's no unicast traffic we don't need to include a PVB. */ + if (!ucast_traffic) + return; + /* Emit an encoded block for each non-zero sub-block */ for (blk = 0; blk < IEEE80211_MAX_SUPPORTED_S1G_TIM_BLOCKS; blk++) { u8 blk_bmap = 0; @@ -5047,25 +5085,16 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, ps->dtim_bc_mc = mcast_traffic; - if (have_bits) { - if (s1g) - ieee80211_s1g_beacon_add_tim_pvb(ps, skb, - mcast_traffic); - else - ieee80211_beacon_add_tim_pvb(ps, skb, mcast_traffic); + if (s1g) { + ieee80211_s1g_beacon_add_tim_pvb(ps, skb, mcast_traffic, + have_bits); + } else if (have_bits) { + ieee80211_beacon_add_tim_pvb(ps, skb, mcast_traffic); } else { - /* - * If there is no buffered unicast traffic for an S1G - * interface, we can exclude the bitmap control. This is in - * contrast to other phy types as they do include the bitmap - * control and pvb even when there is no buffered traffic. - */ - if (!s1g) { - /* Bitmap control */ - skb_put_u8(skb, mcast_traffic); - /* Part Virt Bitmap */ - skb_put_u8(skb, 0); - } + /* Bitmap control */ + skb_put_u8(skb, mcast_traffic); + /* Part Virt Bitmap */ + skb_put_u8(skb, 0); } tim->datalen = skb_tail_pointer(skb) - tim->data; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index af99ac02953d..3ed47a8ebf5c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -2202,9 +2202,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) } } + /* Passing NULL means an interface is picked for configuration */ if (local->virt_monitors > 0 && local->virt_monitors == local->open_count) - ieee80211_add_virtual_monitor(local); + ieee80211_add_virtual_monitor(local, NULL); if (!suspended) return 0; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index bb0fa505cdca..42bbe64617a1 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -18,7 +18,6 @@ #include #include "ieee80211_i.h" -#include "michael.h" #include "tkip.h" #include "aes_ccm.h" #include "aes_cmac.h" diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c index 7a93e22d049d..2fc2e08aecfb 100644 --- a/net/netfilter/nf_flow_table_core.c +++ b/net/netfilter/nf_flow_table_core.c @@ -250,6 +250,14 @@ static void flow_offload_route_release(struct flow_offload *flow) nft_flow_dst_release(flow, FLOW_OFFLOAD_DIR_REPLY); } +static void flow_offload_free_rcu(struct rcu_head *rcu_head) +{ + struct flow_offload *flow = container_of(rcu_head, struct flow_offload, rcu_head); + + nf_ct_put(flow->ct); + kfree(flow); +} + void flow_offload_free(struct flow_offload *flow) { switch (flow->type) { @@ -259,8 +267,7 @@ void flow_offload_free(struct flow_offload *flow) default: break; } - nf_ct_put(flow->ct); - kfree_rcu(flow, rcu_head); + call_rcu(&flow->rcu_head, flow_offload_free_rcu); } EXPORT_SYMBOL_GPL(flow_offload_free); @@ -839,6 +846,7 @@ static int __init nf_flow_table_module_init(void) static void __exit nf_flow_table_module_exit(void) { + rcu_barrier(); nf_flow_table_offload_exit(); unregister_pernet_subsys(&nf_flow_table_net_ops); } diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c index cd84f2aa08f2..658b0f143834 100644 --- a/net/netfilter/nf_nat_core.c +++ b/net/netfilter/nf_nat_core.c @@ -1236,31 +1236,45 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops, } ret = nf_register_net_hooks(net, nat_ops, ops_count); - if (ret < 0) { - mutex_unlock(&nf_nat_proto_mutex); - for (i = 0; i < ops_count; i++) { - priv = nat_ops[i].priv; - kfree_rcu(priv, rcu_head); - } - kfree_rcu(nat_ops, rcu); - return ret; - } - - nat_proto_net->nat_hook_ops = nat_ops; + if (ret < 0) + goto err_free_hooks; + } else { + nat_ops = nat_proto_net->nat_hook_ops; } - nat_ops = nat_proto_net->nat_hook_ops; priv = nat_ops[hooknum].priv; if (WARN_ON_ONCE(!priv)) { - mutex_unlock(&nf_nat_proto_mutex); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto err_unregister_hooks; } ret = nf_hook_entries_insert_raw(&priv->entries, ops); - if (ret == 0) - nat_proto_net->users++; + if (ret) + goto err_unregister_hooks; + + if (!nat_proto_net->nat_hook_ops) + nat_proto_net->nat_hook_ops = nat_ops; + + nat_proto_net->users++; mutex_unlock(&nf_nat_proto_mutex); + + return 0; + +err_unregister_hooks: + if (nat_proto_net->nat_hook_ops) { + mutex_unlock(&nf_nat_proto_mutex); + return ret; + } + nf_unregister_net_hooks(net, nat_ops, ops_count); +err_free_hooks: + mutex_unlock(&nf_nat_proto_mutex); + for (i = 0; i < ops_count; i++) { + priv = nat_ops[i].priv; + kfree_rcu(priv, rcu_head); + } + kfree_rcu(nat_ops, rcu); + return ret; } diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index a3a66b6268cd..321a0dd92178 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -2343,11 +2343,14 @@ static struct nft_hook *nft_netdev_hook_alloc(struct net *net, } static struct nft_hook *nft_hook_list_find(struct list_head *hook_list, - const struct nft_hook *this) + const struct nft_hook *this, + bool strict) { struct nft_hook *hook; list_for_each_entry(hook, hook_list, list) { + if (strict && hook->ifnamelen != this->ifnamelen) + continue; if (!strncmp(hook->ifname, this->ifname, min(hook->ifnamelen, this->ifnamelen))) return hook; @@ -2385,7 +2388,7 @@ static int nf_tables_parse_netdev_hooks(struct net *net, err = PTR_ERR(hook); goto err_hook; } - if (nft_hook_list_find(hook_list, hook)) { + if (nft_hook_list_find(hook_list, hook, false)) { NL_SET_BAD_ATTR(extack, tmp); nft_netdev_hook_free(hook); err = -EEXIST; @@ -2842,7 +2845,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, ops->hook = basechain->ops.hook; } - if (nft_hook_list_find(&basechain->hook_list, h)) { + if (nft_hook_list_find(&basechain->hook_list, h, false)) { list_del(&h->list); nft_netdev_hook_free(h); continue; @@ -2855,7 +2858,8 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy, !nft_trans_chain_update(trans)) continue; - if (nft_hook_list_find(&nft_trans_chain_hooks(trans), h)) { + if (nft_hook_list_find(&nft_trans_chain_hooks(trans), + h, false)) { nft_chain_release_hook(&hook); return -EEXIST; } @@ -3130,7 +3134,7 @@ static int nft_delchain_hook(struct nft_ctx *ctx, return err; list_for_each_entry(this, &chain_hook.list, list) { - hook = nft_hook_list_find(&basechain->hook_list, this); + hook = nft_hook_list_find(&basechain->hook_list, this, true); if (!hook) { err = -ENOENT; goto err_chain_del_hook; @@ -8921,7 +8925,7 @@ static int nft_register_flowtable_net_hooks(struct net *net, if (!nft_is_active_next(net, ft)) continue; - if (nft_hook_list_find(&ft->hook_list, hook)) { + if (nft_hook_list_find(&ft->hook_list, hook, false)) { err = -EEXIST; goto err_unregister_net_hooks; } @@ -8980,7 +8984,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh, return err; list_for_each_entry_safe(hook, next, &flowtable_hook.list, list) { - if (nft_hook_list_find(&flowtable->hook_list, hook)) { + if (nft_hook_list_find(&flowtable->hook_list, hook, false)) { list_del(&hook->list); nft_netdev_hook_free(hook); continue; @@ -8993,7 +8997,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh, !nft_trans_flowtable_update(trans)) continue; - if (nft_hook_list_find(&nft_trans_flowtable_hooks(trans), hook)) { + if (nft_hook_list_find(&nft_trans_flowtable_hooks(trans), hook, false)) { err = -EEXIST; goto err_flowtable_update_hook; } @@ -9213,7 +9217,7 @@ static int nft_delflowtable_hook(struct nft_ctx *ctx, return err; list_for_each_entry(this, &flowtable_hook.list, list) { - hook = nft_hook_list_find(&flowtable->hook_list, this); + hook = nft_hook_list_find(&flowtable->hook_list, this, true); if (!hook) { err = -ENOENT; goto err_flowtable_del_hook; diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c index e32cd9fbc7c2..cdbd800cac96 100644 --- a/net/netfilter/nft_nat.c +++ b/net/netfilter/nft_nat.c @@ -64,8 +64,8 @@ static void nft_nat_setup_netmap(struct nf_nat_range2 *range, const struct nft_pktinfo *pkt, const struct nft_nat *priv) { + union nf_inet_addr new_addr = {}; struct sk_buff *skb = pkt->skb; - union nf_inet_addr new_addr; __be32 netmask; int i, len = 0; diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index 3f51f1968654..89ef350ca91c 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -366,7 +366,7 @@ static struct nf_conn_labels *ovs_ct_get_conn_labels(struct nf_conn *ct) struct nf_conn_labels *cl; cl = nf_ct_labels_find(ct); - if (!cl) { + if (!cl && !nf_ct_is_confirmed(ct)) { nf_ct_labels_ext_add(ct); cl = nf_ct_labels_find(ct); } diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 772ecfa13cd7..e65f783cc78b 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2383,7 +2383,9 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, virtio_net_hdr_from_skb(skb, h.raw + macoff - sizeof(struct virtio_net_hdr), vio_le(), true, 0)) { - if (po->tp_version == TPACKET_V3) + if (po->tp_version <= TPACKET_V2) + __clear_bit(slot_id, po->rx_ring.rx_owner_map); + else prb_clear_blk_fill_status(&po->rx_ring); goto drop_n_account; } diff --git a/net/packet/internal.h b/net/packet/internal.h index b76e645cd78d..f5c8cd0eed2c 100644 --- a/net/packet/internal.h +++ b/net/packet/internal.h @@ -21,7 +21,7 @@ struct tpacket_kbdq_core { unsigned int hdrlen; unsigned char reset_pending_on_curr_blk; unsigned short kactive_blk_num; - unsigned short blk_sizeof_priv; + unsigned int blk_sizeof_priv; unsigned short version; diff --git a/net/psp/psp_sock.c b/net/psp/psp_sock.c index a931d825d1cc..0fcc60c92c32 100644 --- a/net/psp/psp_sock.c +++ b/net/psp/psp_sock.c @@ -143,6 +143,10 @@ int psp_sock_assoc_set_rx(struct sock *sk, struct psp_assoc *pas, NL_SET_ERR_MSG(extack, "Socket already has PSP state"); err = -EBUSY; goto exit_unlock; + } else if (sk_has_decrypt_user(sk)) { + NL_SET_ERR_MSG(extack, "Socket has incompatible state"); + err = -EINVAL; + goto exit_unlock; } refcount_inc(&pas->refcnt); diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index d9b6c9d2f679..1c6e3b3f39d0 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -115,7 +115,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even &conn->c_laddr, &conn->c_faddr, RDS_PROTOCOL_MAJOR(conn->c_version), RDS_PROTOCOL_MINOR(conn->c_version)); - rds_conn_destroy(conn); + rds_conn_drop(conn); return; } } diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 46c7d8441381..0914863dbfa2 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -1218,11 +1218,16 @@ static int tcf_action_put(struct tc_action *p) static void tcf_action_put_many(struct tc_action *actions[]) { - struct tc_action *a; int i; - tcf_act_for_each_action(i, a, actions) { - const struct tc_action_ops *ops = a->ops; + /* Deletion may have cleared entries before failing. */ + for (i = 0; i < TCA_ACT_MAX_PRIO; i++) { + struct tc_action *a = actions[i]; + const struct tc_action_ops *ops; + + if (!a) + continue; + ops = a->ops; if (tcf_action_put(a)) module_put(ops->owner); } diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index 6c5ffc0c4e8d..d6a60ae8938c 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -526,7 +526,7 @@ static void hhf_destroy(struct Qdisc *sch) static const struct nla_policy hhf_policy[TCA_HHF_MAX + 1] = { [TCA_HHF_BACKLOG_LIMIT] = { .type = NLA_U32 }, [TCA_HHF_QUANTUM] = { .type = NLA_U32 }, - [TCA_HHF_HH_FLOWS_LIMIT] = { .type = NLA_U32 }, + [TCA_HHF_HH_FLOWS_LIMIT] = NLA_POLICY_MAX(NLA_U32, 2 * HH_FLOWS_CNT), [TCA_HHF_RESET_TIMEOUT] = { .type = NLA_U32 }, [TCA_HHF_ADMIT_BYTES] = { .type = NLA_U32 }, [TCA_HHF_EVICT_TIMEOUT] = { .type = NLA_U32 }, @@ -545,7 +545,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt, u32 new_hhf_non_hh_weight = q->hhf_non_hh_weight; err = nla_parse_nested_deprecated(tb, TCA_HHF_MAX, opt, hhf_policy, - NULL); + extack); if (err < 0) return err; @@ -623,6 +623,9 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt, q->hhf_evict_timeout = HZ; /* 1 sec */ q->hhf_non_hh_weight = 2; + /* Cap max active HHs at twice len of hh_flows table. */ + q->hh_flows_limit = 2 * HH_FLOWS_CNT; + if (opt) { int err = hhf_change(sch, opt, extack); @@ -639,8 +642,6 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt, for (i = 0; i < HH_FLOWS_CNT; i++) INIT_LIST_HEAD(&q->hh_flows[i]); - /* Cap max active HHs at twice len of hh_flows table. */ - q->hh_flows_limit = 2 * HH_FLOWS_CNT; q->hh_flows_overlimit = 0; q->hh_flows_total_cnt = 0; q->hh_flows_current_cnt = 0; diff --git a/net/unix/garbage.c b/net/unix/garbage.c index cad17f639b01..11b75d37ac03 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -375,7 +375,7 @@ static bool unix_vertex_dead(struct unix_vertex *vertex) static LIST_HEAD(unix_visited_vertices); static unsigned long unix_vertex_grouped_index = UNIX_VERTEX_INDEX_MARK2; -static bool unix_scc_dead(struct list_head *scc, bool fast) +static bool unix_scc_dead(struct list_head *scc) { struct unix_vertex *vertex; bool scc_dead = true; @@ -387,10 +387,6 @@ static bool unix_scc_dead(struct list_head *scc, bool fast) /* Don't restart DFS from this vertex. */ list_move_tail(&vertex->entry, &unix_visited_vertices); - /* Mark vertex as off-stack for __unix_walk_scc(). */ - if (!fast) - vertex->index = unix_vertex_grouped_index; - if (scc_dead) scc_dead = unix_vertex_dead(vertex); } @@ -522,6 +518,7 @@ static unsigned long __unix_walk_scc(struct unix_vertex *vertex, } if (vertex->index == vertex->scc_index) { + struct unix_vertex *v; struct list_head scc; /* SCC finalised. @@ -531,7 +528,13 @@ static unsigned long __unix_walk_scc(struct unix_vertex *vertex, */ __list_cut_position(&scc, &vertex_stack, &vertex->scc_entry); - if (unix_scc_dead(&scc, false)) { + list_for_each_entry_reverse(v, &scc, scc_entry) { + /* Mark vertex as off-stack and assign a unique ID. */ + v->index = unix_vertex_grouped_index; + v->scc_index = vertex->scc_index; + } + + if (unix_scc_dead(&scc)) { unix_collect_skb(&scc, hitlist); } else { if (unix_vertex_max_scc_index < vertex->scc_index) @@ -588,7 +591,7 @@ static void unix_walk_scc_fast(struct sk_buff_head *hitlist) vertex = list_first_entry(&unix_unvisited_vertices, typeof(*vertex), entry); list_add(&scc, &vertex->scc_entry); - if (unix_scc_dead(&scc, true)) { + if (unix_scc_dead(&scc)) { cyclic_sccs--; unix_collect_skb(&scc, hitlist); } diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 62a83faf0e07..a77fd5ba6368 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_WEXT_PRIV) += wext-priv.o cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o trace.o ocb.o -cfg80211-y += pmsr.o +cfg80211-y += michael-mic.o pmsr.o cfg80211-$(CONFIG_OF) += of.o cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o diff --git a/net/wireless/core.c b/net/wireless/core.c index b565f777e556..01e44ba4eddd 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -150,68 +150,93 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, return 0; } -int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, - struct net *net) +static int cfg80211_switch_wdev_netns(struct wireless_dev *wdev, + struct net *net) { - struct wireless_dev *wdev; - int err = 0; + int err; - if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) - return -EOPNOTSUPP; + if (!wdev->netdev) + return 0; - list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { - if (!wdev->netdev) + wdev->netdev->netns_immutable = false; + err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); + wdev->netdev->netns_immutable = true; + + return err; +} + +static int __cfg80211_switch_netns(struct cfg80211_registered_device *rdev, + struct net *net, bool force) +{ + struct net *old_net = wiphy_net(&rdev->wiphy); + struct wireless_dev *wdev, *tmp; + int err = 0; + + list_for_each_entry_safe(wdev, tmp, &rdev->wiphy.wdev_list, list) { + err = cfg80211_switch_wdev_netns(wdev, net); + if (!err) continue; - wdev->netdev->netns_immutable = false; - err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); - if (err) - break; - wdev->netdev->netns_immutable = true; + if (!force) + goto undo; + /* remove interfaces that fail to allow wiphy switching */ + dev_close(wdev->netdev); + scoped_guard(wiphy, &rdev->wiphy) + cfg80211_unregister_wdev(wdev); + err = 0; } - if (err) { - /* failed -- clean up to old netns */ - net = wiphy_net(&rdev->wiphy); - - list_for_each_entry_continue_reverse(wdev, - &rdev->wiphy.wdev_list, - list) { + scoped_guard(wiphy, &rdev->wiphy) { + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { if (!wdev->netdev) continue; - wdev->netdev->netns_immutable = false; - err = dev_change_net_namespace(wdev->netdev, net, - "wlan%d"); - WARN_ON(err); - wdev->netdev->netns_immutable = true; + nl80211_notify_iface(rdev, wdev, + NL80211_CMD_DEL_INTERFACE); } - return err; - } + nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY); - guard(wiphy)(&rdev->wiphy); + wiphy_net_set(&rdev->wiphy, net); - list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { - if (!wdev->netdev) - continue; - nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE); - } + /* this only fails on allocation failure */ + err = device_rename(&rdev->wiphy.dev, + dev_name(&rdev->wiphy.dev)); + if (err && !force) + wiphy_net_set(&rdev->wiphy, old_net); - nl80211_notify_wiphy(rdev, NL80211_CMD_DEL_WIPHY); + nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); - wiphy_net_set(&rdev->wiphy, net); + list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { + if (!wdev->netdev) + continue; + nl80211_notify_iface(rdev, wdev, + NL80211_CMD_NEW_INTERFACE); + } + } - err = device_rename(&rdev->wiphy.dev, dev_name(&rdev->wiphy.dev)); - WARN_ON(err); + if (!err || force) + return err; - nl80211_notify_wiphy(rdev, NL80211_CMD_NEW_WIPHY); + /* set to the last one to undo all of them */ + wdev = list_entry(&rdev->wiphy.wdev_list, typeof(*wdev), list); +undo: + /* + * Move back everything, if this fails again (allocation failures) + * then things get stuck in different network namespaces. + */ + list_for_each_entry_continue_reverse(wdev, &rdev->wiphy.wdev_list, + list) + WARN_ON(cfg80211_switch_wdev_netns(wdev, old_net)); - list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) { - if (!wdev->netdev) - continue; - nl80211_notify_iface(rdev, wdev, NL80211_CMD_NEW_INTERFACE); - } + return err; +} - return 0; +int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, + struct net *net) +{ + if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) + return -EOPNOTSUPP; + + return __cfg80211_switch_netns(rdev, net, false); } static void cfg80211_rfkill_poll(struct rfkill *rfkill, void *data) @@ -241,9 +266,8 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, rdev->opencount--; if (rdev->scan_req && rdev->scan_req->req.wdev == wdev) { - if (WARN_ON(!rdev->scan_req->notified && - (!rdev->int_scan_req || - !rdev->int_scan_req->notified))) + if (!rdev->scan_req->notified && + (!rdev->int_scan_req || !rdev->int_scan_req->notified)) rdev->scan_req->info.aborted = true; ___cfg80211_scan_done(rdev, false); } @@ -1660,9 +1684,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, wiphy_lock(&rdev->wiphy); cfg80211_update_iface_num(rdev, wdev->iftype, -1); if (rdev->scan_req && rdev->scan_req->req.wdev == wdev) { - if (WARN_ON(!rdev->scan_req->notified && - (!rdev->int_scan_req || - !rdev->int_scan_req->notified))) + if (!rdev->scan_req->notified && + (!rdev->int_scan_req || + !rdev->int_scan_req->notified)) rdev->scan_req->info.aborted = true; ___cfg80211_scan_done(rdev, false); } @@ -1753,7 +1777,7 @@ static void __net_exit cfg80211_pernet_exit(struct net *net) rtnl_lock(); for_each_rdev(rdev) { if (net_eq(wiphy_net(&rdev->wiphy), net)) - WARN_ON(cfg80211_switch_netns(rdev, &init_net)); + WARN_ON(__cfg80211_switch_netns(rdev, &init_net, true)); } rtnl_unlock(); } diff --git a/net/wireless/core.h b/net/wireless/core.h index 1086aa1a44f4..d7ac3145fd1a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -24,6 +24,16 @@ struct cfg80211_scan_request_int { struct cfg80211_scan_info info; bool notified; + /* + * set while the request is handed to the driver, i.e. between + * rdev_scan() and cfg80211_scan_done() + */ + bool driver_owns; + /* + * set when cfg80211 is done with the request but the driver still + * owns it, so that cfg80211_scan_done() knows to just free it + */ + bool stale; /* must be last - variable members */ struct cfg80211_scan_request req; }; diff --git a/net/wireless/michael-mic.c b/net/wireless/michael-mic.c new file mode 100644 index 000000000000..50cdb67f0503 --- /dev/null +++ b/net/wireless/michael-mic.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Michael MIC implementation - optimized for TKIP MIC operations + * Copyright 2002-2003, Instant802 Networks, Inc. + */ +#include +#include +#include +#include + +struct michael_mic_ctx { + u32 l, r; +}; + +static void michael_block(struct michael_mic_ctx *mctx, u32 val) +{ + mctx->l ^= val; + mctx->r ^= rol32(mctx->l, 17); + mctx->l += mctx->r; + mctx->r ^= ((mctx->l & 0xff00ff00) >> 8) | + ((mctx->l & 0x00ff00ff) << 8); + mctx->l += mctx->r; + mctx->r ^= rol32(mctx->l, 3); + mctx->l += mctx->r; + mctx->r ^= ror32(mctx->l, 2); + mctx->l += mctx->r; +} + +static void michael_mic_hdr(struct michael_mic_ctx *mctx, const u8 *key, + struct ieee80211_hdr *hdr) +{ + u8 *da, *sa, tid; + + da = ieee80211_get_DA(hdr); + sa = ieee80211_get_SA(hdr); + if (ieee80211_is_data_qos(hdr->frame_control)) + tid = ieee80211_get_tid(hdr); + else + tid = 0; + + mctx->l = get_unaligned_le32(key); + mctx->r = get_unaligned_le32(key + 4); + + /* + * A pseudo header (DA, SA, Priority, 0, 0, 0) is used in Michael MIC + * calculation, but it is _not_ transmitted + */ + michael_block(mctx, get_unaligned_le32(da)); + michael_block(mctx, get_unaligned_le16(&da[4]) | + (get_unaligned_le16(sa) << 16)); + michael_block(mctx, get_unaligned_le32(&sa[2])); + michael_block(mctx, tid); +} + +void michael_mic(const u8 *key, struct ieee80211_hdr *hdr, + const u8 *data, size_t data_len, u8 *mic) +{ + u32 val; + size_t block, blocks, left; + struct michael_mic_ctx mctx; + + michael_mic_hdr(&mctx, key, hdr); + + /* Real data */ + blocks = data_len / 4; + left = data_len % 4; + + for (block = 0; block < blocks; block++) + michael_block(&mctx, get_unaligned_le32(&data[block * 4])); + + /* Partial block of 0..3 bytes and padding: 0x5a + 4..7 zeros to make + * total length a multiple of 4. */ + val = 0x5a; + while (left > 0) { + val <<= 8; + left--; + val |= data[blocks * 4 + left]; + } + + michael_block(&mctx, val); + michael_block(&mctx, 0); + + put_unaligned_le32(mctx.l, mic); + put_unaligned_le32(mctx.r, mic + 4); +} +EXPORT_SYMBOL_GPL(michael_mic); diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index f4c06282b2e1..bc99458b6ed7 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -464,7 +464,10 @@ static inline int rdev_scan(struct cfg80211_registered_device *rdev, return -EINVAL; trace_rdev_scan(&rdev->wiphy, request); + request->driver_owns = true; ret = rdev->ops->scan(&rdev->wiphy, &request->req); + if (ret) + request->driver_owns = false; trace_rdev_return_int(&rdev->wiphy, ret); return ret; } diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 9648e24181fb..29e150b4511f 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1115,6 +1115,21 @@ int cfg80211_scan(struct cfg80211_registered_device *rdev) return 0; } +/* + * Release the scan request, but free it only if the driver is also done, + * e.g. mac80211 may cancel it asynchronously and still use it. + */ +static void cfg80211_put_scan_req(struct cfg80211_scan_request_int *req) +{ + if (!req) + return; + + if (req->driver_owns) + req->stale = true; + else + kfree(req); +} + void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool send_message) { @@ -1174,10 +1189,10 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, dev_put(wdev->netdev); - kfree(rdev->int_scan_req); + cfg80211_put_scan_req(rdev->int_scan_req); rdev->int_scan_req = NULL; - kfree(rdev->scan_req); + cfg80211_put_scan_req(rdev->scan_req); rdev->scan_req = NULL; if (!send_message) @@ -1200,6 +1215,18 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, struct cfg80211_scan_info old_info = intreq->info; trace_cfg80211_scan_done(intreq, info); + + intreq->driver_owns = false; + + if (intreq->stale) { + /* + * The scan is already completed as far as we're concerned, + * it was just kept around for the driver - done now, free it. + */ + kfree(intreq); + return; + } + WARN_ON(intreq != rdev->scan_req && intreq != rdev->int_scan_req); @@ -2023,6 +2050,13 @@ __cfg80211_bss_update(struct cfg80211_registered_device *rdev, if (!hidden) hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_NUL); + /* + * Only group with an entry with beacon data, otherwise + * beacon data can never be filled/updated. + */ + if (hidden && + !rcu_access_pointer(hidden->pub.beacon_ies)) + hidden = NULL; if (hidden) { new->pub.hidden_beacon_bss = &hidden->pub; list_add(&new->hidden_list, @@ -3457,11 +3491,6 @@ void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev, cbss->pub.channel = chan; list_for_each_entry(bss, &rdev->bss_list, list) { - if (!cfg80211_bss_type_match(bss->pub.capability, - bss->pub.channel->band, - wdev->conn_bss_type)) - continue; - if (bss == cbss) continue; diff --git a/net/wireless/util.c b/net/wireless/util.c index 918d8f8468bd..0254cd5f89f1 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -962,12 +962,30 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb, } switch (skb->protocol) { - case htons(ETH_P_IP): - dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc; + case htons(ETH_P_IP): { + const struct iphdr *iph; + struct iphdr _iph; + + iph = skb_header_pointer(skb, sizeof(struct ethhdr), + sizeof(*iph), &_iph); + if (!iph) + return 0; + + dscp = ipv4_get_dsfield(iph) & 0xfc; break; - case htons(ETH_P_IPV6): - dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & 0xfc; + } + case htons(ETH_P_IPV6): { + const struct ipv6hdr *ip6h; + struct ipv6hdr _ip6h; + + ip6h = skb_header_pointer(skb, sizeof(struct ethhdr), + sizeof(*ip6h), &_ip6h); + if (!ip6h) + return 0; + + dscp = ipv6_get_dsfield(ip6h) & 0xfc; break; + } case htons(ETH_P_MPLS_UC): case htons(ETH_P_MPLS_MC): { struct mpls_label mpls_tmp, *mpls; @@ -2385,16 +2403,15 @@ static void cfg80211_calculate_bi_data(struct wiphy *wiphy, u32 new_beacon_int, if (wdev->valid_links) continue; + wdev_bi = cfg80211_wdev_bi(wdev); + if (!wdev_bi) + continue; + /* skip wdevs not active on the given wiphy radio */ if (radio_idx >= 0 && !(rdev_get_radio_mask(rdev, wdev->netdev) & BIT(radio_idx))) continue; - wdev_bi = cfg80211_wdev_bi(wdev); - - if (!wdev_bi) - continue; - if (!*beacon_int_gcd) { *beacon_int_gcd = wdev_bi; continue; diff --git a/net/xfrm/espintcp.c b/net/xfrm/espintcp.c index fb47c2f73104..26c0a46491a4 100644 --- a/net/xfrm/espintcp.c +++ b/net/xfrm/espintcp.c @@ -33,7 +33,11 @@ static void handle_esp(struct sk_buff *skb, struct sock *sk) { struct tcp_skb_cb *tcp_cb = (struct tcp_skb_cb *)skb->cb; - skb_reset_transport_header(skb); + if (!skb_reset_transport_header_careful(skb)) { + XFRM_INC_STATS(sock_net(sk), LINUX_MIB_XFRMINERROR); + kfree_skb(skb); + return; + } /* restore IP CB, we need at least IP6CB->nhoff */ memmove(skb->cb, &tcp_cb->header, sizeof(tcp_cb->header)); diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index cfee63a6c87d..58c153af6fcc 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -464,12 +464,14 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) { const struct xfrm_state_afinfo *afinfo; struct net *net = dev_net(skb->dev); + struct net_device *dev = skb->dev; int err; __be32 seq; __be32 seq_hi; struct xfrm_state *x = NULL; xfrm_address_t *daddr; u32 mark = skb->mark; + u8 xfrm_proto = nexthdr; unsigned int family = AF_UNSPEC; int decaps = 0; int async = 0; @@ -481,6 +483,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) if (encap_type < 0 || (xo && (xo->flags & XFRM_GRO || encap_type == 0 || encap_type == UDP_ENCAP_ESPINUDP))) { x = xfrm_input_state(skb); + xfrm_proto = x->type ? x->type->proto : nexthdr; if (unlikely(x->km.state != XFRM_STATE_VALID)) { if (x->km.state == XFRM_STATE_ACQ) @@ -490,7 +493,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) LINUX_MIB_XFRMINSTATEINVALID); if (encap_type == -1) - dev_put(skb->dev); + dev_put(dev); goto drop; } @@ -504,6 +507,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) if (encap_type == -1) { async = 1; seq = XFRM_SKB_CB(skb)->seq.input.low; + spin_lock(&x->lock); goto resume; } /* GRO call */ @@ -540,6 +544,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); goto drop; } + + nexthdr = x->type_offload->input_tail(x, skb); } goto lock; @@ -585,11 +591,13 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) x = xfrm_input_state_lookup(net, mark, daddr, spi, nexthdr, family); if (x == NULL) { + xfrm_proto = nexthdr; secpath_reset(skb); XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); xfrm_audit_state_notfound(skb, family, spi, seq); goto drop; } + xfrm_proto = x->type ? x->type->proto : nexthdr; if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) { secpath_reset(skb); @@ -597,6 +605,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) xfrm_audit_state_notfound(skb, family, spi, seq); xfrm_state_put(x); x = NULL; + xfrm_proto = nexthdr; goto drop; } @@ -637,11 +646,9 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) goto drop_unlock; } - spin_unlock(&x->lock); - if (xfrm_tunnel_check(skb, x, family)) { XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); - goto drop; + goto drop_unlock; } seq_hi = htonl(xfrm_replay_seqhi(x, seq)); @@ -649,22 +656,21 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) XFRM_SKB_CB(skb)->seq.input.low = seq; XFRM_SKB_CB(skb)->seq.input.hi = seq_hi; - if (crypto_done) { - nexthdr = x->type_offload->input_tail(x, skb); - } else { - dev_hold(skb->dev); + if (!crypto_done) { + spin_unlock(&x->lock); + dev_hold(dev); nexthdr = x->type->input(x, skb); if (nexthdr == -EINPROGRESS) { if (async) - dev_put(skb->dev); + dev_put(dev); return 0; } - dev_put(skb->dev); + dev_put(dev); + spin_lock(&x->lock); } resume: - spin_lock(&x->lock); if (nexthdr < 0) { if (nexthdr == -EBADMSG) { xfrm_audit_state_icvfail(x, skb, @@ -696,7 +702,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) err = xfrm_inner_mode_input(x, skb); if (err == -EINPROGRESS) { if (async) - dev_put(skb->dev); + dev_put(dev); return 0; } else if (err) { XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); @@ -723,9 +729,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) crypto_done = false; } while (!err); - err = xfrm_rcv_cb(skb, family, x->type->proto, 0); - if (err) + rcu_read_lock(); + err = xfrm_rcv_cb(skb, family, xfrm_proto, 0); + if (err) { + rcu_read_unlock(); goto drop; + } nf_reset_ct(skb); @@ -736,8 +745,9 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) if (skb_valid_dst(skb)) skb_dst_drop(skb); if (async) - dev_put(skb->dev); + dev_put(dev); gro_cells_receive(&gro_cells, skb); + rcu_read_unlock(); return 0; } else { xo = xfrm_offload(skb); @@ -745,23 +755,21 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) xfrm_gro = xo->flags & XFRM_GRO; err = -EAFNOSUPPORT; - rcu_read_lock(); - afinfo = xfrm_state_afinfo_get_rcu(x->props.family); + afinfo = xfrm_state_afinfo_get_rcu(family); if (likely(afinfo)) err = afinfo->transport_finish(skb, xfrm_gro || async); - rcu_read_unlock(); if (xfrm_gro) { sp = skb_sec_path(skb); if (sp) sp->olen = 0; if (skb_valid_dst(skb)) skb_dst_drop(skb); - if (async) - dev_put(skb->dev); gro_cells_receive(&gro_cells, skb); - return err; } + if (async) + dev_put(dev); + rcu_read_unlock(); return err; } @@ -769,8 +777,8 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) spin_unlock(&x->lock); drop: if (async) - dev_put(skb->dev); - xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1); + dev_put(dev); + xfrm_rcv_cb(skb, family, xfrm_proto, -1); kfree_skb(skb); return 0; } @@ -794,12 +802,17 @@ static void xfrm_trans_reinject(struct work_struct *work) spin_unlock_bh(&trans->queue_lock); local_bh_disable(); + rcu_read_lock(); while ((skb = __skb_dequeue(&queue))) { struct net *net = XFRM_TRANS_SKB_CB(skb)->net; + struct net_device *dev = skb->dev; XFRM_TRANS_SKB_CB(skb)->finish(net, NULL, skb); + if (dev) + dev_put(dev); put_net(net); } + rcu_read_unlock(); local_bh_enable(); } @@ -815,12 +828,18 @@ int xfrm_trans_queue_net(struct net *net, struct sk_buff *skb, if (skb_queue_len(&trans->queue) >= READ_ONCE(net_hotdata.max_backlog)) return -ENOBUFS; + if (skb_dst(skb) && !skb_dst_force(skb)) + return -EHOSTUNREACH; + BUILD_BUG_ON(sizeof(struct xfrm_trans_cb) > sizeof(skb->cb)); hold_net = maybe_get_net(net); if (!hold_net) return -ENODEV; + if (skb->dev) + dev_hold(skb->dev); + XFRM_TRANS_SKB_CB(skb)->finish = finish; XFRM_TRANS_SKB_CB(skb)->net = hold_net; spin_lock_bh(&trans->queue_lock); diff --git a/net/xfrm/xfrm_iptfs.c b/net/xfrm/xfrm_iptfs.c index d39253b06c4e..4d3489acb099 100644 --- a/net/xfrm/xfrm_iptfs.c +++ b/net/xfrm/xfrm_iptfs.c @@ -416,6 +416,14 @@ static bool iptfs_skb_can_add_frags(const struct sk_buff *skb, if (skb_has_frag_list(skb) || skb->pp_recycle != walk->pp_recycle) return false; + /* Reject an @offset that is at or beyond the end of the walk's data + * before calling iptfs_skb_reset_frag_walk(), whose fragment-advance + * loop is otherwise unbounded and would index past walk->frags[]. + * This mirrors the guard already present in iptfs_skb_add_frags(). + */ + if (!walk->nr_frags || offset >= walk->total + walk->initial_offset) + return false; + /* Make offset relative to current frag after setting that */ offset = iptfs_skb_reset_frag_walk(walk, offset); @@ -820,8 +828,8 @@ static u32 iptfs_reassem_cont(struct xfrm_iptfs_data *xtfs, u64 seq, * allocate an in progress skb */ ipremain = __iptfs_iplen(xtfs->ra_runt); - if (ipremain < sizeof(xtfs->ra_runt)) { - /* length has to be at least runtsize large */ + if (ipremain < __iptfs_iphlen(xtfs->ra_runt)) { + /* length has to be at least the IP header size */ XFRM_INC_STATS(xs_net(xtfs->x), LINUX_MIB_XFRMINIPTFSERROR); goto abandon; diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index f463c7bd5321..f0dd25bdd5d0 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -226,6 +226,7 @@ static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO]; static DEFINE_SPINLOCK(xfrm_state_gc_lock); static DEFINE_SPINLOCK(xfrm_state_dev_gc_lock); +static DEFINE_MUTEX(xfrm_state_gc_mutex); int __xfrm_state_delete(struct xfrm_state *x); @@ -632,8 +633,10 @@ static void xfrm_state_gc_task(struct work_struct *work) synchronize_rcu(); + mutex_lock(&xfrm_state_gc_mutex); hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) xfrm_state_gc_destroy(x); + mutex_unlock(&xfrm_state_gc_mutex); } static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) @@ -823,9 +826,9 @@ int __xfrm_state_delete(struct xfrm_state *x) if (!hlist_unhashed(&x->byseq)) hlist_del_init_rcu(&x->byseq); if (!hlist_unhashed(&x->state_cache)) - hlist_del_rcu(&x->state_cache); + hlist_del_init_rcu(&x->state_cache); if (!hlist_unhashed(&x->state_cache_input)) - hlist_del_rcu(&x->state_cache_input); + hlist_del_init_rcu(&x->state_cache_input); if (!hlist_unhashed(&x->byspi)) hlist_del_init_rcu(&x->byspi); @@ -1000,6 +1003,7 @@ int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_vali out: spin_unlock_bh(&net->xfrm.xfrm_state_lock); + mutex_lock(&xfrm_state_gc_mutex); spin_lock_bh(&xfrm_state_dev_gc_lock); restart_gc: hlist_for_each_entry_safe(x, tmp, &xfrm_state_dev_gc_list, dev_gclist) { @@ -1014,6 +1018,7 @@ int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_vali } spin_unlock_bh(&xfrm_state_dev_gc_lock); + mutex_unlock(&xfrm_state_gc_mutex); xfrm_flush_gc(); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 0f0384b6a11d..2560f3653bd3 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -35,6 +35,15 @@ #endif #include +static struct sock *xfrm_net_nlsk(const struct net *net, const struct sk_buff *skb) +{ + /* get the source of this request, see netlink_unicast_kernel */ + const struct sock *sk = NETLINK_CB(skb).sk; + + /* sk is refcounted, the netns stays alive and nlsk with it */ + return rcu_dereference_protected(net->xfrm.nlsk, sk->sk_net_refcnt); +} + static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type, struct netlink_ext_ack *extack) { @@ -1727,7 +1736,7 @@ static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, err = build_spdinfo(r_skb, net, sportid, seq, *flags); BUG_ON(err < 0); - return nlmsg_unicast(net->xfrm.nlsk, r_skb, sportid); + return nlmsg_unicast(xfrm_net_nlsk(net, skb), r_skb, sportid); } static inline unsigned int xfrm_sadinfo_msgsize(void) @@ -1787,7 +1796,7 @@ static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, err = build_sadinfo(r_skb, net, sportid, seq, *flags); BUG_ON(err < 0); - return nlmsg_unicast(net->xfrm.nlsk, r_skb, sportid); + return nlmsg_unicast(xfrm_net_nlsk(net, skb), r_skb, sportid); } static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -1807,7 +1816,7 @@ static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, if (IS_ERR(resp_skb)) { err = PTR_ERR(resp_skb); } else { - err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).portid); + err = nlmsg_unicast(xfrm_net_nlsk(net, skb), resp_skb, NETLINK_CB(skb).portid); } xfrm_state_put(x); out_noput: @@ -1821,7 +1830,6 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, struct net *net = sock_net(skb->sk); struct xfrm_state *x; struct xfrm_userspi_info *p; - struct xfrm_translator *xtr; struct sk_buff *resp_skb; xfrm_address_t *daddr; int family; @@ -1887,18 +1895,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, goto out; } - xtr = xfrm_get_translator(); - if (xtr) { - err = xtr->alloc_compat(skb, nlmsg_hdr(skb)); - - xfrm_put_translator(xtr); - if (err) { - kfree_skb(resp_skb); - goto out; - } - } - - err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).portid); + err = nlmsg_unicast(xfrm_net_nlsk(net, skb), resp_skb, NETLINK_CB(skb).portid); out: xfrm_state_put(x); @@ -2542,7 +2539,7 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh, r_up->out = READ_ONCE(net->xfrm.policy_default[XFRM_POLICY_OUT]); nlmsg_end(r_skb, r_nlh); - return nlmsg_unicast(net->xfrm.nlsk, r_skb, portid); + return nlmsg_unicast(xfrm_net_nlsk(net, skb), r_skb, portid); } static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -2608,7 +2605,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, if (IS_ERR(resp_skb)) { err = PTR_ERR(resp_skb); } else { - err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, + err = nlmsg_unicast(xfrm_net_nlsk(net, skb), resp_skb, NETLINK_CB(skb).portid); } } else { @@ -2787,7 +2784,7 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, return err; } - err = nlmsg_unicast(net->xfrm.nlsk, r_skb, NETLINK_CB(skb).portid); + err = nlmsg_unicast(xfrm_net_nlsk(net, skb), r_skb, NETLINK_CB(skb).portid); spin_unlock_bh(&x->lock); xfrm_state_put(x); return err; @@ -3491,7 +3488,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, goto err; } - err = netlink_dump_start(net->xfrm.nlsk, skb, nlh, &c); + err = netlink_dump_start(xfrm_net_nlsk(net, skb), skb, nlh, &c); goto err; } diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs index bf6272d87a7b..1d17bf1ae87d 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -123,39 +123,37 @@ pub fn state(&self) -> DeviceState { /// Gets the current link state. /// /// It returns true if the link is up. + #[inline] pub fn is_link_up(&self) -> bool { - const LINK_IS_UP: u64 = 1; - // TODO: the code to access to the bit field will be replaced with automatically - // generated code by bindgen when it becomes possible. - // SAFETY: The struct invariant ensures that we may access - // this field without additional synchronization. - let bit_field = unsafe { &(*self.0.get())._bitfield_1 }; - bit_field.get(14, 1) == LINK_IS_UP + let phydev = self.0.get().cast_const(); + // SAFETY: By the type invariant of `Device`, `phydev` points to a valid + // `struct phy_device`, and there is no concurrent write to this field. + let link = unsafe { bindings::phy_device::link_raw(phydev) }; + link == 1 } /// Gets the current auto-negotiation configuration. /// /// It returns true if auto-negotiation is enabled. + #[inline] pub fn is_autoneg_enabled(&self) -> bool { - // TODO: the code to access to the bit field will be replaced with automatically - // generated code by bindgen when it becomes possible. - // SAFETY: The struct invariant ensures that we may access - // this field without additional synchronization. - let bit_field = unsafe { &(*self.0.get())._bitfield_1 }; - bit_field.get(13, 1) == u64::from(bindings::AUTONEG_ENABLE) + let phydev = self.0.get().cast_const(); + // SAFETY: By the type invariant of `Device`, `phydev` points to a valid + // `struct phy_device`, and there is no concurrent write to this field. + let autoneg = unsafe { bindings::phy_device::autoneg_raw(phydev) }; + autoneg == bindings::AUTONEG_ENABLE } /// Gets the current auto-negotiation state. /// /// It returns true if auto-negotiation is completed. + #[inline] pub fn is_autoneg_completed(&self) -> bool { - const AUTONEG_COMPLETED: u64 = 1; - // TODO: the code to access to the bit field will be replaced with automatically - // generated code by bindgen when it becomes possible. - // SAFETY: The struct invariant ensures that we may access - // this field without additional synchronization. - let bit_field = unsafe { &(*self.0.get())._bitfield_1 }; - bit_field.get(15, 1) == AUTONEG_COMPLETED + let phydev = self.0.get().cast_const(); + // SAFETY: By the type invariant of `Device`, `phydev` points to a valid + // `struct phy_device`, and there is no concurrent write to this field. + let completed = unsafe { bindings::phy_device::autoneg_complete_raw(phydev) }; + completed == 1 } /// Sets the speed of the PHY. diff --git a/scripts/generate_rust_target.rs b/scripts/generate_rust_target.rs index 16f7e855e012..0f2c9edce17a 100644 --- a/scripts/generate_rust_target.rs +++ b/scripts/generate_rust_target.rs @@ -224,6 +224,11 @@ fn main() { features += ",+harden-sls-ijmp"; features += ",+harden-sls-ret"; } + if cfg.has("X86_NATIVE_CPU") { + // Prevent the backend from generating APX instructions. The kernel is not yet prepared + // for general in-kernel EGPR use. + features += ",-apxf"; + } ts.push("features", features); ts.push("llvm-target", "x86_64-linux-gnu"); ts.push("supported-sanitizers", ["kcfi", "kernel-address"]); diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c index 513c09e2b01c..babd9171b00d 100644 --- a/security/keys/encrypted-keys/encrypted.c +++ b/security/keys/encrypted-keys/encrypted.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -578,6 +579,7 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, { struct encrypted_key_payload *epayload = NULL; unsigned short datablob_len; + unsigned short payload_totallen; unsigned short decrypted_datalen; unsigned short payload_datalen; unsigned int encrypted_datalen; @@ -631,16 +633,22 @@ static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, encrypted_datalen = roundup(decrypted_datalen, blksize); - datablob_len = format_len + 1 + strlen(master_desc) + 1 - + strlen(datalen) + 1 + ivsize + 1 + encrypted_datalen; + if (check_add_overflow(format_len + 1 + strlen(master_desc) + 1 + + strlen(datalen) + 1 + ivsize + 1, + encrypted_datalen, &datablob_len)) + return ERR_PTR(-EINVAL); + + if (check_add_overflow(datablob_len, + payload_datalen + HASH_SIZE + 1, + &payload_totallen)) + return ERR_PTR(-EINVAL); - ret = key_payload_reserve(key, payload_datalen + datablob_len - + HASH_SIZE + 1); + ret = key_payload_reserve(key, payload_totallen); if (ret < 0) return ERR_PTR(ret); - epayload = kzalloc(sizeof(*epayload) + payload_datalen + - datablob_len + HASH_SIZE + 1, GFP_KERNEL); + epayload = kzalloc_flex(*epayload, payload_data, payload_totallen, + GFP_KERNEL); if (!epayload) return ERR_PTR(-ENOMEM); diff --git a/security/keys/gc.c b/security/keys/gc.c index 748e83818a76..eda445f815d4 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -318,9 +318,7 @@ static void key_garbage_collector(struct work_struct *work) if (unlikely(gc_state & KEY_GC_REAPING_DEAD_3)) { kdebug("dead wake"); - smp_mb(); - clear_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags); - wake_up_bit(&key_gc_flags, KEY_GC_REAPING_KEYTYPE); + clear_and_wake_up_bit(KEY_GC_REAPING_KEYTYPE, &key_gc_flags); } if (gc_state & KEY_GC_REAP_AGAIN) diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index bd34317b58cc..0f385422ddf9 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -9,6 +9,8 @@ #include #include +#include +#include #include #include #include @@ -73,7 +75,10 @@ static void request_key_auth_describe(const struct key *key, seq_puts(m, "key:"); seq_puts(m, key->description); if (key_is_positive(key)) - seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len); + seq_printf(m, " pid:%d ci:%zu", + pid_nr_ns(rka->pid, + proc_pid_ns(file_inode(m->file)->i_sb)), + rka->callout_len); } /* @@ -113,6 +118,7 @@ static void free_request_key_auth(struct request_key_auth *rka) if (rka->cred) put_cred(rka->cred); kfree(rka->callout_info); + put_pid(rka->pid); kfree(rka); } @@ -226,14 +232,14 @@ struct key *request_key_auth_new(struct key *target, const char *op, irka = cred->request_key_auth->payload.data[0]; rka->cred = get_cred(irka->cred); - rka->pid = irka->pid; + rka->pid = get_pid(irka->pid); up_read(&cred->request_key_auth->sem); } else { /* it isn't - use this process as the context */ rka->cred = get_cred(cred); - rka->pid = current->pid; + rka->pid = get_pid(task_pid(current)); } rka->target_key = key_get(target); diff --git a/security/keys/trusted-keys/trusted_tpm2.c b/security/keys/trusted-keys/trusted_tpm2.c index 74cea80ed9be..aae81332e33d 100644 --- a/security/keys/trusted-keys/trusted_tpm2.c +++ b/security/keys/trusted-keys/trusted_tpm2.c @@ -108,7 +108,7 @@ struct tpm2_key_context { static int tpm2_key_decode(struct trusted_key_payload *payload, struct trusted_key_options *options, - u8 **buf) + u8 **buf, unsigned int *blob_len) { int ret; struct tpm2_key_context ctx; @@ -129,6 +129,7 @@ static int tpm2_key_decode(struct trusted_key_payload *payload, return -ENOMEM; *buf = blob; + *blob_len = ctx.priv_len + ctx.pub_len; options->keyhandle = ctx.parent; memcpy(blob, ctx.priv, ctx.priv_len); @@ -402,10 +403,11 @@ static int tpm2_load_cmd(struct tpm_chip *chip, int rc; u32 attrs; - rc = tpm2_key_decode(payload, options, &blob); + rc = tpm2_key_decode(payload, options, &blob, &blob_len); if (rc) { /* old form */ blob = payload->blob; + blob_len = payload->blob_len; payload->old_format = 1; } else { /* Bind for cleanup: */ @@ -417,17 +419,17 @@ static int tpm2_load_cmd(struct tpm_chip *chip, return -EINVAL; /* must be big enough for at least the two be16 size counts */ - if (payload->blob_len < 4) + if (blob_len < 4) return -EINVAL; private_len = get_unaligned_be16(blob); /* must be big enough for following public_len */ - if (private_len + 2 + 2 > (payload->blob_len)) + if (private_len + 2 + 2 > blob_len) return -E2BIG; public_len = get_unaligned_be16(blob + 2 + private_len); - if (private_len + 2 + public_len + 2 > payload->blob_len) + if (private_len + 2 + public_len + 2 > blob_len) return -E2BIG; pub = blob + 2 + private_len + 2; diff --git a/security/landlock/net.c b/security/landlock/net.c index 7ae97dec0434..9224d9b26429 100644 --- a/security/landlock/net.c +++ b/security/landlock/net.c @@ -235,9 +235,23 @@ static int hook_socket_connect(struct socket *const sock, LANDLOCK_ACCESS_NET_CONNECT_TCP); } +static int hook_socket_sendmsg(struct socket *const sock, + struct msghdr *const msg, const int size) +{ + struct sockaddr *const address = msg->msg_name; + + if ((msg->msg_flags & MSG_FASTOPEN) && address) + return current_check_access_socket( + sock, address, msg->msg_namelen, + LANDLOCK_ACCESS_NET_CONNECT_TCP); + + return 0; +} + static struct security_hook_list landlock_hooks[] __ro_after_init = { LSM_HOOK_INIT(socket_bind, hook_socket_bind), LSM_HOOK_INIT(socket_connect, hook_socket_connect), + LSM_HOOK_INIT(socket_sendmsg, hook_socket_sendmsg), }; __init void landlock_add_net_hooks(void) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 430b0e23ee00..77d8828a8560 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -1149,8 +1149,11 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, u32 denied; struct avc_node *node; - if (WARN_ON(!requested)) + if (WARN_ON(!requested)) { + /* Provide a deny-all, audit-all decision to the caller. */ + *avd = (struct av_decision){ .auditdeny = 0xffffffff }; return -EACCES; + } rcu_read_lock(); node = avc_lookup(ssid, tsid, tclass); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index af188e19c130..eef75bde66f5 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1665,26 +1665,32 @@ static int cred_has_capability(const struct cred *cred, return rc; } -/* Check whether a task has a particular permission to an inode. - The 'adp' parameter is optional and allows other audit - data to be passed (e.g. the dentry). */ -static int inode_has_perm(const struct cred *cred, - struct inode *inode, - u32 perms, - struct common_audit_data *adp) +/* + * Check whether a SID has a particular permission to an inode. The 'adp' + * parameter is optional and allows other audit data to be passed (e.g. the + * dentry). + */ +static int inode_sid_has_perm(u32 sid, struct inode *inode, u32 perms, + struct common_audit_data *adp) { struct inode_security_struct *isec; - u32 sid; if (unlikely(IS_PRIVATE(inode))) return 0; - sid = cred_sid(cred); isec = selinux_inode(inode); return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); } +static int inode_has_perm(const struct cred *cred, + struct inode *inode, + u32 perms, + struct common_audit_data *adp) +{ + return inode_sid_has_perm(cred_sid(cred), inode, perms, adp); +} + /* Same as inode_has_perm, but pass explicit audit data containing the dentry to help the auditing code to more easily generate the pathname if needed. */ @@ -3822,17 +3828,74 @@ static int selinux_file_alloc_security(struct file *file) return 0; } +static inline u32 selinux_file_user_sid(const struct file *file) +{ + if (unlikely(file->f_mode & FMODE_BACKING)) + return selinux_backing_file(file)->uf_sid; + return selinux_file(file)->sid; +} + static int selinux_backing_file_alloc(struct file *backing_file, const struct file *user_file) { struct backing_file_security_struct *bfsec; + const struct backing_file_security_struct *ubfsec; + struct backing_file_security_layer *layer; + u32 i; bfsec = selinux_backing_file(backing_file); - bfsec->uf_sid = selinux_file(user_file)->sid; + bfsec->uf_sid = selinux_file_user_sid(user_file); + if (!(user_file->f_mode & FMODE_BACKING)) + return 0; + + ubfsec = selinux_backing_file(user_file); + /* a wrapped count would make kmalloc_array() return ZERO_SIZE_PTR */ + if (unlikely(ubfsec->layer_count == U32_MAX)) + return -EOVERFLOW; + + /* + * The final VMA only retains the lowest backing file, so record the + * whole chain here rather than in the mmap hook, where concurrent + * mappings would have to be serialized. Size it dynamically: erofs + * inode sharing adds a backing file without bumping s_stack_depth. + */ + bfsec->layers = kmalloc_array(ubfsec->layer_count + 1, + sizeof(*bfsec->layers), GFP_KERNEL); + if (!bfsec->layers) + return -ENOMEM; + + for (i = 0; i < ubfsec->layer_count; i++) { + layer = &bfsec->layers[i]; + *layer = ubfsec->layers[i]; + path_get(&layer->path); + } + + /* f_path, not file_user_path(): this layer, not the top-level file */ + layer = &bfsec->layers[i]; + layer->path = user_file->f_path; + layer->mounter_sid = cred_sid(user_file->f_cred); + layer->fd_sid = selinux_file(user_file)->sid; + path_get(&layer->path); + bfsec->layer_count = ubfsec->layer_count + 1; return 0; } +static void selinux_backing_file_free(struct file *backing_file) +{ + struct backing_file_security_struct *bfsec; + + /* security_backing_file_free() may be called twice after an error */ + if (!backing_file_security(backing_file)) + return; + + bfsec = selinux_backing_file(backing_file); + while (bfsec->layer_count) + path_put(&bfsec->layers[--bfsec->layer_count].path); + kfree(bfsec->layers); + bfsec->layers = NULL; +} + /* * Check whether a task has the ioctl permission and cmd * operation to an inode. @@ -3950,6 +4013,53 @@ static int selinux_file_ioctl_compat(struct file *file, unsigned int cmd, static int default_noexec __ro_after_init; +static u32 file_map_prot_to_av(unsigned long prot, bool shared) +{ + u32 av = FILE__READ; + + if (shared && (prot & PROT_WRITE)) + av |= FILE__WRITE; + if (prot & PROT_EXEC) + av |= FILE__EXECUTE; + + return av; +} + +static int backing_mounters_has_perm(const struct file *file, u32 av) +{ + const struct backing_file_security_struct *bfsec; + const struct backing_file_security_layer *layer; + struct common_audit_data ad; + struct inode *inode; + u32 i; + int rc; + + if (WARN_ON_ONCE(!(file->f_mode & FMODE_BACKING))) + return -EIO; + + bfsec = selinux_backing_file(file); + for (i = 0; i < bfsec->layer_count; i++) { + layer = &bfsec->layers[i]; + inode = d_inode(layer->path.dentry); + + ad.type = LSM_AUDIT_DATA_PATH; + ad.u.path = layer->path; + + if (layer->mounter_sid != layer->fd_sid) { + rc = avc_has_perm(layer->mounter_sid, layer->fd_sid, + SECCLASS_FD, FD__USE, &ad); + if (rc) + return rc; + } + + rc = inode_sid_has_perm(layer->mounter_sid, inode, av, &ad); + if (rc) + return rc; + } + + return 0; +} + static int __file_map_prot_check(const struct file *file, unsigned long prot, bool shared, bool mounter_check, bool bf_user_file) @@ -3983,14 +4093,10 @@ static int __file_map_prot_check(const struct file *file, unsigned long prot, if (file) { const struct cred *cred = mounter_check ? file->f_cred : current_cred(); - /* "read" always possible, "write" only if shared */ - u32 av = FILE__READ; - if (shared && prot_write) - av |= FILE__WRITE; - if (prot_exec) - av |= FILE__EXECUTE; - return __file_has_perm(cred, file, av, bf_user_file); + return __file_has_perm(cred, file, + file_map_prot_to_av(prot, shared), + bf_user_file); } return 0; @@ -4085,6 +4191,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, int rc; const struct cred *cred = current_cred(); u32 sid = cred_sid(cred); + u32 av; const struct file *file = vma->vm_file; bool backing_file; bool shared = vma->vm_flags & VM_SHARED; @@ -4128,6 +4235,10 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, if (rc) return rc; if (backing_file) { + rc = backing_mounters_has_perm(file, + FILE__EXECMOD); + if (rc) + return rc; rc = file_has_perm(file->f_cred, file, FILE__EXECMOD); if (rc) @@ -4140,6 +4251,10 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, if (rc) return rc; if (backing_file) { + av = file_map_prot_to_av(prot, shared); + rc = backing_mounters_has_perm(file, av); + if (rc) + return rc; rc = file_map_prot_check(file, prot, shared, true); if (rc) return rc; @@ -7500,6 +7615,7 @@ static struct security_hook_list selinux_hooks[] __ro_after_init = { LSM_HOOK_INIT(file_permission, selinux_file_permission), LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), LSM_HOOK_INIT(backing_file_alloc, selinux_backing_file_alloc), + LSM_HOOK_INIT(backing_file_free, selinux_backing_file_free), LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl), LSM_HOOK_INIT(file_ioctl_compat, selinux_file_ioctl_compat), LSM_HOOK_INIT(mmap_file, selinux_mmap_file), diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index fcb46793898f..bbb04f26b0df 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -86,8 +86,16 @@ struct file_security_struct { u32 pseqno; /* Policy seqno at the time of file open */ }; +struct backing_file_security_layer { + struct path path; /* this layer's real path */ + u32 mounter_sid; /* SID of the mounter that opened it */ + u32 fd_sid; /* SID of its open file description */ +}; + struct backing_file_security_struct { - u32 uf_sid; /* associated user file fsec->sid */ + u32 uf_sid; /* top-level user file fsec->sid */ + u32 layer_count; /* number of intermediate backing files */ + struct backing_file_security_layer *layers; }; struct superblock_security_struct { diff --git a/sound/core/init.c b/sound/core/init.c index bc5182c5ce12..3a45fa6fc515 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -309,7 +309,7 @@ static int snd_card_init(struct snd_card *card, struct device *parent, kfree(card); /* manually free here, as no destructor called */ return err; } - card->dev = parent; + card->dev = get_device(parent); card->number = idx; WARN_ON(IS_MODULE(CONFIG_SND) && !module); card->module = module; @@ -593,6 +593,7 @@ static int snd_card_do_free(struct snd_card *card) dev_warn(card->dev, "unable to free card info\n"); /* Not fatal error */ } + put_device(card->dev); if (card->release_completion) complete(card->release_completion); if (!managed) diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c index ab0e5bd70f8f..18bedd66435d 100644 --- a/sound/core/pcm_timer.c +++ b/sound/core/pcm_timer.c @@ -111,12 +111,15 @@ void snd_pcm_timer_init(struct snd_pcm_substream *substream) snd_pcm_direction_name(substream->stream), tid.card, tid.device, tid.subdevice); timer->hw = snd_pcm_timer; + /* Set before registering: a concurrent reader can invoke our hw + * callbacks as soon as the timer is on the global list. + */ + timer->private_data = substream; + timer->private_free = snd_pcm_timer_free; if (snd_device_register(timer->card, timer) < 0) { snd_device_free(timer->card, timer); return; } - timer->private_data = substream; - timer->private_free = snd_pcm_timer_free; substream->timer = timer; } diff --git a/sound/hda/common/controller.c b/sound/hda/common/controller.c index b1cfd9bd4dcb..98ab47977e31 100644 --- a/sound/hda/common/controller.c +++ b/sound/hda/common/controller.c @@ -584,11 +584,11 @@ static int azx_pcm_open(struct snd_pcm_substream *substream) snd_hda_codec_pcm_get(apcm->info); mutex_lock(&chip->open_mutex); azx_dev = azx_assign_device(chip, substream); - trace_azx_pcm_open(chip, azx_dev); if (azx_dev == NULL) { err = -EBUSY; goto unlock; } + trace_azx_pcm_open(chip, azx_dev); runtime->private_data = azx_dev; runtime->hw = azx_pcm_hw; diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c index ac955a9b51dc..53567fdf3e2d 100644 --- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c +++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c @@ -189,9 +189,19 @@ static int create_sdw_dailink(struct snd_soc_card *card, return -EINVAL; } + if (!soc_end->link_mask) { + dev_err(dev, "invalid zero link_mask\n"); + return -EINVAL; + } + if ((ffs(soc_end->link_mask) - 1) >= amd_ctx->max_sdw_links) { + dev_err(dev, "link_id %d exceeds max_sdw_links %d\n", + ffs(soc_end->link_mask) - 1, amd_ctx->max_sdw_links); + return -EINVAL; + } + switch (amd_ctx->acp_rev) { case ACP63_PCI_REV: - ret = get_acp63_cpu_pin_id(ffs(soc_end->link_mask - 1), + ret = get_acp63_cpu_pin_id(ffs(soc_end->link_mask) - 1, *be_id, &cpu_pin_id, dev); if (ret) return ret; @@ -199,7 +209,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, case ACP70_PCI_REV: case ACP71_PCI_REV: case ACP72_PCI_REV: - ret = get_acp70_cpu_pin_id(ffs(soc_end->link_mask - 1), + ret = get_acp70_cpu_pin_id(ffs(soc_end->link_mask) - 1, *be_id, &cpu_pin_id, dev); if (ret) return ret; @@ -385,20 +395,25 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; struct asoc_sdw_endpoint *soc_ends __free(kfree) = NULL; struct asoc_sdw_dailink *soc_dais __free(kfree) = NULL; + struct snd_soc_aux_dev *soc_aux; struct snd_soc_codec_conf *codec_conf; struct snd_soc_dai_link *dai_links; int num_devs = 0; int num_ends = 0; + int num_aux = 0; + int num_confs; int num_links; int be_id = 0; int ret; - ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; } + num_confs = num_ends; + /* One per DAI link, worst case is a DAI link for every endpoint */ soc_dais = kcalloc(num_ends, sizeof(*soc_dais), GFP_KERNEL); if (!soc_dais) @@ -409,7 +424,11 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) if (!soc_ends) return -ENOMEM; - ret = asoc_sdw_parse_sdw_endpoints(card, soc_dais, soc_ends, &num_devs); + soc_aux = devm_kcalloc(dev, num_aux, sizeof(*soc_aux), GFP_KERNEL); + if (!soc_aux) + return -ENOMEM; + + ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, soc_aux, soc_dais, soc_ends, &num_confs); if (ret < 0) return ret; @@ -421,7 +440,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num); - codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL); if (!codec_conf) return -ENOMEM; @@ -432,9 +451,11 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) return -ENOMEM; card->codec_conf = codec_conf; - card->num_configs = num_devs; + card->num_configs = num_confs; card->dai_link = dai_links; card->num_links = num_links; + card->aux_dev = soc_aux; + card->num_aux_devs = num_aux; /* SDW */ if (sdw_be_num) { diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c index 14d6e31d5040..4081cccb9050 100644 --- a/sound/soc/amd/acp/acp-sdw-sof-mach.c +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -121,9 +121,18 @@ static int create_sdw_dailink(struct snd_soc_card *card, return -EINVAL; } + if (!sof_end->link_mask) { + dev_err(dev, "invalid zero link_mask\n"); + return -EINVAL; + } + if ((ffs(sof_end->link_mask) - 1) >= amd_ctx->max_sdw_links) { + dev_err(dev, "link_id %d exceeds max_sdw_links %d\n", + ffs(sof_end->link_mask) - 1, amd_ctx->max_sdw_links); + return -EINVAL; + } switch (amd_ctx->acp_rev) { case ACP63_PCI_REV: - ret = get_acp63_cpu_pin_id(ffs(sof_end->link_mask - 1), + ret = get_acp63_cpu_pin_id(ffs(sof_end->link_mask) - 1, *be_id, &cpu_pin_id, dev); if (ret) return ret; @@ -131,7 +140,7 @@ static int create_sdw_dailink(struct snd_soc_card *card, case ACP70_PCI_REV: case ACP71_PCI_REV: case ACP72_PCI_REV: - ret = get_acp70_cpu_pin_id(ffs(sof_end->link_mask - 1), + ret = get_acp70_cpu_pin_id(ffs(sof_end->link_mask) - 1, *be_id, &cpu_pin_id, dev); if (ret) return ret; @@ -273,20 +282,24 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; struct asoc_sdw_endpoint *sof_ends __free(kfree) = NULL; struct asoc_sdw_dailink *sof_dais __free(kfree) = NULL; + struct snd_soc_aux_dev *sof_aux; struct snd_soc_codec_conf *codec_conf; struct snd_soc_dai_link *dai_links; int num_devs = 0; int num_ends = 0; + int num_aux = 0; + int num_confs; int num_links; int be_id = 0; int ret; - ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; } + num_confs = num_ends; /* One per DAI link, worst case is a DAI link for every endpoint */ sof_dais = kcalloc(num_ends, sizeof(*sof_dais), GFP_KERNEL); if (!sof_dais) @@ -297,7 +310,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (!sof_ends) return -ENOMEM; - ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + sof_aux = devm_kcalloc(dev, num_aux, sizeof(*sof_aux), GFP_KERNEL); + if (!sof_aux) + return -ENOMEM; + + ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs); if (ret < 0) return ret; @@ -309,7 +326,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) dev_dbg(dev, "sdw %d, dmic %d", sdw_be_num, dmic_num); - codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL); if (!codec_conf) return -ENOMEM; @@ -320,9 +337,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) return -ENOMEM; card->codec_conf = codec_conf; - card->num_configs = num_devs; + card->num_configs = num_confs; card->dai_link = dai_links; card->num_links = num_links; + card->aux_dev = sof_aux; + card->num_aux_devs = num_aux; /* SDW */ if (sdw_be_num) { diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index e1933f733af1..df32032e631f 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -425,10 +425,14 @@ static int hdmi_codec_iec958_default_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); + if (!memcmp(hcp->iec_status, ucontrol->value.iec958.status, + sizeof(hcp->iec_status))) + return 0; + memcpy(hcp->iec_status, ucontrol->value.iec958.status, sizeof(hcp->iec_status)); - return 0; + return 1; } static int hdmi_codec_iec958_mask_get(struct snd_kcontrol *kcontrol, diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 42f8f7b8bed0..bc5b872f1e42 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "rt712-sdca.h" #include "rt712-sdca-dmic.h" @@ -636,10 +637,10 @@ static int rt712_sdca_dmic_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_component *component = dai->component; struct rt712_sdca_dmic_priv *rt712 = 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; struct sdw_stream_runtime *sdw_stream; - int retval, num_channels; + int retval; unsigned int sampling_rate; dev_dbg(dai->dev, "%s %s", __func__, dai->name); @@ -651,13 +652,8 @@ static int rt712_sdca_dmic_hw_params(struct snd_pcm_substream *substream, if (!rt712->slave) return -EINVAL; - stream_config.frame_rate = params_rate(params); - stream_config.ch_count = params_channels(params); - stream_config.bps = snd_pcm_format_width(params_format(params)); - stream_config.direction = SDW_DATA_DIR_TX; - - num_channels = params_channels(params); - port_config.ch_mask = GENMASK(num_channels - 1, 0); + /* SoundWire specific configuration */ + snd_sdw_params_to_config(substream, params, &stream_config, &port_config); port_config.num = 2; retval = sdw_stream_add_slave(rt712->slave, &stream_config, diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index ffa6e2ad73f7..e27bfc0196d7 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1166,8 +1166,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct asoc_sdw_codec_info *ssp_info; struct asoc_sdw_endpoint *sof_ends; struct asoc_sdw_dailink *sof_dais; + struct snd_soc_aux_dev *sof_aux; int num_devs = 0; int num_ends = 0; + int num_aux = 0; + int num_confs; struct snd_soc_dai_link *dai_links; int num_links; int be_id = 0; @@ -1175,12 +1178,14 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) unsigned long ssp_mask; int ret; - ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; } + num_confs = num_ends; + /* * One per DAI link, worst case is a DAI link for every endpoint, also * add one additional to act as a terminator such that code can iterate @@ -1197,7 +1202,13 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) goto err_dai; } - ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + sof_aux = devm_kcalloc(dev, num_aux, sizeof(*sof_aux), GFP_KERNEL); + if (!sof_aux) { + ret = -ENOMEM; + goto err_dai; + } + + ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs); if (ret < 0) goto err_end; @@ -1245,7 +1256,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) sdw_be_num, ssp_num, dmic_num, intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); - codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + codec_conf = devm_kcalloc(dev, num_confs, sizeof(*codec_conf), GFP_KERNEL); if (!codec_conf) { ret = -ENOMEM; goto err_end; @@ -1260,9 +1271,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) } card->codec_conf = codec_conf; - card->num_configs = num_devs; + card->num_configs = num_confs; card->dai_link = dai_links; card->num_links = num_links; + card->aux_dev = sof_aux; + card->num_aux_devs = num_aux; /* SDW */ if (sdw_be_num) { diff --git a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c index c7e55f443351..8f189025c20c 100644 --- a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c +++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c @@ -104,11 +104,9 @@ static const struct snd_soc_dai_link bridge_dai_template = { SND_SOC_DAILINK_REG(asoc_sdw_bridge_dai), }; -int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card, +int asoc_sdw_bridge_cs35l56_count_sidecar(struct asoc_sdw_mc_private *ctx, int *num_dais, int *num_devs) { - struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); - if (ctx->mc_quirk & SOC_SDW_SIDECAR_AMPS) { (*num_dais)++; (*num_devs) += ARRAY_SIZE(bridge_cs35l56_name_prefixes); diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 3facb78748ac..fd0092eb7924 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -974,7 +974,7 @@ int asoc_sdw_hw_params(struct snd_pcm_substream *substream, * ASoC will set the corresponding channel numbers for each cpu dai. */ for_each_link_ch_maps(rtd->dai_link, i, ch_maps) - ch_maps->ch_mask = ch_mask << (i * step); + ch_maps->cpu_ch_mask = ch_mask << (i * step); return 0; } @@ -1196,7 +1196,8 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d } EXPORT_SYMBOL_NS(asoc_sdw_init_simple_dai_link, "SND_SOC_SDW_UTILS"); -int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends) +int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, + int *num_devs, int *num_ends, int *num_aux) { struct device *dev = card->dev; struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); @@ -1207,8 +1208,18 @@ int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int * for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { *num_devs += adr_link->num_adr; - for (i = 0; i < adr_link->num_adr; i++) - *num_ends += adr_link->adr_d[i].num_endpoints; + for (i = 0; i < adr_link->num_adr; i++) { + const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; + struct asoc_sdw_codec_info *codec_info; + + *num_ends += adr_dev->num_endpoints; + + codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); + if (!codec_info) + return -EINVAL; + + *num_aux += codec_info->aux_num; + } } dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); @@ -1345,13 +1356,13 @@ static int is_sdca_endpoint_present(struct device *dev, return ret; } -int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, +int asoc_sdw_parse_sdw_endpoints(struct device *dev, + struct asoc_sdw_mc_private *ctx, + struct snd_soc_aux_dev *soc_aux, struct asoc_sdw_dailink *soc_dais, struct asoc_sdw_endpoint *soc_ends, int *num_devs) { - struct device *dev = card->dev; - struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; const struct snd_soc_acpi_link_adr *adr_link; @@ -1385,19 +1396,15 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, if (!codec_info) return -EINVAL; - ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; - - codec_name = asoc_sdw_get_codec_name(dev, codec_info, adr_link, i); - if (!codec_name) - return -ENOMEM; - - dev_dbg(dev, "Adding prefix %s for %s\n", - adr_dev->name_prefix, codec_name); + for (j = 0; j < codec_info->aux_num; j++) { + soc_aux->dlc.name = codec_info->auxs[j].codec_name; + soc_aux++; + } - soc_end->name_prefix = adr_dev->name_prefix; + ctx->ignore_internal_dmic |= codec_info->ignore_internal_dmic; if (codec_info->count_sidecar && codec_info->add_sidecar) { - ret = codec_info->count_sidecar(card, &num_dais, num_devs); + ret = codec_info->count_sidecar(ctx, &num_dais, num_devs); if (ret) return ret; @@ -1434,8 +1441,10 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, * endpoint check is not necessary */ if (dai_info->quirk && - !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) + !(dai_info->quirk_exclude ^ !!(dai_info->quirk & ctx->mc_quirk))) { + (*num_devs)--; continue; + } } else { /* Check SDCA codec endpoint if there is no matching quirk */ ret = is_sdca_endpoint_present(dev, codec_info, adr_link, i, j); @@ -1443,8 +1452,10 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, return ret; /* The endpoint is not present, skip */ - if (!ret) + if (!ret) { + (*num_devs)--; continue; + } } dev_dbg(dev, @@ -1483,6 +1494,16 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card, num_link_dailinks += !!list_empty(&soc_dai->endpoints); list_add_tail(&soc_end->list, &soc_dai->endpoints); + codec_name = asoc_sdw_get_codec_name(dev, codec_info, + adr_link, i); + if (!codec_name) + return -ENOMEM; + + dev_dbg(dev, "Adding prefix %s for %s\n", + adr_dev->name_prefix, codec_name); + + soc_end->name_prefix = adr_dev->name_prefix; + soc_end->link_mask = adr_link->mask; soc_end->codec_name = codec_name; soc_end->codec_info = codec_info; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 99299364c9ba..b6e35cfe50b7 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1075,7 +1075,9 @@ static int __soc_pcm_hw_params(struct snd_pcm_substream *substream, goto out; for_each_rtd_codec_dais(rtd, i, codec_dai) { - unsigned int tdm_mask = snd_soc_dai_tdm_mask_get(codec_dai, substream->stream); + unsigned int ch_mask = snd_soc_dai_tdm_mask_get(codec_dai, substream->stream); + struct snd_soc_dai_link_ch_map *ch_maps; + int j; /* * Skip CODECs which don't support the current stream type, @@ -1097,9 +1099,15 @@ static int __soc_pcm_hw_params(struct snd_pcm_substream *substream, /* copy params for each codec */ tmp_params = *params; - /* fixup params based on TDM slot masks */ - if (tdm_mask) - soc_pcm_codec_params_fixup(&tmp_params, tdm_mask); + /* fixup params based on TDM or ch_map masks */ + if (!ch_mask) { + for_each_rtd_ch_maps(rtd, j, ch_maps) + if (ch_maps->codec == i) + ch_mask |= ch_maps->codec_ch_mask; + } + + if (ch_mask) + soc_pcm_codec_params_fixup(&tmp_params, ch_mask); ret = snd_soc_dai_hw_params(codec_dai, substream, &tmp_params); @@ -1133,7 +1141,7 @@ static int __soc_pcm_hw_params(struct snd_pcm_substream *substream, */ for_each_rtd_ch_maps(rtd, j, ch_maps) if (ch_maps->cpu == i) - ch_mask |= ch_maps->ch_mask; + ch_mask |= ch_maps->cpu_ch_mask; /* fixup cpu channel number */ if (ch_mask) diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index 2bf2699bdc49..c66ef455e138 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h @@ -147,8 +147,8 @@ enum msp_direction { #define RCKPOL_MASK BIT(0) #define TCKPOL_MASK BIT(0) #define SPICKM_MASK (BIT(1) | BIT(0)) -#define MSP_RX_CLKPOL_BIT(n) ((n & RCKPOL_MASK) << RCKPOL_SHIFT) -#define MSP_TX_CLKPOL_BIT(n) ((n & TCKPOL_MASK) << TCKPOL_SHIFT) +#define MSP_RX_CLKPOL_BIT(n) (((n) & RCKPOL_MASK) << RCKPOL_SHIFT) +#define MSP_TX_CLKPOL_BIT(n) (((n) & TCKPOL_MASK) << TCKPOL_SHIFT) #define P1ELEN_SHIFT 0 #define P1FLEN_SHIFT 3 diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c index bcfb34db37d9..cfaaad9d2402 100644 --- a/sound/usb/6fire/comm.c +++ b/sound/usb/6fire/comm.c @@ -21,7 +21,6 @@ enum { static void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *urb, u8 *buffer, void *context, void(*handler)(struct urb *urb)) { - usb_init_urb(urb); urb->transfer_buffer = buffer; urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP); urb->complete = handler; @@ -142,6 +141,19 @@ static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request, return ret; } +static void usb6fire_comm_free(struct comm_runtime *rt) +{ + if (!rt) + return; + + if (rt->chip) + rt->chip->comm = NULL; + + usb_free_urb(rt->receiver); + kfree(rt->receiver_buffer); + kfree(rt); +} + int usb6fire_comm_init(struct sfire_chip *chip) { struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime), @@ -154,14 +166,18 @@ int usb6fire_comm_init(struct sfire_chip *chip) rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL); if (!rt->receiver_buffer) { - kfree(rt); - return -ENOMEM; + ret = -ENOMEM; + goto error; } - urb = &rt->receiver; + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + ret = -ENOMEM; + goto error; + } + rt->receiver = urb; rt->serial = 1; rt->chip = chip; - usb_init_urb(urb); rt->init_urb = usb6fire_comm_init_urb; rt->write8 = usb6fire_comm_write8; rt->write16 = usb6fire_comm_write16; @@ -176,13 +192,15 @@ int usb6fire_comm_init(struct sfire_chip *chip) urb->interval = 1; ret = usb_submit_urb(urb, GFP_KERNEL); if (ret < 0) { - kfree(rt->receiver_buffer); - kfree(rt); dev_err(&chip->dev->dev, "cannot create comm data receiver."); - return ret; + goto error; } chip->comm = rt; return 0; + + error: + usb6fire_comm_free(rt); + return ret; } void usb6fire_comm_abort(struct sfire_chip *chip) @@ -190,14 +208,10 @@ void usb6fire_comm_abort(struct sfire_chip *chip) struct comm_runtime *rt = chip->comm; if (rt) - usb_poison_urb(&rt->receiver); + usb_poison_urb(rt->receiver); } void usb6fire_comm_destroy(struct sfire_chip *chip) { - struct comm_runtime *rt = chip->comm; - - kfree(rt->receiver_buffer); - kfree(rt); - chip->comm = NULL; + usb6fire_comm_free(chip->comm); } diff --git a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h index 2447d7ecf179..89976f510f6c 100644 --- a/sound/usb/6fire/comm.h +++ b/sound/usb/6fire/comm.h @@ -19,7 +19,7 @@ enum /* settings for comm */ struct comm_runtime { struct sfire_chip *chip; - struct urb receiver; + struct urb *receiver; u8 *receiver_buffer; u8 serial; /* urb serial */ diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c index 4d1eeb32c5fe..f79fb368594d 100644 --- a/sound/usb/6fire/midi.c +++ b/sound/usb/6fire/midi.c @@ -66,7 +66,7 @@ static void usb6fire_midi_out_trigger( struct snd_rawmidi_substream *alsa_sub, int up) { struct midi_runtime *rt = alsa_sub->rmidi->private_data; - struct urb *urb = &rt->out_urb; + struct urb *urb = rt->out_urb; __s8 ret; guard(spinlock_irqsave)(&rt->out_lock); @@ -137,6 +137,19 @@ static const struct snd_rawmidi_ops in_ops = { .trigger = usb6fire_midi_in_trigger }; +static void usb6fire_midi_free(struct midi_runtime *rt) +{ + if (!rt) + return; + + if (rt->chip) + rt->chip->midi = NULL; + + usb_free_urb(rt->out_urb); + kfree(rt->out_buffer); + kfree(rt); +} + int usb6fire_midi_init(struct sfire_chip *chip) { int ret; @@ -149,8 +162,14 @@ int usb6fire_midi_init(struct sfire_chip *chip) rt->out_buffer = kzalloc(MIDI_BUFSIZE, GFP_KERNEL); if (!rt->out_buffer) { - kfree(rt); - return -ENOMEM; + ret = -ENOMEM; + goto error; + } + + rt->out_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rt->out_urb) { + ret = -ENOMEM; + goto error; } rt->chip = chip; @@ -161,15 +180,13 @@ int usb6fire_midi_init(struct sfire_chip *chip) spin_lock_init(&rt->in_lock); spin_lock_init(&rt->out_lock); - comm_rt->init_urb(comm_rt, &rt->out_urb, rt->out_buffer, rt, + comm_rt->init_urb(comm_rt, rt->out_urb, rt->out_buffer, rt, usb6fire_midi_out_handler); ret = snd_rawmidi_new(chip->card, "6FireUSB", 0, 1, 1, &rt->instance); if (ret < 0) { - kfree(rt->out_buffer); - kfree(rt); dev_err(&chip->dev->dev, "unable to create midi.\n"); - return ret; + goto error; } rt->instance->private_data = rt; strscpy(rt->instance->name, "DMX6FireUSB MIDI"); @@ -183,6 +200,10 @@ int usb6fire_midi_init(struct sfire_chip *chip) chip->midi = rt; return 0; + + error: + usb6fire_midi_free(rt); + return ret; } void usb6fire_midi_abort(struct sfire_chip *chip) @@ -190,14 +211,10 @@ void usb6fire_midi_abort(struct sfire_chip *chip) struct midi_runtime *rt = chip->midi; if (rt) - usb_poison_urb(&rt->out_urb); + usb_poison_urb(rt->out_urb); } void usb6fire_midi_destroy(struct sfire_chip *chip) { - struct midi_runtime *rt = chip->midi; - - kfree(rt->out_buffer); - kfree(rt); - chip->midi = NULL; + usb6fire_midi_free(chip->midi); } diff --git a/sound/usb/6fire/midi.h b/sound/usb/6fire/midi.h index 47640c845903..8716ab8a863a 100644 --- a/sound/usb/6fire/midi.h +++ b/sound/usb/6fire/midi.h @@ -22,7 +22,7 @@ struct midi_runtime { spinlock_t in_lock; spinlock_t out_lock; struct snd_rawmidi_substream *out; - struct urb out_urb; + struct urb *out_urb; u8 out_serial; /* serial number of out packet */ u8 *out_buffer; int buffer_offset; diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index 08515da5dcc8..ff00137ab13e 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c @@ -138,8 +138,8 @@ static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt) rt->stream_state = STREAM_STOPPING; for (i = 0; i < PCM_N_URBS; i++) { - usb_kill_urb(&rt->in_urbs[i].instance); - usb_kill_urb(&rt->out_urbs[i].instance); + usb_kill_urb(rt->in_urbs[i].instance); + usb_kill_urb(rt->out_urbs[i].instance); } ctrl_rt->usb_streaming = false; ctrl_rt->update_streaming(ctrl_rt); @@ -161,13 +161,13 @@ static int usb6fire_pcm_stream_start(struct pcm_runtime *rt) rt->stream_state = STREAM_STARTING; for (i = 0; i < PCM_N_URBS; i++) { for (k = 0; k < PCM_N_PACKETS_PER_URB; k++) { - packet = &rt->in_urbs[i].packets[k]; + packet = &rt->in_urbs[i].instance->iso_frame_desc[k]; packet->offset = k * rt->in_packet_size; packet->length = rt->in_packet_size; packet->actual_length = 0; packet->status = 0; } - ret = usb_submit_urb(&rt->in_urbs[i].instance, + ret = usb_submit_urb(rt->in_urbs[i].instance, GFP_ATOMIC); if (ret) { usb6fire_pcm_stream_stop(rt); @@ -197,6 +197,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) unsigned int total_length = 0; struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; + struct usb_iso_packet_descriptor *isoc; u32 *src = NULL; u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off * (alsa_rt->frame_bits >> 3)); @@ -207,8 +208,9 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { /* at least 4 header bytes for valid packet. * after that: 32 bits per sample for analog channels */ - if (urb->packets[i].actual_length > 4) - frame_count = (urb->packets[i].actual_length - 4) + isoc = &urb->instance->iso_frame_desc[i]; + if (isoc->actual_length > 4) + frame_count = (isoc->actual_length - 4) / (rt->in_n_analog << 2); else frame_count = 0; @@ -220,7 +222,7 @@ static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb) else return; src++; /* skip leading 4 bytes of every packet */ - total_length += urb->packets[i].length; + total_length += isoc->length; for (frame = 0; frame < frame_count; frame++) { memcpy(dest, src, bytes_per_frame); dest += alsa_rt->channels; @@ -244,6 +246,7 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub, int frame_count; struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance); struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; + struct usb_iso_packet_descriptor *isoc; u32 *src = (u32 *) (alsa_rt->dma_area + sub->dma_off * (alsa_rt->frame_bits >> 3)); u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size @@ -263,8 +266,9 @@ static void usb6fire_pcm_playback(struct pcm_substream *sub, for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { /* at least 4 header bytes for valid packet. * after that: 32 bits per sample for analog channels */ - if (urb->packets[i].length > 4) - frame_count = (urb->packets[i].length - 4) + isoc = &urb->instance->iso_frame_desc[i]; + if (isoc->length > 4) + frame_count = (isoc->length - 4) / (rt->out_n_analog << 2); else frame_count = 0; @@ -289,6 +293,7 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb) struct pcm_urb *out_urb = in_urb->peer; struct pcm_runtime *rt = in_urb->chip->pcm; struct pcm_substream *sub; + struct usb_iso_packet_descriptor *isoc_out, *isoc_in; bool period_elapsed; int total_length = 0; int frame_count; @@ -299,11 +304,13 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb) if (usb_urb->status || rt->panic || rt->stream_state == STREAM_STOPPING) return; - for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) - if (in_urb->packets[i].status) { + for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { + isoc_in = &in_urb->instance->iso_frame_desc[i]; + if (isoc_in->status) { rt->panic = true; return; } + } if (rt->stream_state == STREAM_DISABLED) { dev_err(&rt->chip->dev->dev, @@ -328,12 +335,21 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb) /* setup out urb structure */ for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { - out_urb->packets[i].offset = total_length; - out_urb->packets[i].length = (in_urb->packets[i].actual_length - - 4) / (rt->in_n_analog << 2) - * (rt->out_n_analog << 2) + 4; - out_urb->packets[i].status = 0; - total_length += out_urb->packets[i].length; + unsigned int frames = 0; + + isoc_out = &out_urb->instance->iso_frame_desc[i]; + isoc_in = &in_urb->instance->iso_frame_desc[i]; + if (isoc_in->actual_length > 4) + frames = (isoc_in->actual_length - 4) + / (rt->in_n_analog << 2); + frames = min_t(unsigned int, frames, + (rt->out_packet_size - 4) + / (rt->out_n_analog << 2)); + + isoc_out->offset = total_length; + isoc_out->length = frames * (rt->out_n_analog << 2) + 4; + isoc_out->status = 0; + total_length += isoc_out->length; } memset(out_urb->buffer, 0, total_length); @@ -354,9 +370,10 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb) /* setup the 4th byte of each sample (0x40 for analog channels) */ dest = out_urb->buffer; - for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) - if (out_urb->packets[i].length >= 4) { - frame_count = (out_urb->packets[i].length - 4) + for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) { + isoc_out = &out_urb->instance->iso_frame_desc[i]; + if (isoc_out->length >= 4) { + frame_count = (isoc_out->length - 4) / (rt->out_n_analog << 2); *(dest++) = 0xaa; *(dest++) = 0xaa; @@ -370,8 +387,10 @@ static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb) *(dest++) = 0x40; } } - usb_submit_urb(&out_urb->instance, GFP_ATOMIC); - usb_submit_urb(&in_urb->instance, GFP_ATOMIC); + } + + usb_submit_urb(out_urb->instance, GFP_ATOMIC); + usb_submit_urb(in_urb->instance, GFP_ATOMIC); } static void usb6fire_pcm_out_urb_handler(struct urb *usb_urb) @@ -534,22 +553,25 @@ static const struct snd_pcm_ops pcm_ops = { .pointer = usb6fire_pcm_pointer, }; -static void usb6fire_pcm_init_urb(struct pcm_urb *urb, - struct sfire_chip *chip, bool in, int ep, - void (*handler)(struct urb *)) +static int usb6fire_pcm_init_urb(struct pcm_urb *urb, + struct sfire_chip *chip, bool in, int ep, + void (*handler)(struct urb *)) { urb->chip = chip; - usb_init_urb(&urb->instance); - urb->instance.transfer_buffer = urb->buffer; - urb->instance.transfer_buffer_length = + urb->instance = usb_alloc_urb(PCM_N_PACKETS_PER_URB, GFP_KERNEL); + if (!urb->instance) + return -ENOMEM; + urb->instance->transfer_buffer = urb->buffer; + urb->instance->transfer_buffer_length = PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE; - urb->instance.dev = chip->dev; - urb->instance.pipe = in ? usb_rcvisocpipe(chip->dev, ep) + urb->instance->dev = chip->dev; + urb->instance->pipe = in ? usb_rcvisocpipe(chip->dev, ep) : usb_sndisocpipe(chip->dev, ep); - urb->instance.interval = 1; - urb->instance.complete = handler; - urb->instance.context = urb; - urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB; + urb->instance->interval = 1; + urb->instance->complete = handler; + urb->instance->context = urb; + urb->instance->number_of_packets = PCM_N_PACKETS_PER_URB; + return 0; } static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt) @@ -571,14 +593,23 @@ static int usb6fire_pcm_buffers_init(struct pcm_runtime *rt) return 0; } -static void usb6fire_pcm_buffers_destroy(struct pcm_runtime *rt) +static void usb6fire_pcm_free(struct pcm_runtime *rt) { int i; + if (!rt) + return; + + if (rt->chip) + rt->chip->pcm = NULL; + for (i = 0; i < PCM_N_URBS; i++) { + usb_free_urb(rt->out_urbs[i].instance); kfree(rt->out_urbs[i].buffer); + usb_free_urb(rt->in_urbs[i].instance); kfree(rt->in_urbs[i].buffer); } + kfree(rt); } int usb6fire_pcm_init(struct sfire_chip *chip) @@ -593,11 +624,8 @@ int usb6fire_pcm_init(struct sfire_chip *chip) return -ENOMEM; ret = usb6fire_pcm_buffers_init(rt); - if (ret) { - usb6fire_pcm_buffers_destroy(rt); - kfree(rt); - return ret; - } + if (ret) + goto error; rt->chip = chip; rt->stream_state = STREAM_DISABLED; @@ -609,10 +637,14 @@ int usb6fire_pcm_init(struct sfire_chip *chip) spin_lock_init(&rt->capture.lock); for (i = 0; i < PCM_N_URBS; i++) { - usb6fire_pcm_init_urb(&rt->in_urbs[i], chip, true, IN_EP, - usb6fire_pcm_in_urb_handler); - usb6fire_pcm_init_urb(&rt->out_urbs[i], chip, false, OUT_EP, - usb6fire_pcm_out_urb_handler); + ret = usb6fire_pcm_init_urb(&rt->in_urbs[i], chip, true, IN_EP, + usb6fire_pcm_in_urb_handler); + if (ret < 0) + goto error; + ret = usb6fire_pcm_init_urb(&rt->out_urbs[i], chip, false, OUT_EP, + usb6fire_pcm_out_urb_handler); + if (ret < 0) + goto error; rt->in_urbs[i].peer = &rt->out_urbs[i]; rt->out_urbs[i].peer = &rt->in_urbs[i]; @@ -620,10 +652,8 @@ int usb6fire_pcm_init(struct sfire_chip *chip) ret = snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm); if (ret < 0) { - usb6fire_pcm_buffers_destroy(rt); - kfree(rt); dev_err(&chip->dev->dev, "cannot create pcm instance.\n"); - return ret; + goto error; } pcm->private_data = rt; @@ -636,6 +666,10 @@ int usb6fire_pcm_init(struct sfire_chip *chip) chip->pcm = rt; return 0; + + error: + usb6fire_pcm_free(rt); + return ret; } void usb6fire_pcm_abort(struct sfire_chip *chip) @@ -653,8 +687,8 @@ void usb6fire_pcm_abort(struct sfire_chip *chip) snd_pcm_stop_xrun(rt->capture.instance); for (i = 0; i < PCM_N_URBS; i++) { - usb_poison_urb(&rt->in_urbs[i].instance); - usb_poison_urb(&rt->out_urbs[i].instance); + usb_poison_urb(rt->in_urbs[i].instance); + usb_poison_urb(rt->out_urbs[i].instance); } } @@ -662,9 +696,5 @@ void usb6fire_pcm_abort(struct sfire_chip *chip) void usb6fire_pcm_destroy(struct sfire_chip *chip) { - struct pcm_runtime *rt = chip->pcm; - - usb6fire_pcm_buffers_destroy(rt); - kfree(rt); - chip->pcm = NULL; + usb6fire_pcm_free(chip->pcm); } diff --git a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h index 5a092dfd69f5..b586fe220fd1 100644 --- a/sound/usb/6fire/pcm.h +++ b/sound/usb/6fire/pcm.h @@ -24,10 +24,7 @@ enum /* settings for pcm */ struct pcm_urb { struct sfire_chip *chip; - /* BEGIN DO NOT SEPARATE */ - struct urb instance; - struct usb_iso_packet_descriptor packets[PCM_N_PACKETS_PER_URB]; - /* END DO NOT SEPARATE */ + struct urb *instance; u8 *buffer; struct pcm_urb *peer; diff --git a/sound/usb/bcd2000/bcd2000.c b/sound/usb/bcd2000/bcd2000.c index c5c542d17ccc..2bd49bf82748 100644 --- a/sound/usb/bcd2000/bcd2000.c +++ b/sound/usb/bcd2000/bcd2000.c @@ -43,6 +43,7 @@ struct bcd2000 { struct usb_interface *intf; int card_index; + spinlock_t midi_lock; int midi_out_active; struct snd_rawmidi *rmidi; struct snd_rawmidi_substream *midi_receive_substream; @@ -90,6 +91,8 @@ static void bcd2000_midi_input_trigger(struct snd_rawmidi_substream *substream, int up) { struct bcd2000 *bcd2k = substream->rmidi->private_data; + + guard(spinlock_irqsave)(&bcd2k->midi_lock); bcd2k->midi_receive_substream = up ? substream : NULL; } @@ -195,6 +198,8 @@ static void bcd2000_midi_output_trigger(struct snd_rawmidi_substream *substream, { struct bcd2000 *bcd2k = substream->rmidi->private_data; + guard(spinlock_irqsave)(&bcd2k->midi_lock); + if (up) { bcd2k->midi_out_substream = substream; /* check if there is data userspace wants to send */ @@ -219,6 +224,7 @@ static void bcd2000_output_complete(struct urb *urb) return; /* check if there is more data userspace wants to send */ + guard(spinlock_irqsave)(&bcd2k->midi_lock); bcd2000_midi_send(bcd2k); } @@ -234,6 +240,8 @@ static void bcd2000_input_complete(struct urb *urb) if (!bcd2k || urb->status == -ESHUTDOWN) return; + guard(spinlock_irqsave)(&bcd2k->midi_lock); + if (urb->actual_length > 0) bcd2000_midi_handle_input(bcd2k, urb->transfer_buffer, urb->actual_length); @@ -348,16 +356,26 @@ static int bcd2000_init_midi(struct bcd2000 *bcd2k) return 0; } +static void bcd2000_midi_free(struct bcd2000 *bcd2k, + struct urb **urb_p) +{ + struct urb *urb = *urb_p; + + if (!urb) + return; + + usb_poison_urb(urb); + scoped_guard(spinlock_irq, &bcd2k->midi_lock) + *urb_p = NULL; + + usb_free_urb(urb); +} + static void bcd2000_free_usb_related_resources(struct bcd2000 *bcd2k, struct usb_interface *interface) { - usb_poison_urb(bcd2k->midi_out_urb); - usb_poison_urb(bcd2k->midi_in_urb); - - usb_free_urb(bcd2k->midi_out_urb); - usb_free_urb(bcd2k->midi_in_urb); - bcd2k->midi_out_urb = NULL; - bcd2k->midi_in_urb = NULL; + bcd2000_midi_free(bcd2k, &bcd2k->midi_out_urb); + bcd2000_midi_free(bcd2k, &bcd2k->midi_in_urb); if (bcd2k->intf) { usb_set_intfdata(bcd2k->intf, NULL); @@ -393,6 +411,7 @@ static int bcd2000_probe(struct usb_interface *interface, bcd2k->card = card; bcd2k->card_index = card_index; bcd2k->intf = interface; + spin_lock_init(&bcd2k->midi_lock); snd_card_set_dev(card, &interface->dev); diff --git a/sound/usb/card.h b/sound/usb/card.h index 94404c24d240..8299ac241c60 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -90,7 +90,7 @@ struct snd_usb_endpoint { struct snd_urb_ctx urb[MAX_URBS]; struct snd_usb_packet_info { - uint32_t packet_size[MAX_PACKS_HS]; + int packet_size[MAX_PACKS_HS]; int packets; } next_packet[MAX_URBS]; unsigned int next_packet_head; /* ring buffer offset to read */ @@ -116,6 +116,7 @@ struct snd_usb_endpoint { unsigned int phase; /* phase accumulator */ unsigned int maxpacksize; /* max packet size in bytes */ unsigned int maxframesize; /* max packet size in frames */ + unsigned int max_urb_packs; /* packets allocated per data URB */ unsigned int max_urb_frames; /* max URB size in frames */ unsigned int curpacksize; /* current packet size in bytes (for capture) */ unsigned int curframesize; /* current packet size in frames (for capture) */ diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index bdf0e724d418..b0202ae44b96 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -470,7 +470,7 @@ int snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep, while (ep_state_running(ep)) { struct snd_usb_packet_info *packet; struct snd_urb_ctx *ctx = NULL; - int err, i; + int err; scoped_guard(spinlock_irqsave, &ep->lock) { if ((!implicit_fb || ep->next_packet_queued > 0) && @@ -489,9 +489,10 @@ int snd_usb_queue_pending_output_urbs(struct snd_usb_endpoint *ep, /* copy over the length information */ if (implicit_fb) { - ctx->packets = packet->packets; - for (i = 0; i < packet->packets; i++) - ctx->packet_size[i] = packet->packet_size[i]; + ctx->packets = min_t(int, packet->packets, + ep->max_urb_packs); + memcpy(ctx->packet_size, packet->packet_size, + ctx->packets * sizeof(packet->packet_size[0])); } /* call the data handler to fill in playback data */ @@ -1235,15 +1236,16 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep) ep->nurbs = min(max_urbs, urbs_per_period * ep->cur_buffer_periods); } + if (fmt->fmt_type == UAC_FORMAT_TYPE_II) + urb_packs++; /* for transfer delimiter */ + ep->max_urb_packs = urb_packs; + /* allocate and initialize data urbs */ for (i = 0; i < ep->nurbs; i++) { struct snd_urb_ctx *u = &ep->urb[i]; u->index = i; u->ep = ep; u->packets = urb_packs; - - if (fmt->fmt_type == UAC_FORMAT_TYPE_II) - u->packets++; /* for transfer delimiter */ u->buffer_size = maxsize * u->packets; u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); if (!u->urb) diff --git a/sound/virtio/virtio_card.c b/sound/virtio/virtio_card.c index 52c5757585c6..a3e69a460b85 100644 --- a/sound/virtio/virtio_card.c +++ b/sound/virtio/virtio_card.c @@ -355,8 +355,8 @@ static void virtsnd_remove(struct virtio_device *vdev) if (snd->card) snd_card_free(snd->card); - vdev->config->del_vqs(vdev); virtio_reset_device(vdev); + vdev->config->del_vqs(vdev); for (i = 0; snd->substreams && i < snd->nsubstreams; ++i) { struct virtio_pcm_substream *vss = &snd->substreams[i]; @@ -384,8 +384,8 @@ static int virtsnd_freeze(struct virtio_device *vdev) virtsnd_disable_event_vq(snd); virtsnd_ctl_msg_cancel_all(snd); - vdev->config->del_vqs(vdev); virtio_reset_device(vdev); + vdev->config->del_vqs(vdev); for (i = 0; i < snd->nsubstreams; ++i) cancel_work_sync(&snd->substreams[i].elapsed_period); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index a4f244a04686..c64005278687 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -709,8 +709,6 @@ struct block_hist { struct hist_entry he; }; -#define NO_ADDR 0 - #ifdef HAVE_SLANG_SUPPORT #include "../ui/keysyms.h" void attr_to_script(char *buf, struct perf_event_attr *attr); @@ -748,16 +746,14 @@ int evlist__tui_browse_hists(struct evlist *evlist __maybe_unused, static inline int __hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, struct map_symbol *ms __maybe_unused, struct evsel *evsel __maybe_unused, - struct hist_browser_timer *hbt __maybe_unused, - u64 al_addr __maybe_unused) + struct hist_browser_timer *hbt __maybe_unused) { return 0; } static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, struct evsel *evsel __maybe_unused, - struct hist_browser_timer *hbt __maybe_unused, - u64 al_addr __maybe_unused) + struct hist_browser_timer *hbt __maybe_unused) { return 0; } diff --git a/tools/testing/selftests/arm64/mte/check_gcr_el1_cswitch.c b/tools/testing/selftests/arm64/mte/check_gcr_el1_cswitch.c index d23f154d3288..5d9dc8bcfbf5 100644 --- a/tools/testing/selftests/arm64/mte/check_gcr_el1_cswitch.c +++ b/tools/testing/selftests/arm64/mte/check_gcr_el1_cswitch.c @@ -69,7 +69,7 @@ void *execute_thread(void *x) int execute_test(pid_t pid) { pthread_t thread_id[MAX_THREADS]; - int thread_data[MAX_THREADS]; + intptr_t thread_data[MAX_THREADS]; for (int i = 0; i < MAX_THREADS; i++) pthread_create(&thread_id[i], NULL, diff --git a/tools/testing/selftests/landlock/audit.h b/tools/testing/selftests/landlock/audit.h index d6d6f5116dc9..a1768a4dbf39 100644 --- a/tools/testing/selftests/landlock/audit.h +++ b/tools/testing/selftests/landlock/audit.h @@ -45,17 +45,25 @@ struct audit_message { }; }; -static const struct timeval audit_tv_dom_drop = { +static const struct timeval audit_tv_default = { /* - * Because domain deallocation is tied to asynchronous credential - * freeing, receiving such event may take some time. In practice, - * on a small VM, it should not exceed 100k usec, but let's wait up - * to 1 second to be safe. + * Default socket timeout for audit_match_record() callers that expect a + * record to arrive. Asynchronous kauditd delivery can exceed 1 usec + * under heavy debug configs (KASAN, lockdep), where kauditd_thread + * scheduling between audit_log_end() and netlink_unicast() takes longer + * than the previous 1 usec timeout. 1 second is a generous ceiling: on + * the happy path, kauditd delivers within dozens of usec. */ .tv_sec = 1, }; -static const struct timeval audit_tv_default = { +static const struct timeval audit_tv_fast = { + /* + * Fast timeout for paths that expect no record (audit_init() drain, + * audit_count_records(), probes). Causes audit_recv() to return + * -EAGAIN once the socket buffer is empty, naturally terminating the + * read loop. + */ .tv_usec = 1, }; @@ -334,8 +342,13 @@ static int __maybe_unused matches_log_domain_allocated(int audit_fd, pid_t pid, * Matches a domain deallocation record. When expected_domain_id is non-zero, * the pattern includes the specific domain ID so that stale deallocation * records from a previous test (with a different domain ID) are skipped by - * audit_match_record(), and the socket timeout is temporarily increased to - * audit_tv_dom_drop to wait for the asynchronous kworker deallocation. + * audit_match_record(), waiting for the asynchronous kworker deallocation with + * the default patient timeout. + * + * When expected_domain_id is zero, the caller is probing for any dealloc record + * that may or may not arrive. Temporarily lowers the socket timeout to + * audit_tv_fast for this probe so it returns promptly when no record is + * pending; restores audit_tv_default after. */ static int __maybe_unused matches_log_domain_deallocated(int audit_fd, unsigned int num_denials, @@ -361,16 +374,21 @@ matches_log_domain_deallocated(int audit_fd, unsigned int num_denials, if (log_match_len >= sizeof(log_match)) return -E2BIG; - if (expected_domain_id) - setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, - &audit_tv_dom_drop, sizeof(audit_tv_dom_drop)); + if (!expected_domain_id) { + if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, + &audit_tv_fast, sizeof(audit_tv_fast))) + return -errno; + } err = audit_match_record(audit_fd, AUDIT_LANDLOCK_DOMAIN, log_match, domain_id); - if (expected_domain_id) - setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default, - sizeof(audit_tv_default)); + if (!expected_domain_id) { + if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, + &audit_tv_default, sizeof(audit_tv_default)) && + !err) + err = -errno; + } return err; } @@ -387,6 +405,11 @@ struct audit_records { * audit_init() and after the preceding audit_match_record() call. Allocation * records are emitted synchronously during landlock_log_denial() in the current * test's syscall context, so only those are counted in records->domain. + * + * Temporarily lowers SO_RCVTIMEO to audit_tv_fast for the read loop: this is a + * "no record expected" path that should terminate on the first -EAGAIN. The + * default patient timeout is restored on exit for subsequent + * audit_match_record() callers. */ static int audit_count_records(int audit_fd, struct audit_records *records) { @@ -403,6 +426,12 @@ static int audit_count_records(int audit_fd, struct audit_records *records) records->access = 0; records->domain = 0; + if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_fast, + sizeof(audit_tv_fast))) { + err = -errno; + goto out; + } + do { memset(&msg, 0, sizeof(msg)); err = audit_recv(audit_fd, &msg); @@ -429,6 +458,10 @@ static int audit_count_records(int audit_fd, struct audit_records *records) } while (true); out: + if (setsockopt(audit_fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default, + sizeof(audit_tv_default)) && + !err) + err = -errno; regfree(&dealloc_re); return err; } @@ -443,17 +476,19 @@ static int audit_init(void) err = audit_set_status(fd, AUDIT_STATUS_ENABLED, 1); if (err) - return err; + goto err_close; err = audit_set_status(fd, AUDIT_STATUS_PID, getpid()); if (err) - return err; - - /* Sets a timeout for negative tests. */ - err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default, - sizeof(audit_tv_default)); - if (err) - return -errno; + goto err_close; + + /* Uses the fast timeout to drain stale records below. */ + err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_fast, + sizeof(audit_tv_fast)); + if (err) { + err = -errno; + goto err_close; + } /* * Drains stale audit records that accumulated in the kernel backlog @@ -465,7 +500,24 @@ static int audit_init(void) while (audit_recv(fd, NULL) == 0) ; + /* + * Restores the default timeout for audit_match_record() callers that + * expect a record to arrive. Paths that expect no record restore the + * fast timeout locally (audit_count_records(), the expected_domain_id + * == 0 probe in matches_log_domain_deallocated()). + */ + err = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &audit_tv_default, + sizeof(audit_tv_default)); + if (err) { + err = -errno; + goto err_close; + } + return fd; + +err_close: + close(fd); + return err; } static int audit_init_filter_exe(struct audit_filter *filter, const char *path) @@ -501,10 +553,9 @@ static int audit_init_filter_exe(struct audit_filter *filter, const char *path) static int audit_cleanup(int audit_fd, struct audit_filter *filter) { struct audit_filter new_filter; + int err = 0; if (audit_fd < 0 || !filter) { - int err; - /* * Simulates audit_init_with_exe_filter() when called from * FIXTURE_TEARDOWN_PARENT(). @@ -516,20 +567,18 @@ static int audit_cleanup(int audit_fd, struct audit_filter *filter) filter = &new_filter; err = audit_init_filter_exe(filter, NULL); if (err) - return err; + goto err_close; } /* Filters might not be in place. */ audit_filter_exe(audit_fd, filter, AUDIT_DEL_RULE); audit_filter_drop(audit_fd, AUDIT_DEL_RULE); - /* - * Because audit_cleanup() might not be called by the test auditd - * process, it might not be possible to explicitly set it. Anyway, - * AUDIT_STATUS_ENABLED will implicitly be set to 0 when the auditd - * process will exit. - */ - return close(audit_fd); + err = audit_set_status(audit_fd, AUDIT_STATUS_ENABLED, 0); + +err_close: + close(audit_fd); + return err; } static int audit_init_with_exe_filter(struct audit_filter *filter) @@ -542,11 +591,15 @@ static int audit_init_with_exe_filter(struct audit_filter *filter) err = audit_init_filter_exe(filter, NULL); if (err) - return err; + goto err_close; err = audit_filter_exe(fd, filter, AUDIT_ADD_RULE); if (err) - return err; + goto err_close; return fd; + +err_close: + close(fd); + return err; } diff --git a/tools/testing/selftests/landlock/audit_test.c b/tools/testing/selftests/landlock/audit_test.c index 67ab175ef5e3..dcf63b2f822e 100644 --- a/tools/testing/selftests/landlock/audit_test.c +++ b/tools/testing/selftests/landlock/audit_test.c @@ -617,10 +617,8 @@ FIXTURE_SETUP(audit_exec) FIXTURE_TEARDOWN(audit_exec) { set_cap(_metadata, CAP_AUDIT_CONTROL); - EXPECT_EQ(0, audit_filter_exe(self->audit_fd, &self->audit_filter, - AUDIT_DEL_RULE)); + EXPECT_EQ(0, audit_cleanup(self->audit_fd, &self->audit_filter)); clear_cap(_metadata, CAP_AUDIT_CONTROL); - EXPECT_EQ(0, close(self->audit_fd)); } TEST_F(audit_exec, signal_and_open) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 29cdbb836735..ab5d7f792ee2 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -791,6 +791,27 @@ static int create_ruleset(struct __test_metadata *const _metadata, return ruleset_fd; } +static void enforce_fs(struct __test_metadata *const _metadata, + const __u64 access_fs, const struct rule rules[]) +{ + int ruleset_fd; + + if (rules) { + ruleset_fd = create_ruleset(_metadata, access_fs, rules); + } else { + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_fs = access_fs, + }; + + ruleset_fd = landlock_create_ruleset(&ruleset_attr, + sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + } + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); +} + TEST_F_FORK(layout0, proc_nsfs) { const struct rule rules[] = { @@ -2267,6 +2288,22 @@ static int test_exchange(const char *const oldpath, const char *const newpath) return 0; } +static int test_renameat(int olddirfd, const char *oldpath, int newdirfd, + const char *newpath) +{ + if (renameat2(olddirfd, oldpath, newdirfd, newpath, 0)) + return errno; + return 0; +} + +static int test_exchangeat(int olddirfd, const char *oldpath, int newdirfd, + const char *newpath) +{ + if (renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_EXCHANGE)) + return errno; + return 0; +} + TEST_F_FORK(layout1, rename_file) { const struct rule rules[] = { @@ -2349,6 +2386,170 @@ TEST_F_FORK(layout1, rename_file) RENAME_EXCHANGE)); } +TEST_F_FORK(layout1, rename_whiteout_denied) +{ + /* The affected file is a FIFO. */ + ASSERT_EQ(0, unlink(file1_s3d3)); + ASSERT_EQ(0, mknod(file1_s3d3, S_IFIFO | 0600, 0)); + + /* Deny MAKE_REG, but allow MAKE_FIFO. */ + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, NULL); + + /* + * Try to rename a file with RENAME_WHITEOUT. + * file1_s3d3 is in dir_s3d2 (tmpfs), so it supports RENAME_WHITEOUT. + * Denied, because whiteout creation is guarded with MAKE_REG. + */ + EXPECT_EQ(-1, renameat2(AT_FDCWD, file1_s3d3, AT_FDCWD, + TMP_DIR "/s3d1/s3d2/s3d3/f2", RENAME_WHITEOUT)); + EXPECT_EQ(EACCES, errno); +} + +static bool is_whiteout(const char *const path) +{ + struct stat st; + + if (stat(path, &st) == -1) + return false; + + return S_ISCHR(st.st_mode) && st.st_rdev == makedev(0, 0); +} + +static bool is_fifo(const char *const path) +{ + struct stat st; + + return stat(path, &st) == 0 && S_ISFIFO(st.st_mode); +} + +TEST_F_FORK(layout1, rename_whiteout_allowed) +{ + const struct rule rules[] = { + { + .path = dir_s3d3, + .access = LANDLOCK_ACCESS_FS_MAKE_REG, + }, + {}, + }; + + /* The affected file is a FIFO. */ + ASSERT_EQ(0, unlink(file1_s3d3)); + ASSERT_EQ(0, mknod(file1_s3d3, S_IFIFO | 0600, 0)); + + /* Allow MAKE_REG below dir_s3d3. */ + enforce_fs(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, rules); + + /* + * Rename a file with RENAME_WHITEOUT within the same directory. + * Allowed, because MAKE_REG is granted for the whiteout object which + * gets created in the source location. + */ + EXPECT_EQ(0, renameat2(AT_FDCWD, file1_s3d3, AT_FDCWD, + TMP_DIR "/s3d1/s3d2/s3d3/f2", RENAME_WHITEOUT)); + + /* A whiteout object took the place of the moved FIFO. */ + EXPECT_TRUE(is_whiteout(file1_s3d3)); + EXPECT_TRUE(is_fifo(TMP_DIR "/s3d1/s3d2/s3d3/f2")); +} + +TEST_F_FORK(layout1, rename_whiteout_reparenting) +{ + const struct rule rules[] = { + { + .path = dir_s3d2, + .access = LANDLOCK_ACCESS_FS_REFER, + }, + { + .path = dir_s3d3, + .access = LANDLOCK_ACCESS_FS_MAKE_REG, + }, + {}, + }; + + /* The moved files are FIFOs. */ + ASSERT_EQ(0, unlink(file1_s3d3)); + ASSERT_EQ(0, mknod(file1_s3d3, S_IFIFO | 0600, 0)); + ASSERT_EQ(0, unlink(file1_s3d4)); + ASSERT_EQ(0, mknod(file1_s3d4, S_IFIFO | 0600, 0)); + + /* Allow REFER below dir_s3d2, but MAKE_REG only below dir_s3d3. */ + enforce_fs(_metadata, + LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, + rules); + + /* + * The whiteout object is created in the source directory: Moving the + * FIFO out of dir_s3d4 is denied because MAKE_REG is not granted + * there, even though it is granted in the destination directory + * dir_s3d3. + */ + EXPECT_EQ(-1, renameat2(AT_FDCWD, file1_s3d4, AT_FDCWD, + TMP_DIR "/s3d1/s3d2/s3d3/f2", RENAME_WHITEOUT)); + EXPECT_EQ(EACCES, errno); + + /* + * Moving the FIFO out of dir_s3d3 is allowed, because MAKE_REG is + * granted there for the created whiteout object. + */ + EXPECT_EQ(0, renameat2(AT_FDCWD, file1_s3d3, AT_FDCWD, + TMP_DIR "/s3d1/s3d2/s3d4/f2", RENAME_WHITEOUT)); + + /* A whiteout object took the place of the moved FIFO. */ + EXPECT_TRUE(is_whiteout(file1_s3d3)); + EXPECT_TRUE(is_fifo(TMP_DIR "/s3d1/s3d2/s3d4/f2")); +} + +TEST_F_FORK(layout1, rename_whiteout_exchange) +{ + const char *const whiteout_s3d3 = TMP_DIR "/s3d1/s3d2/s3d3/f2"; + const struct rule rules[] = { + { + .path = dir_s3d2, + .access = LANDLOCK_ACCESS_FS_REFER, + }, + { + .path = dir_s3d3, + .access = LANDLOCK_ACCESS_FS_MAKE_REG, + }, + {}, + }; + + /* The exchanged files are FIFOs and an existing whiteout object. */ + ASSERT_EQ(0, unlink(file1_s3d3)); + ASSERT_EQ(0, mknod(file1_s3d3, S_IFIFO | 0600, 0)); + ASSERT_EQ(0, mknod(whiteout_s3d3, S_IFCHR | 0600, makedev(0, 0))); + ASSERT_EQ(0, unlink(file1_s3d4)); + ASSERT_EQ(0, mknod(file1_s3d4, S_IFIFO | 0600, 0)); + + /* Allow REFER below dir_s3d2, but MAKE_REG only below dir_s3d3. */ + enforce_fs(_metadata, + LANDLOCK_ACCESS_FS_MAKE_REG | LANDLOCK_ACCESS_FS_REFER, + rules); + + /* + * With RENAME_EXCHANGE, the whiteout object moves into the source + * directory of the rename: Exchanging the FIFO in dir_s3d4 with the + * whiteout object is denied because MAKE_REG is not granted in + * dir_s3d4, even though it is granted in the whiteout object's own + * directory dir_s3d3. + */ + EXPECT_EQ(-1, renameat2(AT_FDCWD, file1_s3d4, AT_FDCWD, whiteout_s3d3, + RENAME_EXCHANGE)); + EXPECT_EQ(EACCES, errno); + + /* + * Exchanging the FIFO in dir_s3d3 with the whiteout object is + * allowed, because MAKE_REG is granted in the directory into which + * the whiteout object moves. + */ + EXPECT_EQ(0, renameat2(AT_FDCWD, file1_s3d3, AT_FDCWD, whiteout_s3d3, + RENAME_EXCHANGE)); + + /* The FIFO and the whiteout object swapped places. */ + EXPECT_TRUE(is_whiteout(file1_s3d3)); + EXPECT_TRUE(is_fifo(whiteout_s3d3)); +} + TEST_F_FORK(layout1, rename_dir) { const struct rule rules[] = { @@ -3440,6 +3641,18 @@ TEST_F_FORK(layout1, make_char) makedev(1, 3)); } +TEST_F_FORK(layout1, make_whiteout) +{ + /* + * Creates a whiteout object (creation guarded by MAKE_REG). + * + * Contrary to the other character devices, this does not require + * CAP_MKNOD, cf. vfs_mknod(). + */ + test_make_file(_metadata, LANDLOCK_ACCESS_FS_MAKE_REG, S_IFCHR, + makedev(0, 0)); +} + TEST_F_FORK(layout1, make_block) { /* Creates a /dev/loop0 device. */ @@ -4559,6 +4772,18 @@ TEST_F_FORK(ioctl, handle_file_access_file) FIXTURE(layout1_bind) {}; /* clang-format on */ +static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3"; +static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1"; + +/* Move targets for disconnected path tests. */ +static const char dir_s4d1[] = TMP_DIR "/s4d1"; +static const char file1_s4d1[] = TMP_DIR "/s4d1/f1"; +static const char file2_s4d1[] = TMP_DIR "/s4d1/f2"; +static const char dir_s4d2[] = TMP_DIR "/s4d1/s4d2"; +static const char file1_s4d2[] = TMP_DIR "/s4d1/s4d2/f1"; +static const char file1_name[] = "f1"; +static const char file2_name[] = "f2"; + FIXTURE_SETUP(layout1_bind) { prepare_layout(_metadata); @@ -4574,14 +4799,14 @@ FIXTURE_TEARDOWN_PARENT(layout1_bind) { /* umount(dir_s2d2)) is handled by namespace lifetime. */ + remove_path(file1_s4d1); + remove_path(file2_s4d1); + remove_layout1(_metadata); cleanup_layout(_metadata); } -static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3"; -static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1"; - /* * layout1_bind hierarchy: * @@ -4592,20 +4817,25 @@ static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1"; * │   └── s1d2 * │   ├── f1 * │   ├── f2 - * │   └── s1d3 + * │   └── s1d3 [disconnected by path_disconnected] * │   ├── f1 * │   └── f2 * ├── s2d1 * │   ├── f1 - * │   └── s2d2 + * │   └── s2d2 [bind mount from s1d2] * │   ├── f1 * │   ├── f2 * │   └── s1d3 * │   ├── f1 * │   └── f2 - * └── s3d1 - * └── s3d2 - * └── s3d3 + * ├── s3d1 + * │   └── s3d2 + * │   └── s3d3 + * └── s4d1 [renamed from s1d3 by path_disconnected] + *    ├── f1 + *    ├── f2 + * └── s4d2 + * └── f1 */ TEST_F_FORK(layout1_bind, no_restriction) @@ -4804,103 +5034,1528 @@ TEST_F_FORK(layout1_bind, reparent_cross_mount) ASSERT_EQ(0, rename(bind_file1_s1d3, file1_s2d2)); } -#define LOWER_BASE TMP_DIR "/lower" -#define LOWER_DATA LOWER_BASE "/data" -static const char lower_fl1[] = LOWER_DATA "/fl1"; -static const char lower_dl1[] = LOWER_DATA "/dl1"; -static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2"; -static const char lower_fo1[] = LOWER_DATA "/fo1"; -static const char lower_do1[] = LOWER_DATA "/do1"; -static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2"; -static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3"; +/* + * Make sure access to file through a disconnected path works as expected. + * This test moves s1d3 to s4d1. + */ +TEST_F_FORK(layout1_bind, path_disconnected) +{ + const struct rule layer1_allow_all[] = { + { + .path = TMP_DIR, + .access = ACCESS_ALL, + }, + {}, + }; + const struct rule layer2_allow_just_f1[] = { + { + .path = file1_s1d3, + .access = LANDLOCK_ACCESS_FS_READ_FILE, + }, + {}, + }; + const struct rule layer3_only_s1d2[] = { + { + .path = dir_s1d2, + .access = LANDLOCK_ACCESS_FS_READ_FILE, + }, + {}, + }; -static const char (*lower_base_files[])[] = { - &lower_fl1, - &lower_fo1, - NULL, -}; -static const char (*lower_base_directories[])[] = { - &lower_dl1, - &lower_do1, - NULL, -}; -static const char (*lower_sub_files[])[] = { - &lower_dl1_fl2, - &lower_do1_fo2, - &lower_do1_fl3, - NULL, -}; + /* Landlock should not deny access just because it is disconnected. */ + int ruleset_fd_l1 = + create_ruleset(_metadata, ACCESS_ALL, layer1_allow_all); -#define UPPER_BASE TMP_DIR "/upper" -#define UPPER_DATA UPPER_BASE "/data" -#define UPPER_WORK UPPER_BASE "/work" -static const char upper_fu1[] = UPPER_DATA "/fu1"; -static const char upper_du1[] = UPPER_DATA "/du1"; -static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2"; -static const char upper_fo1[] = UPPER_DATA "/fo1"; -static const char upper_do1[] = UPPER_DATA "/do1"; -static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2"; -static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3"; + /* Creates the new ruleset now before we move the dir containing the file. */ + int ruleset_fd_l2 = + create_ruleset(_metadata, ACCESS_RW, layer2_allow_just_f1); + int ruleset_fd_l3 = + create_ruleset(_metadata, ACCESS_RW, layer3_only_s1d2); + int bind_s1d3_fd; -static const char (*upper_base_files[])[] = { - &upper_fu1, - &upper_fo1, - NULL, -}; -static const char (*upper_base_directories[])[] = { - &upper_du1, - &upper_do1, - NULL, -}; -static const char (*upper_sub_files[])[] = { - &upper_du1_fu2, - &upper_do1_fo2, - &upper_do1_fu3, - NULL, -}; + ASSERT_LE(0, ruleset_fd_l1); + ASSERT_LE(0, ruleset_fd_l2); + ASSERT_LE(0, ruleset_fd_l3); -#define MERGE_BASE TMP_DIR "/merge" -#define MERGE_DATA MERGE_BASE "/data" -static const char merge_fl1[] = MERGE_DATA "/fl1"; -static const char merge_dl1[] = MERGE_DATA "/dl1"; -static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2"; -static const char merge_fu1[] = MERGE_DATA "/fu1"; -static const char merge_du1[] = MERGE_DATA "/du1"; -static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2"; -static const char merge_fo1[] = MERGE_DATA "/fo1"; -static const char merge_do1[] = MERGE_DATA "/do1"; -static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2"; -static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3"; -static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3"; + enforce_ruleset(_metadata, ruleset_fd_l1); + EXPECT_EQ(0, close(ruleset_fd_l1)); -static const char (*merge_base_files[])[] = { - &merge_fl1, - &merge_fu1, - &merge_fo1, - NULL, -}; -static const char (*merge_base_directories[])[] = { - &merge_dl1, - &merge_du1, - &merge_do1, - NULL, -}; -static const char (*merge_sub_files[])[] = { - &merge_dl1_fl2, &merge_du1_fu2, &merge_do1_fo2, - &merge_do1_fl3, &merge_do1_fu3, NULL, -}; + bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC); + ASSERT_LE(0, bind_s1d3_fd); + + /* Tests access is possible before we move. */ + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, "..", O_RDONLY | O_DIRECTORY)); + + /* Makes it disconnected. */ + ASSERT_EQ(0, rename(dir_s1d3, dir_s4d1)) + { + TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d1, + strerror(errno)); + } + + /* Tests that access is still possible. */ + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY)); + + /* + * Tests that ".." is not possible (not because of Landlock, but just + * because it's disconnected). + */ + EXPECT_EQ(ENOENT, + test_open_rel(bind_s1d3_fd, "..", O_RDONLY | O_DIRECTORY)); + + /* This should still work with a narrower rule. */ + enforce_ruleset(_metadata, ruleset_fd_l2); + EXPECT_EQ(0, close(ruleset_fd_l2)); + + EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY)); + /* + * Accessing a file through a disconnected file descriptor can still be + * allowed by a rule tied to this file, even if it is no longer visible in + * its mount point. + */ + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY)); + + enforce_ruleset(_metadata, ruleset_fd_l3); + EXPECT_EQ(0, close(ruleset_fd_l3)); + + EXPECT_EQ(EACCES, test_open(file1_s4d1, O_RDONLY)); + /* + * Accessing a file through a disconnected file descriptor can still be + * allowed by a rule tied to the original mount point, even if it is no + * longer visible in its mount point. + */ + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY)); +} /* - * layout2_overlay hierarchy: - * - * tmp - * ├── lower - * │   └── data - * │   ├── dl1 - * │   │   └── fl2 - * │   ├── do1 - * │   │   ├── fl3 - * │   │   └── fo2 + * Test that renameat with disconnected paths works under Landlock. This test + * moves s1d3 to s4d2, so that we can have a rule allowing refers on the move + * target's immediate parent. + */ +TEST_F_FORK(layout1_bind, path_disconnected_rename) +{ + const struct rule layer1[] = { + { + .path = dir_s1d2, + .access = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_MAKE_DIR | + LANDLOCK_ACCESS_FS_REMOVE_DIR | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_REMOVE_FILE | + LANDLOCK_ACCESS_FS_READ_FILE, + }, + { + .path = dir_s4d1, + .access = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_MAKE_DIR | + LANDLOCK_ACCESS_FS_REMOVE_DIR | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_REMOVE_FILE | + LANDLOCK_ACCESS_FS_READ_FILE, + }, + {} + }; + + /* This layer only handles LANDLOCK_ACCESS_FS_READ_FILE. */ + const struct rule layer2_only_s1d2[] = { + { + .path = dir_s1d2, + .access = LANDLOCK_ACCESS_FS_READ_FILE, + }, + {}, + }; + int ruleset_fd_l1, ruleset_fd_l2; + pid_t child_pid; + int bind_s1d3_fd, status; + + ASSERT_EQ(0, mkdir(dir_s4d1, 0755)) + { + TH_LOG("Failed to create %s: %s", dir_s4d1, strerror(errno)); + } + ruleset_fd_l1 = create_ruleset(_metadata, ACCESS_ALL, layer1); + ruleset_fd_l2 = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, + layer2_only_s1d2); + ASSERT_LE(0, ruleset_fd_l1); + ASSERT_LE(0, ruleset_fd_l2); + + enforce_ruleset(_metadata, ruleset_fd_l1); + EXPECT_EQ(0, close(ruleset_fd_l1)); + + bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC); + ASSERT_LE(0, bind_s1d3_fd); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + + /* Tests ENOENT priority over EACCES for disconnected directory. */ + EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, "..", O_DIRECTORY)); + ASSERT_EQ(0, rename(dir_s1d3, dir_s4d2)) + { + TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d2, + strerror(errno)); + } + EXPECT_EQ(ENOENT, test_open_rel(bind_s1d3_fd, "..", O_DIRECTORY)); + + /* + * The file is no longer under s1d2 but we should still be able to access it + * with layer 2 because its mount point is evaluated as the first valid + * directory because it was initially a parent. Do a fork to test this so + * we don't prevent ourselves from renaming it back later. + */ + child_pid = fork(); + ASSERT_LE(0, child_pid); + if (child_pid == 0) { + enforce_ruleset(_metadata, ruleset_fd_l2); + EXPECT_EQ(0, close(ruleset_fd_l2)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(EACCES, test_open(file1_s4d2, O_RDONLY)); + + /* + * Tests that access widening checks indeed prevents us from renaming it + * back. + */ + EXPECT_EQ(-1, rename(dir_s4d2, dir_s1d3)); + EXPECT_EQ(EXDEV, errno); + + /* + * Including through the now disconnected fd (but it should return + * EXDEV). + */ + EXPECT_EQ(-1, renameat(bind_s1d3_fd, file1_name, AT_FDCWD, + file1_s2d2)); + EXPECT_EQ(EXDEV, errno); + _exit(_metadata->exit_code); + return; + } + + EXPECT_EQ(child_pid, waitpid(child_pid, &status, 0)); + EXPECT_EQ(1, WIFEXITED(status)); + EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + + ASSERT_EQ(0, rename(dir_s4d2, dir_s1d3)) + { + TH_LOG("Failed to rename %s back to %s: %s", dir_s4d1, dir_s1d3, + strerror(errno)); + } + + /* Now checks that we can access it under l2. */ + child_pid = fork(); + ASSERT_LE(0, child_pid); + if (child_pid == 0) { + enforce_ruleset(_metadata, ruleset_fd_l2); + EXPECT_EQ(0, close(ruleset_fd_l2)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(0, test_open(file1_s1d3, O_RDONLY)); + _exit(_metadata->exit_code); + return; + } + + EXPECT_EQ(child_pid, waitpid(child_pid, &status, 0)); + EXPECT_EQ(1, WIFEXITED(status)); + EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + + /* + * Also test that we can rename via a disconnected path. We move the + * dir back to the disconnected place first, then we rename file1 to + * file2 through our dir fd. + */ + ASSERT_EQ(0, rename(dir_s1d3, dir_s4d2)) + { + TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d2, + strerror(errno)); + } + ASSERT_EQ(0, + renameat(bind_s1d3_fd, file1_name, bind_s1d3_fd, file2_name)) + { + TH_LOG("Failed to rename %s to %s within disconnected %s: %s", + file1_name, file2_name, bind_dir_s1d3, strerror(errno)); + } + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY)); + ASSERT_EQ(0, renameat(bind_s1d3_fd, file2_name, AT_FDCWD, file1_s2d2)) + { + TH_LOG("Failed to rename %s to %s through disconnected %s: %s", + file2_name, file1_s2d2, bind_dir_s1d3, strerror(errno)); + } + EXPECT_EQ(0, test_open(file1_s2d2, O_RDONLY)); + EXPECT_EQ(0, test_open(file1_s1d2, O_RDONLY)); + + /* Move it back using the disconnected path as the target. */ + ASSERT_EQ(0, renameat(AT_FDCWD, file1_s2d2, bind_s1d3_fd, file1_name)) + { + TH_LOG("Failed to rename %s to %s through disconnected %s: %s", + file1_s1d2, file1_name, bind_dir_s1d3, strerror(errno)); + } + + /* Now make it connected again. */ + ASSERT_EQ(0, rename(dir_s4d2, dir_s1d3)) + { + TH_LOG("Failed to rename %s back to %s: %s", dir_s4d2, dir_s1d3, + strerror(errno)); + } + + /* Checks again that we can access it under l2. */ + enforce_ruleset(_metadata, ruleset_fd_l2); + EXPECT_EQ(0, close(ruleset_fd_l2)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(0, test_open(file1_s1d3, O_RDONLY)); +} + +/* + * Test that linkat(2) with disconnected paths works under Landlock. This + * test moves s1d3 to s4d1. + */ +TEST_F_FORK(layout1_bind, path_disconnected_link) +{ + /* Ruleset to be applied after renaming s1d3 to s4d1. */ + const struct rule layer1[] = { + { + .path = dir_s4d1, + .access = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_REMOVE_FILE, + }, + { + .path = dir_s2d2, + .access = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_REMOVE_FILE, + }, + {} + }; + int ruleset_fd, bind_s1d3_fd; + + /* Removes unneeded files created by layout1, otherwise it will EEXIST. */ + ASSERT_EQ(0, unlink(file1_s1d2)); + ASSERT_EQ(0, unlink(file2_s1d3)); + + bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC); + ASSERT_LE(0, bind_s1d3_fd); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + + /* Disconnects bind_s1d3_fd. */ + ASSERT_EQ(0, rename(dir_s1d3, dir_s4d1)) + { + TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d1, + strerror(errno)); + } + + /* Need this later to test different parent link. */ + ASSERT_EQ(0, mkdir(dir_s4d2, 0755)) + { + TH_LOG("Failed to create %s: %s", dir_s4d2, strerror(errno)); + } + + ruleset_fd = create_ruleset(_metadata, ACCESS_ALL, layer1); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + /* From disconnected to connected. */ + ASSERT_EQ(0, linkat(bind_s1d3_fd, file1_name, AT_FDCWD, file1_s2d2, 0)) + { + TH_LOG("Failed to link %s to %s via disconnected %s: %s", + file1_name, file1_s2d2, bind_dir_s1d3, strerror(errno)); + } + + /* Tests that we can access via the new link... */ + EXPECT_EQ(0, test_open(file1_s2d2, O_RDONLY)) + { + TH_LOG("Failed to open newly linked %s: %s", file1_s2d2, + strerror(errno)); + } + + /* ...as well as the old one. */ + EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY)) + { + TH_LOG("Failed to open original %s: %s", file1_s4d1, + strerror(errno)); + } + + /* From connected to disconnected. */ + ASSERT_EQ(0, unlink(file1_s4d1)); + ASSERT_EQ(0, linkat(AT_FDCWD, file1_s2d2, bind_s1d3_fd, file2_name, 0)) + { + TH_LOG("Failed to link %s to %s via disconnected %s: %s", + file1_s2d2, file2_name, bind_dir_s1d3, strerror(errno)); + } + EXPECT_EQ(0, test_open(file2_s4d1, O_RDONLY)); + ASSERT_EQ(0, unlink(file1_s2d2)); + + /* From disconnected to disconnected (same parent). */ + ASSERT_EQ(0, + linkat(bind_s1d3_fd, file2_name, bind_s1d3_fd, file1_name, 0)) + { + TH_LOG("Failed to link %s to %s within disconnected %s: %s", + file2_name, file1_name, bind_dir_s1d3, strerror(errno)); + } + EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY)) + { + TH_LOG("Failed to open newly linked %s: %s", file1_s4d1, + strerror(errno)); + } + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)) + { + TH_LOG("Failed to open %s through newly created link under disconnected path: %s", + file1_name, strerror(errno)); + } + ASSERT_EQ(0, unlink(file2_s4d1)); + + /* From disconnected to disconnected (different parent). */ + ASSERT_EQ(0, + linkat(bind_s1d3_fd, file1_name, bind_s1d3_fd, "s4d2/f1", 0)) + { + TH_LOG("Failed to link %s to %s within disconnected %s: %s", + file1_name, "s4d2/f1", bind_dir_s1d3, strerror(errno)); + } + EXPECT_EQ(0, test_open(file1_s4d2, O_RDONLY)) + { + TH_LOG("Failed to open %s after link: %s", file1_s4d2, + strerror(errno)); + } + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, "s4d2/f1", O_RDONLY)) + { + TH_LOG("Failed to open %s through disconnected path after link: %s", + "s4d2/f1", strerror(errno)); + } +} + +/* + * layout4_disconnected_leafs with bind mount and renames: + * + * tmp + * ├── s1d1 + * │   └── s1d2 [source of the bind mount] + * │ ├── s1d31 + * │   │ └── s1d41 [now renamed beneath s3d1] + * │ │ ├── f1 + * │ │ └── f2 + * │   └── s1d32 + * │ └── s1d42 [now renamed beneath s4d1] + * │ ├── f3 + * │ └── f4 + * ├── s2d1 + * │   └── s2d2 [bind mount of s1d2] + * │ ├── s1d31 + * │   │ └── s1d41 [opened FD, now renamed beneath s3d1] + * │ │ ├── f1 + * │ │ └── f2 + * │   └── s1d32 + * │ └── s1d42 [opened FD, now renamed beneath s4d1] + * │ ├── f3 + * │ └── f4 + * ├── s3d1 + * │  └── s1d41 [renamed here] + * │ ├── f1 + * │ └── f2 + * └── s4d1 + * └── s1d42 [renamed here] + * ├── f3 + * └── f4 + */ +/* clang-format off */ +FIXTURE(layout4_disconnected_leafs) { + int s2d2_fd; +}; +/* clang-format on */ + +FIXTURE_SETUP(layout4_disconnected_leafs) +{ + prepare_layout(_metadata); + + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f1"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f2"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f3"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f4"); + create_directory(_metadata, TMP_DIR "/s2d1/s2d2"); + create_directory(_metadata, TMP_DIR "/s3d1"); + create_directory(_metadata, TMP_DIR "/s4d1"); + + self->s2d2_fd = + open(TMP_DIR "/s2d1/s2d2", O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, self->s2d2_fd); + + set_cap(_metadata, CAP_SYS_ADMIN); + ASSERT_EQ(0, mount(TMP_DIR "/s1d1/s1d2", TMP_DIR "/s2d1/s2d2", NULL, + MS_BIND, NULL)); + clear_cap(_metadata, CAP_SYS_ADMIN); +} + +FIXTURE_TEARDOWN_PARENT(layout4_disconnected_leafs) +{ + /* umount(TMP_DIR "/s2d1") is handled by namespace lifetime. */ + + /* Removes files after renames. */ + remove_path(TMP_DIR "/s3d1/s1d41/f1"); + remove_path(TMP_DIR "/s3d1/s1d41/f2"); + remove_path(TMP_DIR "/s4d1/s1d42/f1"); + remove_path(TMP_DIR "/s4d1/s1d42/f3"); + remove_path(TMP_DIR "/s4d1/s1d42/f4"); + remove_path(TMP_DIR "/s4d1/s1d42/f5"); + + cleanup_layout(_metadata); +} + +FIXTURE_VARIANT(layout4_disconnected_leafs) +{ + /* + * Parent of the bind mount source. It should always be ignored when + * testing against files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_s1d1; + /* + * Source of bind mount (to s2d2). It should always be enforced when + * testing against files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_s1d2; + /* + * Original parent of s1d41. It should always be ignored when testing + * against files under the s1d41 disconnected directory. + */ + const __u64 allowed_s1d31; + /* + * Original parent of s1d42. It should always be ignored when testing + * against files under the s1d42 disconnected directory. + */ + const __u64 allowed_s1d32; + /* + * Opened and disconnected source directory. It should always be enforced + * when testing against files under the s1d41 disconnected directory. + */ + const __u64 allowed_s1d41; + /* + * Opened and disconnected source directory. It should always be enforced + * when testing against files under the s1d42 disconnected directory. + */ + const __u64 allowed_s1d42; + /* + * File in the s1d41 disconnected directory. It should always be enforced + * when testing against itself under the s1d41 disconnected directory. + */ + const __u64 allowed_f1; + /* + * File in the s1d41 disconnected directory. It should always be enforced + * when testing against itself under the s1d41 disconnected directory. + */ + const __u64 allowed_f2; + /* + * File in the s1d42 disconnected directory. It should always be enforced + * when testing against itself under the s1d42 disconnected directory. + */ + const __u64 allowed_f3; + /* + * Parent of the bind mount destination. It should always be enforced when + * testing against files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_s2d1; + /* + * Directory covered by the bind mount. It should always be ignored when + * testing against files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_s2d2; + /* + * New parent of the renamed s1d41. It should always be ignored when + * testing against files under the s1d41 disconnected directory. + */ + const __u64 allowed_s3d1; + /* + * New parent of the renamed s1d42. It should always be ignored when + * testing against files under the s1d42 disconnected directory. + */ + const __u64 allowed_s4d1; + + /* Expected result of the call to open([fd:s1d41]/f1, O_RDONLY). */ + const int expected_read_result; + /* Expected result of the call to renameat([fd:s1d41]/f1, [fd:s1d42]/f1). */ + const int expected_rename_result; + /* + * Expected result of the call to renameat([fd:s1d41]/f2, [fd:s1d42]/f3, + * RENAME_EXCHANGE). + */ + const int expected_exchange_result; + /* Expected result of the call to renameat([fd:s1d42]/f4, [fd:s1d42]/f5). */ + const int expected_same_dir_rename_result; +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d1_mount_src_parent) { + /* clang-format on */ + .allowed_s1d1 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_refer) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_create) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_rename) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d31_s1d32_old_parent) { + /* clang-format on */ + .allowed_s1d31 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s1d32 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_refer) { + /* clang-format on */ + .allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE, + .allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_create) { + /* clang-format on */ + .allowed_s1d41 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s1d42 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_even) { + /* clang-format on */ + .allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* The destination directory has more access right. */ +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_more) { + /* clang-format on */ + .allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_EXECUTE, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + /* Access denied. */ + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* The destination directory has less access right. */ +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_less) { + /* clang-format on */ + .allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_EXECUTE, + .allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + /* Access allowed. */ + .expected_rename_result = 0, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_create) { + /* clang-format on */ + .allowed_s2d1 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_refer) { + /* clang-format on */ + .allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_mini) { + /* clang-format on */ + .allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d2_covered_by_mount) { + /* clang-format on */ + .allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* Tests collect_domain_accesses(). */ +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_new_parent_refer) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_new_parent_create) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s4d1 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, + s3d1_s4d1_disconnected_rename_even){ + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* The destination directory has more access right. */ +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_disconnected_rename_more) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_EXECUTE, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + /* Access denied. */ + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* The destination directory has less access right. */ +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_disconnected_rename_less) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_EXECUTE, + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + /* Access allowed. */ + .expected_rename_result = 0, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, f1_f2_f3) { + /* clang-format on */ + .allowed_f1 = LANDLOCK_ACCESS_FS_READ_FILE, + .allowed_f2 = LANDLOCK_ACCESS_FS_READ_FILE, + .allowed_f3 = LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +TEST_F_FORK(layout4_disconnected_leafs, read_rename_exchange) +{ + const __u64 handled_access = + LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_MAKE_REG; + const struct rule rules[] = { + { + .path = TMP_DIR "/s1d1", + .access = variant->allowed_s1d1, + }, + { + .path = TMP_DIR "/s1d1/s1d2", + .access = variant->allowed_s1d2, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d31", + .access = variant->allowed_s1d31, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d32", + .access = variant->allowed_s1d32, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41", + .access = variant->allowed_s1d41, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d32/s1d42", + .access = variant->allowed_s1d42, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f1", + .access = variant->allowed_f1, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f2", + .access = variant->allowed_f2, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f3", + .access = variant->allowed_f3, + }, + { + .path = TMP_DIR "/s2d1", + .access = variant->allowed_s2d1, + }, + /* s2d2_fd */ + { + .path = TMP_DIR "/s3d1", + .access = variant->allowed_s3d1, + }, + { + .path = TMP_DIR "/s4d1", + .access = variant->allowed_s4d1, + }, + {}, + }; + int ruleset_fd, s1d41_bind_fd, s1d42_bind_fd; + + ruleset_fd = create_ruleset(_metadata, handled_access, rules); + ASSERT_LE(0, ruleset_fd); + + /* Adds rule for the covered directory. */ + if (variant->allowed_s2d2) { + ASSERT_EQ(0, landlock_add_rule( + ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, + &(struct landlock_path_beneath_attr){ + .parent_fd = self->s2d2_fd, + .allowed_access = + variant->allowed_s2d2, + }, + 0)); + } + EXPECT_EQ(0, close(self->s2d2_fd)); + + s1d41_bind_fd = open(TMP_DIR "/s2d1/s2d2/s1d31/s1d41", + O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, s1d41_bind_fd); + s1d42_bind_fd = open(TMP_DIR "/s2d1/s2d2/s1d32/s1d42", + O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, s1d42_bind_fd); + + /* Disconnects and checks source and destination directories. */ + EXPECT_EQ(0, test_open_rel(s1d41_bind_fd, "..", O_DIRECTORY)); + EXPECT_EQ(0, test_open_rel(s1d42_bind_fd, "..", O_DIRECTORY)); + /* Renames to make it accessible through s3d1/s1d41 */ + ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s1d1/s1d2/s1d31/s1d41", + AT_FDCWD, TMP_DIR "/s3d1/s1d41")); + /* Renames to make it accessible through s4d1/s1d42 */ + ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s1d1/s1d2/s1d32/s1d42", + AT_FDCWD, TMP_DIR "/s4d1/s1d42")); + EXPECT_EQ(ENOENT, test_open_rel(s1d41_bind_fd, "..", O_DIRECTORY)); + EXPECT_EQ(ENOENT, test_open_rel(s1d42_bind_fd, "..", O_DIRECTORY)); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + EXPECT_EQ(variant->expected_read_result, + test_open_rel(s1d41_bind_fd, "f1", O_RDONLY)); + + EXPECT_EQ(variant->expected_rename_result, + test_renameat(s1d41_bind_fd, "f1", s1d42_bind_fd, "f1")); + EXPECT_EQ(variant->expected_exchange_result, + test_exchangeat(s1d41_bind_fd, "f2", s1d42_bind_fd, "f3")); + + EXPECT_EQ(variant->expected_same_dir_rename_result, + test_renameat(s1d42_bind_fd, "f4", s1d42_bind_fd, "f5")); +} + +/* + * layout5_disconnected_branch before rename: + * + * tmp + * ├── s1d1 + * │   └── s1d2 [source of the first bind mount] + * │   └── s1d3 + * │   ├── s1d41 + * │   │   ├── f1 + * │   │   └── f2 + * │   └── s1d42 + * │   ├── f3 + * │   └── f4 + * ├── s2d1 + * │   └── s2d2 [source of the second bind mount] + * │   └── s2d3 + * │   └── s2d4 [first s1d2 bind mount] + * │   └── s1d3 + * │   ├── s1d41 + * │   │   ├── f1 + * │   │   └── f2 + * │   └── s1d42 + * │   ├── f3 + * │   └── f4 + * ├── s3d1 + * │   └── s3d2 [second s2d2 bind mount] + * │   └── s2d3 + * │   └── s2d4 [first s1d2 bind mount] + * │   └── s1d3 + * │   ├── s1d41 + * │   │   ├── f1 + * │   │   └── f2 + * │   └── s1d42 + * │   ├── f3 + * │   └── f4 + * └── s4d1 + * + * After rename: + * + * tmp + * ├── s1d1 + * │   └── s1d2 [source of the first bind mount] + * │   └── s1d3 + * │   ├── s1d41 + * │   │   ├── f1 + * │   │   └── f2 + * │   └── s1d42 + * │   ├── f3 + * │   └── f4 + * ├── s2d1 + * │   └── s2d2 [source of the second bind mount] + * ├── s3d1 + * │   └── s3d2 [second s2d2 bind mount] + * └── s4d1 + * └── s2d3 [renamed here] + * └── s2d4 [first s1d2 bind mount] + * └── s1d3 + * ├── s1d41 + * │   ├── f1 + * │   └── f2 + * └── s1d42 + * ├── f3 + * └── f4 + * + * Decision path for access from the s3d1/s3d2/s2d3/s2d4/s1d3 file descriptor: + * 1. first bind mount: s1d3 -> s1d2 + * 2. second bind mount: s2d3 + * 3. tmp mount: s4d1 -> tmp [disconnected branch] + * 4. second bind mount: s2d2 + * 5. tmp mount: s3d1 -> tmp + * 6. parent mounts: [...] -> / + * + * The s4d1 directory is evaluated even if it is not in the s2d2 mount. + */ + +/* clang-format off */ +FIXTURE(layout5_disconnected_branch) { + int s2d4_fd, s3d2_fd; +}; +/* clang-format on */ + +FIXTURE_SETUP(layout5_disconnected_branch) +{ + prepare_layout(_metadata); + + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f1"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f2"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f3"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f4"); + create_directory(_metadata, TMP_DIR "/s2d1/s2d2/s2d3/s2d4"); + create_directory(_metadata, TMP_DIR "/s3d1/s3d2"); + create_directory(_metadata, TMP_DIR "/s4d1"); + + self->s2d4_fd = open(TMP_DIR "/s2d1/s2d2/s2d3/s2d4", + O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, self->s2d4_fd); + + self->s3d2_fd = + open(TMP_DIR "/s3d1/s3d2", O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, self->s3d2_fd); + + set_cap(_metadata, CAP_SYS_ADMIN); + ASSERT_EQ(0, mount(TMP_DIR "/s1d1/s1d2", TMP_DIR "/s2d1/s2d2/s2d3/s2d4", + NULL, MS_BIND, NULL)); + ASSERT_EQ(0, mount(TMP_DIR "/s2d1/s2d2", TMP_DIR "/s3d1/s3d2", NULL, + MS_BIND | MS_REC, NULL)); + clear_cap(_metadata, CAP_SYS_ADMIN); +} + +FIXTURE_TEARDOWN_PARENT(layout5_disconnected_branch) +{ + /* Bind mounts are handled by namespace lifetime. */ + + /* Removes files after renames. */ + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f1"); + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f2"); + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f1"); + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f3"); + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f4"); + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f5"); + + cleanup_layout(_metadata); +} + +FIXTURE_VARIANT(layout5_disconnected_branch) +{ + /* + * Parent of all files. It should always be enforced when testing against + * files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_base; + /* + * Parent of the first bind mount source. It should always be ignored when + * testing against files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_s1d1; + const __u64 allowed_s1d2; + const __u64 allowed_s1d3; + const __u64 allowed_s2d1; + const __u64 allowed_s2d2; + const __u64 allowed_s2d3; + const __u64 allowed_s2d4; + const __u64 allowed_s3d1; + const __u64 allowed_s3d2; + const __u64 allowed_s4d1; + + /* Expected result of the call to open([fd:s1d3]/s1d41/f1, O_RDONLY). */ + const int expected_read_result; + /* + * Expected result of the call to renameat([fd:s1d3]/s1d41/f1, + * [fd:s1d3]/s1d42/f1). + */ + const int expected_rename_result; + /* + * Expected result of the call to renameat([fd:s1d3]/s1d41/f2, + * [fd:s1d3]/s1d42/f3, RENAME_EXCHANGE). + */ + const int expected_exchange_result; + /* + * Expected result of the call to renameat([fd:s1d3]/s1d42/f4, + * [fd:s1d3]/s1d42/f5). + */ + const int expected_same_dir_rename_result; +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d1_mount1_src_parent) { + /* clang-format on */ + .allowed_s1d1 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_refer) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_create) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_rename) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_refer) { + /* clang-format on */ + .allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_create) { + /* clang-format on */ + .allowed_s1d3 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_rename) { + /* clang-format on */ + .allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_full) { + /* clang-format on */ + .allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d1_mount2_src_parent) { + /* clang-format on */ + .allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_refer) { + /* clang-format on */ + .allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_create) { + /* clang-format on */ + .allowed_s2d2 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_rename) { + /* clang-format on */ + .allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_refer) { + /* clang-format on */ + .allowed_s2d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_create) { + /* clang-format on */ + .allowed_s2d3 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_rename) { + /* clang-format on */ + .allowed_s2d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d4_mount1_dst) { + /* clang-format on */ + .allowed_s2d4 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_refer) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_create) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_rename) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d2_mount1_dst) { + /* clang-format on */ + .allowed_s3d2 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_refer) { + /* clang-format on */ + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_create) { + /* clang-format on */ + .allowed_s4d1 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_rename) { + /* clang-format on */ + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +TEST_F_FORK(layout5_disconnected_branch, read_rename_exchange) +{ + const __u64 handled_access = + LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_MAKE_REG; + const struct rule rules[] = { + { + .path = TMP_DIR "/s1d1", + .access = variant->allowed_s1d1, + }, + { + .path = TMP_DIR "/s1d1/s1d2", + .access = variant->allowed_s1d2, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d3", + .access = variant->allowed_s1d3, + }, + { + .path = TMP_DIR "/s2d1", + .access = variant->allowed_s2d1, + }, + { + .path = TMP_DIR "/s2d1/s2d2", + .access = variant->allowed_s2d2, + }, + { + .path = TMP_DIR "/s2d1/s2d2/s2d3", + .access = variant->allowed_s2d3, + }, + /* s2d4_fd */ + { + .path = TMP_DIR "/s3d1", + .access = variant->allowed_s3d1, + }, + /* s3d2_fd */ + { + .path = TMP_DIR "/s4d1", + .access = variant->allowed_s4d1, + }, + {}, + }; + int ruleset_fd, s1d3_bind_fd; + + ruleset_fd = create_ruleset(_metadata, handled_access, rules); + ASSERT_LE(0, ruleset_fd); + + /* Adds rules for the covered directories. */ + if (variant->allowed_s2d4) { + ASSERT_EQ(0, landlock_add_rule( + ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, + &(struct landlock_path_beneath_attr){ + .parent_fd = self->s2d4_fd, + .allowed_access = + variant->allowed_s2d4, + }, + 0)); + } + EXPECT_EQ(0, close(self->s2d4_fd)); + + if (variant->allowed_s3d2) { + ASSERT_EQ(0, landlock_add_rule( + ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, + &(struct landlock_path_beneath_attr){ + .parent_fd = self->s3d2_fd, + .allowed_access = + variant->allowed_s3d2, + }, + 0)); + } + EXPECT_EQ(0, close(self->s3d2_fd)); + + s1d3_bind_fd = open(TMP_DIR "/s3d1/s3d2/s2d3/s2d4/s1d3", + O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, s1d3_bind_fd); + + /* Disconnects and checks source and destination directories. */ + EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "..", O_DIRECTORY)); + EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "../..", O_DIRECTORY)); + /* Renames to make it accessible through s3d1/s1d41 */ + ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s2d1/s2d2/s2d3", + AT_FDCWD, TMP_DIR "/s4d1/s2d3")); + EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "..", O_DIRECTORY)); + EXPECT_EQ(ENOENT, test_open_rel(s1d3_bind_fd, "../..", O_DIRECTORY)); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + EXPECT_EQ(variant->expected_read_result, + test_open_rel(s1d3_bind_fd, "s1d41/f1", O_RDONLY)); + + EXPECT_EQ(variant->expected_rename_result, + test_renameat(s1d3_bind_fd, "s1d41/f1", s1d3_bind_fd, + "s1d42/f1")); + EXPECT_EQ(variant->expected_exchange_result, + test_exchangeat(s1d3_bind_fd, "s1d41/f2", s1d3_bind_fd, + "s1d42/f3")); + + EXPECT_EQ(variant->expected_same_dir_rename_result, + test_renameat(s1d3_bind_fd, "s1d42/f4", s1d3_bind_fd, + "s1d42/f5")); +} + +#define LOWER_BASE TMP_DIR "/lower" +#define LOWER_DATA LOWER_BASE "/data" +static const char lower_fl1[] = LOWER_DATA "/fl1"; +static const char lower_dl1[] = LOWER_DATA "/dl1"; +static const char lower_dl1_fl2[] = LOWER_DATA "/dl1/fl2"; +static const char lower_fo1[] = LOWER_DATA "/fo1"; +static const char lower_do1[] = LOWER_DATA "/do1"; +static const char lower_do1_fo2[] = LOWER_DATA "/do1/fo2"; +static const char lower_do1_fl3[] = LOWER_DATA "/do1/fl3"; + +static const char (*lower_base_files[])[] = { + &lower_fl1, + &lower_fo1, + NULL, +}; +static const char (*lower_base_directories[])[] = { + &lower_dl1, + &lower_do1, + NULL, +}; +static const char (*lower_sub_files[])[] = { + &lower_dl1_fl2, + &lower_do1_fo2, + &lower_do1_fl3, + NULL, +}; + +#define UPPER_BASE TMP_DIR "/upper" +#define UPPER_DATA UPPER_BASE "/data" +#define UPPER_WORK UPPER_BASE "/work" +static const char upper_fu1[] = UPPER_DATA "/fu1"; +static const char upper_du1[] = UPPER_DATA "/du1"; +static const char upper_du1_fu2[] = UPPER_DATA "/du1/fu2"; +static const char upper_fo1[] = UPPER_DATA "/fo1"; +static const char upper_do1[] = UPPER_DATA "/do1"; +static const char upper_do1_fo2[] = UPPER_DATA "/do1/fo2"; +static const char upper_do1_fu3[] = UPPER_DATA "/do1/fu3"; + +static const char (*upper_base_files[])[] = { + &upper_fu1, + &upper_fo1, + NULL, +}; +static const char (*upper_base_directories[])[] = { + &upper_du1, + &upper_do1, + NULL, +}; +static const char (*upper_sub_files[])[] = { + &upper_du1_fu2, + &upper_do1_fo2, + &upper_do1_fu3, + NULL, +}; + +#define MERGE_BASE TMP_DIR "/merge" +#define MERGE_DATA MERGE_BASE "/data" +static const char merge_fl1[] = MERGE_DATA "/fl1"; +static const char merge_dl1[] = MERGE_DATA "/dl1"; +static const char merge_dl1_fl2[] = MERGE_DATA "/dl1/fl2"; +static const char merge_fu1[] = MERGE_DATA "/fu1"; +static const char merge_du1[] = MERGE_DATA "/du1"; +static const char merge_du1_fu2[] = MERGE_DATA "/du1/fu2"; +static const char merge_fo1[] = MERGE_DATA "/fo1"; +static const char merge_do1[] = MERGE_DATA "/do1"; +static const char merge_do1_fo2[] = MERGE_DATA "/do1/fo2"; +static const char merge_do1_fl3[] = MERGE_DATA "/do1/fl3"; +static const char merge_do1_fu3[] = MERGE_DATA "/do1/fu3"; + +static const char (*merge_base_files[])[] = { + &merge_fl1, + &merge_fu1, + &merge_fo1, + NULL, +}; +static const char (*merge_base_directories[])[] = { + &merge_dl1, + &merge_du1, + &merge_do1, + NULL, +}; +static const char (*merge_sub_files[])[] = { + &merge_dl1_fl2, &merge_du1_fu2, &merge_do1_fo2, + &merge_do1_fl3, &merge_do1_fu3, NULL, +}; + +/* + * layout2_overlay hierarchy: + * + * tmp + * ├── lower + * │   └── data + * │   ├── dl1 + * │   │   └── fl2 + * │   ├── do1 + * │   │   ├── fl3 + * │   │   └── fo2 * │   ├── fl1 * │   └── fo1 * ├── merge @@ -5857,7 +7512,7 @@ TEST_F(audit_layout1, make_char) .handled_access_fs = access_fs_16, }); - EXPECT_EQ(-1, mknod(file1_s1d3, S_IFCHR | 0644, 0)); + EXPECT_EQ(-1, mknod(file1_s1d3, S_IFCHR | 0644, makedev(7, 0))); EXPECT_EQ(EACCES, errno); EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_char", dir_s1d3)); @@ -5867,6 +7522,27 @@ TEST_F(audit_layout1, make_char) EXPECT_EQ(1, records.domain); } +TEST_F(audit_layout1, make_whiteout) +{ + struct audit_records records; + + EXPECT_EQ(0, unlink(file1_s1d3)); + + drop_access_rights(_metadata, &(struct landlock_ruleset_attr){ + .handled_access_fs = access_fs_16, + }); + + /* Whiteout creation is denied and logged as fs.make_reg. */ + EXPECT_EQ(-1, mknod(file1_s1d3, S_IFCHR | 0644, makedev(0, 0))); + EXPECT_EQ(EACCES, errno); + EXPECT_EQ(0, matches_log_fs(_metadata, self->audit_fd, "fs\\.make_reg", + dir_s1d3)); + + EXPECT_EQ(0, audit_count_records(self->audit_fd, &records)); + EXPECT_EQ(0, records.access); + EXPECT_EQ(1, records.domain); +} + TEST_F(audit_layout1, make_dir) { struct audit_records records; diff --git a/tools/testing/selftests/landlock/net_test.c b/tools/testing/selftests/landlock/net_test.c index 6fecd36f74c6..8f3a780d354b 100644 --- a/tools/testing/selftests/landlock/net_test.c +++ b/tools/testing/selftests/landlock/net_test.c @@ -258,6 +258,64 @@ static int connect_variant(const int sock_fd, return connect_variant_addrlen(sock_fd, srv, get_addrlen(srv, false)); } +static int sendto_variant_addrlen(const int sock_fd, + const struct service_fixture *const srv, + const socklen_t addrlen, void *buf, + size_t len, size_t flags) +{ + const struct sockaddr *dst = NULL; + ssize_t ret; + + /* + * We never want our processes to be killed by SIGPIPE: we check return + * codes and errno, so that we have actual error messages. + */ + flags |= MSG_NOSIGNAL; + + if (srv != NULL) { + switch (srv->protocol.domain) { + case AF_UNSPEC: + case AF_INET: + dst = (const struct sockaddr *)&srv->ipv4_addr; + break; + + case AF_INET6: + dst = (const struct sockaddr *)&srv->ipv6_addr; + break; + + case AF_UNIX: + dst = (const struct sockaddr *)&srv->unix_addr; + break; + + default: + errno = EAFNOSUPPORT; + return -errno; + } + } + + ret = sendto(sock_fd, buf, len, flags, dst, addrlen); + if (ret < 0) + return -errno; + + /* errno is not set in cases of partial writes. */ + if (ret != len) + return -EINTR; + + return 0; +} + +static int sendto_variant(const int sock_fd, + const struct service_fixture *const srv, void *buf, + size_t len, size_t flags) +{ + socklen_t addrlen = 0; + + if (srv != NULL) + addrlen = get_addrlen(srv, false); + + return sendto_variant_addrlen(sock_fd, srv, addrlen, buf, len, flags); +} + FIXTURE(protocol) { struct service_fixture srv0, srv1, srv2, unspec_any0, unspec_srv0; @@ -906,7 +964,19 @@ TEST_F(protocol, connect_unspec) EXPECT_EQ(0, close(ruleset_fd)); } - ret = connect_variant(connect_fd, &self->unspec_any0); + /* Try to re-disconnect with a truncated address struct. */ + EXPECT_EQ(-EINVAL, + connect_variant_addrlen( + connect_fd, &self->unspec_any0, + get_addrlen(&self->unspec_any0, true) - 1)); + + /* + * Re-disconnect, with a minimal sockaddr struct (just a + * bare af_family=AF_UNSPEC field). + */ + ret = connect_variant_addrlen(connect_fd, &self->unspec_any0, + get_addrlen(&self->unspec_any0, + true)); if (self->srv0.protocol.domain == AF_UNIX && self->srv0.protocol.type == SOCK_STREAM) { EXPECT_EQ(-EINVAL, ret); @@ -938,6 +1008,103 @@ TEST_F(protocol, connect_unspec) EXPECT_EQ(0, close(bind_fd)); } +TEST_F(protocol, tcp_fastopen) +{ + const bool restricted = variant->sandbox == TCP_SANDBOX && + variant->prot.type == SOCK_STREAM && + (variant->prot.protocol == IPPROTO_TCP || + variant->prot.protocol == IPPROTO_IP) && + (variant->prot.domain == AF_INET || + variant->prot.domain == AF_INET6); + const struct landlock_ruleset_attr ruleset_attr = { + .handled_access_net = LANDLOCK_ACCESS_NET_CONNECT_TCP, + }; + int bind_fd, client_fd, status; + char buf; + pid_t child; + + bind_fd = socket_variant(&self->srv0); + ASSERT_LE(0, bind_fd); + EXPECT_EQ(0, bind_variant(bind_fd, &self->srv0)); + if (self->srv0.protocol.type == SOCK_STREAM) + EXPECT_EQ(0, listen(bind_fd, backlog)); + + child = fork(); + ASSERT_LE(0, child); + if (child == 0) { + int connect_fd, ret; + + /* Closes listening socket for the child. */ + EXPECT_EQ(0, close(bind_fd)); + + connect_fd = socket_variant(&self->srv0); + ASSERT_LE(0, connect_fd); + + if (variant->sandbox == TCP_SANDBOX) { + const int ruleset_fd = landlock_create_ruleset( + &ruleset_attr, sizeof(ruleset_attr), 0); + ASSERT_LE(0, ruleset_fd); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + } + + /* Fast Open with no address. */ + ret = sendto_variant(connect_fd, NULL, NULL, 0, MSG_FASTOPEN); + if (self->srv0.protocol.domain == AF_UNIX) { + EXPECT_EQ(-ENOTCONN, ret); + } else if (self->srv0.protocol.type == SOCK_DGRAM) { + EXPECT_EQ(-EDESTADDRREQ, ret); + } else { + EXPECT_EQ(-EINVAL, ret); + } + + /* Fast Open to a denied address. */ + ret = sendto_variant(connect_fd, &self->srv0, "A", 1, + MSG_FASTOPEN); + if (restricted) { + EXPECT_EQ(-EACCES, ret); + } else if (self->srv0.protocol.domain == AF_UNIX && + self->srv0.protocol.type == SOCK_STREAM) { + EXPECT_EQ(-EOPNOTSUPP, ret); + } else { + EXPECT_EQ(0, ret); + } + + EXPECT_EQ(0, close(connect_fd)); + _exit(_metadata->exit_code); + return; + } + + client_fd = bind_fd; + if (!restricted && self->srv0.protocol.type == SOCK_STREAM && + self->srv0.protocol.domain != AF_UNIX) { + client_fd = accept(bind_fd, NULL, 0); + ASSERT_LE(0, client_fd); + } + + if (restricted) { + EXPECT_EQ(-1, read(client_fd, &buf, 1)); + EXPECT_EQ(ENOTCONN, errno); + } else if (self->srv0.protocol.domain == AF_UNIX && + self->srv0.protocol.type == SOCK_STREAM) { + EXPECT_EQ(-1, read(client_fd, &buf, 1)); + EXPECT_EQ(EINVAL, errno); + } else { + EXPECT_EQ(1, read(client_fd, &buf, 1)); + EXPECT_EQ('A', buf); + } + + EXPECT_EQ(child, waitpid(child, &status, 0)); + EXPECT_EQ(1, WIFEXITED(status)); + EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + + if (client_fd != bind_fd) + EXPECT_LE(0, close(client_fd)); + + EXPECT_EQ(0, close(bind_fd)); +} + FIXTURE(ipv4) { struct service_fixture srv0, srv1;