From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
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 <gregkh@linuxfoundation.org>
Subject: Re: Linux 7.2.8
Date: Fri, 25 Sep 2026 16:46:02 +0200 [thread overview]
Message-ID: <2026092502-yippee-sedation-7579@gregkh> (raw)
In-Reply-To: <2026092502-collapse-bully-a8f5@gregkh>
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/arch/arm64/memory-tagging-extension.rst b/Documentation/arch/arm64/memory-tagging-extension.rst
index e6fe428f0e2a..1d32fc5df183 100644
--- a/Documentation/arch/arm64/memory-tagging-extension.rst
+++ b/Documentation/arch/arm64/memory-tagging-extension.rst
@@ -208,11 +208,10 @@ will use the corresponding aligned address.
tracer's space cannot be accessed or does not have valid tags.
- ``-EPERM`` - the specified process cannot be traced.
- ``-EIO`` - the tracee's address range cannot be accessed (e.g. invalid
- address) and no tags copied. ``iov_len`` not updated.
+ address) or does not have valid tags (not mapped with the ``PROT_MTE``
+ flag) and no tags copied. ``iov_len`` not updated.
- ``-EFAULT`` - fault on accessing the tracer's memory (``struct iovec``
or ``iov_base`` buffer) and no tags copied. ``iov_len`` not updated.
-- ``-EOPNOTSUPP`` - the tracee's address does not have valid tags (never
- mapped with the ``PROT_MTE`` flag). ``iov_len`` not updated.
**Note**: There are no transient errors for the requests above, so user
programs should not retry in case of a non-zero system call return.
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 0f46ef313590..c8e55c98d564 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 208f46967ee5..f7af0286341c 100644
--- a/Documentation/networking/ip-sysctl.rst
+++ b/Documentation/networking/ip-sysctl.rst
@@ -248,7 +248,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
@@ -874,6 +874,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 c28f11c617a4..ad1a1ffe789e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
VERSION = 7
PATCHLEVEL = 2
-SUBLEVEL = 7
+SUBLEVEL = 8
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/altera/socfpga_stratix10_socdk.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dtsi
old mode 100755
new mode 100644
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_emmc.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk_emmc.dts
old mode 100755
new mode 100644
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-an400.dts b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-an400.dts
index cab2ee9ea0d3..ca7536f772ff 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-an400.dts
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-an400.dts
@@ -33,7 +33,7 @@ xtal: xtal-clk {
};
&uart_a {
- clocks = <&xtal>, <&xtal>, <&xtal>;
+ clocks = <&xtal>, <&clkc_periphs CLKID_SYS_UART_A>, <&xtal>;
clock-names = "xtal", "pclk", "baud";
status = "okay";
};
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
index c41525a34b72..77abfd555ec5 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
@@ -71,7 +71,6 @@ sd_3v3: regulator-sdcard-3v3 {
vin-supply = <&vddao_3v3>;
gpio = <&gpio GPIOD_11 GPIO_ACTIVE_LOW>;
regulator-boot-on;
- regulator-always-on;
};
sdio_pwrseq: sdio-pwrseq {
@@ -105,6 +104,66 @@ vcc5v0_usb: regulator-vcc-usb {
enable-active-high;
};
+ vdd_ddr: regulator-vddddr {
+ /*
+ * SY8003ADFC Regulator.
+ */
+ compatible = "pwm-regulator";
+ regulator-name = "VDDDDR";
+ regulator-min-microvolt = <690000>;
+ regulator-max-microvolt = <890000>;
+ pwm-supply = <&dc_in>;
+ pwms = <&pwm_ao_gh 0 1500 0>;
+ pwm-dutycycle-range = <100 0>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vdd_ee: regulator-vddee {
+ /*
+ * MP8756GD Regulator.
+ */
+ compatible = "pwm-regulator";
+ regulator-name = "VDDEE";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <922000>;
+ pwm-supply = <&dc_in>;
+ pwms = <&pwm_ao_ab 0 1500 0>;
+ pwm-dutycycle-range = <100 0>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vdd_gpu: regulator-vddgpu {
+ /*
+ * SY8003ADFC Regulator.
+ */
+ compatible = "pwm-regulator";
+ regulator-name = "VDDGPU";
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <922000>;
+ pwm-supply = <&dc_in>;
+ pwms = <&pwm_ao_ef 0 1500 0>;
+ pwm-dutycycle-range = <100 0>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vdd_npu: regulator-vddnpu {
+ /*
+ * SY8003ADFC Regulator.
+ */
+ compatible = "pwm-regulator";
+ regulator-name = "VDDNPU";
+ regulator-min-microvolt = <733000>;
+ regulator-max-microvolt = <933000>;
+ pwm-supply = <&dc_in>;
+ pwms = <&pwm_ao_ef 1 1500 0>;
+ pwm-dutycycle-range = <100 0>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
vddao_1v8: regulator-vddao-1v8 {
compatible = "regulator-fixed";
regulator-name = "VDDAO_1V8";
@@ -123,6 +182,36 @@ vddao_3v3: regulator-vddao-3v3 {
regulator-always-on;
};
+ vddcpu_a: regulator-vddcpu-a {
+ /*
+ * MP8756GD Regulator.
+ */
+ compatible = "pwm-regulator";
+ regulator-name = "VDDCPU_A";
+ regulator-min-microvolt = <689000>;
+ regulator-max-microvolt = <1049000>;
+ pwm-supply = <&dc_in>;
+ pwms = <&pwm_ao_cd 1 1500 0>;
+ pwm-dutycycle-range = <100 0>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vddcpu_b: regulator-vddcpu-b {
+ /*
+ * MP8756GD Regulator.
+ */
+ compatible = "pwm-regulator";
+ regulator-name = "VDDCPU_B";
+ regulator-min-microvolt = <689000>;
+ regulator-max-microvolt = <1049000>;
+ pwm-supply = <&dc_in>;
+ pwms = <&pwm_ao_ab 1 1500 0>;
+ pwm-dutycycle-range = <100 0>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
vddio_1v8: regulator-vddio-1v8 {
compatible = "regulator-fixed";
regulator-name = "VDDIO_1V8";
@@ -173,9 +262,27 @@ &pwm_ab {
pinctrl-names = "default";
};
+&pwm_ao_ab {
+ status = "okay";
+ pinctrl-0 = <&pwm_ao_a_pins>, <&pwm_ao_b_pins>;
+ pinctrl-names = "default";
+};
+
&pwm_ao_cd {
status = "okay";
- pinctrl-0 = <&pwm_ao_c_d_pins>;
+ pinctrl-0 = <&pwm_ao_c_d_pins>, <&pwm_ao_d_pins>;
+ pinctrl-names = "default";
+};
+
+&pwm_ao_ef {
+ status = "okay";
+ pinctrl-0 = <&pwm_ao_e_pins>, <&pwm_ao_f_pins>;
+ pinctrl-names = "default";
+};
+
+&pwm_ao_gh {
+ status = "okay";
+ pinctrl-0 = <&pwm_ao_g_e_pins>;
pinctrl-names = "default";
};
@@ -266,6 +373,6 @@ &sd_emmc_c {
&uart_a {
status = "okay";
- clocks = <&xtal>, <&xtal>, <&xtal>;
+ clocks = <&xtal>, <&clkc_periphs CLKID_SYS_UART_A>, <&xtal>;
clock-names = "xtal", "pclk", "baud";
};
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index cc371fcd1896..1711e24cce17 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -458,9 +458,25 @@ mux {
};
};
- pwm_ao_g_pins: pwm-ao-g {
+ pwm_ao_g_d11_pins: pwm-ao-g-d11 {
mux {
- groups = "pwm_ao_g";
+ groups = "pwm_ao_g_d11";
+ function = "pwm_ao_g";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_g_d7_pins: pwm-ao-g-d7 {
+ mux {
+ groups = "pwm_ao_g_d7";
+ function = "pwm_ao_g";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_g_e_pins: pwm-ao-g-e {
+ mux {
+ groups = "pwm_ao_g_e";
function = "pwm_ao_g";
bias-disable;
};
@@ -474,9 +490,17 @@ mux {
};
};
- pwm_ao_h_pins: pwm-ao-h {
+ pwm_ao_h_d5_pins: pwm-ao-h-d5 {
mux {
- groups = "pwm_ao_h";
+ groups = "pwm_ao_h_d5";
+ function = "pwm_ao_h";
+ bias-disable;
+ };
+ };
+
+ pwm_ao_h_d10_pins: pwm-ao-h-d10 {
+ mux {
+ groups = "pwm_ao_h_d10";
function = "pwm_ao_h";
bias-disable;
};
@@ -522,9 +546,17 @@ mux {
};
};
- pwm_vs_pins: pwm-vs {
+ pwm_vs_y_pins: pwm-vs-y {
+ mux {
+ groups = "pwm_vs_y";
+ function = "pwm_vs";
+ bias-disable;
+ };
+ };
+
+ pwm_vs_h_pins: pwm-vs-h {
mux {
- groups = "pwm_vs";
+ groups = "pwm_vs_h";
function = "pwm_vs";
bias-disable;
};
diff --git a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi
index cbb161c863ac..a5118c2f2742 100644
--- a/arch/arm64/boot/dts/renesas/r8a779f0.dtsi
+++ b/arch/arm64/boot/dts/renesas/r8a779f0.dtsi
@@ -901,6 +901,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 b6193c158370..4de93fceb605 100644
--- a/arch/arm64/boot/dts/renesas/r9a09g047.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a09g047.dtsi
@@ -1394,23 +1394,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>;
};
@@ -1494,23 +1499,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 5a3a6f72029a..6e1444b80a28 100644
--- a/arch/arm64/boot/dts/renesas/r9a09g056.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a09g056.dtsi
@@ -1569,23 +1569,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>;
};
@@ -1670,23 +1675,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 1e94366bb7ee..99d197f309d0 100644
--- a/arch/arm64/boot/dts/renesas/r9a09g057.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a09g057.dtsi
@@ -1559,23 +1559,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>;
};
@@ -1660,23 +1665,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/r9a09g077.dtsi b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi
index 40494159831d..bac39390ead7 100644
--- a/arch/arm64/boot/dts/renesas/r9a09g077.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a09g077.dtsi
@@ -642,36 +642,45 @@ queue7 {
mtl_tx_setup0: tx-queues-config {
snps,tx-queues-to-use = <8>;
+ snps,tx-sched-wrr;
queue0 {
+ snps,weight = <0x10>;
snps,dcb-algorithm;
};
queue1 {
+ snps,weight = <0x11>;
snps,dcb-algorithm;
};
queue2 {
+ snps,weight = <0x12>;
snps,dcb-algorithm;
};
queue3 {
+ snps,weight = <0x13>;
snps,dcb-algorithm;
};
queue4 {
+ snps,weight = <0x14>;
snps,dcb-algorithm;
};
queue5 {
+ snps,weight = <0x15>;
snps,dcb-algorithm;
};
queue6 {
+ snps,weight = <0x16>;
snps,dcb-algorithm;
};
queue7 {
+ snps,weight = <0x17>;
snps,dcb-algorithm;
};
};
@@ -788,36 +797,45 @@ queue7 {
mtl_tx_setup1: tx-queues-config {
snps,tx-queues-to-use = <8>;
+ snps,tx-sched-wrr;
queue0 {
+ snps,weight = <0x10>;
snps,dcb-algorithm;
};
queue1 {
+ snps,weight = <0x11>;
snps,dcb-algorithm;
};
queue2 {
+ snps,weight = <0x12>;
snps,dcb-algorithm;
};
queue3 {
+ snps,weight = <0x13>;
snps,dcb-algorithm;
};
queue4 {
+ snps,weight = <0x14>;
snps,dcb-algorithm;
};
queue5 {
+ snps,weight = <0x15>;
snps,dcb-algorithm;
};
queue6 {
+ snps,weight = <0x16>;
snps,dcb-algorithm;
};
queue7 {
+ snps,weight = <0x17>;
snps,dcb-algorithm;
};
};
@@ -934,36 +952,45 @@ queue7 {
mtl_tx_setup2: tx-queues-config {
snps,tx-queues-to-use = <8>;
+ snps,tx-sched-wrr;
queue0 {
+ snps,weight = <0x10>;
snps,dcb-algorithm;
};
queue1 {
+ snps,weight = <0x11>;
snps,dcb-algorithm;
};
queue2 {
+ snps,weight = <0x12>;
snps,dcb-algorithm;
};
queue3 {
+ snps,weight = <0x13>;
snps,dcb-algorithm;
};
queue4 {
+ snps,weight = <0x14>;
snps,dcb-algorithm;
};
queue5 {
+ snps,weight = <0x15>;
snps,dcb-algorithm;
};
queue6 {
+ snps,weight = <0x16>;
snps,dcb-algorithm;
};
queue7 {
+ snps,weight = <0x17>;
snps,dcb-algorithm;
};
};
diff --git a/arch/arm64/boot/dts/renesas/r9a09g087.dtsi b/arch/arm64/boot/dts/renesas/r9a09g087.dtsi
index e8d4f76949cc..03b976d93e10 100644
--- a/arch/arm64/boot/dts/renesas/r9a09g087.dtsi
+++ b/arch/arm64/boot/dts/renesas/r9a09g087.dtsi
@@ -643,36 +643,45 @@ queue7 {
mtl_tx_setup0: tx-queues-config {
snps,tx-queues-to-use = <8>;
+ snps,tx-sched-wrr;
queue0 {
+ snps,weight = <0x10>;
snps,dcb-algorithm;
};
queue1 {
+ snps,weight = <0x11>;
snps,dcb-algorithm;
};
queue2 {
+ snps,weight = <0x12>;
snps,dcb-algorithm;
};
queue3 {
+ snps,weight = <0x13>;
snps,dcb-algorithm;
};
queue4 {
+ snps,weight = <0x14>;
snps,dcb-algorithm;
};
queue5 {
+ snps,weight = <0x15>;
snps,dcb-algorithm;
};
queue6 {
+ snps,weight = <0x16>;
snps,dcb-algorithm;
};
queue7 {
+ snps,weight = <0x17>;
snps,dcb-algorithm;
};
};
@@ -790,36 +799,45 @@ queue7 {
mtl_tx_setup1: tx-queues-config {
snps,tx-queues-to-use = <8>;
+ snps,tx-sched-wrr;
queue0 {
+ snps,weight = <0x10>;
snps,dcb-algorithm;
};
queue1 {
+ snps,weight = <0x11>;
snps,dcb-algorithm;
};
queue2 {
+ snps,weight = <0x12>;
snps,dcb-algorithm;
};
queue3 {
+ snps,weight = <0x13>;
snps,dcb-algorithm;
};
queue4 {
+ snps,weight = <0x14>;
snps,dcb-algorithm;
};
queue5 {
+ snps,weight = <0x15>;
snps,dcb-algorithm;
};
queue6 {
+ snps,weight = <0x16>;
snps,dcb-algorithm;
};
queue7 {
+ snps,weight = <0x17>;
snps,dcb-algorithm;
};
};
@@ -937,36 +955,45 @@ queue7 {
mtl_tx_setup2: tx-queues-config {
snps,tx-queues-to-use = <8>;
+ snps,tx-sched-wrr;
queue0 {
+ snps,weight = <0x10>;
snps,dcb-algorithm;
};
queue1 {
+ snps,weight = <0x11>;
snps,dcb-algorithm;
};
queue2 {
+ snps,weight = <0x12>;
snps,dcb-algorithm;
};
queue3 {
+ snps,weight = <0x13>;
snps,dcb-algorithm;
};
queue4 {
+ snps,weight = <0x14>;
snps,dcb-algorithm;
};
queue5 {
+ snps,weight = <0x15>;
snps,dcb-algorithm;
};
queue6 {
+ snps,weight = <0x16>;
snps,dcb-algorithm;
};
queue7 {
+ snps,weight = <0x17>;
snps,dcb-algorithm;
};
};
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/arm64/kernel/mte.c b/arch/arm64/kernel/mte.c
index 1a9aad6ef22a..31f5c6b0510e 100644
--- a/arch/arm64/kernel/mte.c
+++ b/arch/arm64/kernel/mte.c
@@ -476,7 +476,7 @@ static int __access_remote_tags(struct mm_struct *mm, unsigned long addr,
* was never mapped with PROT_MTE.
*/
if (!(vma->vm_flags & VM_MTE)) {
- err = -EOPNOTSUPP;
+ err = -EIO;
put_page(page);
break;
}
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 8555bbf47c63..1f8bdfd7e9a6 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -397,10 +397,7 @@ config ECONET
select BOOT_RAW
select CPU_BIG_ENDIAN
select DEBUG_ZBOOT if DEBUG_KERNEL
- select EARLY_PRINTK_8250
select ECONET_EN751221_TIMER
- select SERIAL_8250
- select SERIAL_OF_PLATFORM
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_HAS_CPU_MIPS32_R1
select SYS_HAS_CPU_MIPS32_R2
@@ -662,6 +659,7 @@ config EYEQ
select USB_UHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
select USE_OF
select HOTPLUG_PARALLEL if HOTPLUG_CPU
+ select WEAK_REORDERING_BEYOND_LLSC
help
Select this to build a kernel supporting EyeQ SoC from Mobileye.
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 <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-helper-board.h>
-#ifdef CONFIG_USB
+#if IS_ENABLED(CONFIG_USB)
#include <linux/usb/ehci_def.h>
#include <linux/usb/ehci_pdriver.h>
#include <linux/usb/ohci_pdriver.h>
@@ -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 ee1b5cb557c9..1ae8384637b5 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -1076,7 +1076,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 22e616662255..a6ff42d7666c 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 5fbb95d90e99..463aef870c4e 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 e4654388d794..6e7a366f0798 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -204,10 +204,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 598f178102ee..8af6b80cffdd 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -161,6 +161,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 fb3594ddf731..854899bfec5d 100644
--- a/arch/x86/entry/entry_fred.c
+++ b/arch/x86/entry/entry_fred.c
@@ -10,6 +10,7 @@
#include <asm/desc.h>
#include <asm/fred.h>
#include <asm/idtentry.h>
+#include <asm/processor-flags.h>
#include <asm/syscall.h>
#include <asm/trapnr.h>
#include <asm/traps.h>
@@ -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/div64.h b/arch/x86/include/asm/div64.h
index 30fd06ede751..8a2d343f977e 100644
--- a/arch/x86/include/asm/div64.h
+++ b/arch/x86/include/asm/div64.h
@@ -111,7 +111,7 @@ static inline u64 mul_u64_add_u64_div_u64(u64 rax, u64 mul, u64 add, u64 div)
if (!statically_true(!add))
asm ("addq %[add], %[lo]; adcq $0, %[hi]" :
- [lo] "+r" (rax), [hi] "+r" (rdx) : [add] "irm" (add));
+ [lo] "+r" (rax), [hi] "+r" (rdx) : [add] "erm" (add));
asm ("divq %[div]" : "+a" (rax), "+d" (rdx) : [div] "rm" (div));
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 b0b576ab2fa6..f24d7e911d3e 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -2319,6 +2319,7 @@ int3_exception_notify(struct notifier_block *self, unsigned long val, void *data
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);
@@ -2331,7 +2332,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_selftest_callee);
+ ip = regs->ip - INT3_INSN_SIZE + CALL_INSN_SIZE;
+ int3_emulate_call(regs, ip, (unsigned long)&int3_selftest_callee);
return NOTIFY_STOP;
}
@@ -2929,7 +2931,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 f4a444e6114d..ab87e56788df 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -345,6 +345,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,
@@ -366,6 +386,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.
@@ -914,6 +937,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 c1fac3a9fecc..03d2710ec302 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -510,10 +510,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/ata/libahci.c b/drivers/ata/libahci.c
index 6d72eb017b49..08ab56e95566 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -744,15 +744,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 6e072d681341..f6524135ea11 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -620,10 +620,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 24ad56536ed6..2be8231dcd5b 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 c64e96fe8897..3262e950a6bd 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -404,6 +404,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
*/
@@ -502,7 +508,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 26d525acd659..7ea8bcd8a7ec 100644
--- a/drivers/bluetooth/btmtk.c
+++ b/drivers/bluetooth/btmtk.c
@@ -721,7 +721,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 94aa60d9cc20..a15ae6598c66 100644
--- a/drivers/bluetooth/btmtksdio.c
+++ b/drivers/bluetooth/btmtksdio.c
@@ -217,7 +217,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
}
/* Parse and handle the return WMT event */
- wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data;
+ wmt_evt = skb_pull_data(bdev->evt_skb, sizeof(*wmt_evt));
+ if (!wmt_evt) {
+ bt_dev_err(hdev, "WMT event too short (%u bytes)",
+ bdev->evt_skb->len);
+ err = -EINVAL;
+ goto err_free_skb;
+ }
+
if (wmt_evt->whdr.op != hdr->op) {
bt_dev_err(hdev, "Wrong op received %d expected %d",
wmt_evt->whdr.op, hdr->op);
@@ -233,6 +240,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
status = BTMTK_WMT_PATCH_DONE;
break;
case BTMTK_WMT_FUNC_CTRL:
+ if (!skb_pull_data(bdev->evt_skb,
+ sizeof(wmt_evt_funcc->status))) {
+ /* 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;
+ }
+
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
status = BTMTK_WMT_ON_DONE;
@@ -1244,10 +1262,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/btmtkuart.c b/drivers/bluetooth/btmtkuart.c
index 27aa48ff3ac2..4af6fbbbd302 100644
--- a/drivers/bluetooth/btmtkuart.c
+++ b/drivers/bluetooth/btmtkuart.c
@@ -151,7 +151,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
}
/* Parse and handle the return WMT event */
- wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data;
+ wmt_evt = skb_pull_data(bdev->evt_skb, sizeof(*wmt_evt));
+ if (!wmt_evt) {
+ bt_dev_err(hdev, "WMT event too short (%u bytes)",
+ bdev->evt_skb->len);
+ err = -EINVAL;
+ goto err_free_wc;
+ }
+
if (wmt_evt->whdr.op != hdr->op) {
bt_dev_err(hdev, "Wrong op received %d expected %d",
wmt_evt->whdr.op, hdr->op);
@@ -167,6 +174,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev,
status = BTMTK_WMT_PATCH_DONE;
break;
case BTMTK_WMT_FUNC_CTRL:
+ if (!skb_pull_data(bdev->evt_skb,
+ sizeof(wmt_evt_funcc->status))) {
+ /* 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;
+ }
+
wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt;
if (be16_to_cpu(wmt_evt_funcc->status) == 0x404)
status = BTMTK_WMT_ON_DONE;
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 84f55f67523e..87d50efcd271 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -71,6 +71,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) },
@@ -475,6 +484,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 1222f97800f4..875093e61c68 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -2228,8 +2228,8 @@ static void qca_power_off(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);
@@ -2251,8 +2251,14 @@ static void qca_power_off(struct hci_uart *hu)
case QCA_WCN3990:
case QCA_WCN3991:
case QCA_WCN3998:
- host_set_baudrate(hu, 2400);
- qca_send_power_pulse(hu, false);
+ /* 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;
diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c
index 24cee7c9fda6..e1891351c221 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;
@@ -284,10 +284,14 @@ static int scpi_clocks_probe(struct platform_device *pdev)
if (match->data != &scpi_dvfs_ops)
continue;
/* Add the virtual cpufreq device if it's DVFS clock provider */
+ if (cpufreq_dev)
+ continue;
cpufreq_dev = platform_device_register_simple("scpi-cpufreq",
-1, NULL, 0);
- if (IS_ERR(cpufreq_dev))
+ if (IS_ERR(cpufreq_dev)) {
pr_warn("unable to register cpufreq device");
+ cpufreq_dev = NULL;
+ }
}
return 0;
}
diff --git a/drivers/dma-buf/dma-buf-mapping.c b/drivers/dma-buf/dma-buf-mapping.c
index 794acff2546a..833be519e1e6 100644
--- a/drivers/dma-buf/dma-buf-mapping.c
+++ b/drivers/dma-buf/dma-buf-mapping.c
@@ -5,16 +5,18 @@
*/
#include <linux/dma-buf-mapping.h>
#include <linux/dma-resv.h>
+#include <linux/overflow.h>
+#include <linux/align.h>
+
+#define MAX_SG_ENT_SZ ALIGN_DOWN(UINT_MAX, PAGE_SIZE)
static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t length,
dma_addr_t addr)
{
- unsigned int len, nents;
- int i;
+ size_t len;
- nents = DIV_ROUND_UP(length, UINT_MAX);
- for (i = 0; i < nents; i++) {
- len = min_t(size_t, length, UINT_MAX);
+ while (length) {
+ len = min(length, MAX_SG_ENT_SZ);
length -= len;
/*
* DMABUF abuses scatterlist to create a scatterlist
@@ -24,8 +26,10 @@ static struct scatterlist *fill_sg_entry(struct scatterlist *sgl, size_t length,
* does not require the CPU list for mapping or unmapping.
*/
sg_set_page(sgl, NULL, 0, 0);
- sg_dma_address(sgl) = addr + (dma_addr_t)i * UINT_MAX;
+ sg_dma_address(sgl) = addr;
sg_dma_len(sgl) = len;
+ addr += len;
+ /* Unconditionally advance. On last segment, this becomes NULL */
sgl = sg_next(sgl);
}
@@ -40,15 +44,19 @@ static unsigned int calc_sg_nents(struct dma_iova_state *state,
size_t i;
if (!state || !dma_use_iova(state)) {
- for (i = 0; i < nr_ranges; i++)
- nents += DIV_ROUND_UP(phys_vec[i].len, UINT_MAX);
+ for (i = 0; i < nr_ranges; i++) {
+ unsigned int added = DIV_ROUND_UP(phys_vec[i].len, MAX_SG_ENT_SZ);
+
+ if (check_add_overflow(nents, added, &nents))
+ return 0;
+ }
} else {
/*
* In IOVA case, there is only one SG entry which spans
* for whole IOVA address space, but we need to make sure
* that it fits sg->length, maybe we need more.
*/
- nents = DIV_ROUND_UP(size, UINT_MAX);
+ nents = DIV_ROUND_UP(size, MAX_SG_ENT_SZ);
}
return nents;
@@ -95,9 +103,10 @@ struct sg_table *dma_buf_phys_vec_to_sgt(struct dma_buf_attachment *attach,
size_t nr_ranges, size_t size,
enum dma_data_direction dir)
{
- unsigned int nents, mapped_len = 0;
struct dma_buf_dma *dma;
struct scatterlist *sgl;
+ size_t mapped_len = 0;
+ unsigned int nents;
dma_addr_t addr;
size_t i;
int ret;
@@ -133,6 +142,8 @@ struct sg_table *dma_buf_phys_vec_to_sgt(struct dma_buf_attachment *attach,
}
nents = calc_sg_nents(dma->state, phys_vec, nr_ranges, size);
+
+ /* sg_alloc_table will cleanly fail and return -EINVAL if nents == 0 */
ret = sg_alloc_table(&dma->sgt, nents, GFP_KERNEL | __GFP_ZERO);
if (ret)
goto err_free_state;
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 87797bea91cb..1037a815aa0e 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -1168,7 +1168,12 @@ const char __rcu *dma_fence_driver_name(struct dma_fence *fence)
/* RCU protection is required for safe access to returned string */
ops = rcu_dereference(fence->ops);
- if (ops)
+
+ /*
+ * Make load ordering irrelevant by checking both signaled state and ops
+ * pointer and ops pointer is only set to NULL on newer implementations.
+ */
+ if (!dma_fence_test_signaled_flag(fence) && ops)
return (const char __rcu *)ops->get_driver_name(fence);
else
return (const char __rcu *)"detached-driver";
@@ -1201,7 +1206,12 @@ const char __rcu *dma_fence_timeline_name(struct dma_fence *fence)
/* RCU protection is required for safe access to returned string */
ops = rcu_dereference(fence->ops);
- if (ops)
+
+ /*
+ * Make load ordering irrelevant by checking both signaled state and ops
+ * pointer and ops pointer is only set to NULL on newer implementations.
+ */
+ if (!dma_fence_test_signaled_flag(fence) && ops)
return (const char __rcu *)ops->get_timeline_name(fence);
else
return (const char __rcu *)"signaled-timeline";
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 9049171df857..5b5673fc7344 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 386e85cd4882..ed520737882b 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -52,7 +52,6 @@
#define DCSR_EORINTR BIT(9) /* The end of Receive */
#define DRCMR_BASE 0x0100
-#define DRCMR_EXT_BASE_K3 0x1000
#define DRCMR_EXT_BASE_DEFAULT 0x1100
#define DRCMR_REQ_LIMIT 64
#define DRCMR_MAPVLD BIT(7) /* Map Valid (read / write) */
@@ -713,7 +712,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);
@@ -1219,7 +1218,7 @@ static const struct mmp_pdma_ops spacemit_k3_pdma_ops = {
.get_desc_dst_addr = get_desc_dst_addr_64,
.run_bits = (DCSR_RUN | DCSR_LPAEEN | DCSR_EORIRQEN | DCSR_EORSTOPEN),
.dma_width = 64,
- .drcmr_ext_base = DRCMR_EXT_BASE_K3,
+ .drcmr_ext_base = DRCMR_EXT_BASE_DEFAULT,
};
static const struct of_device_id mmp_pdma_dt_ids[] = {
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index fa2ee0b3e09f..fc43124fefa8 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -744,6 +744,7 @@ pxad_alloc_desc(struct pxad_chan *chan, unsigned int nb_hw_desc)
sw_desc = kzalloc_flex(*sw_desc, hw_desc, nb_hw_desc, GFP_NOWAIT);
if (!sw_desc)
return NULL;
+ sw_desc->nb_desc = nb_hw_desc;
sw_desc->desc_pool = chan->desc_pool;
for (i = 0; i < nb_hw_desc; i++) {
@@ -752,10 +753,10 @@ pxad_alloc_desc(struct pxad_chan *chan, unsigned int nb_hw_desc)
dev_err(&chan->vc.chan.dev->device,
"%s(): Couldn't allocate the %dth hw_desc from dma_pool %p\n",
__func__, i, sw_desc->desc_pool);
+ sw_desc->nb_desc = i;
goto err;
}
- sw_desc->nb_desc++;
sw_desc->hw_desc[i] = desc;
if (i == 0)
diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c
index 087fea3af2e4..19b32a23c882 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 f47a326dd7ff..7704b016aed8 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;
@@ -979,7 +981,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;
@@ -991,9 +992,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 686dc140293e..70eaf7ee57e6 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 74ad80d6c5a5..12cf1ca3a98a 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -756,15 +756,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)
@@ -786,7 +796,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);
}
@@ -920,9 +930,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 2acad5fa5a28..6eeb0ad9b008 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_obj(*info);
if (!info)
diff --git a/drivers/gpio/gpio-virtuser.c b/drivers/gpio/gpio-virtuser.c
index 7d0d366be37a..d5876c19cfef 100644
--- a/drivers/gpio/gpio-virtuser.c
+++ b/drivers/gpio/gpio-virtuser.c
@@ -692,7 +692,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/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 940b566946ce..f36e4b171fa7 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -788,13 +788,13 @@ static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
if (!of_property_read_bool(rd->dn, "gpio-hog"))
return NOTIFY_DONE; /* not for us */
- if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
- return NOTIFY_DONE;
-
gdev = of_find_gpio_device_by_node(rd->dn->parent);
if (!gdev)
return NOTIFY_DONE; /* not for us */
+ if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
+ return NOTIFY_DONE;
+
ret = gpiochip_add_hog(gpio_device_get_chip(gdev), of_fwnode_handle(rd->dn));
if (ret < 0) {
pr_err("%s: failed to add hogs for %pOF\n", __func__,
diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c
index 495bd3d0ddf0..5f9623e40b0f 100644
--- a/drivers/gpio/gpiolib-shared.c
+++ b/drivers/gpio/gpiolib-shared.c
@@ -261,10 +261,13 @@ static int gpio_shared_of_traverse(struct device_node *curr)
con_id[con_id_len - suffix_len] = '\0';
}
- ref = gpio_shared_make_ref(fwnode_handle_get(of_fwnode_handle(curr)),
- con_id, args.args[1]);
- if (!ref)
+ struct fwnode_handle *curr_fwnode =
+ fwnode_handle_get(of_fwnode_handle(curr));
+ ref = gpio_shared_make_ref(curr_fwnode, con_id, args.args[1]);
+ if (!ref) {
+ fwnode_handle_put(curr_fwnode);
return -ENOMEM;
+ }
if (!list_empty(&entry->refs))
pr_debug("GPIO %u at %s is shared by multiple firmware nodes\n",
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 7b09410d6d8f..6b0c1ad5a053 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -822,6 +822,9 @@ enum amdgpu_enforce_isolation_mode {
struct amdgpu_device {
struct device *dev;
struct pci_dev *pdev;
+ /* The two ends of the physical PCIe link outside the device. */
+ struct pci_dev *link_dev;
+ struct pci_dev *link_partner;
struct drm_device ddev;
#ifdef CONFIG_DRM_AMD_ACP
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
index da325863ad76..4b29e7eee610 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
@@ -329,7 +329,7 @@ void amdgpu_amdkfd_clear_kfd_mapping(struct amdgpu_device *adev)
struct kfd_dev *kfd = adev->kfd.dev;
unsigned int i;
- if (!kfd)
+ if (!kfd || !kfd->init_complete)
return;
for (i = 0; i < kfd->num_nodes; i++) {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
index ddfc51a92d79..ea9a6ed4bcc9 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
@@ -750,6 +750,67 @@ void amdgpu_device_mm_access(struct amdgpu_device *adev, loff_t pos,
drm_dev_exit(idx);
}
+#ifdef CONFIG_64BIT
+/*
+ * During early SR-IOV VF init, host-provided init data can live in FB before
+ * the normal VRAM aperture mapping is ready. Use a temporary BAR0 mapping for
+ * reads only, and verify it matches the VRAM aperture when aperture information
+ * is already available.
+ */
+static int amdgpu_device_read_fb_via_bar0(struct amdgpu_device *adev,
+ u64 offset, void *buf, size_t size)
+{
+ resource_size_t aper_base, aper_size, bar_start, bar_size, map_base;
+ void __iomem *vram;
+ size_t map_offset, map_size;
+ unsigned long flags;
+ u64 end;
+
+ if (!buf || !size)
+ return -EINVAL;
+
+ if (!amdgpu_sriov_vf(adev))
+ return -EINVAL;
+
+ flags = pci_resource_flags(adev->pdev, 0);
+ if ((flags & IORESOURCE_UNSET) || !(flags & IORESOURCE_MEM))
+ return -EINVAL;
+
+ bar_start = pci_resource_start(adev->pdev, 0);
+ bar_size = pci_resource_len(adev->pdev, 0);
+ if (!bar_size)
+ return -ENODEV;
+
+ aper_base = adev->gmc.aper_base;
+ aper_size = adev->gmc.visible_vram_size ? adev->gmc.visible_vram_size :
+ adev->gmc.aper_size;
+
+ if (aper_base || aper_size) {
+ if (aper_base != bar_start || aper_size > bar_size)
+ return -EINVAL;
+ } else {
+ aper_base = bar_start;
+ aper_size = bar_size;
+ }
+
+ if (check_add_overflow(offset, size, &end) || end > aper_size)
+ return -EINVAL;
+
+ map_offset = offset_in_page(offset);
+ map_base = aper_base + (offset & PAGE_MASK);
+ map_size = PAGE_ALIGN(map_offset + size);
+
+ vram = ioremap_wc(map_base, map_size);
+ if (!vram)
+ return -ENOMEM;
+
+ memcpy_fromio(buf, (u8 __iomem *)vram + map_offset, size);
+ iounmap(vram);
+
+ return 0;
+}
+#endif
+
/**
* amdgpu_device_aper_access - access vram by vram aperture
*
@@ -769,8 +830,12 @@ size_t amdgpu_device_aper_access(struct amdgpu_device *adev, loff_t pos,
size_t count = 0;
uint64_t last;
- if (!adev->mman.aper_base_kaddr)
+ if (!adev->mman.aper_base_kaddr) {
+ /* Writes still require the regular aperture/MM path. */
+ if (!write && !amdgpu_device_read_fb_via_bar0(adev, pos, buf, size))
+ return size;
return 0;
+ }
last = min(pos + size, adev->gmc.visible_vram_size);
if (last > pos) {
@@ -1983,18 +2048,17 @@ static void amdgpu_uid_fini(struct amdgpu_device *adev)
adev->uid_info = NULL;
}
-static struct pci_dev *amdgpu_device_find_parent(struct amdgpu_device *adev)
+static void amdgpu_device_init_pcie_links(struct amdgpu_device *adev)
{
- struct pci_dev *parent = adev->pdev;
+ adev->link_dev = adev->pdev;
+ adev->link_partner = pci_upstream_bridge(adev->link_dev);
- /* skip upstream/downstream switches internal to dGPU */
- while ((parent = pci_upstream_bridge(parent))) {
- if (parent->vendor == PCI_VENDOR_ID_ATI)
- continue;
- break;
+ /* Skip upstream/downstream switches internal to the dGPU. */
+ while (adev->link_partner &&
+ adev->link_partner->vendor == PCI_VENDOR_ID_ATI) {
+ adev->link_dev = adev->link_partner;
+ adev->link_partner = pci_upstream_bridge(adev->link_dev);
}
-
- return parent;
}
/**
@@ -2010,17 +2074,25 @@ static struct pci_dev *amdgpu_device_find_parent(struct amdgpu_device *adev)
static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
{
struct amdgpu_ip_block *ip_block;
- struct pci_dev *parent;
- bool total, skip_bios;
+ bool total, skip_bios, early_full_gpu_access = false;
uint32_t bios_flags;
int i, r;
amdgpu_device_enable_virtual_display(adev);
if (amdgpu_sriov_vf(adev)) {
- r = amdgpu_virt_request_full_gpu(adev, true);
- if (r)
- return r;
+ /*
+ * Legacy hosts do not provide init data before early init, so
+ * keep the original early full GPU access request for them. Newer
+ * hosts publish the init data through VF FB, which lets us defer
+ * full GPU access until after non-GPU early init work is done.
+ */
+ early_full_gpu_access = (adev->virt.req_init_data_ver == 0);
+ if (early_full_gpu_access) {
+ r = amdgpu_virt_request_full_gpu(adev, true);
+ if (r)
+ return r;
+ }
r = amdgpu_virt_init_critical_region(adev);
if (r)
@@ -2097,10 +2169,9 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
!dev_is_removable(&adev->pdev->dev))
adev->flags |= AMD_IS_PX;
- if (!(adev->flags & AMD_IS_APU)) {
- parent = amdgpu_device_find_parent(adev);
- adev->has_pr3 = parent ? pci_pr3_present(parent) : false;
- }
+ if (!(adev->flags & AMD_IS_APU))
+ adev->has_pr3 = adev->link_partner &&
+ pci_pr3_present(adev->link_partner);
adev->pm.pp_feature = amdgpu_pp_feature_mask;
if (amdgpu_sriov_vf(adev) || sched_policy == KFD_SCHED_POLICY_NO_HWS)
@@ -2183,6 +2254,13 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev)
if (!total)
return -ENODEV;
+ /* Request full GPU access only for the remaining SR-IOV init work. */
+ if (amdgpu_sriov_vf(adev) && !early_full_gpu_access) {
+ r = amdgpu_virt_request_full_gpu(adev, true);
+ if (r)
+ return r;
+ }
+
if (adev->gmc.xgmi.supported)
amdgpu_xgmi_early_init(adev);
@@ -3785,6 +3863,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
adev->shutdown = false;
adev->flags = flags;
+ amdgpu_device_init_pcie_links(adev);
if (amdgpu_force_asic_type >= 0 && amdgpu_force_asic_type < CHIP_LAST)
adev->asic_type = amdgpu_force_asic_type;
@@ -4344,7 +4423,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);
@@ -4386,11 +4465,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))
@@ -6048,11 +6125,9 @@ static void amdgpu_device_partner_bandwidth(struct amdgpu_device *adev,
*width = PCIE_LNK_WIDTH_UNKNOWN;
if (amdgpu_device_pcie_dynamic_switching_supported(adev)) {
- struct pci_dev *parent = amdgpu_device_find_parent(adev);
-
- if (parent) {
- *speed = pcie_get_speed_cap(parent);
- *width = pcie_get_width_cap(parent);
+ if (adev->link_partner) {
+ *speed = pcie_get_speed_cap(adev->link_partner);
+ *width = pcie_get_width_cap(adev->link_partner);
}
} else {
/* use the current speeds rather than max if switching is not supported */
@@ -6074,21 +6149,11 @@ static void amdgpu_device_gpu_bandwidth(struct amdgpu_device *adev,
enum pci_bus_speed *speed,
enum pcie_link_width *width)
{
- struct pci_dev *parent = adev->pdev;
-
if (!speed || !width)
return;
- /* use the device itself */
- *speed = pcie_get_speed_cap(adev->pdev);
- *width = pcie_get_width_cap(adev->pdev);
-
- /* use the link outside the device */
- parent = amdgpu_device_find_parent(adev);
- if (parent) {
- *speed = pcie_get_speed_cap(parent);
- *width = pcie_get_width_cap(parent);
- }
+ *speed = pcie_get_speed_cap(adev->link_dev);
+ *width = pcie_get_width_cap(adev->link_dev);
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
index b33c300e26e2..9adf3eed8822 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dma_buf.c
@@ -43,6 +43,7 @@
#include <linux/dma-buf.h>
#include <linux/dma-fence-array.h>
#include <linux/pci-p2pdma.h>
+#include <linux/pm_runtime.h>
static const struct dma_buf_attach_ops amdgpu_dma_buf_attach_ops;
@@ -100,15 +101,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)
- return 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);
}
/**
@@ -350,6 +390,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/mxgpu_ai.c b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
index 9a40107a0869..fec08f235b92 100644
--- a/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
+++ b/drivers/gpu/drm/amd/amdgpu/mxgpu_ai.c
@@ -185,8 +185,11 @@ static int xgpu_ai_send_access_requests(struct amdgpu_device *adev,
} else if (req == IDH_REQ_GPU_INIT_DATA){
/* Dummy REQ_GPU_INIT_DATA handling */
r = xgpu_ai_poll_msg(adev, IDH_REQ_GPU_INIT_DATA_READY);
- /* version set to 0 since dummy */
- adev->virt.req_init_data_ver = 0;
+ /*
+ * AI uses the GPU_CRIT_REGION_V1 layout in practice, so fix the
+ * dummy version value to match the actual init-data format.
+ */
+ adev->virt.req_init_data_ver = GPU_CRIT_REGION_V1;
}
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c
index bdfd2917e3ca..def02993b7cf 100644
--- a/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c
+++ b/drivers/gpu/drm/amd/amdgpu/nbio_v7_9.c
@@ -535,7 +535,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/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index 8b522fede60a..487cf746c450 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -797,10 +797,12 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm,
mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
q->properties.type)];
if (qd && !mqd_mgr->restore_mqd) {
- pr_debug("restore_mqd not implemented for this GPU\n");
+ pr_debug("restore_mqd not implemented for queue type %d\n",
+ q->properties.type);
retval = -EOPNOTSUPP;
goto deallocate_vmid;
}
+
if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) {
retval = allocate_hqd(dqm, q);
if (retval)
@@ -2168,7 +2170,8 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
mqd_mgr = dqm->mqd_mgrs[get_mqd_type_from_queue_type(
q->properties.type)];
if (qd && !mqd_mgr->restore_mqd) {
- pr_debug("restore_mqd not implemented for this GPU\n");
+ pr_debug("restore_mqd not implemented for queue type %d\n",
+ q->properties.type);
retval = -EOPNOTSUPP;
goto out_deallocate_doorbell;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
index e034da638c07..4f8a8a1a6186 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c
@@ -204,7 +204,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
* is safe, giving a maximum field value of 0xA.
*/
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
- ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
+ ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
m->cp_hqd_eop_base_addr_hi =
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
index 350fcbbba4b2..bf015dc5b868 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c
@@ -242,7 +242,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
* is safe, giving a maximum field value of 0xA.
*/
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
- ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
+ ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
m->cp_hqd_eop_base_addr_hi =
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
index 7c387fa90076..6ea09b031caf 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c
@@ -217,7 +217,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
* is safe, giving a maximum field value of 0xA.
*/
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
- ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
+ ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
m->cp_hqd_eop_base_addr_hi =
@@ -380,6 +380,63 @@ static int debugfs_show_mqd_sdma(struct seq_file *m, void *data)
#endif
+static void restore_mqd(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *qp, const void *mqd_src,
+ const void *ctl_stack_src, const u32 ctl_stack_size)
+{
+ u64 addr;
+ struct v12_compute_mqd *m;
+
+ m = (struct v12_compute_mqd *)mqd_mem_obj->cpu_ptr;
+ addr = mqd_mem_obj->gpu_addr;
+
+ memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
+ memcpy(m, mqd_src, sizeof(*m));
+
+ /* Update MQD base address to the newly allocated location */
+ m->cp_mqd_base_addr_lo = lower_32_bits(addr);
+ m->cp_mqd_base_addr_hi = upper_32_bits(addr);
+
+ m->cp_hqd_pq_doorbell_control &=
+ ~CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK;
+ m->cp_hqd_pq_doorbell_control |=
+ qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
+ pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
+
+ *mqd = m;
+ if (gart_addr)
+ *gart_addr = addr;
+
+ qp->is_active = 0;
+}
+
+static void restore_mqd_sdma(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *qp,
+ const void *mqd_src,
+ const void *ctl_stack_src,
+ const u32 ctl_stack_size)
+{
+ u64 addr;
+ struct v12_sdma_mqd *m;
+
+ m = (struct v12_sdma_mqd *)mqd_mem_obj->cpu_ptr;
+ addr = mqd_mem_obj->gpu_addr;
+
+ memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
+ memcpy(m, mqd_src, sizeof(*m));
+
+ m->sdmax_rlcx_doorbell_offset =
+ qp->doorbell_off << SDMA0_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
+
+ *mqd = m;
+ if (gart_addr)
+ *gart_addr = addr;
+
+ qp->is_active = 0;
+}
+
struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
struct kfd_node *dev)
{
@@ -407,6 +464,7 @@ struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
mqd->mqd_size = sizeof(struct v12_compute_mqd);
mqd->get_wave_state = get_wave_state;
mqd->mqd_stride = kfd_mqd_stride;
+ mqd->restore_mqd = restore_mqd;
#if defined(CONFIG_DEBUG_FS)
mqd->debugfs_show_mqd = debugfs_show_mqd;
#endif
@@ -453,6 +511,7 @@ struct mqd_manager *mqd_manager_init_v12(enum KFD_MQD_TYPE type,
mqd->is_occupied = kfd_is_occupied_sdma;
mqd->mqd_size = sizeof(struct v12_sdma_mqd);
mqd->mqd_stride = kfd_mqd_stride;
+ mqd->restore_mqd = restore_mqd_sdma;
#if defined(CONFIG_DEBUG_FS)
mqd->debugfs_show_mqd = debugfs_show_mqd_sdma;
#endif
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
index 431a940f91f3..c709db0210ce 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c
@@ -295,7 +295,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
* is safe, giving a maximum field value of 0xA.
*/
m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA,
- ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0;
+ ffs(q->eop_ring_buffer_size / sizeof(unsigned int) / 4)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
m->cp_hqd_eop_base_addr_hi =
@@ -641,6 +641,72 @@ static int debugfs_show_mqd_sdma(struct seq_file *m, void *data)
#endif
+static void restore_mqd_v12_1(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *qp, const void *mqd_src,
+ const void *ctl_stack_src, const u32 ctl_stack_size)
+{
+ u64 addr;
+ struct v12_1_compute_mqd *m;
+
+ /*
+ * GFX12.1 is multi-XCC capable but this restore handles XCC0 only.
+ * Multi-XCC CRIU restore is currently unreachable because
+ * kfd_criu_restore_queue() validates against unscaled mqd_size.
+ */
+ if (NUM_XCC(mm->dev->xcc_mask) > 1)
+ pr_warn_once("GFX12.1 multi-XCC CRIU restore not fully supported\n");
+
+ m = (struct v12_1_compute_mqd *)mqd_mem_obj->cpu_ptr;
+ addr = mqd_mem_obj->gpu_addr;
+
+ memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size) *
+ NUM_XCC(mm->dev->xcc_mask));
+ memcpy(m, mqd_src, sizeof(*m));
+
+ /* Update MQD base address to the newly allocated location */
+ m->cp_mqd_base_addr_lo = lower_32_bits(addr);
+ m->cp_mqd_base_addr_hi = upper_32_bits(addr);
+
+ m->cp_hqd_pq_doorbell_control &=
+ ~CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET_MASK;
+ m->cp_hqd_pq_doorbell_control |=
+ qp->doorbell_off << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT;
+ pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", m->cp_hqd_pq_doorbell_control);
+
+ *mqd = m;
+ if (gart_addr)
+ *gart_addr = addr;
+
+ qp->is_active = 0;
+}
+
+static void restore_mqd_sdma_v12_1(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *qp,
+ const void *mqd_src,
+ const void *ctl_stack_src,
+ const u32 ctl_stack_size)
+{
+ u64 addr;
+ struct v12_sdma_mqd *m;
+
+ m = (struct v12_sdma_mqd *)mqd_mem_obj->cpu_ptr;
+ addr = mqd_mem_obj->gpu_addr;
+
+ memset(m, 0, AMDGPU_MQD_SIZE_ALIGN(mm->mqd_size));
+ memcpy(m, mqd_src, sizeof(*m));
+
+ m->sdmax_rlcx_doorbell_offset =
+ qp->doorbell_off << SDMA0_SDMA_QUEUE0_DOORBELL_OFFSET__OFFSET__SHIFT;
+
+ *mqd = m;
+ if (gart_addr)
+ *gart_addr = addr;
+
+ qp->is_active = 0;
+}
+
struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
struct kfd_node *dev)
{
@@ -668,6 +734,7 @@ struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
mqd->mqd_size = sizeof(struct v12_1_compute_mqd);
mqd->get_wave_state = get_wave_state_v12_1;
mqd->mqd_stride = kfd_mqd_stride;
+ mqd->restore_mqd = restore_mqd_v12_1;
#if defined(CONFIG_DEBUG_FS)
mqd->debugfs_show_mqd = debugfs_show_mqd;
#endif
@@ -714,6 +781,7 @@ struct mqd_manager *mqd_manager_init_v12_1(enum KFD_MQD_TYPE type,
mqd->is_occupied = kfd_is_occupied_sdma;
mqd->mqd_size = sizeof(struct v12_sdma_mqd);
mqd->mqd_stride = kfd_mqd_stride;
+ mqd->restore_mqd = restore_mqd_sdma_v12_1;
#if defined(CONFIG_DEBUG_FS)
mqd->debugfs_show_mqd = debugfs_show_mqd_sdma;
#endif
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
index be99f0d53b18..1f7224a9c5cb 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c
@@ -299,6 +299,10 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
1 << CP_HQD_IB_CONTROL__IB_EXE_DISABLE__SHIFT;
/*
+ * The lowest 6 bits of eop_control store the EOP ring size. If
+ * their value is X, the ring size is 2^(X + 1) dwords, or
+ * 2^(X + 3) bytes.
+ *
* HW does not clamp this field correctly. Maximum EOP queue size
* is constrained by per-SE EOP done signal count, which is 8-bit.
* Limit is 0xFF EOP entries (= 0x7F8 dwords). CP will not submit
@@ -310,7 +314,7 @@ static void update_mqd(struct mqd_manager *mm, void *mqd,
*
*/
m->cp_hqd_eop_control = q->eop_ring_buffer_size ?
- min(0xA, order_base_2(q->eop_ring_buffer_size / 4) - 1) : 0;
+ min(0xA, order_base_2(q->eop_ring_buffer_size / 8)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
index 60b87a500698..029572548c14 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
@@ -208,6 +208,9 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd,
mtype << CP_HQD_IB_CONTROL__MTYPE__SHIFT;
/*
+ * The lowest 6 bits of eop_control store the EOP ring size. If
+ * their value is X, the ring size is 2^(X + 1) dwords, or
+ * 2^(X + 3) bytes.
* HW does not clamp this field correctly. Maximum EOP queue size
* is constrained by per-SE EOP done signal count, which is 8-bit.
* Limit is 0xFF EOP entries (= 0x7F8 dwords). CP will not submit
@@ -215,7 +218,7 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd,
* is safe, giving a maximum field value of 0xA.
*/
m->cp_hqd_eop_control |= q->eop_ring_buffer_size ? min(0xA,
- order_base_2(q->eop_ring_buffer_size / 4) - 1) : 0;
+ order_base_2(q->eop_ring_buffer_size / 8)) : 0;
m->cp_hqd_eop_base_addr_lo =
lower_32_bits(q->eop_ring_buffer_address >> 8);
m->cp_hqd_eop_base_addr_hi =
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
index 2d3587a31bc8..2ecd3a4068c0 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c
@@ -1058,10 +1058,12 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
*/
unsigned int denom = refresh_hz * 6528;
unsigned int stutter_period = dc->current_state->perf_params.stutter_period_us;
+ uint64_t num = (1000000LL + 2 * stutter_period * refresh_hz) *
+ (100LL + dc->debug.mall_additional_timer_percent);
+ uint64_t tmr_ticks;
- tmr_delay = (uint32_t)(div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
- (100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
- denom) - 64LL);
+ tmr_ticks = div_u64(num + denom - 1, denom);
+ tmr_delay = tmr_ticks > 64 ? (uint32_t)(tmr_ticks - 64) : 0;
/* In some cases the stutter period is really big (tiny modes) in these
* cases MALL cant be enabled, So skip these cases to avoid a ASSERT()
@@ -1083,9 +1085,8 @@ bool dcn30_apply_idle_power_optimizations(struct dc *dc, bool enable)
}
denom *= 2;
- tmr_delay = (uint32_t)(div_u64(((1000000LL + 2 * stutter_period * refresh_hz) *
- (100LL + dc->debug.mall_additional_timer_percent) + denom - 1),
- denom) - 64LL);
+ tmr_ticks = div_u64(num + denom - 1, denom);
+ tmr_delay = tmr_ticks > 64 ? (uint32_t)(tmr_ticks - 64) : 0;
}
/* Copy HW cursor */
diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
index 7b951af5ab32..66b591b39a51 100644
--- a/drivers/gpu/drm/drm_atomic_uapi.c
+++ b/drivers/gpu/drm/drm_atomic_uapi.c
@@ -1461,10 +1461,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));
@@ -1473,12 +1475,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;
@@ -1534,6 +1536,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 5ef887d8485a..aa7792966287 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/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c
index 18ef7e64821b..52347668f27d 100644
--- a/drivers/gpu/drm/i915/display/intel_cursor.c
+++ b/drivers/gpu/drm/i915/display/intel_cursor.c
@@ -530,18 +530,13 @@ static int i9xx_check_cursor(struct intel_crtc_state *crtc_state,
}
static void i9xx_cursor_disable_sel_fetch_arm(struct intel_dsb *dsb,
- struct intel_plane *plane)
+ struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
- /*
- * Clear this whenever the hardware has selective fetch, not just when
- * the current state uses it. The cursor may have been enabled with
- * selective fetch earlier and had its enable bit orphaned when the
- * feature was switched off.
- */
- if (!HAS_PSR2_SEL_FETCH(display))
+ if (!crtc_state->enable_psr2_sel_fetch)
return;
intel_de_write_dsb(display, dsb, SEL_FETCH_CUR_CTL(pipe), 0);
@@ -591,7 +586,7 @@ static void i9xx_cursor_update_sel_fetch_arm(struct intel_dsb *dsb,
if (crtc_state->enable_psr2_su_region_et)
wa_16021440873(dsb, plane, crtc_state, plane_state);
else
- i9xx_cursor_disable_sel_fetch_arm(dsb, plane);
+ i9xx_cursor_disable_sel_fetch_arm(dsb, plane, crtc_state);
}
}
@@ -700,7 +695,7 @@ static void i9xx_cursor_update_arm(struct intel_dsb *dsb,
if (plane_state)
i9xx_cursor_update_sel_fetch_arm(dsb, plane, crtc_state, plane_state);
else
- i9xx_cursor_disable_sel_fetch_arm(dsb, plane);
+ i9xx_cursor_disable_sel_fetch_arm(dsb, plane, crtc_state);
if (plane->cursor.base != base ||
plane->cursor.size != fbc_ctl ||
diff --git a/drivers/gpu/drm/i915/display/skl_universal_plane.c b/drivers/gpu/drm/i915/display/skl_universal_plane.c
index 4369c8eeaac2..164b7d61c9a3 100644
--- a/drivers/gpu/drm/i915/display/skl_universal_plane.c
+++ b/drivers/gpu/drm/i915/display/skl_universal_plane.c
@@ -879,18 +879,13 @@ skl_plane_disable_arm(struct intel_dsb *dsb,
}
static void icl_plane_disable_sel_fetch_arm(struct intel_dsb *dsb,
- struct intel_plane *plane)
+ struct intel_plane *plane,
+ const struct intel_crtc_state *crtc_state)
{
struct intel_display *display = to_intel_display(plane);
enum pipe pipe = plane->pipe;
- /*
- * Clear this whenever the hardware has selective fetch, not just when
- * the current state uses it. The plane may have been enabled with
- * selective fetch earlier and had its enable bit orphaned when the
- * feature was switched off.
- */
- if (!HAS_PSR2_SEL_FETCH(display))
+ if (!crtc_state->enable_psr2_sel_fetch)
return;
intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id), 0);
@@ -926,7 +921,7 @@ icl_plane_disable_arm(struct intel_dsb *dsb,
skl_write_plane_wm(dsb, plane, crtc_state);
- icl_plane_disable_sel_fetch_arm(dsb, plane);
+ icl_plane_disable_sel_fetch_arm(dsb, plane, crtc_state);
if (plane_has_normalizer(plane))
intel_de_write_dsb(display, dsb,
@@ -1646,7 +1641,7 @@ static void icl_plane_update_sel_fetch_arm(struct intel_dsb *dsb,
intel_de_write_dsb(display, dsb, SEL_FETCH_PLANE_CTL(pipe, plane->id),
SEL_FETCH_PLANE_CTL_ENABLE);
else
- icl_plane_disable_sel_fetch_arm(dsb, plane);
+ icl_plane_disable_sel_fetch_arm(dsb, plane, crtc_state);
}
static void
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 7f20320ef66a..05c77fe27e62 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 c62c45bb0ddb..29c59899fdef 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c
@@ -1252,6 +1252,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 36a497f1d6c1..e8729fe1cfef 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 79e2b171e269..22eade11c615 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -698,6 +698,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;
@@ -719,6 +720,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;
@@ -730,9 +733,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)
@@ -1412,6 +1415,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 2685cc3d0359..89face267018 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;
}
@@ -2500,9 +2504,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 eb1088755cb3..77dce35cd45e 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 32d5ebea2596..fa46ab3063e6 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 762e546d25ef..43a938e8f288 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 7441d4a01d31..2e16f3ebcf3f 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 59c69aa75649..38e1e6866301 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 3631ec283c6e..0bfb6b0f42fa 100644
--- a/drivers/gpu/drm/msm/msm_ringbuffer.h
+++ b/drivers/gpu/drm/msm/msm_ringbuffer.h
@@ -55,6 +55,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 700cea5def35..035b575722db 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 f544afa12b6b..94925f1590ea 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
@@ -1749,7 +1749,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);
@@ -1761,8 +1761,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 fcd0221dcea1..e9ac47d86b69 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/scheduler/sched_entity.c b/drivers/gpu/drm/scheduler/sched_entity.c
index 672b5c57ed8e..fd1824d79706 100644
--- a/drivers/gpu/drm/scheduler/sched_entity.c
+++ b/drivers/gpu/drm/scheduler/sched_entity.c
@@ -566,9 +566,10 @@ struct drm_sched_job *drm_sched_entity_pop_job(struct drm_sched_entity *entity)
*/
smp_wmb();
+ spin_lock(&entity->lock);
spsc_queue_pop(&entity->job_queue);
-
drm_sched_rq_pop_entity(entity);
+ spin_unlock(&entity->lock);
/* Jobs and entities might have different lifecycles. Since we're
* removing the job from the entities queue, set the jobs entity pointer
@@ -654,6 +655,9 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job)
* Make sure to set the submit_ts first, to avoid a race.
*/
sched_job->submit_ts = submit_ts = ktime_get();
+
+ spin_lock(&entity->lock);
+
first = spsc_queue_push(&entity->job_queue, &sched_job->queue_node);
/* first job wakes up scheduler */
@@ -664,5 +668,7 @@ void drm_sched_entity_push_job(struct drm_sched_job *sched_job)
if (sched)
drm_sched_wakeup(sched);
}
+
+ spin_unlock(&entity->lock);
}
EXPORT_SYMBOL(drm_sched_entity_push_job);
diff --git a/drivers/gpu/drm/scheduler/sched_rq.c b/drivers/gpu/drm/scheduler/sched_rq.c
index 0464d324d98d..23f46ec610e7 100644
--- a/drivers/gpu/drm/scheduler/sched_rq.c
+++ b/drivers/gpu/drm/scheduler/sched_rq.c
@@ -257,19 +257,17 @@ static ktime_t drm_sched_entity_get_job_ts(struct drm_sched_entity *entity)
struct drm_gpu_scheduler *
drm_sched_rq_add_entity(struct drm_sched_entity *entity, ktime_t ts)
{
+ struct drm_sched_rq *rq = entity->rq;
struct drm_gpu_scheduler *sched;
- struct drm_sched_rq *rq;
/* Add the entity to the run queue */
- spin_lock(&entity->lock);
- if (entity->stopped) {
- spin_unlock(&entity->lock);
+ lockdep_assert_held(&entity->lock);
+ if (entity->stopped) {
DRM_ERROR("Trying to push to a killed entity\n");
return NULL;
}
- rq = entity->rq;
spin_lock(&rq->lock);
sched = rq->sched;
@@ -289,7 +287,6 @@ drm_sched_rq_add_entity(struct drm_sched_entity *entity, ktime_t ts)
drm_sched_rq_update_fifo_locked(entity, rq, ts);
spin_unlock(&rq->lock);
- spin_unlock(&entity->lock);
return sched;
}
@@ -343,16 +340,17 @@ drm_sched_rq_next_rr_ts(struct drm_sched_rq *rq,
*/
void drm_sched_rq_pop_entity(struct drm_sched_entity *entity)
{
+ struct drm_sched_rq *rq = entity->rq;
struct drm_sched_job *next_job;
- struct drm_sched_rq *rq;
+
+ lockdep_assert_held(&entity->lock);
+
+ spin_lock(&rq->lock);
/*
* Update the entity's location in the min heap according to
* the timestamp of the next job, if any.
*/
- spin_lock(&entity->lock);
- rq = entity->rq;
- spin_lock(&rq->lock);
next_job = drm_sched_entity_queue_peek(entity);
if (next_job) {
ktime_t ts;
@@ -375,8 +373,8 @@ void drm_sched_rq_pop_entity(struct drm_sched_entity *entity)
drm_sched_entity_save_vruntime(entity, min_vruntime);
}
}
+
spin_unlock(&rq->lock);
- spin_unlock(&entity->lock);
}
/**
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index bcd76f6bb7f0..ca6fc5cddacb 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1178,7 +1178,7 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
if (ttm_tt_is_populated(tt)) {
ret = ttm_tt_swapout(bdev, tt, swapout_walk->gfp_flags);
- if (!ret) {
+ if (ret > 0) {
spin_lock(&bdev->lru_lock);
ttm_resource_del_bulk_move_unevictable(bo->resource, bo);
ttm_resource_move_to_lru_tail(bo->resource);
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index b17e73bce384..82a7f2ac4c7e 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -1188,7 +1188,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_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c
index 5504cd9dd359..6fce3de27296 100644
--- a/drivers/gpu/drm/xe/xe_i2c.c
+++ b/drivers/gpu/drm/xe/xe_i2c.c
@@ -277,8 +277,10 @@ void xe_i2c_pm_resume(struct xe_device *xe, bool d3cold)
static void xe_i2c_remove(void *data)
{
struct xe_i2c *i2c = data;
+ struct xe_device *xe = tile_to_xe(i2c->mmio->tile);
unsigned int i;
+ xe_i2c_irq_reset(xe);
xe_amc_exit(i2c);
for (i = 0; i < XE_I2C_MAX_CLIENTS; i++) {
@@ -288,6 +290,7 @@ static void xe_i2c_remove(void *data)
bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier);
xe_i2c_unregister_adapter(i2c);
+ xe->i2c = NULL;
}
/**
diff --git a/drivers/gpu/drm/xe/xe_mmio_gem.c b/drivers/gpu/drm/xe/xe_mmio_gem.c
index 8c803ef233cc..ad3c9fa05223 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 83374cd57660..deb4378c1ec1 100644
--- a/drivers/gpu/drm/xe/xe_shrinker.c
+++ b/drivers/gpu/drm/xe/xe_shrinker.c
@@ -54,13 +54,40 @@ 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 bool __xe_shrinker_runtime_pm_get(struct xe_shrinker *shrinker)
+{
+ struct xe_device *xe = shrinker->xe;
+
+ if (xe_pm_runtime_get_if_active(xe))
+ return true;
+
+ if (xe_rpm_reclaim_safe(xe) && !ttm_bo_shrink_avoid_wait()) {
+ xe_pm_runtime_get(xe);
+ return true;
+ }
+
+ queue_work(xe->unordered_wq, &shrinker->pm_worker);
+
+ return false;
+}
+
+static void xe_shrinker_runtime_pm_put(struct xe_shrinker *shrinker, bool runtime_pm)
+{
+ if (runtime_pm)
+ xe_pm_runtime_put(shrinker->xe);
+}
+
+static int __xe_shrinker_walk(struct xe_shrinker *shrinker,
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)
{
+ struct xe_device *xe = shrinker->xe;
unsigned int mem_type;
- s64 freed = 0, lret;
+ bool rpm = false;
+ int ret = 0;
+ 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);
@@ -74,23 +101,35 @@ static s64 __xe_shrinker_walk(struct xe_device *xe,
if (!man || !man->use_tt)
continue;
+ if (mem_type != XE_PL_SYSTEM && !rpm &&
+ xe_device_is_l2_flush_optimized(xe)) {
+ if (!__xe_shrinker_runtime_pm_get(shrinker))
+ break;
+ rpm = true;
+ }
+
ttm_bo_lru_for_each_reserved_guarded(&curs, man, &arg, ttm_bo) {
if (!ttm_bo_shrink_suitable(ttm_bo, ctx))
continue;
lret = xe_bo_shrink(ctx, ttm_bo, flags, scanned);
- if (lret < 0)
- return lret;
+ if (lret < 0) {
+ ret = lret;
+ goto out;
+ }
- freed += lret;
+ *freed += lret;
if (*scanned >= to_scan)
- break;
+ goto out;
}
/* Trylocks should never error, just fail. */
xe_assert(xe, !IS_ERR(ttm_bo));
}
- return freed;
+out:
+ xe_shrinker_runtime_pm_put(shrinker, rpm);
+
+ return ret;
}
/*
@@ -99,40 +138,36 @@ 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_shrinker *shrinker,
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(shrinker, 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(shrinker, 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(shrinker, ctx, flags, to_scan, scanned,
+ freed);
- return freed;
+ return ret;
}
static unsigned long
@@ -180,22 +215,7 @@ static bool xe_shrinker_runtime_pm_get(struct xe_shrinker *shrinker, bool force,
return false;
}
- if (!xe_pm_runtime_get_if_active(xe)) {
- if (xe_rpm_reclaim_safe(xe) && !ttm_bo_shrink_avoid_wait()) {
- xe_pm_runtime_get(xe);
- return true;
- }
- queue_work(xe->unordered_wq, &shrinker->pm_worker);
- return false;
- }
-
- return true;
-}
-
-static void xe_shrinker_runtime_pm_put(struct xe_shrinker *shrinker, bool runtime_pm)
-{
- if (runtime_pm)
- xe_pm_runtime_put(shrinker->xe);
+ return __xe_shrinker_runtime_pm_get(shrinker);
}
static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc)
@@ -214,7 +234,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 +244,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, &ctx, shrink_flags,
+ nr_to_scan, &nr_scanned, &freed);
sc->nr_scanned = nr_scanned;
if (nr_scanned >= nr_to_scan || !can_backup)
@@ -242,10 +258,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, &ctx, shrink_flags,
+ nr_to_scan, &nr_scanned, &freed);
sc->nr_scanned = nr_scanned;
out:
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 df8bd9707605..3f78375eeb44 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 23e3eda58870..3d5586c67f84 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 31e54608b3c9..6c25701b36fc 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 37f37813ea51..2983f9fad8d2 100644
--- a/drivers/hwmon/pwm-fan.c
+++ b/drivers/hwmon/pwm-fan.c
@@ -483,7 +483,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);
@@ -494,6 +493,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;
@@ -648,6 +654,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 4a777430af5c..4b07a25ae59e 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 a548586369e1..c6ef04c69856 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 25b6e4e9e3fa..873e901a23d7 100644
--- a/drivers/i2c/busses/i2c-qcom-cci.c
+++ b/drivers/i2c/busses/i2c-qcom-cci.c
@@ -497,10 +497,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;
@@ -516,7 +520,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;
@@ -537,6 +541,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;
@@ -606,10 +613,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;
@@ -617,10 +622,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);
@@ -636,7 +639,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 e6d2af659d81..ca29633dcd62 100644
--- a/drivers/i2c/i2c-atr.c
+++ b/drivers/i2c/i2c-atr.c
@@ -855,6 +855,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 990cf928b32a..51af8c1c49f9 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 e0b3b36b8b14..3c91f00d09c6 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/rdma_core.c b/drivers/infiniband/core/rdma_core.c
index fd5651c003ae..a7cbe643e33c 100644
--- a/drivers/infiniband/core/rdma_core.c
+++ b/drivers/infiniband/core/rdma_core.c
@@ -69,7 +69,6 @@ void ib_uverbs_release_file(struct kref *ref)
if (file->disassociate_page)
__free_pages(file->disassociate_page, 0);
- mutex_destroy(&file->disassociation_lock);
mutex_destroy(&file->umap_lock);
mutex_destroy(&file->ucontext_lock);
kfree(file);
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 4929636f7c53..a15182f7a7c5 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/uverbs_flow.c b/drivers/infiniband/core/uverbs_flow.c
index 1528a294f7f8..de5a2769f084 100644
--- a/drivers/infiniband/core/uverbs_flow.c
+++ b/drivers/infiniband/core/uverbs_flow.c
@@ -26,6 +26,7 @@ struct ib_uflow_resources *flow_resources_alloc(size_t num_specs)
return resources;
err:
+ kfree(resources->collection);
kfree(resources->counters);
kfree(resources);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 0d88b2ee68ff..2a046c888dfa 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -644,12 +644,15 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma)
goto out;
}
- mutex_lock(&file->disassociation_lock);
+ if (!down_read_trylock(&file->hw_destroy_rwsem)) {
+ ret = -EIO;
+ goto out;
+ }
vma->vm_ops = &rdma_umap_ops;
ret = ucontext->device->ops.mmap(ucontext, vma);
- mutex_unlock(&file->disassociation_lock);
+ up_read(&file->hw_destroy_rwsem);
out:
srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
return ret;
@@ -671,7 +674,6 @@ static void rdma_umap_open(struct vm_area_struct *vma)
/* We are racing with disassociation */
if (!down_read_trylock(&ufile->hw_destroy_rwsem))
goto out_zap;
- mutex_lock(&ufile->disassociation_lock);
/*
* Disassociation already completed, the VMA should already be zapped.
@@ -684,12 +686,10 @@ static void rdma_umap_open(struct vm_area_struct *vma)
goto out_unlock;
rdma_umap_priv_init(priv, vma, opriv->entry);
- mutex_unlock(&ufile->disassociation_lock);
up_read(&ufile->hw_destroy_rwsem);
return;
out_unlock:
- mutex_unlock(&ufile->disassociation_lock);
up_read(&ufile->hw_destroy_rwsem);
out_zap:
/*
@@ -773,7 +773,7 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
{
struct rdma_umap_priv *priv, *next_priv;
- mutex_lock(&ufile->disassociation_lock);
+ lockdep_assert_held_write(&ufile->hw_destroy_rwsem);
while (1) {
struct mm_struct *mm = NULL;
@@ -799,10 +799,8 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
break;
}
mutex_unlock(&ufile->umap_lock);
- if (!mm) {
- mutex_unlock(&ufile->disassociation_lock);
+ if (!mm)
return;
- }
/*
* The umap_lock is nested under mmap_lock since it used within
@@ -832,8 +830,6 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile)
mmap_read_unlock(mm);
mmput(mm);
}
-
- mutex_unlock(&ufile->disassociation_lock);
}
/**
@@ -851,8 +847,11 @@ void rdma_user_mmap_disassociate(struct ib_device *device)
mutex_lock(&uverbs_dev->lists_mutex);
list_for_each_entry(ufile, &uverbs_dev->uverbs_file_list, list) {
- if (ufile->ucontext)
+ if (ufile->ucontext) {
+ down_write(&ufile->hw_destroy_rwsem);
uverbs_user_mmap_disassociate(ufile);
+ up_write(&ufile->hw_destroy_rwsem);
+ }
}
mutex_unlock(&uverbs_dev->lists_mutex);
}
@@ -927,8 +926,6 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp)
mutex_init(&file->umap_lock);
INIT_LIST_HEAD(&file->umaps);
- mutex_init(&file->disassociation_lock);
-
filp->private_data = file;
list_add_tail(&file->list, &dev->uverbs_file_list);
mutex_unlock(&dev->lists_mutex);
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index f8b219bd308b..5447d39fa89d 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -2056,11 +2056,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 {
@@ -2069,6 +2071,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 d25fdc458120..c2fa83eb0da5 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)
@@ -2343,7 +2347,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/bnxt_re/uapi.c b/drivers/infiniband/hw/bnxt_re/uapi.c
index 263238a6e4cd..f278c4f70ff7 100644
--- a/drivers/infiniband/hw/bnxt_re/uapi.c
+++ b/drivers/infiniband/hw/bnxt_re/uapi.c
@@ -409,7 +409,6 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_DBR_ALLOC)(struct uverbs_attr_bundle *a
uobj->object = obj;
uverbs_finalize_uobj_create(attrs, BNXT_RE_ALLOC_DBR_HANDLE);
- dbr.umdbr = dpi->umdbr;
dbr.dpi = dpi->dpi;
ret = uverbs_copy_to_struct_or_zero(attrs, BNXT_RE_ALLOC_DBR_ATTR,
&dbr, sizeof(dbr));
@@ -472,7 +471,6 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_DEFAULT_DBR)(struct uverbs_attr_bun
return PTR_ERR(ib_uctx);
uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx);
- dpi.umdbr = uctx->dpi.umdbr;
dpi.dpi = uctx->dpi.dpi;
ret = uverbs_copy_to_struct_or_zero(attrs, BNXT_RE_DEFAULT_DBR_ATTR,
@@ -490,7 +488,7 @@ DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_DBR_ALLOC,
UA_MANDATORY),
UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_DBR_ATTR,
UVERBS_ATTR_STRUCT(struct bnxt_re_db_region,
- umdbr),
+ reserved2),
UA_MANDATORY),
UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_DBR_OFFSET,
UVERBS_ATTR_TYPE(u64),
@@ -510,7 +508,7 @@ DECLARE_UVERBS_NAMED_OBJECT(BNXT_RE_OBJECT_DBR,
DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_GET_DEFAULT_DBR,
UVERBS_ATTR_PTR_OUT(BNXT_RE_DEFAULT_DBR_ATTR,
UVERBS_ATTR_STRUCT(struct bnxt_re_db_region,
- umdbr),
+ reserved2),
UA_MANDATORY));
DECLARE_UVERBS_GLOBAL_METHODS(BNXT_RE_OBJECT_DEFAULT_DBR,
diff --git a/drivers/infiniband/hw/efa/efa_com.c b/drivers/infiniband/hw/efa/efa_com.c
index 7cc3f4af0bb9..eed6000fc62d 100644
--- a/drivers/infiniband/hw/efa/efa_com.c
+++ b/drivers/infiniband/hw/efa/efa_com.c
@@ -786,7 +786,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);
@@ -804,8 +804,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;
@@ -1194,7 +1192,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;
@@ -1283,7 +1281,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 f8c692b0e092..d9b3eb0cdf37 100644
--- a/drivers/infiniband/hw/efa/efa_com.h
+++ b/drivers/infiniband/hw/efa/efa_com.h
@@ -159,6 +159,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 97da8e828e34..c2ecd44476d4 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/erdma/erdma_main.c b/drivers/infiniband/hw/erdma/erdma_main.c
index 7e87a815e853..445182c6bc5d 100644
--- a/drivers/infiniband/hw/erdma/erdma_main.c
+++ b/drivers/infiniband/hw/erdma/erdma_main.c
@@ -572,8 +572,8 @@ static int erdma_ib_device_add(struct pci_dev *pdev)
INIT_LIST_HEAD(&dev->cep_list);
spin_lock_init(&dev->lock);
- xa_init_flags(&dev->qp_xa, XA_FLAGS_ALLOC1);
- xa_init_flags(&dev->cq_xa, XA_FLAGS_ALLOC1);
+ xa_init_flags(&dev->qp_xa, XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_IRQ);
+ xa_init_flags(&dev->cq_xa, XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_IRQ);
dev->next_alloc_cqn = 1;
dev->next_alloc_qpn = 1;
diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c
index 20944d506da7..5efd3bfb59d6 100644
--- a/drivers/infiniband/hw/erdma/erdma_verbs.c
+++ b/drivers/infiniband/hw/erdma/erdma_verbs.c
@@ -1023,15 +1023,15 @@ int erdma_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
init_completion(&qp->safe_free);
if (qp->ibqp.qp_type == IB_QPT_GSI) {
- old_entry = xa_store(&dev->qp_xa, 1, qp, GFP_KERNEL);
+ old_entry = xa_store_irq(&dev->qp_xa, 1, qp, GFP_KERNEL);
if (xa_is_err(old_entry))
ret = xa_err(old_entry);
else
qp->ibqp.qp_num = 1;
} else {
- ret = xa_alloc_cyclic(&dev->qp_xa, &qp->ibqp.qp_num, qp,
- XA_LIMIT(1, dev->attrs.max_qp - 1),
- &dev->next_alloc_qpn, GFP_KERNEL);
+ ret = xa_alloc_cyclic_irq(&dev->qp_xa, &qp->ibqp.qp_num, qp,
+ XA_LIMIT(1, dev->attrs.max_qp - 1),
+ &dev->next_alloc_qpn, GFP_KERNEL);
}
if (ret < 0) {
@@ -1091,7 +1091,7 @@ int erdma_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs,
else
free_kernel_qp(qp);
err_out_xa:
- xa_erase(&dev->qp_xa, QP_ID(qp));
+ xa_erase_irq(&dev->qp_xa, QP_ID(qp));
err_out:
return ret;
}
@@ -1995,9 +1995,9 @@ int erdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
refcount_set(&cq->refcount, 1);
init_completion(&cq->free);
- ret = xa_alloc_cyclic(&dev->cq_xa, &cq->cqn, cq,
- XA_LIMIT(1, dev->attrs.max_cq - 1),
- &dev->next_alloc_cqn, GFP_KERNEL);
+ ret = xa_alloc_cyclic_irq(&dev->cq_xa, &cq->cqn, cq,
+ XA_LIMIT(1, dev->attrs.max_cq - 1),
+ &dev->next_alloc_cqn, GFP_KERNEL);
if (ret < 0)
return ret;
@@ -2043,7 +2043,7 @@ int erdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
}
err_out_xa:
- xa_erase(&dev->cq_xa, cq->cqn);
+ xa_erase_irq(&dev->cq_xa, cq->cqn);
return ret;
}
diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c
index 56031becb273..ad2044d1f12c 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 04d5af78686b..e926eb37982c 100644
--- a/drivers/infiniband/hw/irdma/verbs.c
+++ b/drivers/infiniband/hw/irdma/verbs.c
@@ -4244,7 +4244,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 e688ad66a895..5438224bf325 100644
--- a/drivers/infiniband/hw/mlx4/sysfs.c
+++ b/drivers/infiniband/hw/mlx4/sysfs.c
@@ -751,11 +751,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);
@@ -785,6 +787,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 c283a902ea7e..05985395fca0 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -1684,11 +1684,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 acd03bd87794..5ca9211ab33b 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 875eceb55fdf..71d9ea477289 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 1b1c4a0c7110..0f24a55c0637 100644
--- a/drivers/infiniband/sw/rxe/rxe_odp.c
+++ b/drivers/infiniband/sw/rxe/rxe_odp.c
@@ -125,19 +125,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;
}
@@ -160,6 +164,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;
@@ -168,7 +173,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);
@@ -178,7 +183,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;
@@ -340,8 +345,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 1ec130fee8ea..f8c29fc5961d 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -1327,19 +1327,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 0245b25e7271..ed49818793dd 100644
--- a/drivers/infiniband/sw/siw/siw_cm.c
+++ b/drivers/infiniband/sw/siw/siw_cm.c
@@ -1719,9 +1719,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 5061d52a7b12..81bbb3f7c113 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 6401af2fd548..379b78374e21 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 12a2d12fef07..7ea6888b479c 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -598,11 +598,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)) {
@@ -611,12 +608,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;
}
@@ -627,6 +628,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 df5d8295a7fc..6a9e76d60f81 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -21,6 +21,7 @@
#include <target/target_core_fabric.h>
#include <target/iscsi/iscsi_transport.h>
#include <linux/semaphore.h>
+#include <linux/wait_bit.h>
#include "ib_isert.h"
@@ -310,6 +311,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);
}
@@ -1695,6 +1697,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);
@@ -1716,6 +1720,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
@@ -1759,6 +1771,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;
@@ -2603,6 +2621,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-trace.h b/drivers/infiniband/ulp/rtrs/rtrs-clt-trace.h
index 7738e2676855..29e23404bb7b 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-clt-trace.h
+++ b/drivers/infiniband/ulp/rtrs/rtrs-clt-trace.h
@@ -55,7 +55,7 @@ DECLARE_EVENT_CLASS(rtrs_clt_conn_class,
__entry->max_reconnect_attempts = clt->max_reconnect_attempts;
__entry->fail_cnt = clt_path->stats->reconnects.fail_cnt;
__entry->success_cnt = clt_path->stats->reconnects.successful_cnt;
- memcpy(__entry->sessname, kobject_name(&clt_path->kobj), NAME_MAX);
+ strscpy(__entry->sessname, kobject_name(&clt_path->kobj) ?: "", NAME_MAX);
),
TP_printk("RTRS-CLT: sess='%s' state=%s attempts='%d' max-attempts='%d' fail='%d' success='%d'",
diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
index d34d7e5f34d6..62cc93be7b87 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c
+++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c
@@ -1735,6 +1735,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);
@@ -1769,6 +1771,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) {
@@ -2224,6 +2230,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);
@@ -2390,6 +2397,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 1305601a6251..ad64f4517c4b 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/infiniband/ulp/rtrs/rtrs-srv-trace.h b/drivers/infiniband/ulp/rtrs/rtrs-srv-trace.h
index 587d3e033081..a7d7b971e6c8 100644
--- a/drivers/infiniband/ulp/rtrs/rtrs-srv-trace.h
+++ b/drivers/infiniband/ulp/rtrs/rtrs-srv-trace.h
@@ -61,7 +61,7 @@ TRACE_EVENT(send_io_resp_imm,
__entry->msg_id = id->msg_id;
__entry->wr_cnt = atomic_read(&con->c.wr_cnt);
__entry->signal_interval = s->signal_interval;
- memcpy(__entry->sessname, kobject_name(&srv_path->kobj), NAME_MAX);
+ strscpy(__entry->sessname, kobject_name(&srv_path->kobj) ?: "", NAME_MAX);
),
TP_printk("sess='%s' state='%s' dir=%s err='%d' inval='%d' glob-inval='%d' msgid='%u' wrcnt='%d' sig-interval='%u'",
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 3a718d600006..8bfaaa45e0b9 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 2da0b7f1722a..6406ceab988a 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -215,7 +215,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 },
@@ -227,6 +227,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 },
@@ -292,6 +293,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 },
@@ -534,6 +541,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 40371f5bd9ba..4f0ddff5baba 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -446,12 +446,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);
@@ -459,6 +453,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 4c82e988260e..5041443e0efe 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -1954,6 +1954,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 <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/gpio.h>
+#include <linux/platform_data/x86/soc.h>
#include <linux/platform_device.h>
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 c70502e24031..007f90759d06 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 5d49a9021c7d..a349dfd17519 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -991,6 +991,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",
@@ -1005,6 +1014,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 6de68c602558..d799405fbd33 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 412f82d7a303..67da08af75cb 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 9266c07314be..e878a02dc9b7 100644
--- a/drivers/input/touchscreen/cyttsp5.c
+++ b/drivers/input/touchscreen/cyttsp5.c
@@ -710,6 +710,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 b12602bc368e..b870a939508b 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -276,6 +276,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/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c
index ce33907bfc24..65154e569a9e 100644
--- a/drivers/memstick/core/ms_block.c
+++ b/drivers/memstick/core/ms_block.c
@@ -2204,6 +2204,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 02c9d1192812..4a805919bb0c 100644
--- a/drivers/misc/ntsync.c
+++ b/drivers/misc/ntsync.c
@@ -875,6 +875,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 be5cf338bdeb..92ad39c0cabc 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 b7ce3137d452..828078b3f962 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -698,6 +698,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 7fd5dedf3ac0..705163c42972 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 <baolin.wang@linaro.org>
*/
+#include <linux/devm-helpers.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
@@ -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 b471a7795b4d..5217d713c826 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 8dfbc62f165b..d25d4cb59bc9 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -1425,6 +1425,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 f5d973783cbe..d317626feb4a 100644
--- a/drivers/mmc/host/sdhci-of-aspeed.c
+++ b/drivers/mmc/host/sdhci-of-aspeed.c
@@ -560,12 +560,14 @@ static int aspeed_sdc_probe(struct platform_device *pdev)
cpdev = of_platform_device_create(child, NULL, &pdev->dev);
if (!cpdev) {
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;
@@ -575,6 +577,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 9831956de1c8..3e1d46cfbf70 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -1461,6 +1461,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);
@@ -1519,8 +1520,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/dsa/mxl862xx/mxl862xx.c b/drivers/net/dsa/mxl862xx/mxl862xx.c
index cfa7e3e269a2..e05ad52cd297 100644
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -685,10 +685,22 @@ static int mxl862xx_setup(struct dsa_switch *ds)
if (ret)
return ret;
+ ret = mxl862xx_setup_mdio(ds);
+ if (ret)
+ return ret;
+
schedule_delayed_work(&priv->stats_work,
MXL862XX_STATS_POLL_INTERVAL);
- return mxl862xx_setup_mdio(ds);
+ return 0;
+}
+
+static void mxl862xx_teardown(struct dsa_switch *ds)
+{
+ struct mxl862xx_priv *priv = ds->priv;
+
+ set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
+ disable_delayed_work_sync(&priv->stats_work);
}
static int mxl862xx_port_state(struct dsa_switch *ds, int port, bool enable)
@@ -2047,9 +2059,7 @@ static void mxl862xx_get_stats64(struct dsa_switch *ds, int port,
spin_unlock_bh(&priv->ports[port].stats_lock);
- /* Trigger a fresh poll so the next read sees up-to-date counters.
- * No-op if the work is already pending, running, or teardown started.
- */
+ /* Trigger a fresh poll so the next read sees up-to-date counters. */
if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags))
schedule_delayed_work(&priv->stats_work, 0);
}
@@ -2057,6 +2067,7 @@ static void mxl862xx_get_stats64(struct dsa_switch *ds, int port,
static const struct dsa_switch_ops mxl862xx_switch_ops = {
.get_tag_protocol = mxl862xx_get_tag_protocol,
.setup = mxl862xx_setup,
+ .teardown = mxl862xx_teardown,
.port_setup = mxl862xx_port_setup,
.port_teardown = mxl862xx_port_teardown,
.phylink_get_caps = mxl862xx_phylink_get_caps,
@@ -2131,7 +2142,6 @@ static int mxl862xx_probe(struct mdio_device *mdiodev)
err = dsa_register_switch(ds);
if (err) {
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
- cancel_delayed_work_sync(&priv->stats_work);
mxl862xx_host_shutdown(priv);
for (i = 0; i < MXL862XX_MAX_PORTS; i++)
cancel_work_sync(&priv->ports[i].host_flood_work);
@@ -2152,7 +2162,6 @@ static void mxl862xx_remove(struct mdio_device *mdiodev)
priv = ds->priv;
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
- cancel_delayed_work_sync(&priv->stats_work);
dsa_unregister_switch(ds);
@@ -2181,7 +2190,7 @@ static void mxl862xx_shutdown(struct mdio_device *mdiodev)
dsa_switch_shutdown(ds);
set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags);
- cancel_delayed_work_sync(&priv->stats_work);
+ disable_delayed_work_sync(&priv->stats_work);
mxl862xx_host_shutdown(priv);
diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c
index f6396925722d..bc2b4deafd83 100644
--- a/drivers/net/ethernet/airoha/airoha_ppe.c
+++ b/drivers/net/ethernet/airoha/airoha_ppe.c
@@ -280,27 +280,36 @@ static int airoha_ppe_get_wdma_info(struct net_device *dev, const u8 *addr,
struct airoha_wdma_info *info)
{
struct net_device_path_stack stack;
+ struct net_device_path_ctx ctx = {
+ .dev = dev,
+ };
struct net_device_path *path;
int err;
if (!dev)
return -ENODEV;
+ ether_addr_copy(ctx.daddr, addr);
+
rcu_read_lock();
- err = dev_fill_forward_path(dev, addr, &stack);
+ err = dev_fill_forward_path(&ctx, &stack);
rcu_read_unlock();
if (err)
return err;
path = &stack.path[stack.num_paths - 1];
- if (path->type != DEV_PATH_MTK_WDMA)
- return -EINVAL;
+ if (path->type != DEV_PATH_MTK_WDMA) {
+ err = -EINVAL;
+ goto err_out;
+ }
info->idx = path->mtk_wdma.wdma_idx;
info->bss = path->mtk_wdma.bss;
info->wcid = path->mtk_wdma.wcid;
+err_out:
+ dev_fill_forward_path_release(&stack);
- return 0;
+ return err;
}
static int airoha_get_dsa_port(struct net_device **dev)
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index a2305e6428d1..b916080f4ff1 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -749,8 +749,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)
@@ -3376,8 +3385,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);
@@ -4075,6 +4084,7 @@ static int bcmgenet_probe(struct platform_device *pdev)
/* Mii wait queue */
init_waitqueue_head(&priv->wq);
+ 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");
@@ -4272,10 +4282,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/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c
index 6d9166389988..14ae57fa00cb 100644
--- a/drivers/net/ethernet/cadence/macb_ptp.c
+++ b/drivers/net/ethernet/cadence/macb_ptp.c
@@ -50,7 +50,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);
@@ -62,7 +67,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 f08de623e6f7..2dd2fa801829 100644
--- a/drivers/net/ethernet/cortina/gemini.c
+++ b/drivers/net/ethernet/cortina/gemini.c
@@ -1798,7 +1798,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/intel/igc/igc_tsn.c b/drivers/net/ethernet/intel/igc/igc_tsn.c
index 52de2bcbadbe..0c08650d3bb2 100644
--- a/drivers/net/ethernet/intel/igc/igc_tsn.c
+++ b/drivers/net/ethernet/intel/igc/igc_tsn.c
@@ -183,13 +183,15 @@ static u32 igc_fpe_map_preempt_tc_to_queue(const struct igc_adapter *adapter,
u32 i, queue = 0;
for (i = 0; i < dev->num_tc; i++) {
+ struct netdev_tc_txq res;
u32 offset, count;
if (!(preemptible_tcs & BIT(i)))
continue;
- offset = dev->tc_to_txq[i].offset;
- count = dev->tc_to_txq[i].count;
+ res.combined = READ_ONCE(dev->tc_to_txq[i].combined);
+ offset = res.offset;
+ count = res.count;
queue |= GENMASK(offset + count - 1, offset);
}
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 8873a8cc4a18..f91856498eb2 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -9273,10 +9273,11 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
if (sb_dev) {
u8 tc = netdev_get_prio_tc_map(dev, skb->priority);
struct net_device *vdev = sb_dev;
+ struct netdev_tc_txq res;
- txq = vdev->tc_to_txq[tc].offset;
- txq += reciprocal_scale(skb_get_hash(skb),
- vdev->tc_to_txq[tc].count);
+ res.combined = READ_ONCE(vdev->tc_to_txq[tc].combined);
+ txq = res.offset;
+ txq += reciprocal_scale(skb_get_hash(skb), res.count);
return txq;
}
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index ccc24a1301f2..848ee655c6ea 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -5086,7 +5086,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/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index cc8c4ef8038f..99b28aaa7cc4 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -92,6 +92,9 @@ static int
mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_info *info)
{
struct net_device_path_stack stack;
+ struct net_device_path_ctx ctx = {
+ .dev = dev,
+ };
struct net_device_path *path;
int err;
@@ -101,23 +104,29 @@ mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_i
if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED))
return -1;
+ ether_addr_copy(ctx.daddr, addr);
+
rcu_read_lock();
- err = dev_fill_forward_path(dev, addr, &stack);
+ err = dev_fill_forward_path(&ctx, &stack);
rcu_read_unlock();
if (err)
return err;
path = &stack.path[stack.num_paths - 1];
- if (path->type != DEV_PATH_MTK_WDMA)
- return -1;
+ if (path->type != DEV_PATH_MTK_WDMA) {
+ err = -EINVAL;
+ goto err_out;
+ }
info->wdma_idx = path->mtk_wdma.wdma_idx;
info->queue = path->mtk_wdma.queue;
info->bss = path->mtk_wdma.bss;
info->wcid = path->mtk_wdma.wcid;
info->amsdu = path->mtk_wdma.amsdu;
+err_out:
+ dev_fill_forward_path_release(&stack);
- return 0;
+ return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index f0407a850ea8..8634c970cd00 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -3247,7 +3247,7 @@ static int mlx5e_update_tc_and_tx_queues(struct mlx5e_priv *priv)
old_num_txqs = netdev->real_num_tx_queues;
old_ntc = netdev->num_tc ? : 1;
for (i = 0; i < ARRAY_SIZE(old_tc_to_txq); i++)
- old_tc_to_txq[i] = netdev->tc_to_txq[i];
+ old_tc_to_txq[i].combined = READ_ONCE(netdev->tc_to_txq[i].combined);
nch = priv->channels.params.num_channels;
ntc = priv->channels.params.mqprio.num_tc;
diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c
index 401f8b8ae1ca..e7918d3f6aba 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);
@@ -2491,6 +2514,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 e03c9d2c38dc..f5899446dcc5 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 e759171bfd76..2d6e6e8e16f2 100644
--- a/drivers/net/ethernet/microchip/lan743x_main.c
+++ b/drivers/net/ethernet/microchip/lan743x_main.c
@@ -2594,7 +2594,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/sfc/falcon/tx.c b/drivers/net/ethernet/sfc/falcon/tx.c
index 9e18aaf44bad..e4d47d26a87a 100644
--- a/drivers/net/ethernet/sfc/falcon/tx.c
+++ b/drivers/net/ethernet/sfc/falcon/tx.c
@@ -439,8 +439,12 @@ int ef4_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
return 0;
for (tc = 0; tc < num_tc; tc++) {
- net_dev->tc_to_txq[tc].offset = tc * efx->n_tx_channels;
- net_dev->tc_to_txq[tc].count = efx->n_tx_channels;
+ struct netdev_tc_txq res = {
+ .offset = tc * efx->n_tx_channels,
+ .count = efx->n_tx_channels,
+ };
+
+ WRITE_ONCE(net_dev->tc_to_txq[tc].combined, res.combined);
}
if (num_tc > net_dev->num_tc) {
diff --git a/drivers/net/ethernet/sfc/siena/tx.c b/drivers/net/ethernet/sfc/siena/tx.c
index 91e87594ed1e..1ce98f8fdaf8 100644
--- a/drivers/net/ethernet/sfc/siena/tx.c
+++ b/drivers/net/ethernet/sfc/siena/tx.c
@@ -380,8 +380,12 @@ int efx_siena_setup_tc(struct net_device *net_dev, enum tc_setup_type type,
return 0;
for (tc = 0; tc < num_tc; tc++) {
- net_dev->tc_to_txq[tc].offset = tc * efx->n_tx_channels;
- net_dev->tc_to_txq[tc].count = efx->n_tx_channels;
+ struct netdev_tc_txq res = {
+ .offset = tc * efx->n_tx_channels,
+ .count = efx->n_tx_channels,
+ };
+
+ WRITE_ONCE(net_dev->tc_to_txq[tc].combined, res.combined);
}
net_dev->num_tc = num_tc;
diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c
index d14a6584473c..79a0a324c921 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 04dafec021b4..9314bcb85c22 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -494,7 +494,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 92585d27ab88..2a4882f2a498 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -1013,8 +1013,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_fpe.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
index c54c70224351..c889204a7aa5 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c
@@ -217,8 +217,11 @@ int dwmac5_fpe_map_preemption_class(struct net_device *ndev,
* and is direct one-to-one mapping."
*/
for (u32 tc = 0; tc < num_tc; tc++) {
- count = ndev->tc_to_txq[tc].count;
- offset = ndev->tc_to_txq[tc].offset;
+ struct netdev_tc_txq res;
+
+ res.combined = READ_ONCE(ndev->tc_to_txq[tc].combined);
+ count = res.count;
+ offset = res.offset;
if (pclass & BIT(tc))
preemptible_txqs |= GENMASK(offset + count - 1, offset);
@@ -275,8 +278,11 @@ int dwxgmac3_fpe_map_preemption_class(struct net_device *ndev,
* any of the scheduling algorithms."
*/
for (u32 tc = 0; tc < num_tc; tc++) {
- count = ndev->tc_to_txq[tc].count;
- offset = ndev->tc_to_txq[tc].offset;
+ struct netdev_tc_txq res;
+
+ res.combined = READ_ONCE(ndev->tc_to_txq[tc].combined);
+ count = res.count;
+ offset = res.offset;
if (pclass & BIT(tc))
preemptible_txqs |= GENMASK(offset + count - 1, offset);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index f801caf65fff..5f717f02c3c0 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4513,16 +4513,16 @@ static int stmmac_tso_get_num_desc(struct stmmac_tx_queue *tx_q,
*/
static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
{
+ unsigned int first_entry, entry, tx_packets, proto_hdr_len;
struct dma_desc *desc, *first, *mss_desc = NULL;
struct stmmac_priv *priv = netdev_priv(dev);
- unsigned int first_entry, entry, tx_packets;
struct stmmac_txq_stats *txq_stats;
int i, first_tx, nfrags, ndesc;
struct stmmac_tx_queue *tx_q;
bool set_ic, is_last_segment;
u32 pay_len, mss, queue;
- u8 proto_hdr_len, hdr;
dma_addr_t des;
+ u8 hdr;
nfrags = skb_shinfo(skb)->nr_frags;
queue = skb_get_queue_mapping(skb);
@@ -4570,7 +4570,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (netif_msg_tx_queued(priv)) {
- pr_info("%s: hdrlen %d, hdr_len %d, pay_len %d, mss %d\n",
+ pr_info("%s: hdrlen %d, hdr_len %u, pay_len %d, mss %d\n",
__func__, hdr, proto_hdr_len, pay_len, mss);
pr_info("\tskb->len %d, skb->data_len %d\n", skb->len,
skb->data_len);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c
index 14cabe76e53e..42a00446e9b4 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,58 +1237,99 @@ 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_set_ndev_tcs(struct net_device *ndev, u8 ntc,
+ struct netdev_tc_txq *tc_to_txq)
+{
+ int i, err;
+
+ netdev_reset_tc(ndev);
+ if (!ntc)
+ return 0;
+
+ err = netdev_set_num_tc(ndev, ntc);
+ if (err)
+ return err;
+
+ for (i = 0; i < ntc; i++) {
+ u16 count, offset;
+
+ count = tc_to_txq[i].count;
+ offset = tc_to_txq[i].offset;
+ netdev_set_tc_queue(ndev, i, count, offset);
+ }
+
+ return 0;
+}
+
+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,
struct tc_mqprio_qopt_offload *mqprio)
{
+ unsigned int ndev_num_tx_queues, num_tx_queues = 0;
+ struct netdev_tc_txq ndev_tc_to_txq[TC_MAX_QUEUE];
+ struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE] = {};
struct netlink_ext_ack *extack = mqprio->extack;
struct tc_mqprio_qopt *qopt = &mqprio->qopt;
- u32 offset, count, num_stack_tx_queues = 0;
struct net_device *ndev = priv->dev;
- u32 num_tc = qopt->num_tc;
- int err;
-
- if (!num_tc) {
- stmmac_reset_tc_mqprio(ndev, extack);
- return 0;
- }
+ u8 ndev_prio_tc_map[TC_BITMASK + 1];
+ int i, err, ndev_ntc;
- err = netdev_set_num_tc(ndev, num_tc);
- if (err)
- return err;
+ if (!qopt->num_tc)
+ return stmmac_reset_tc_mqprio(ndev, extack);
- for (u32 tc = 0; tc < num_tc; tc++) {
- offset = qopt->offset[tc];
- count = qopt->count[tc];
- num_stack_tx_queues += count;
+ if (qopt->num_tc > ARRAY_SIZE(tc_to_txq))
+ return -EINVAL;
- err = netdev_set_tc_queue(ndev, tc, count, offset);
- if (err)
- goto err_reset_tc;
+ /* save current tc values for reset */
+ ndev_ntc = netdev_get_num_tc(ndev);
+ for (i = 0; i < ARRAY_SIZE(ndev->tc_to_txq); i++)
+ ndev_tc_to_txq[i].combined =
+ READ_ONCE(ndev->tc_to_txq[i].combined);
+ for (i = 0; i < ARRAY_SIZE(ndev_prio_tc_map); i++)
+ ndev_prio_tc_map[i] = READ_ONCE(ndev->prio_tc_map[i]);
+
+ for (i = 0; i < qopt->num_tc; i++) {
+ tc_to_txq[i] = (struct netdev_tc_txq) {
+ .count = qopt->count[i],
+ .offset = qopt->offset[i],
+ };
+ num_tx_queues += qopt->count[i];
}
- err = netif_set_real_num_tx_queues(ndev, num_stack_tx_queues);
+ err = stmmac_set_ndev_tcs(ndev, qopt->num_tc, tc_to_txq);
+ if (err)
+ goto error_reset_tc;
+
+ ndev_num_tx_queues = ndev->real_num_tx_queues;
+ err = netif_set_real_num_tx_queues(ndev, num_tx_queues);
if (err)
- goto err_reset_tc;
+ goto error_reset_tc;
err = stmmac_fpe_map_preemption_class(priv, ndev, extack,
mqprio->preemptible_tcs);
if (err)
- goto err_reset_tc;
+ goto error_reset_num_tx_queues;
return 0;
-err_reset_tc:
- stmmac_reset_tc_mqprio(ndev, extack);
+error_reset_num_tx_queues:
+ if (netif_set_real_num_tx_queues(ndev, ndev_num_tx_queues))
+ netdev_warn(ndev, "Failed to restore %u TX queues\n",
+ ndev_num_tx_queues);
+error_reset_tc:
+ stmmac_set_ndev_tcs(ndev, ndev_ntc, ndev_tc_to_txq);
+ for (i = 0; i < ARRAY_SIZE(ndev_prio_tc_map); i++)
+ netdev_set_prio_tc_map(ndev, i, ndev_prio_tc_map[i]);
return 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 2d55cdc4d165..ae91b57c8422 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);
}
@@ -9892,7 +9909,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 &&
@@ -9916,12 +9932,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 44020ec265fb..801f1218ef89 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 dad6f4563d14..d2ae67985606 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 873754be5174..c86d0bdde832 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c
@@ -200,7 +200,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");
@@ -208,6 +208,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 6255d673d2d3..c1a2318d7ea6 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/libipw_crypto_tkip.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c
index 24bb28ab7a49..2b0cf0ec496a 100644
--- a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c
+++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c
@@ -474,14 +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(&tkey->key[24], (struct ieee80211_hdr *)skb->data,
- skb->data + hdr_len, skb->len - 8 - hdr_len, mic);
- if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
+ 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 "
@@ -499,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;
}
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 0bb807ff8edf..e5113c6b2d5c 100644
--- a/drivers/net/wireless/intel/iwlegacy/common.c
+++ b/drivers/net/wireless/intel/iwlegacy/common.c
@@ -2326,7 +2326,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--;
if (WARN_ON(il->num_stations < 0))
il->num_stations = 0;
diff --git a/drivers/net/wireless/intersil/p54/eeprom.c b/drivers/net/wireless/intersil/p54/eeprom.c
index 95580921d933..0475222d54fc 100644
--- a/drivers/net/wireless/intersil/p54/eeprom.c
+++ b/drivers/net/wireless/intersil/p54/eeprom.c
@@ -414,17 +414,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)
@@ -466,17 +471,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)
@@ -763,6 +773,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;
@@ -770,10 +781,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,
@@ -801,7 +812,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 abc703441c5d..e4ad2e29f10e 100644
--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c
@@ -4279,6 +4279,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;
@@ -4351,10 +4352,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 97c0ec3b822e..bdd4b8465863 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;
}
@@ -2096,6 +2115,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;
@@ -2111,6 +2131,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,
@@ -2128,8 +2156,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);
@@ -2137,15 +2163,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 7d3631d21223..71305efb77ac 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 6654fce4ded8..2737f3b72684 100644
--- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c
+++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c
@@ -1058,6 +1058,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)
@@ -1207,6 +1214,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 4b116fe6f9ea..55a77a2e3288 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/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index bb167f03367b..d9dcbb255317 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 be583ae331c0..ecf55e34caae 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -3724,10 +3724,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_put_autosuspend(wl->dev);
out:
diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
index b4cabbfa9cdb..8c634cada5dd 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
@@ -2317,7 +2317,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);
@@ -6453,12 +6458,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);
@@ -6483,10 +6488,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));
@@ -6505,22 +6517,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;
@@ -6528,7 +6536,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;
@@ -6538,10 +6546,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 2335e45db8b8..48afc2432f93 100644
--- a/drivers/net/wireless/virtual/virt_wifi.c
+++ b/drivers/net/wireless/virtual/virt_wifi.c
@@ -434,6 +434,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;
}
@@ -557,7 +558,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_obj(*dev->ieee80211_ptr);
@@ -583,6 +583,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 a94998712597..336f89756f10 100644
--- a/drivers/net/wwan/mhi_wwan_mbim.c
+++ b/drivers/net/wwan/mhi_wwan_mbim.c
@@ -251,6 +251,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;
@@ -320,7 +328,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:
@@ -332,10 +343,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;
}
@@ -349,9 +357,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/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
index f7389b5437df..f799e4b62815 100644
--- a/drivers/pci/controller/dwc/pci-imx6.c
+++ b/drivers/pci/controller/dwc/pci-imx6.c
@@ -1388,12 +1388,6 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
goto err_pwrctrl_destroy;
}
- ret = imx_pcie_clk_enable(imx_pcie);
- if (ret) {
- dev_err(dev, "unable to enable pcie clocks: %d\n", ret);
- goto err_pwrctrl_power_off;
- }
-
if (pp->bridge && imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT)) {
pp->bridge->enable_device = imx_pcie_enable_device;
pp->bridge->disable_device = imx_pcie_disable_device;
@@ -1409,6 +1403,12 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
imx_pcie_configure_type(imx_pcie);
+ ret = imx_pcie_clk_enable(imx_pcie);
+ if (ret) {
+ dev_err(dev, "unable to enable pcie clocks: %d\n", ret);
+ goto err_pwrctrl_power_off;
+ }
+
if (imx_pcie->phy) {
ret = phy_init(imx_pcie->phy);
if (ret) {
diff --git a/drivers/perf/arm-cmn.c b/drivers/perf/arm-cmn.c
index 6e5cc4086a9e..7e7590381171 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 1426a2db984d..a4bc1268946d 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 7dab11bfcb1c..d0fcc3663e88 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -27,6 +27,7 @@
#include <linux/reset.h>
#include <linux/string.h>
#include <linux/usb/of.h>
+#include <linux/wait.h>
#include <linux/workqueue.h>
/******* USB2.0 Host registers (original offset is +0x200) *******/
@@ -106,6 +107,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,
@@ -138,12 +146,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;
+
+ spin_lock_irqsave(&channel->lock, flags);
- guard(spinlock_irqsave)(&channel->lock);
+ 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;
+
+ 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);
+ }
- guard(spinlock_irqsave)(&channel->lock);
+ /* 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)
return ret;
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 1c5f5820f5b7..226c62704d9b 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 02f42da91598..112f05625aa6 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;
@@ -912,6 +913,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 554dea767885..5880ca28a0ad 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_obj(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_obj(*reclaim_entry);
@@ -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_obj(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_obj(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_obj(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_obj(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);
@@ -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,7 +5077,7 @@ 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);
@@ -5075,7 +5087,7 @@ void fnic_fdls_link_down(struct fnic_iport_s *iport)
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 28c9861b6501..231dec180675 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_obj(*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,7 +723,7 @@ 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) {
@@ -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 8724d64f2525..7c685abd5a5a 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.3"
+#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 {
@@ -598,7 +606,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]);
@@ -613,7 +621,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 063eb864a5cd..ca592bc3f618 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;
@@ -521,7 +521,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);
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 = mempool_alloc(fnic->frame_recv_pool, 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;
@@ -706,13 +706,13 @@ fdls_send_fcoe_frame(struct fnic *fnic, void *frame, int frame_size,
&& (fnic->state != FNIC_IN_ETH_MODE)) {
frame_elem = mempool_alloc(fnic->frame_elem_pool, GFP_ATOMIC);
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;
}
memset(frame_elem, 0, sizeof(struct fnic_frame_list));
- 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;
}
@@ -931,7 +931,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;
@@ -943,12 +943,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 */
@@ -987,7 +987,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);
@@ -1014,7 +1014,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);
@@ -1041,36 +1041,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;
}
@@ -1142,7 +1142,7 @@ void fnic_fcpio_reset(struct fnic *fnic)
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->host, fnic->fnic_num,
+ FNIC_FCS_DBG(KERN_INFO, fnic,
"fnic is in unexpected state: %d for fw_reset\n",
fnic->state);
return;
@@ -1155,7 +1155,7 @@ void fnic_fcpio_reset(struct fnic *fnic)
fnic->fw_reset_done = &fw_reset_done;
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
- FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
+ FNIC_FCS_DBG(KERN_INFO, fnic,
"Issuing fw reset\n");
if (fnic_fw_reset_handler(fnic)) {
spin_lock_irqsave(&fnic->fnic_lock, flags);
@@ -1163,14 +1163,14 @@ void fnic_fcpio_reset(struct fnic *fnic)
fnic->state = old_state;
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
} else {
- FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
+ 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->host, fnic->fnic_num,
+ FNIC_FCS_DBG(KERN_INFO, fnic,
"Woken up after fw completion timeout\n");
if (time_remain == 0) {
- FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
+ FNIC_FCS_DBG(KERN_INFO, fnic,
"FW reset completion timed out after %d ms\n",
FNIC_FW_RESET_TIMEOUT);
}
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 24d62c0874ac..de88786a3bb9 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -185,7 +185,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);
@@ -235,7 +235,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;
@@ -261,7 +261,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;
}
@@ -287,64 +287,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;
@@ -370,7 +372,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;
@@ -678,27 +680,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 6ee3c559e129..0759540f6675 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 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
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 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
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 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
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 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
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 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
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 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
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;
@@ -704,7 +704,7 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
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);
}
@@ -744,12 +744,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));
@@ -758,7 +758,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);
@@ -810,19 +810,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));
@@ -933,19 +932,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;
@@ -957,7 +956,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);
@@ -985,7 +984,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);
@@ -1012,7 +1011,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",
@@ -1044,7 +1043,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;
@@ -1107,7 +1106,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));
}
@@ -1200,27 +1199,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;
@@ -1243,7 +1242,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;
@@ -1255,7 +1254,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);
@@ -1266,7 +1265,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));
@@ -1278,7 +1277,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));
@@ -1293,7 +1292,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;
@@ -1328,7 +1327,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));
@@ -1341,11 +1340,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));
@@ -1376,7 +1375,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));
@@ -1388,7 +1387,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));
@@ -1401,7 +1400,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),
@@ -1410,7 +1409,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));
@@ -1419,7 +1418,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);
@@ -1474,7 +1473,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;
@@ -1535,7 +1534,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;
@@ -1573,7 +1572,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));
@@ -1605,7 +1604,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));
@@ -1630,7 +1629,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));
@@ -1686,7 +1685,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,
@@ -1730,7 +1729,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;
@@ -1775,7 +1774,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;
}
@@ -1789,7 +1788,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);
@@ -1806,16 +1805,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);
}
@@ -1826,13 +1825,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);
@@ -1850,7 +1849,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)
@@ -1881,7 +1880,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);
@@ -1889,7 +1888,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));
@@ -1915,7 +1914,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);
}
@@ -2040,10 +2039,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);
@@ -2052,18 +2051,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);
@@ -2072,7 +2071,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);
@@ -2123,7 +2122,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);
/*
@@ -2214,7 +2213,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;
@@ -2262,7 +2261,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");
@@ -2303,7 +2302,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;
@@ -2371,7 +2370,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));
@@ -2381,14 +2380,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;
@@ -2404,7 +2403,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);
}
@@ -2426,7 +2425,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;
@@ -2518,7 +2517,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;
}
@@ -2568,7 +2567,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);
@@ -2576,7 +2575,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);
@@ -2585,7 +2584,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;
@@ -2593,7 +2592,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;
@@ -2656,7 +2655,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
@@ -2707,13 +2706,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;
@@ -2728,7 +2727,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);
@@ -2740,8 +2739,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;
@@ -2757,7 +2755,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;
}
@@ -2811,13 +2809,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");
@@ -2852,13 +2850,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);
@@ -2869,7 +2867,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);
@@ -2895,7 +2893,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;
}
@@ -2933,7 +2931,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;
}
@@ -2973,7 +2971,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));
@@ -3027,7 +3025,7 @@ 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);
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 54b35893261a..5af81c73a8f8 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -58,15 +58,15 @@ MODULE_PARM_DESC(link_rate, "Enable link rate.\n"
bool pm8001_use_msix = true;
module_param_named(use_msix, pm8001_use_msix, bool, 0444);
-MODULE_PARM_DESC(zoned, "Use MSIX interrupts. Default: true");
+MODULE_PARM_DESC(use_msix, "Use MSIX interrupts. Default: true");
static bool pm8001_use_tasklet = true;
module_param_named(use_tasklet, pm8001_use_tasklet, bool, 0444);
-MODULE_PARM_DESC(zoned, "Use MSIX interrupts. Default: true");
+MODULE_PARM_DESC(use_tasklet, "Use tasklets for interrupt handling. Default: true");
static bool pm8001_read_wwn = true;
module_param_named(read_wwn, pm8001_read_wwn, bool, 0444);
-MODULE_PARM_DESC(zoned, "Get WWN from the controller. Default: true");
+MODULE_PARM_DESC(read_wwn, "Get WWN from the controller. Default: true");
uint pcs_event_log_severity = 0x03;
module_param(pcs_event_log_severity, int, 0644);
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index e0c5732037ad..f2114b386fa0 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -352,7 +352,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 76cdad063f7b..f285521d9de6 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -727,6 +727,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),
@@ -735,11 +736,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 f5fcdde9750e..efccdd63e40e 100644
--- a/drivers/soc/samsung/exynos-pmu.c
+++ b/drivers/soc/samsung/exynos-pmu.c
@@ -409,13 +409,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
@@ -431,8 +430,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 98ed337fb9b0..cf456d7cf0a8 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -1701,6 +1701,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/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c
index 32a46a2d90f7..ff00c4b2578e 100644
--- a/drivers/soundwire/dmi-quirks.c
+++ b/drivers/soundwire/dmi-quirks.c
@@ -192,6 +192,13 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
},
.driver_data = (void *)ghost_realtek,
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUS"),
+ DMI_MATCH(DMI_BOARD_NAME, "GX651AX"),
+ },
+ .driver_data = (void *)ghost_realtek,
+ },
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
diff --git a/drivers/spi/spi-fsl-qspi.c b/drivers/spi/spi-fsl-qspi.c
index 57358851029b..d2c2090442f8 100644
--- a/drivers/spi/spi-fsl-qspi.c
+++ b/drivers/spi/spi-fsl-qspi.c
@@ -289,6 +289,7 @@ struct fsl_qspi {
struct pm_qos_request pm_qos_req;
struct device *dev;
int selected;
+ u32 selected_freq;
u32 memmap_phy;
};
@@ -551,7 +552,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))
@@ -571,6 +573,7 @@ static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi,
}
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 b6c58d9cfe14..8388c637eee0 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,
@@ -1008,8 +1006,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 2256dfec5407..3e181bd8bc94 100644
--- a/drivers/spi/spi-virtio.c
+++ b/drivers/spi/spi-virtio.c
@@ -168,7 +168,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 4a5cce2a16b1..d62586f6e09d 100644
--- a/drivers/watchdog/msc313e_wdt.c
+++ b/drivers/watchdog/msc313e_wdt.c
@@ -46,6 +46,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);
@@ -76,6 +79,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);
@@ -191,11 +197,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 3b6abb66a1da..83540dd9a37b 100644
--- a/drivers/watchdog/rzv2h_wdt.c
+++ b/drivers/watchdog/rzv2h_wdt.c
@@ -278,6 +278,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);
@@ -314,8 +315,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 1ac0b3dcc077..13cf87a5f90c 100644
--- a/fs/9p/vfs_addr.c
+++ b/fs/9p/vfs_addr.c
@@ -54,11 +54,37 @@ 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) {
+ uoff_t end = subreq->start + len, i_size, remote, zp;
+ 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;
+ zp = ictx->_zero_point;
+
+ if (end > i_size) {
+ i_size = end;
+ set = true;
+ }
+ if (end > remote) {
+ remote = end;
+ set = true;
+ }
+
+ if (set)
+ netfs_write_sizes(inode, i_size, remote, zp);
+ 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 318ddb790429..7e78215b2049 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -493,6 +493,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 de6e23b88b40..12b771bda43a 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2358,6 +2358,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 f949805f2c3e..d89268392714 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2513,8 +2513,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 1b3d82ae3de8..b7a4a6ade30f 100644
--- a/fs/btrfs/free-space-tree.c
+++ b/fs/btrfs/free-space-tree.c
@@ -1353,7 +1353,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);
@@ -1371,14 +1371,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);
}
@@ -1390,6 +1392,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 188b4ac9889f..7fe0a63d690a 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2338,12 +2338,27 @@ static int run_delalloc_inline(struct btrfs_inode *inode, struct folio *locked_f
} else if (inode->prop_compress) {
compress_type = inode->prop_compress;
}
+ /*
+ * We need to pass blocksize and not i_size, otherwise we can't
+ * create compressed inline extents for data smaller than sector
+ * size with lzo.
+ */
cb = btrfs_compress_bio(inode, 0, blocksize, compress_type, compress_level, 0);
if (IS_ERR(cb)) {
cb = NULL;
/* Just fall back to non-compressed case. */
} else {
compressed_size = cb->bbio.bio.bi_iter.bi_size;
+ /*
+ * If we did not save space, it's pointless and wasteful
+ * to have an inline compressed extent, so fallback to
+ * an uncompressed inline extent.
+ */
+ if (compressed_size >= i_size) {
+ cleanup_compressed_bio(cb);
+ cb = NULL;
+ compressed_size = 0;
+ }
}
}
if (!can_cow_file_range_inline(inode, 0, i_size, compressed_size)) {
@@ -3876,7 +3891,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/super.c b/fs/btrfs/super.c
index f4e34898d581..2608d03076e0 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1845,8 +1845,12 @@ static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
f_fsid.val[0] ^= btrfs_root_id(BTRFS_I(d_inode(dentry))->root) >> 32;
f_fsid.val[1] ^= btrfs_root_id(BTRFS_I(d_inode(dentry))->root);
- /* Hash dev_t to avoid f_fsid collision with cloned filesystems. */
- if (fs_info->fs_devices->total_devices == 1) {
+ /*
+ * Hash dev_t to avoid f_fsid collisions with cloned filesystems.
+ * Only do this when a clone is present so the original filesystem
+ * (mounted first) maintains backward-compatible f_fsid behavior.
+ */
+ if (fs_info->fs_devices->temp_fsid) {
__kernel_fsid_t dev_fsid =
u64_to_fsid(huge_encode_dev(fs_info->fs_devices->latest_dev->bdev->bd_dev));
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 0ce91396b517..1326bbc1322d 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -2100,7 +2100,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/verity.c b/fs/btrfs/verity.c
index 1133a56c0568..1f05525386c9 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.
*
@@ -120,7 +134,7 @@ 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);
+ trans = start_verity_cleanup_trans(root, 1);
if (IS_ERR(trans))
return PTR_ERR(trans);
@@ -466,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/dax.c b/fs/dax.c
index df19c9317d10..cadbf76da227 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -480,11 +480,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)
@@ -505,21 +506,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 7ae972f3c886..834d622777d6 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1104,6 +1104,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
@@ -1137,6 +1148,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;
/*
@@ -1191,14 +1212,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/nfsd/export.c b/fs/nfsd/export.c
index a47c90f40422..1f678583f612 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1006,7 +1006,8 @@ static int nfsd_nl_parse_one_export(struct cache_detail *cd,
goto out_uuid;
err = 0;
- nfsd4_setup_layout_type(&exp);
+ if (exp.ex_flags & NFSEXP_PNFS)
+ nfsd4_setup_layout_type(&exp);
}
expp = svc_export_lookup(&exp);
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index 918ff4db75f7..b10ef76c98f3 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -2912,7 +2912,7 @@ int ntfs_attr_add(struct ntfs_inode *ni, __le32 type,
attr_ni = NULL;
/* Allocate new extent. */
- err = ntfs_mft_record_alloc(ni->vol, 0, &attr_ni, ni, NULL);
+ err = ntfs_mft_record_alloc(ni->vol, 0, &attr_ni, ni, NULL, -1);
if (err) {
ntfs_error(sb, "Failed to allocate extent record");
goto err_out;
@@ -3545,7 +3545,7 @@ int ntfs_attr_record_move_away(struct ntfs_attr_search_ctx *ctx, int extra)
* new extent and move attribute to it.
*/
ni = NULL;
- err = ntfs_mft_record_alloc(base_ni->vol, 0, &ni, base_ni, NULL);
+ err = ntfs_mft_record_alloc(base_ni->vol, 0, &ni, base_ni, NULL, -1);
if (err) {
ntfs_error(sb, "Couldn't allocate MFT record, err : %d", err);
return err;
@@ -3569,7 +3569,8 @@ int ntfs_attr_record_move_away(struct ntfs_attr_search_ctx *ctx, int extra)
* update allocated and compressed size.
*/
static int ntfs_attr_update_meta(struct attr_record *a, struct ntfs_inode *ni,
- struct mft_record *m, struct ntfs_attr_search_ctx *ctx)
+ struct mft_record *m, struct ntfs_attr_search_ctx *ctx,
+ struct ntfs_inode *locked_ni, bool defer_attrlist)
{
int sparse, err = 0;
struct ntfs_inode *base_ni;
@@ -3605,6 +3606,8 @@ static int ntfs_attr_update_meta(struct attr_record *a, struct ntfs_inode *ni,
le16_to_cpu(a->data.non_resident.mapping_pairs_offset) == 8) &&
!(le32_to_cpu(m->bytes_allocated) - le32_to_cpu(m->bytes_in_use))) {
+ if (defer_attrlist)
+ return -ENOSPC;
if (!NInoAttrList(base_ni)) {
err = ntfs_inode_add_attrlist(base_ni);
if (err)
@@ -3618,7 +3621,7 @@ static int ntfs_attr_update_meta(struct attr_record *a, struct ntfs_inode *ni,
goto out;
}
- err = ntfs_attrlist_update(base_ni);
+ err = ntfs_attrlist_update_locked(base_ni, locked_ni);
if (err)
goto out;
err = -EAGAIN;
@@ -3698,6 +3701,8 @@ static int ntfs_attr_update_meta(struct attr_record *a, struct ntfs_inode *ni,
* ntfs_attr_update_mapping_pairs - update mapping pairs for ntfs attribute
* @ni: non-resident ntfs inode for which we need update
* @from_vcn: update runlist starting this VCN
+ * @locked_ni: inode whose runlist write lock is already held
+ * @defer_attrlist: return -ENOSPC instead of updating an attribute list
*
* Build mapping pairs from @na->rl and write them to the disk. Also, this
* function updates sparse bit, allocated and compressed size (allocates/frees
@@ -3707,7 +3712,10 @@ static int ntfs_attr_update_meta(struct attr_record *a, struct ntfs_inode *ni,
* call to this function. Vice-versa @na->compressed_size will be calculated and
* set to correct value during this function.
*/
-int ntfs_attr_update_mapping_pairs(struct ntfs_inode *ni, s64 from_vcn)
+static int __ntfs_attr_update_mapping_pairs(struct ntfs_inode *ni,
+ s64 from_vcn,
+ struct ntfs_inode *locked_ni,
+ bool defer_attrlist)
{
struct ntfs_attr_search_ctx *ctx;
struct ntfs_inode *base_ni;
@@ -3799,7 +3807,8 @@ int ntfs_attr_update_mapping_pairs(struct ntfs_inode *ni, s64 from_vcn)
continue;
}
- err = ntfs_attr_update_meta(a, ni, m, ctx);
+ err = ntfs_attr_update_meta(a, ni, m, ctx, locked_ni,
+ defer_attrlist);
if (err < 0) {
if (err == -EAGAIN) {
ntfs_attr_put_search_ctx(ctx);
@@ -3839,18 +3848,28 @@ int ntfs_attr_update_mapping_pairs(struct ntfs_inode *ni, s64 from_vcn)
*/
if (ni->type == AT_ATTRIBUTE_LIST) {
ntfs_attr_put_search_ctx(ctx);
- if (ntfs_inode_free_space(base_ni, mp_size -
- cur_max_mp_size)) {
- ntfs_debug("Attribute list is too big. Defragment the volume\n");
- return -ENOSPC;
+ ctx = NULL;
+ if (locked_ni == ni || defer_attrlist) {
+ err = -ENOSPC;
+ goto put_err_out;
}
- if (ntfs_attrlist_update(base_ni))
- return -EIO;
+ err = ntfs_inode_free_space(base_ni, mp_size -
+ cur_max_mp_size);
+ if (err)
+ return err;
+ err = ntfs_attrlist_update_locked(
+ base_ni, locked_ni);
+ if (err)
+ return err;
goto retry;
}
/* Add attribute list if it isn't present, and retry. */
if (!NInoAttrList(base_ni)) {
+ if (defer_attrlist) {
+ err = -ENOSPC;
+ goto put_err_out;
+ }
ntfs_attr_put_search_ctx(ctx);
if (ntfs_inode_add_attrlist(base_ni)) {
ntfs_error(sb, "Can not add attrlist");
@@ -3878,13 +3897,21 @@ int ntfs_attr_update_mapping_pairs(struct ntfs_inode *ni, s64 from_vcn)
}
}
+ if (defer_attrlist &&
+ (ctx->ntfs_ino->nr_extents == -1 ||
+ NInoAttrList(ctx->ntfs_ino)) &&
+ ctx->attr->type != AT_ATTRIBUTE_LIST) {
+ err = -ENOSPC;
+ goto put_err_out;
+ }
+
/* Update lowest vcn. */
a->data.non_resident.lowest_vcn = cpu_to_le64(stop_vcn);
mark_mft_record_dirty(ctx->ntfs_ino);
if ((ctx->ntfs_ino->nr_extents == -1 || NInoAttrList(ctx->ntfs_ino)) &&
ctx->attr->type != AT_ATTRIBUTE_LIST) {
ctx->al_entry->lowest_vcn = cpu_to_le64(stop_vcn);
- err = ntfs_attrlist_update(base_ni);
+ err = ntfs_attrlist_update_locked(base_ni, locked_ni);
if (err)
goto put_err_out;
}
@@ -3971,7 +3998,10 @@ int ntfs_attr_update_mapping_pairs(struct ntfs_inode *ni, s64 from_vcn)
unsigned int de_cnt = 0;
/* Allocate new mft record. */
- err = ntfs_mft_record_alloc(ni->vol, 0, &ext_ni, base_ni, NULL);
+ err = ntfs_mft_record_alloc(ni->vol, 0, &ext_ni, base_ni, NULL,
+ base_ni->mft_no == FILE_MFT &&
+ ni->type == AT_DATA &&
+ ni->name == AT_UNNAMED ? stop_vcn : -1);
if (err) {
ntfs_error(sb, "Failed to allocate extent record");
goto put_err_out;
@@ -4056,6 +4086,19 @@ int ntfs_attr_update_mapping_pairs(struct ntfs_inode *ni, s64 from_vcn)
return err;
}
+int ntfs_attr_update_mapping_pairs_locked(struct ntfs_inode *ni,
+ s64 from_vcn,
+ struct ntfs_inode *locked_ni)
+{
+ return __ntfs_attr_update_mapping_pairs(ni, from_vcn, locked_ni,
+ false);
+}
+
+int ntfs_attr_update_mapping_pairs(struct ntfs_inode *ni, s64 from_vcn)
+{
+ return ntfs_attr_update_mapping_pairs_locked(ni, from_vcn, NULL);
+}
+
/*
* ntfs_attr_make_resident - convert a non-resident to a resident attribute
* @ni: open ntfs attribute to make resident
@@ -4189,7 +4232,9 @@ static int ntfs_attr_make_resident(struct ntfs_inode *ni, struct ntfs_attr_searc
*
* Reduce the size of a non-resident, open ntfs attribute @na to @newsize bytes.
*/
-static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni, const s64 newsize)
+static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni,
+ const s64 newsize,
+ struct ntfs_inode *locked_ni)
{
struct ntfs_volume *vol;
struct ntfs_attr_search_ctx *ctx;
@@ -4197,6 +4242,7 @@ static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni, const s64 newsiz
s64 nr_freed_clusters;
int err;
struct ntfs_inode *base_ni;
+ bool runlist_locked = locked_ni == ni;
ntfs_debug("Inode 0x%llx attr 0x%x new size %lld\n",
(unsigned long long)ni->mft_no, ni->type, (long long)newsize);
@@ -4242,18 +4288,24 @@ static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni, const s64 newsiz
* clusters if there is a change.
*/
if (ntfs_bytes_to_cluster(vol, ni->allocated_size) != first_free_vcn) {
- struct ntfs_attr_search_ctx *ctx;
+ /*
+ * ntfs_cluster_free() and ntfs_rl_truncate_nolock()
+ * both require this lock.
+ */
+ if (!runlist_locked)
+ down_write(&ni->runlist.lock);
err = ntfs_attr_map_whole_runlist(ni);
if (err) {
ntfs_debug("Eeek! ntfs_attr_map_whole_runlist failed.\n");
- return err;
+ goto unlock_runlist;
}
ctx = ntfs_attr_get_search_ctx(ni, NULL);
if (!ctx) {
ntfs_error(vol->sb, "%s: Failed to get search context", __func__);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto unlock_runlist;
}
/* Deallocate all clusters starting with the first free one. */
@@ -4261,7 +4313,8 @@ static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni, const s64 newsiz
if (nr_freed_clusters < 0) {
ntfs_debug("Eeek! Freeing of clusters failed. Aborting...\n");
ntfs_attr_put_search_ctx(ctx);
- return (int)nr_freed_clusters;
+ err = (int)nr_freed_clusters;
+ goto unlock_runlist;
}
ntfs_attr_put_search_ctx(ctx);
@@ -4274,7 +4327,8 @@ static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni, const s64 newsiz
kvfree(ni->runlist.rl);
ni->runlist.rl = NULL;
ntfs_error(vol->sb, "Eeek! Run list truncation failed.\n");
- return -EIO;
+ err = -EIO;
+ goto unlock_runlist;
}
/* Prepare to mapping pairs update. */
@@ -4290,11 +4344,13 @@ static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni, const s64 newsiz
VFS_I(base_ni)->i_blocks = ni->allocated_size >> 9;
/* Write mapping pairs for new runlist. */
- err = ntfs_attr_update_mapping_pairs(ni, 0 /*first_free_vcn*/);
+ err = ntfs_attr_update_mapping_pairs_locked(ni, 0, ni);
if (err) {
ntfs_debug("Eeek! Mapping pairs update failed. Leaving inconstant metadata. Run chkdsk.\n");
- return err;
+ goto unlock_runlist;
}
+ if (!runlist_locked)
+ up_write(&ni->runlist.lock);
}
/* Get the first attribute record. */
@@ -4336,7 +4392,11 @@ static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni, const s64 newsiz
/* If the attribute now has zero size, make it resident. */
if (!newsize && !NInoEncrypted(ni) && !NInoCompressed(ni)) {
+ if (!runlist_locked)
+ down_write(&ni->runlist.lock);
err = ntfs_attr_make_resident(ni, ctx);
+ if (!runlist_locked)
+ up_write(&ni->runlist.lock);
if (err) {
/* If couldn't make resident, just continue. */
if (err != -EPERM)
@@ -4353,6 +4413,11 @@ static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni, const s64 newsiz
put_err_out:
ntfs_attr_put_search_ctx(ctx);
return err;
+
+unlock_runlist:
+ if (!runlist_locked)
+ up_write(&ni->runlist.lock);
+ return err;
}
/*
@@ -4361,13 +4426,14 @@ static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni, const s64 newsiz
* @prealloc_size: preallocation size (in bytes) to which to expand the attribute
* @newsize: new size (in bytes) to which to expand the attribute
* @holes: how to create a hole if expanding
- * @need_lock: whether mrec lock is needed or not
+ * @locked_ni: inode whose runlist lock is already held
*
* Expand the size of a non-resident, open ntfs attribute @na to @newsize bytes,
* by allocating new clusters.
*/
static int ntfs_non_resident_attr_expand(struct ntfs_inode *ni, const s64 newsize,
- const s64 prealloc_size, unsigned int holes, bool need_lock)
+ const s64 prealloc_size, unsigned int holes,
+ struct ntfs_inode *locked_ni)
{
s64 lcn_seek_from;
s64 first_free_vcn;
@@ -4514,13 +4580,39 @@ static int ntfs_non_resident_attr_expand(struct ntfs_inode *ni, const s64 newsiz
ntfs_bytes_to_cluster(vol, ni->allocated_size),
first_free_vcn -
ntfs_bytes_to_cluster(vol, ni->allocated_size),
- lcn_seek_from, DATA_ZONE, false, false, false);
+ lcn_seek_from, DATA_ZONE, false,
+ ni->type == AT_ATTRIBUTE_LIST, false);
if (IS_ERR(rl)) {
ntfs_debug("Cluster allocation failed (%lld)",
(long long)first_free_vcn -
ntfs_bytes_to_cluster(vol, ni->allocated_size));
return PTR_ERR(rl);
}
+ /*
+ * A contiguous ATTRIBUTE_LIST allocation keeps its mapping
+ * pairs small enough to fit in the base MFT record. The
+ * allocator can return a short run when contiguity was
+ * requested, so discard it and retry normally if necessary.
+ */
+ if (ni->type == AT_ATTRIBUTE_LIST &&
+ (rl->vcn != ntfs_bytes_to_cluster(vol,
+ ni->allocated_size) ||
+ rl->length != first_free_vcn -
+ ntfs_bytes_to_cluster(vol, ni->allocated_size) ||
+ rl[1].length)) {
+ ntfs_cluster_free_from_rl(vol, rl);
+ kvfree(rl);
+ rl = ntfs_cluster_alloc(vol,
+ ntfs_bytes_to_cluster(vol,
+ ni->allocated_size),
+ first_free_vcn -
+ ntfs_bytes_to_cluster(vol,
+ ni->allocated_size),
+ lcn_seek_from, DATA_ZONE, false,
+ false, false);
+ if (IS_ERR(rl))
+ return PTR_ERR(rl);
+ }
}
if (!NInoCompressed(ni)) {
@@ -4539,7 +4631,8 @@ static int ntfs_non_resident_attr_expand(struct ntfs_inode *ni, const s64 newsiz
/* Prepare to mapping pairs update. */
ni->allocated_size = ntfs_cluster_to_bytes(vol, first_free_vcn);
- err = ntfs_attr_update_mapping_pairs(ni, 0);
+ err = ntfs_attr_update_mapping_pairs_locked(
+ ni, 0, locked_ni);
if (err) {
ntfs_debug("Mapping pairs update failed");
goto rollback;
@@ -4583,11 +4676,11 @@ static int ntfs_non_resident_attr_expand(struct ntfs_inode *ni, const s64 newsiz
ntfs_debug("Leaking clusters");
/* Now, truncate the runlist itself. */
- if (need_lock)
+ if (ni != locked_ni)
down_write(&ni->runlist.lock);
err2 = ntfs_rl_truncate_nolock(vol, &ni->runlist,
ntfs_bytes_to_cluster(vol, org_alloc_size));
- if (need_lock)
+ if (ni != locked_ni)
up_write(&ni->runlist.lock);
if (err2) {
/*
@@ -4601,11 +4694,11 @@ static int ntfs_non_resident_attr_expand(struct ntfs_inode *ni, const s64 newsiz
/* Prepare to mapping pairs update. */
ni->allocated_size = org_alloc_size;
/* Restore mapping pairs. */
- if (need_lock)
+ if (ni != locked_ni)
down_read(&ni->runlist.lock);
- if (ntfs_attr_update_mapping_pairs(ni, 0))
+ if (__ntfs_attr_update_mapping_pairs(ni, 0, locked_ni, true))
ntfs_error(sb, "Failed to restore old mapping pairs");
- if (need_lock)
+ if (ni != locked_ni)
up_read(&ni->runlist.lock);
if (NInoSparse(ni) || NInoCompressed(ni)) {
@@ -4710,7 +4803,8 @@ static int ntfs_resident_attr_resize(struct ntfs_inode *attr_ni, const s64 newsi
mark_mft_record_dirty(ctx->ntfs_ino);
ntfs_attr_put_search_ctx(ctx);
/* Resize non-resident attribute */
- return ntfs_non_resident_attr_expand(attr_ni, newsize, prealloc_size, holes, true);
+ return ntfs_non_resident_attr_expand(
+ attr_ni, newsize, prealloc_size, holes, NULL);
} else if (err != -ENOSPC && err != -EPERM) {
ntfs_error(sb, "Failed to make attribute non-resident");
goto put_err_out;
@@ -4831,7 +4925,7 @@ static int ntfs_resident_attr_resize(struct ntfs_inode *attr_ni, const s64 newsi
}
/* Allocate new mft record. */
- err = ntfs_mft_record_alloc(base_ni->vol, 0, &ext_ni, base_ni, NULL);
+ err = ntfs_mft_record_alloc(base_ni->vol, 0, &ext_ni, base_ni, NULL, -1);
if (err) {
ntfs_error(sb, "Couldn't allocate MFT record");
goto put_err_out;
@@ -4885,13 +4979,14 @@ int __ntfs_attr_truncate_vfs(struct ntfs_inode *ni, const s64 newsize,
if (NInoNonResident(ni)) {
if (newsize > i_size) {
down_write(&ni->runlist.lock);
- err = ntfs_non_resident_attr_expand(ni, newsize, 0,
- NVolDisableSparse(ni->vol) ?
- HOLES_NO : HOLES_OK,
- false);
+ err = ntfs_non_resident_attr_expand(
+ ni, newsize, 0,
+ NVolDisableSparse(ni->vol) ?
+ HOLES_NO : HOLES_OK, ni);
up_write(&ni->runlist.lock);
} else
- err = ntfs_non_resident_attr_shrink(ni, newsize);
+ err = ntfs_non_resident_attr_shrink(
+ ni, newsize, NULL);
} else
err = ntfs_resident_attr_resize(ni, newsize, 0,
NVolDisableSparse(ni->vol) ?
@@ -4900,7 +4995,9 @@ int __ntfs_attr_truncate_vfs(struct ntfs_inode *ni, const s64 newsize,
return err;
}
-int ntfs_attr_expand(struct ntfs_inode *ni, const s64 newsize, const s64 prealloc_size)
+int ntfs_attr_expand_locked(struct ntfs_inode *ni, const s64 newsize,
+ const s64 prealloc_size,
+ struct ntfs_inode *locked_ni)
{
int err = 0;
@@ -4913,7 +5010,8 @@ int ntfs_attr_expand(struct ntfs_inode *ni, const s64 newsize, const s64 preallo
ntfs_debug("Entering for inode 0x%llx, attr 0x%x, size %lld\n",
(unsigned long long)ni->mft_no, ni->type, newsize);
- if (ni->data_size == newsize) {
+ if (ni->data_size == newsize &&
+ (!prealloc_size || prealloc_size <= ni->allocated_size)) {
ntfs_debug("Size is already ok\n");
return 0;
}
@@ -4928,10 +5026,11 @@ int ntfs_attr_expand(struct ntfs_inode *ni, const s64 newsize, const s64 preallo
}
if (NInoNonResident(ni)) {
- if (newsize > ni->data_size)
- err = ntfs_non_resident_attr_expand(ni, newsize, prealloc_size,
- NVolDisableSparse(ni->vol) ?
- HOLES_NO : HOLES_OK, true);
+ if (newsize > ni->data_size || prealloc_size > ni->allocated_size)
+ err = ntfs_non_resident_attr_expand(
+ ni, newsize, prealloc_size,
+ NVolDisableSparse(ni->vol) ?
+ HOLES_NO : HOLES_OK, locked_ni);
} else
err = ntfs_resident_attr_resize(ni, newsize, prealloc_size,
NVolDisableSparse(ni->vol) ?
@@ -4942,6 +5041,12 @@ int ntfs_attr_expand(struct ntfs_inode *ni, const s64 newsize, const s64 preallo
return err;
}
+int ntfs_attr_expand(struct ntfs_inode *ni, const s64 newsize,
+ const s64 prealloc_size)
+{
+ return ntfs_attr_expand_locked(ni, newsize, prealloc_size, NULL);
+}
+
/*
* ntfs_attr_truncate_i - resize an ntfs attribute
* @ni: open ntfs inode to resize
@@ -4954,7 +5059,9 @@ int ntfs_attr_expand(struct ntfs_inode *ni, const s64 newsize, const s64 preallo
* newly allocated space is marked as not initialised and no real allocation
* on disk is performed.
*/
-int ntfs_attr_truncate_i(struct ntfs_inode *ni, const s64 newsize, unsigned int holes)
+int ntfs_attr_truncate_i_locked(struct ntfs_inode *ni, const s64 newsize,
+ unsigned int holes,
+ struct ntfs_inode *locked_ni)
{
int err;
@@ -4988,15 +5095,23 @@ int ntfs_attr_truncate_i(struct ntfs_inode *ni, const s64 newsize, unsigned int
if (NInoNonResident(ni)) {
if (newsize > ni->data_size)
- err = ntfs_non_resident_attr_expand(ni, newsize, 0, holes, true);
+ err = ntfs_non_resident_attr_expand(
+ ni, newsize, 0, holes, locked_ni);
else
- err = ntfs_non_resident_attr_shrink(ni, newsize);
+ err = ntfs_non_resident_attr_shrink(
+ ni, newsize, locked_ni);
} else
err = ntfs_resident_attr_resize(ni, newsize, 0, holes);
ntfs_debug("Return status %d\n", err);
return err;
}
+int ntfs_attr_truncate_i(struct ntfs_inode *ni, const s64 newsize,
+ unsigned int holes)
+{
+ return ntfs_attr_truncate_i_locked(ni, newsize, holes, NULL);
+}
+
/*
* Resize an attribute, creating a hole if relevant
*/
@@ -5014,10 +5129,11 @@ int ntfs_attr_map_cluster(struct ntfs_inode *ni, s64 vcn_start, s64 *lcn_start,
struct ntfs_volume *vol = ni->vol;
struct ntfs_attr_search_ctx *ctx;
struct runlist_element *rl, *rlc;
+ struct runlist_element *old_rl = NULL;
s64 vcn = vcn_start, lcn, clu_count;
s64 lcn_seek_from = -1;
int err = 0;
- size_t new_rl_count;
+ size_t new_rl_count, old_rl_count;
err = ntfs_attr_map_whole_runlist(ni);
if (err)
@@ -5110,6 +5226,19 @@ int ntfs_attr_map_cluster(struct ntfs_inode *ni, s64 vcn_start, s64 *lcn_start,
WARN_ON(rlc->vcn != vcn);
lcn = rlc->lcn;
clu_count = rlc->length;
+ old_rl_count = ni->runlist.count;
+ old_rl = kmemdup(ni->runlist.rl,
+ old_rl_count * sizeof(*old_rl), GFP_NOFS);
+ if (!old_rl) {
+ err = -ENOMEM;
+ if (ntfs_cluster_free_from_rl(vol, rlc)) {
+ ntfs_error(vol->sb,
+ "Failed to free cluster allocation after runlist backup failure.");
+ NVolSetErrors(vol);
+ }
+ kvfree(rlc);
+ goto out;
+ }
rl = ntfs_runlists_merge(&ni->runlist, rlc, 0, &new_rl_count);
if (IS_ERR(rl)) {
@@ -5133,15 +5262,32 @@ int ntfs_attr_map_cluster(struct ntfs_inode *ni, s64 vcn_start, s64 *lcn_start,
if (update_mp) {
ntfs_attr_reinit_search_ctx(ctx);
- err = ntfs_attr_update_mapping_pairs(ni, 0);
+ err = ntfs_attr_update_mapping_pairs_locked(ni, 0, ni);
if (err) {
int err2;
err2 = ntfs_cluster_free(ni, vcn, clu_count, ctx);
- if (err2 < 0)
+ if (err2 < 0 || err2 != clu_count) {
ntfs_error(vol->sb,
- "Failed to free cluster allocation. Leaving inconstant metadata.\n");
- goto out;
+ "Failed to free cluster allocation. Leaving inconsistent metadata.\n");
+ NVolSetErrors(vol);
+ goto out;
+ }
+
+ /*
+ * Restore the runlist before repairing the on-disk
+ * mapping pairs.
+ */
+ kvfree(ni->runlist.rl);
+ ni->runlist.rl = old_rl;
+ ni->runlist.count = old_rl_count;
+ old_rl = NULL;
+ if (ntfs_attr_update_mapping_pairs_locked(
+ ni, 0, ni)) {
+ ntfs_error(vol->sb,
+ "Failed to restore mapping pairs after allocation rollback.\n");
+ NVolSetErrors(vol);
+ }
}
} else {
VFS_I(ni)->i_blocks += clu_count << (vol->cluster_size_bits - 9);
@@ -5153,6 +5299,7 @@ int ntfs_attr_map_cluster(struct ntfs_inode *ni, s64 vcn_start, s64 *lcn_start,
*lcn_count = clu_count;
*balloc = true;
out:
+ kvfree(old_rl);
ntfs_attr_put_search_ctx(ctx);
return err;
}
@@ -5390,7 +5537,7 @@ int ntfs_non_resident_attr_insert_range(struct ntfs_inode *ni, s64 start_vcn, s6
ni->data_size += ntfs_cluster_to_bytes(vol, len);
if (ntfs_cluster_to_bytes(vol, start_vcn) < ni->initialized_size)
ni->initialized_size += ntfs_cluster_to_bytes(vol, len);
- ret = ntfs_attr_update_mapping_pairs(ni, 0);
+ ret = ntfs_attr_update_mapping_pairs_locked(ni, 0, ni);
up_write(&ni->runlist.lock);
if (ret)
return ret;
@@ -5475,7 +5622,7 @@ int ntfs_non_resident_attr_collapse_range(struct ntfs_inode *ni, s64 start_vcn,
}
if (ni->allocated_size > 0) {
- ret = ntfs_attr_update_mapping_pairs(ni, 0);
+ ret = ntfs_attr_update_mapping_pairs_locked(ni, 0, ni);
if (ret) {
up_write(&ni->runlist.lock);
goto out_rl;
@@ -5553,7 +5700,7 @@ int ntfs_non_resident_attr_punch_hole(struct ntfs_inode *ni, s64 start_vcn, s64
ni->runlist.rl = rl;
ni->runlist.count = new_rl_count;
- ret = ntfs_attr_update_mapping_pairs(ni, 0);
+ ret = ntfs_attr_update_mapping_pairs_locked(ni, 0, ni);
up_write(&ni->runlist.lock);
if (ret) {
kvfree(punch_rl);
@@ -5729,7 +5876,7 @@ int ntfs_attr_fallocate(struct ntfs_inode *ni, loff_t start, loff_t byte_len, bo
if (NInoRunlistDirty(ni)) {
mutex_lock_nested(&ni->mrec_lock, NTFS_INODE_MUTEX_NORMAL);
down_write(&ni->runlist.lock);
- err = ntfs_attr_update_mapping_pairs(ni, 0);
+ err = ntfs_attr_update_mapping_pairs_locked(ni, 0, ni);
if (err)
ntfs_error(ni->vol->sb, "Updating mapping pairs failed");
else
diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h
index e2224fbfaabe..6b4fa9f57640 100644
--- a/fs/ntfs/attrib.h
+++ b/fs/ntfs/attrib.h
@@ -112,7 +112,13 @@ int ntfs_non_resident_attr_punch_hole(struct ntfs_inode *ni, s64 start_vcn, s64
int __ntfs_attr_truncate_vfs(struct ntfs_inode *ni, const s64 newsize,
const s64 i_size);
int ntfs_attr_expand(struct ntfs_inode *ni, const s64 newsize, const s64 prealloc_size);
+int ntfs_attr_expand_locked(struct ntfs_inode *ni, const s64 newsize,
+ const s64 prealloc_size,
+ struct ntfs_inode *locked_ni);
int ntfs_attr_truncate_i(struct ntfs_inode *ni, const s64 newsize, unsigned int holes);
+int ntfs_attr_truncate_i_locked(struct ntfs_inode *ni, const s64 newsize,
+ unsigned int holes,
+ struct ntfs_inode *locked_ni);
int ntfs_attr_truncate(struct ntfs_inode *ni, const s64 newsize);
int ntfs_attr_rm(struct ntfs_inode *ni);
int ntfs_attr_exist(struct ntfs_inode *ni, const __le32 type, __le16 *name,
@@ -133,6 +139,9 @@ int ntfs_resident_attr_record_add(struct ntfs_inode *ni, __le32 type,
__le16 *name, u8 name_len, u8 *val, u32 size,
__le16 flags);
int ntfs_attr_update_mapping_pairs(struct ntfs_inode *ni, s64 from_vcn);
+int ntfs_attr_update_mapping_pairs_locked(struct ntfs_inode *ni,
+ s64 from_vcn,
+ struct ntfs_inode *locked_ni);
struct runlist_element *ntfs_attr_vcn_to_rl(struct ntfs_inode *ni, s64 vcn, s64 *lcn);
/*
diff --git a/fs/ntfs/attrlist.c b/fs/ntfs/attrlist.c
index be3086d34338..bb191953dcb1 100644
--- a/fs/ntfs/attrlist.c
+++ b/fs/ntfs/attrlist.c
@@ -12,6 +12,9 @@
#include "mft.h"
#include "attrib.h"
#include "attrlist.h"
+#include "lcnalloc.h"
+
+#define NTFS_MAX_ATTR_LIST_SIZE (256 * 1024)
/*
* ntfs_attrlist_need - check whether inode need attribute list
@@ -51,11 +54,155 @@ int ntfs_attrlist_need(struct ntfs_inode *ni)
return 0;
}
-int ntfs_attrlist_update(struct ntfs_inode *base_ni)
+/*
+ * Repack the $MFT/$ATTRIBUTE_LIST data into one run.
+ *
+ * The mapping pairs for an $ATTRIBUTE_LIST must remain in the base MFT
+ * record. Once that record has no room left, extending a fragmented list
+ * can require one more mapping-pairs byte than the record can hold. There
+ * is no attribute that can legally be moved out in that state: $STANDARD_
+ * INFORMATION, $ATTRIBUTE_LIST, and the first $MFT/$DATA extent all have to
+ * stay in the base record. Move the list data to one contiguous run. The
+ * caller supplies the minimum allocation size so a recovery can use the
+ * smallest useful run while normal updates can still request the maximum
+ * legal list size as a reserve.
+ */
+static int ntfs_attrlist_repack(struct inode *attr_vi,
+ struct ntfs_inode *attr_ni, s64 min_alloc_size,
+ struct ntfs_inode *locked_ni)
+{
+ struct ntfs_volume *vol = attr_ni->vol;
+ struct runlist_element *old_rl, *new_rl;
+ u8 *data = NULL;
+ s64 data_size, alloc_size, nr_clusters, written;
+ s64 old_alloc_size;
+ size_t old_rl_count, new_rl_count;
+ unsigned long flags;
+ int err, restore_err;
+ if (attr_ni->mft_no != FILE_MFT || !NInoNonResident(attr_ni) ||
+ min_alloc_size < 0)
+ return -EINVAL;
+ /* The buffered I/O below can reacquire the attribute runlist lock. */
+ if (attr_ni == locked_ni)
+ return -ENOSPC;
+
+ err = ntfs_attr_map_whole_runlist(attr_ni);
+ if (err)
+ return err;
+
+ data_size = attr_ni->data_size;
+ if (data_size < 0)
+ return -EIO;
+
+ if (data_size) {
+ data = kvmalloc(data_size, GFP_NOFS);
+ if (!data)
+ return -ENOMEM;
+
+ written = ntfs_inode_attr_pread(attr_vi, 0, data_size, data);
+ if (written != data_size) {
+ err = written < 0 ? (int)written : -EIO;
+ goto out_free_data;
+ }
+ }
+
+ old_alloc_size = attr_ni->allocated_size;
+ alloc_size = max_t(s64, old_alloc_size, min_alloc_size);
+ nr_clusters = ntfs_bytes_to_cluster(vol,
+ alloc_size + vol->cluster_size - 1);
+ if (nr_clusters <= 0) {
+ err = -EFBIG;
+ goto out_free_data;
+ }
+
+ /* A single run keeps the mapping pairs at the minimum size. */
+ new_rl = ntfs_cluster_alloc(vol, 0, nr_clusters, -1, DATA_ZONE,
+ true, true, false);
+ if (IS_ERR(new_rl)) {
+ err = PTR_ERR(new_rl);
+ goto out_free_data;
+ }
+
+ new_rl_count = 0;
+ if (new_rl->vcn == 0 && new_rl->length == nr_clusters &&
+ !new_rl[1].length)
+ new_rl_count = 2;
+
+ if (new_rl_count != 2) {
+ ntfs_cluster_free_from_rl(vol, new_rl);
+ kvfree(new_rl);
+ err = -ENOSPC;
+ goto out_free_data;
+ }
+ old_rl = attr_ni->runlist.rl;
+ old_rl_count = attr_ni->runlist.count;
+ down_write(&attr_ni->runlist.lock);
+ attr_ni->runlist.rl = new_rl;
+ attr_ni->runlist.count = new_rl_count;
+ up_write(&attr_ni->runlist.lock);
+
+ write_lock_irqsave(&attr_ni->size_lock, flags);
+ attr_ni->allocated_size = ntfs_cluster_to_bytes(vol, nr_clusters);
+ write_unlock_irqrestore(&attr_ni->size_lock, flags);
+
+ /* Populate the replacement extent before publishing its mapping pairs. */
+ if (data_size) {
+ written = ntfs_inode_attr_pwrite(attr_vi, 0, data_size, data, true);
+ if (written != data_size) {
+ err = written < 0 ? (int)written : -EIO;
+ goto restore_old_runlist;
+ }
+ }
+
+ err = ntfs_attr_update_mapping_pairs_locked(attr_ni, 0, locked_ni);
+ if (err)
+ goto restore_old_runlist;
+
+ /* The new mapping is now authoritative; release the old data runs. */
+ if (ntfs_cluster_free_from_rl(vol, old_rl)) {
+ ntfs_error(vol->sb,
+ "Failed to free old ATTRIBUTE_LIST extent: inode %#llx",
+ (long long)attr_ni->mft_no);
+ NVolSetErrors(vol);
+ }
+ kvfree(old_rl);
+ kvfree(data);
+ return 0;
+
+restore_old_runlist:
+ down_write(&attr_ni->runlist.lock);
+ attr_ni->runlist.rl = old_rl;
+ attr_ni->runlist.count = old_rl_count;
+ up_write(&attr_ni->runlist.lock);
+
+ write_lock_irqsave(&attr_ni->size_lock, flags);
+ attr_ni->allocated_size = old_alloc_size;
+ write_unlock_irqrestore(&attr_ni->size_lock, flags);
+
+ restore_err = ntfs_attr_update_mapping_pairs_locked(
+ attr_ni, 0, locked_ni);
+ if (restore_err) {
+ ntfs_error(vol->sb, "Failed to restore ATTRIBUTE_LIST mapping pairs (%d)",
+ restore_err);
+ NVolSetErrors(vol);
+ }
+
+ ntfs_cluster_free_from_rl(vol, new_rl);
+ kvfree(new_rl);
+ err = err ? err : restore_err;
+
+out_free_data:
+ kvfree(data);
+ return err;
+}
+
+int ntfs_attrlist_update_locked(struct ntfs_inode *base_ni,
+ struct ntfs_inode *locked_ni)
{
struct inode *attr_vi;
struct ntfs_inode *attr_ni;
- int err;
+ s64 written;
+ int err, retry_err;
/*
* generic_shutdown_super() clears SB_ACTIVE before evicting cached
@@ -72,23 +219,66 @@ int ntfs_attrlist_update(struct ntfs_inode *base_ni)
return err;
}
attr_ni = NTFS_I(attr_vi);
+ /* Truncation and page-cache writes can reacquire this runlist lock. */
+ if (attr_ni == locked_ni) {
+ iput(attr_vi);
+ return -ENOSPC;
+ }
- err = ntfs_attr_truncate_i(attr_ni, base_ni->attr_list_size, HOLES_NO);
- if (err == -ENOSPC && attr_ni->mft_no == FILE_MFT) {
- err = ntfs_attr_truncate(attr_ni, 0);
- if (err || ntfs_attr_truncate_i(attr_ni, base_ni->attr_list_size, HOLES_NO) != 0) {
+ err = ntfs_attr_truncate_i_locked(
+ attr_ni, base_ni->attr_list_size, HOLES_NO, locked_ni);
+ if (err == -ENOSPC && attr_ni->mft_no == FILE_MFT &&
+ NInoNonResident(attr_ni)) {
+ retry_err = ntfs_attrlist_repack(attr_vi, attr_ni,
+ base_ni->attr_list_size, locked_ni);
+ if (retry_err) {
+ ntfs_error(base_ni->vol->sb, "Failed to repack attribute list");
iput(attr_vi);
+ return retry_err;
+ }
+
+ retry_err = ntfs_attr_truncate_i_locked(
+ attr_ni, base_ni->attr_list_size,
+ HOLES_NO, locked_ni);
+ if (retry_err) {
ntfs_error(base_ni->vol->sb,
- "Failed to truncate attribute list of inode %#llx",
- (long long)base_ni->mft_no);
- return -EIO;
+ "Failed to resize attribute list after repack");
+ iput(attr_vi);
+ return retry_err;
}
} else if (err) {
iput(attr_vi);
ntfs_error(base_ni->vol->sb,
"Failed to truncate attribute list of inode %#llx",
(long long)base_ni->mft_no);
- return -EIO;
+ return err;
+ }
+
+ /*
+ * Reserve the maximum legal list size while the MFT metadata area is
+ * still easy to allocate contiguously. This prevents a later list entry
+ * from needing another mapping-pairs byte in the full base MFT record.
+ * Failure to obtain the optional reserve must not reject the current
+ * metadata update; the repack retry above remains available if needed.
+ */
+ if (base_ni->mft_no == FILE_MFT && NInoNonResident(attr_ni) &&
+ attr_ni->allocated_size < NTFS_MAX_ATTR_LIST_SIZE) {
+ retry_err = ntfs_attr_expand_locked(
+ attr_ni, base_ni->attr_list_size,
+ NTFS_MAX_ATTR_LIST_SIZE, locked_ni);
+ if (retry_err == -ENOSPC) {
+ retry_err = ntfs_attrlist_repack(
+ attr_vi, attr_ni,
+ NTFS_MAX_ATTR_LIST_SIZE, locked_ni);
+ if (retry_err == -ENOSPC)
+ retry_err = 0;
+ }
+ if (retry_err) {
+ ntfs_error(base_ni->vol->sb,
+ "Failed to reserve attribute list space");
+ iput(attr_vi);
+ return retry_err;
+ }
}
i_size_write(attr_vi, base_ni->attr_list_size);
@@ -96,14 +286,15 @@ int ntfs_attrlist_update(struct ntfs_inode *base_ni)
if (NInoNonResident(attr_ni) && !NInoAttrListNonResident(base_ni))
NInoSetAttrListNonResident(base_ni);
- if (ntfs_inode_attr_pwrite(attr_vi, 0, base_ni->attr_list_size,
- base_ni->attr_list, false) !=
- base_ni->attr_list_size) {
+ written = ntfs_inode_attr_pwrite(attr_vi, 0, base_ni->attr_list_size,
+ base_ni->attr_list, false);
+ if (written != base_ni->attr_list_size) {
+ err = written < 0 ? (int)written : -EIO;
iput(attr_vi);
ntfs_error(base_ni->vol->sb,
"Failed to write attribute list of inode %#llx",
(long long)base_ni->mft_no);
- return -EIO;
+ return err;
}
NInoSetAttrListDirty(base_ni);
@@ -111,6 +302,11 @@ int ntfs_attrlist_update(struct ntfs_inode *base_ni)
return 0;
}
+int ntfs_attrlist_update(struct ntfs_inode *base_ni)
+{
+ return ntfs_attrlist_update_locked(base_ni, NULL);
+}
+
/*
* ntfs_attrlist_entry_add - add an attribute list attribute entry
* @ni: opened ntfs inode, which contains that attribute
diff --git a/fs/ntfs/attrlist.h b/fs/ntfs/attrlist.h
index 1892a3934d3a..10cc2cc8e208 100644
--- a/fs/ntfs/attrlist.h
+++ b/fs/ntfs/attrlist.h
@@ -16,5 +16,7 @@ int ntfs_attrlist_need(struct ntfs_inode *ni);
int ntfs_attrlist_entry_add(struct ntfs_inode *ni, struct attr_record *attr);
int ntfs_attrlist_entry_rm(struct ntfs_attr_search_ctx *ctx);
int ntfs_attrlist_update(struct ntfs_inode *base_ni);
+int ntfs_attrlist_update_locked(struct ntfs_inode *base_ni,
+ struct ntfs_inode *locked_ni);
#endif /* defined _NTFS_ATTRLIST_H */
diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c
index 4ea1a6bfb3eb..89a151901b9d 100644
--- a/fs/ntfs/compress.c
+++ b/fs/ntfs/compress.c
@@ -1390,7 +1390,7 @@ static int ntfs_write_cb(struct ntfs_inode *ni, loff_t pos, struct page **pages,
ni->runlist.count = new_rl_count;
ni->runlist.rl = rl;
- err = ntfs_attr_update_mapping_pairs(ni, 0);
+ err = ntfs_attr_update_mapping_pairs_locked(ni, 0, ni);
up_write(&ni->runlist.lock);
if (err) {
err = -EIO;
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 7c1cf27bcaad..8f682dbe51ea 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -111,7 +111,8 @@ static int ntfs_trim_prealloc(struct inode *vi)
ntfs_error(vol->sb, "Preallocated block rollback failed");
} else {
ni->allocated_size = ntfs_cluster_to_bytes(vol, vcn_tr);
- err = ntfs_attr_update_mapping_pairs(ni, 0);
+ err = ntfs_attr_update_mapping_pairs_locked(
+ ni, 0, ni);
if (err)
ntfs_error(vol->sb,
"Failed to rollback mapping pairs for prealloc");
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index f40f35afcda9..cfb753be4f6b 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -1232,7 +1232,8 @@ static int ntfs_read_locked_inode(struct inode *vi)
if (m)
unmap_mft_record(ni);
err_out:
- if (err != -EOPNOTSUPP && err != -ENOMEM && vol_err == true) {
+ if (err != -EOPNOTSUPP && err != -ENOMEM &&
+ err != -EINTR && err != -ERESTARTSYS && vol_err == true) {
ntfs_error(vol->sb,
"Failed with error code %i. Marking corrupt inode 0x%llx as bad. Run chkdsk.",
err, ni->mft_no);
@@ -1458,12 +1459,13 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
ntfs_attr_put_search_ctx(ctx);
unmap_mft_record(base_ni);
err_out:
- if (err != -ENOENT)
+ if (err != -ENOENT && err != -EINTR && err != -ERESTARTSYS)
ntfs_error(vol->sb,
"Failed with error code %i while reading attribute inode (mft_no 0x%llx, type 0x%x, name_len %i). Marking corrupt inode and base inode 0x%llx as bad. Run chkdsk.",
err, ni->mft_no, ni->type, ni->name_len,
base_ni->mft_no);
- if (err != -ENOENT && err != -ENOMEM)
+ if (err != -ENOENT && err != -ENOMEM &&
+ err != -EINTR && err != -ERESTARTSYS)
NVolSetErrors(vol);
return err;
}
@@ -1667,8 +1669,9 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
/* Get the index bitmap attribute inode. */
bvi = ntfs_attr_iget(base_vi, AT_BITMAP, ni->name, ni->name_len);
if (IS_ERR(bvi)) {
- ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
err = PTR_ERR(bvi);
+ if (err != -EINTR && err != -ERESTARTSYS)
+ ntfs_error(vi->i_sb, "Failed to get bitmap attribute.");
goto unm_err_out;
}
bni = NTFS_I(bvi);
@@ -1712,10 +1715,12 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
if (m)
unmap_mft_record(base_ni);
err_out:
- ntfs_error(vi->i_sb,
- "Failed with error code %i while reading index inode (mft_no 0x%llx, name_len %i.",
- err, ni->mft_no, ni->name_len);
- if (err != -EOPNOTSUPP && err != -ENOMEM)
+ if (err != -EINTR && err != -ERESTARTSYS)
+ ntfs_error(vi->i_sb,
+ "Failed with error code %i while reading index inode (mft_no 0x%llx, name_len %i.",
+ err, ni->mft_no, ni->name_len);
+ if (err != -EOPNOTSUPP && err != -ENOMEM &&
+ err != -EINTR && err != -ERESTARTSYS)
NVolSetErrors(vol);
return err;
}
@@ -2772,7 +2777,7 @@ int __ntfs_write_inode(struct inode *vi, int sync)
if (NInoNonResident(ni) && NInoRunlistDirty(ni)) {
down_write(&ni->runlist.lock);
- err = ntfs_attr_update_mapping_pairs(ni, 0);
+ err = ntfs_attr_update_mapping_pairs_locked(ni, 0, ni);
if (!err)
NInoClearRunlistDirty(ni);
up_write(&ni->runlist.lock);
@@ -3713,7 +3718,7 @@ static s64 __ntfs_inode_non_resident_attr_pwrite(struct inode *vi,
FGP_CREAT | FGP_LOCK,
mapping_gfp_mask(mapping));
if (IS_ERR(folio)) {
- ret = -ENOMEM;
+ ret = PTR_ERR(folio);
break;
}
} else {
@@ -3745,6 +3750,7 @@ static s64 __ntfs_inode_non_resident_attr_pwrite(struct inode *vi,
u64 rl_length = 0;
s64 vcn;
struct runlist_element *rl;
+ int bio_err;
lcn_count = max_t(s64, 1, ntfs_bytes_to_cluster(vol, attr_len));
vcn = ntfs_pidx_to_cluster(vol, folio->index);
@@ -3788,8 +3794,15 @@ static s64 __ntfs_inode_non_resident_attr_pwrite(struct inode *vi,
goto err_unlock_folio;
}
- submit_bio_wait(bio);
+ bio_err = submit_bio_wait(bio);
bio_put(bio);
+ if (bio_err) {
+ ntfs_error(vi->i_sb,
+ "Synchronous attribute write failed (%d)",
+ bio_err);
+ ret = bio_err;
+ goto err_unlock_folio;
+ }
vcn += rl_length;
offset += length;
} while (lcn_count != 0);
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
index 3ad739179c7a..8dcbc93a8cca 100644
--- a/fs/ntfs/mft.c
+++ b/fs/ntfs/mft.c
@@ -213,7 +213,8 @@ struct mft_record *map_mft_record(struct ntfs_inode *ni)
return m;
atomic_dec(&ni->count);
- ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
+ if (PTR_ERR(m) != -EINTR && PTR_ERR(m) != -ERESTARTSYS)
+ ntfs_error(ni->vol->sb, "Failed with error code %lu.", -PTR_ERR(m));
return m;
}
@@ -841,12 +842,126 @@ static bool ntfs_may_write_mft_record(struct ntfs_volume *vol, const u64 mft_no,
static const char *es = " Leaving inconsistent metadata. Unmount and run chkdsk.";
-#define RESERVED_MFT_RECORDS 64
+#define FIRST_NORMAL_MFT_RECORD 24
+#define MFT_RECORD_RESERVE 4
/*
- * ntfs_mft_bitmap_find_and_alloc_free_rec_nolock - see name
+ * Records 12-15 are marked in use by Windows but normally have no name
+ * and no links. Keep them as the last bootstrap option when a volume
+ * mounted without an in-memory tail reserve needs its first $MFT metadata
+ * extent.
+ */
+static bool mft_reserved_is_free(struct ntfs_volume *vol,
+ struct ntfs_inode *mft_ni, s64 mft_no)
+{
+ struct attr_record *a;
+ struct mft_record *m;
+ struct folio *folio;
+ void *mapped;
+ pgoff_t index = NTFS_MFT_NR_TO_PIDX(vol, mft_no);
+ unsigned int ofs = NTFS_MFT_NR_TO_POFS(vol, mft_no);
+ u32 attrs_offset, bytes_in_use;
+ bool available = false, have_std = false;
+ int i;
+
+ for (i = 0; i < mft_ni->nr_extents; i++) {
+ if (mft_ni->ext.extent_ntfs_inos[i] &&
+ mft_ni->ext.extent_ntfs_inos[i]->mft_no == mft_no)
+ return false;
+ }
+ m = kmalloc(vol->mft_record_size, GFP_NOFS);
+ if (!m)
+ return false;
+
+ folio = read_mapping_folio(vol->mft_ino->i_mapping, index, NULL);
+ if (IS_ERR(folio))
+ goto free_m;
+
+ folio_lock(folio);
+ mapped = kmap_local_folio(folio, 0);
+ memcpy(m, (u8 *)mapped + ofs, vol->mft_record_size);
+ kunmap_local(mapped);
+ folio_unlock(folio);
+ folio_put(folio);
+ if (post_read_mst_fixup((struct ntfs_record *)m, vol->mft_record_size))
+ goto free_m;
+
+ if (!ntfs_is_mft_record(m->magic) ||
+ !(m->flags & MFT_RECORD_IN_USE) || m->base_mft_record ||
+ m->link_count)
+ goto out;
+
+ attrs_offset = le16_to_cpu(m->attrs_offset);
+ bytes_in_use = le32_to_cpu(m->bytes_in_use);
+ if (attrs_offset > bytes_in_use || bytes_in_use > vol->mft_record_size ||
+ bytes_in_use - attrs_offset < sizeof(a->type))
+ goto out;
+
+ for (a = (struct attr_record *)((u8 *)m + attrs_offset);
+ (u8 *)a + sizeof(a->type) <= (u8 *)m + bytes_in_use;) {
+ u32 len;
+
+ if (a->type == AT_END) {
+ if ((u8 *)a + sizeof(a->type) + sizeof(a->length) >
+ (u8 *)m + bytes_in_use)
+ break;
+ /* Also accept a record emptied by an earlier bootstrap. */
+ available = have_std ||
+ (u8 *)a == (u8 *)m + attrs_offset;
+ break;
+ }
+ if (a->type == AT_FILE_NAME)
+ break;
+ len = le32_to_cpu(a->length);
+ if (len < offsetof(struct attr_record, data) ||
+ (u8 *)a + len > (u8 *)m + bytes_in_use)
+ break;
+ if (a->type == AT_STANDARD_INFORMATION) {
+ u32 value_len, value_ofs;
+
+ if (have_std || a->non_resident ||
+ len < offsetof(struct attr_record,
+ data.resident.reserved) + 1)
+ break;
+ value_len = le32_to_cpu(a->data.resident.value_length);
+ value_ofs = le16_to_cpu(a->data.resident.value_offset);
+ if (value_ofs > len || value_len > len - value_ofs)
+ break;
+ have_std = true;
+ }
+ a = (struct attr_record *)((u8 *)a + len);
+ }
+out:
+ kfree(m);
+ return available;
+free_m:
+ kfree(m);
+ return false;
+}
+
+static s64 mft_reserve_end(const u8 *buf, s64 buf_start, s64 buf_end,
+ s64 start, s64 pass_end, s64 initialized_mft_records)
+{
+ s64 end = start + 1;
+ s64 limit = min_t(s64, start + MFT_RECORD_RESERVE, pass_end);
+
+ if (limit > initialized_mft_records)
+ limit = initialized_mft_records;
+ if (limit > buf_end)
+ limit = buf_end;
+ while (end < limit &&
+ !(buf[(end - buf_start) >> 3] &
+ (1 << ((end - buf_start) & 7))))
+ end++;
+ return end;
+}
+
+/*
+ * mft_bitmap_alloc_free_rec - find and allocate a free MFT record
* @vol: volume on which to search for a free mft record
* @base_ni: open base inode if allocating an extent mft record or NULL
+ * @max_mft_no: first record which must not be allocated, or -1
+ * @new_reserve_end: if not NULL, end of a free run starting after the result
*
* Search for a free mft record in the mft bitmap attribute on the ntfs volume
* @vol.
@@ -862,10 +977,12 @@ static const char *es = " Leaving inconsistent metadata. Unmount and run chkds
*
* Locking: Caller must hold vol->mftbmp_lock for writing.
*/
-static s64 ntfs_mft_bitmap_find_and_alloc_free_rec_nolock(struct ntfs_volume *vol,
- struct ntfs_inode *base_ni)
+static s64 mft_bitmap_alloc_free_rec(struct ntfs_volume *vol,
+ struct ntfs_inode *base_ni,
+ s64 max_mft_no, s64 *new_reserve_end)
{
s64 pass_end, ll, data_pos, pass_start, ofs, bit;
+ s64 initialized_mft_records;
unsigned long flags;
struct address_space *mftbmp_mapping;
u8 *buf = NULL, *byte;
@@ -882,30 +999,36 @@ static s64 ntfs_mft_bitmap_find_and_alloc_free_rec_nolock(struct ntfs_volume *vo
read_lock_irqsave(&NTFS_I(vol->mft_ino)->size_lock, flags);
pass_end = NTFS_I(vol->mft_ino)->allocated_size >>
vol->mft_record_size_bits;
+ initialized_mft_records = NTFS_I(vol->mft_ino)->initialized_size >>
+ vol->mft_record_size_bits;
read_unlock_irqrestore(&NTFS_I(vol->mft_ino)->size_lock, flags);
read_lock_irqsave(&NTFS_I(vol->mftbmp_ino)->size_lock, flags);
ll = NTFS_I(vol->mftbmp_ino)->initialized_size << 3;
read_unlock_irqrestore(&NTFS_I(vol->mftbmp_ino)->size_lock, flags);
if (pass_end > ll)
pass_end = ll;
- pass = 1;
- if (!base_ni)
- data_pos = vol->mft_data_pos;
- else
- data_pos = base_ni->mft_no + 1;
- if (data_pos < RESERVED_MFT_RECORDS)
- data_pos = RESERVED_MFT_RECORDS;
- if (data_pos >= pass_end) {
- data_pos = RESERVED_MFT_RECORDS;
+ if (max_mft_no >= 0 && pass_end > max_mft_no)
+ pass_end = max_mft_no;
+ if (base_ni && base_ni->mft_no == FILE_MFT) {
+ data_pos = FILE_first_user;
pass = 2;
- /* This happens on a freshly formatted volume. */
if (data_pos >= pass_end)
return -ENOSPC;
- }
-
- if (base_ni && base_ni->mft_no == FILE_MFT) {
- data_pos = 0;
- pass = 2;
+ } else {
+ pass = 1;
+ if (!base_ni)
+ data_pos = vol->mft_data_pos;
+ else
+ data_pos = base_ni->mft_no + 1;
+ if (data_pos < FIRST_NORMAL_MFT_RECORD)
+ data_pos = FIRST_NORMAL_MFT_RECORD;
+ if (data_pos >= pass_end) {
+ data_pos = FIRST_NORMAL_MFT_RECORD;
+ pass = 2;
+ /* This happens on a freshly formatted volume. */
+ if (data_pos >= pass_end)
+ return -ENOSPC;
+ }
}
pass_start = data_pos;
@@ -940,38 +1063,28 @@ static s64 ntfs_mft_bitmap_find_and_alloc_free_rec_nolock(struct ntfs_volume *vo
size, data_pos, bit);
for (; bit < size && data_pos + bit < pass_end;
bit &= ~7ull, bit += 8) {
- /*
- * If we're extending $MFT and running out of the first
- * mft record (base record) then give up searching since
- * no guarantee that the found record will be accessible.
- */
- if (base_ni && base_ni->mft_no == FILE_MFT && bit > 400) {
- folio_unlock(folio);
- kunmap_local(buf);
- folio_put(folio);
- return -ENOSPC;
- }
-
byte = buf + (bit >> 3);
if (*byte == 0xff)
continue;
- b = ffz((unsigned long)*byte);
- if (b < 8 && b >= (bit & 7)) {
+ b = bit & 7;
+ for (; b < 8; b++) {
+ if (*byte & (1 << b))
+ continue;
ll = data_pos + (bit & ~7ull) + b;
+ if (ll >= pass_end)
+ break;
+ /* Keep the dynamic tail reserve for $MFT metadata. */
+ if ((!base_ni || base_ni->mft_no != FILE_MFT) &&
+ ll >= vol->mft_record_reserve_pos &&
+ ll < vol->mft_record_reserve_end)
+ continue;
if (unlikely(ll >= (1ll << 32))) {
folio_unlock(folio);
kunmap_local(buf);
folio_put(folio);
return -ENOSPC;
}
- *byte |= 1 << b;
- folio_mark_dirty(folio);
- folio_unlock(folio);
- kunmap_local(buf);
- folio_put(folio);
- ntfs_debug("Done. (Found and allocated mft record 0x%llx.)",
- ll);
- return ll;
+ goto found;
}
}
ntfs_debug("After inner for loop: size 0x%x, data_pos 0x%llx, bit 0x%llx",
@@ -994,7 +1107,8 @@ static s64 ntfs_mft_bitmap_find_and_alloc_free_rec_nolock(struct ntfs_volume *vo
* part of the zone which we omitted earlier.
*/
pass_end = pass_start;
- data_pos = pass_start = RESERVED_MFT_RECORDS;
+ data_pos = FIRST_NORMAL_MFT_RECORD;
+ pass_start = FIRST_NORMAL_MFT_RECORD;
ntfs_debug("pass %i, pass_start 0x%llx, pass_end 0x%llx.",
pass, pass_start, pass_end);
if (data_pos >= pass_end)
@@ -1004,9 +1118,22 @@ static s64 ntfs_mft_bitmap_find_and_alloc_free_rec_nolock(struct ntfs_volume *vo
/* No free mft records in currently initialized mft bitmap. */
ntfs_debug("Done. (No free mft records left in currently initialized mft bitmap.)");
return -ENOSPC;
+found:
+ if (new_reserve_end)
+ *new_reserve_end = mft_reserve_end(buf, data_pos,
+ data_pos + size, ll, pass_end,
+ initialized_mft_records);
+ *byte |= 1 << b;
+ folio_mark_dirty(folio);
+ folio_unlock(folio);
+ kunmap_local(buf);
+ folio_put(folio);
+ ntfs_debug("Done. (Found and allocated mft record 0x%llx.)", ll);
+ return ll;
}
-static int ntfs_mft_attr_extend(struct ntfs_inode *ni)
+static int ntfs_mft_attr_extend(struct ntfs_inode *ni,
+ struct ntfs_inode *locked_ni)
{
int ret = 0;
struct ntfs_inode *base_ni;
@@ -1027,7 +1154,7 @@ static int ntfs_mft_attr_extend(struct ntfs_inode *ni)
}
}
- ret = ntfs_attr_update_mapping_pairs(ni, 0);
+ ret = ntfs_attr_update_mapping_pairs_locked(ni, 0, locked_ni);
if (ret)
pr_err("MP update failed\n");
@@ -1215,7 +1342,7 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(struct ntfs_volume *vol)
ret = ntfs_attr_record_resize(ctx->mrec, a, mp_size +
le16_to_cpu(a->data.non_resident.mapping_pairs_offset));
if (unlikely(ret)) {
- ret = ntfs_mft_attr_extend(mftbmp_ni);
+ ret = ntfs_mft_attr_extend(mftbmp_ni, mftbmp_ni);
if (!ret)
goto extended_ok;
if (ret != -EAGAIN)
@@ -1326,7 +1453,9 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(struct ntfs_volume *vol)
NVolSetErrors(vol);
}
mark_mft_record_dirty(ctx->ntfs_ino);
- } else if (status.mp_extended && ntfs_attr_update_mapping_pairs(mftbmp_ni, 0)) {
+ } else if (status.mp_extended &&
+ ntfs_attr_update_mapping_pairs_locked(mftbmp_ni, 0,
+ mftbmp_ni)) {
ntfs_error(vol->sb, "Failed to restore mapping pairs.%s", es);
NVolSetErrors(vol);
}
@@ -1414,7 +1543,6 @@ static int ntfs_mft_bitmap_extend_initialized_nolock(struct ntfs_volume *vol)
ret = ntfs_attr_set(mftbmp_ni, old_initialized_size, 8, 0);
if (likely(!ret)) {
ntfs_debug("Done. (Wrote eight initialized bytes to mft bitmap.");
- ntfs_inc_free_mft_records(vol, 8 * 8);
return 0;
}
ntfs_error(vol->sb, "Failed to write to mft bitmap.");
@@ -1471,8 +1599,9 @@ static int ntfs_mft_bitmap_extend_initialized_nolock(struct ntfs_volume *vol)
* @vol: volume on which to extend the mft data attribute
*
* Extend the mft data attribute on the ntfs volume @vol by 16 mft records
- * worth of clusters or if not enough space for this by one mft record worth
- * of clusters.
+ * worth of clusters or if not enough space for this by two mft records worth
+ * of clusters. Keeping at least two new records breaks the recursion between
+ * extending $MFT and allocating a record for a new $MFT attribute extent.
*
* Note: Only changes allocated_size, i.e. does not touch initialized_size or
* data_size.
@@ -1526,10 +1655,8 @@ static int ntfs_mft_data_extend_allocation_nolock(struct ntfs_volume *vol)
}
lcn = rl->lcn + rl->length;
ntfs_debug("Last lcn of mft data attribute is 0x%llx.", lcn);
- /* Minimum allocation is one mft record worth of clusters. */
- min_nr = NTFS_B_TO_CLU(vol, vol->mft_record_size);
- if (!min_nr)
- min_nr = 1;
+ /* Keep room for the allocating record and at least one MFT reserve. */
+ min_nr = DIV_ROUND_UP_ULL((u64)vol->mft_record_size * 2, vol->cluster_size);
/* Want to allocate 16 mft records worth of clusters. */
nr = vol->mft_record_size << 4 >> vol->cluster_size_bits;
if (!nr)
@@ -1653,7 +1780,7 @@ static int ntfs_mft_data_extend_allocation_nolock(struct ntfs_volume *vol)
ret = ntfs_attr_record_resize(ctx->mrec, a, mp_size +
le16_to_cpu(a->data.non_resident.mapping_pairs_offset));
if (unlikely(ret)) {
- ret = ntfs_mft_attr_extend(mft_ni);
+ ret = ntfs_mft_attr_extend(mft_ni, NULL);
if (!ret)
goto extended_ok;
if (ret != -EAGAIN)
@@ -1928,6 +2055,7 @@ static int ntfs_mft_record_format(const struct ntfs_volume *vol, const s64 mft_n
* @ni: [OUT] on success, set to the allocated ntfs inode
* @base_ni: [IN] open base inode if allocating an extent mft record or NULL
* @ni_mrec: [OUT] on successful return this is the mapped mft record
+ * @mft_data_vcn: [IN] lowest VCN of a new $MFT/$DATA extent, or -1
*
* Allocate an mft record in $MFT/$DATA of an open ntfs volume @vol.
*
@@ -1955,30 +2083,23 @@ static int ntfs_mft_record_format(const struct ntfs_volume *vol, const s64 mft_n
* optimize this we start scanning at the place specified by @base_ni or if
* @base_ni is NULL we start where we last stopped and we perform wrap around
* when we reach the end. Note, we do not try to allocate mft records below
- * number 64 because numbers 0 to 15 are the defined system files anyway and 16
- * to 64 are special in that they are used for storing extension mft records
- * for the $DATA attribute of $MFT. This is required to avoid the possibility
- * of creating a runlist with a circular dependency which once written to disk
- * can never be read in again. Windows will only use records 16 to 24 for
- * normal files if the volume is completely out of space. We never use them
- * which means that when the volume is really out of space we cannot create any
- * more files while Windows can still create up to 8 small files. We can start
- * doing this at some later time, it does not matter much for now.
+ * number 24 because numbers 0 to 15 are the defined system files and records
+ * 16 to 23 are kept for metadata compatibility. Records reserved dynamically
+ * at the initialized MFT tail are skipped by normal allocation and consumed by
+ * $MFT metadata extent allocation.
*
* When scanning the mft bitmap, we only search up to the last allocated mft
- * record. If there are no free records left in the range 64 to number of
+ * record. If there are no free records left in the range 24 to number of
* allocated mft records, then we extend the $MFT/$DATA attribute in order to
* create free mft records. We extend the allocated size of $MFT/$DATA by 16
* records at a time or one cluster, if cluster size is above 16kiB. If there
- * is not sufficient space to do this, we try to extend by a single mft record
- * or one cluster, if cluster size is above the mft record size.
+ * is not sufficient space to do this, we try to extend by two mft records or
+ * one cluster, if a cluster already contains at least two mft records.
*
- * No matter how many mft records we allocate, we initialize only the first
- * allocated mft record, incrementing mft data size and initialized size
- * accordingly, open an struct ntfs_inode for it and return it to the caller, unless
- * there are less than 64 mft records, in which case we allocate and initialize
- * mft records until we reach record 64 which we consider as the first free mft
- * record for use by normal files.
+ * When extending the initialized MFT tail, we also initialize up to four
+ * additional records and reserve them in memory for future $MFT metadata
+ * extents. If there are less than 24 mft records, records are initialized
+ * until record 24, which is the first record used for normal files.
*
* If during any stage we overflow the initialized data in the mft bitmap, we
* extend the initialized size (and data size) by 8 bytes, allocating another
@@ -2014,9 +2135,13 @@ static int ntfs_mft_record_format(const struct ntfs_volume *vol, const s64 mft_n
*/
int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
struct ntfs_inode **ni, struct ntfs_inode *base_ni,
- struct mft_record **ni_mrec)
+ struct mft_record **ni_mrec, const s64 mft_data_vcn)
{
s64 ll, bit, old_data_initialized, old_data_size;
+ s64 nr_new_mft_records = 0;
+ s64 max_mft_no = -1, reserve_start = -1, reserve_end = -1;
+ s64 candidate_reserve_end = -1;
+ s64 *reserve_endp;
unsigned long flags;
struct folio *folio;
struct ntfs_inode *mft_ni, *mftbmp_ni;
@@ -2027,7 +2152,9 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
unsigned int ofs;
int err;
__le16 seq_no, usn;
- bool record_formatted = false;
+ bool record_formatted = false, from_reserve = false, tail_alloc = false;
+ bool reserve_created = false;
+ bool forced_reserved_record = false;
unsigned int memalloc_flags;
if (base_ni && *ni)
@@ -2036,6 +2163,21 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
/* @mode and @base_ni are mutually exclusive. */
if (mode && base_ni)
return -EINVAL;
+ if (mft_data_vcn >= 0 &&
+ (!base_ni || base_ni->mft_no != FILE_MFT))
+ return -EINVAL;
+ if (mft_data_vcn >= 0) {
+ u64 vbo;
+
+ if ((u64)mft_data_vcn > (U64_MAX >> vol->cluster_size_bits))
+ return -EOVERFLOW;
+ vbo = (u64)mft_data_vcn << vol->cluster_size_bits;
+ /*
+ * The whole extent record must be reachable without this
+ * extent, including when an MFT record spans multiple clusters.
+ */
+ max_mft_no = vbo >> vol->mft_record_size_bits;
+ }
if (base_ni)
ntfs_debug("Entering (allocating an extent mft record for base mft record 0x%llx).",
@@ -2050,10 +2192,39 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
mutex_lock(&mft_ni->mrec_lock);
mftbmp_ni = NTFS_I(vol->mftbmp_ino);
search_free_rec:
+ from_reserve = false;
+ reserve_created = false;
+ candidate_reserve_end = -1;
if (!base_ni || base_ni->mft_no != FILE_MFT)
down_write(&vol->mftbmp_lock);
- bit = ntfs_mft_bitmap_find_and_alloc_free_rec_nolock(vol, base_ni);
+ if (base_ni && base_ni->mft_no == FILE_MFT &&
+ vol->mft_record_reserve_pos < vol->mft_record_reserve_end &&
+ (max_mft_no < 0 || vol->mft_record_reserve_pos < max_mft_no)) {
+ bit = vol->mft_record_reserve_pos;
+ err = ntfs_bitmap_set_bit(vol->mftbmp_ino, bit);
+ if (unlikely(err)) {
+ ntfs_error(vol->sb,
+ "Failed to allocate reserved MFT record 0x%llx.",
+ bit);
+ goto err_out;
+ }
+ vol->mft_record_reserve_pos++;
+ from_reserve = true;
+ ntfs_debug("Allocated MFT metadata record 0x%llx from tail reserve.",
+ bit);
+ goto have_alloc_rec;
+ }
+ reserve_endp = vol->mft_record_reserve_pos >=
+ vol->mft_record_reserve_end ? &candidate_reserve_end : NULL;
+ bit = mft_bitmap_alloc_free_rec(vol, base_ni, max_mft_no, reserve_endp);
if (bit >= 0) {
+ if (candidate_reserve_end > bit + 1) {
+ vol->mft_record_reserve_pos = bit + 1;
+ vol->mft_record_reserve_end = candidate_reserve_end;
+ reserve_created = true;
+ ntfs_debug("Reserved free MFT records [0x%llx, 0x%llx) for metadata.",
+ bit + 1, candidate_reserve_end);
+ }
ntfs_debug("Found and allocated free record (#1), bit 0x%llx.",
(long long)bit);
goto have_alloc_rec;
@@ -2068,6 +2239,24 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
}
if (base_ni && base_ni->mft_no == FILE_MFT) {
+ static const u8 bootstrap_records[] = {
+ FILE_reserved15, FILE_reserved12, FILE_reserved13,
+ FILE_reserved14,
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(bootstrap_records); i++) {
+ if (max_mft_no >= 0 && bootstrap_records[i] >= max_mft_no)
+ continue;
+ if (!mft_reserved_is_free(vol, mft_ni,
+ bootstrap_records[i]))
+ continue;
+ bit = bootstrap_records[i];
+ forced_reserved_record = true;
+ ntfs_debug("Using reserved MFT record %lld to bootstrap metadata extension.",
+ bit);
+ goto have_alloc_rec;
+ }
memalloc_nofs_restore(memalloc_flags);
return bit;
}
@@ -2087,10 +2276,10 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
old_data_initialized = mftbmp_ni->initialized_size;
read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
if (old_data_initialized << 3 > ll &&
- old_data_initialized > RESERVED_MFT_RECORDS / 8) {
+ old_data_initialized << 3 > FIRST_NORMAL_MFT_RECORD) {
bit = ll;
- if (bit < RESERVED_MFT_RECORDS)
- bit = RESERVED_MFT_RECORDS;
+ if (bit < FIRST_NORMAL_MFT_RECORD)
+ bit = FIRST_NORMAL_MFT_RECORD;
if (unlikely(bit >= (1ll << 32)))
goto max_err_out;
ntfs_debug("Found free record (#2), bit 0x%llx.",
@@ -2176,6 +2365,11 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
read_lock_irqsave(&mft_ni->size_lock, flags);
old_data_initialized = mft_ni->initialized_size;
read_unlock_irqrestore(&mft_ni->size_lock, flags);
+ tail_alloc = (!base_ni || base_ni->mft_no != FILE_MFT) &&
+ bit >= (old_data_initialized >> vol->mft_record_size_bits) &&
+ vol->mft_record_reserve_pos >= vol->mft_record_reserve_end;
+ if (tail_alloc)
+ ll = (bit + 2) << vol->mft_record_size_bits;
if (ll <= old_data_initialized) {
ntfs_debug("Allocated mft record already initialized.");
goto mft_rec_already_initialized;
@@ -2208,6 +2402,29 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
mft_ni->initialized_size);
}
read_unlock_irqrestore(&mft_ni->size_lock, flags);
+ if (tail_alloc) {
+ s64 bitmap_records;
+
+ read_lock_irqsave(&mft_ni->size_lock, flags);
+ reserve_end = mft_ni->allocated_size >>
+ vol->mft_record_size_bits;
+ read_unlock_irqrestore(&mft_ni->size_lock, flags);
+ read_lock_irqsave(&mftbmp_ni->size_lock, flags);
+ bitmap_records = mftbmp_ni->initialized_size << 3;
+ read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);
+ if (reserve_end > bitmap_records)
+ reserve_end = bitmap_records;
+ if (reserve_end > bit + 1 + MFT_RECORD_RESERVE)
+ reserve_end = bit + 1 + MFT_RECORD_RESERVE;
+ reserve_start = bit + 1;
+ if (reserve_end > reserve_start) {
+ ll = reserve_end << vol->mft_record_size_bits;
+ } else {
+ reserve_start = -1;
+ reserve_end = -1;
+ ll = (bit + 1) << vol->mft_record_size_bits;
+ }
+ }
} else if (ll > mft_ni->allocated_size) {
err = -ENOSPC;
goto undo_mftbmp_alloc_nolock;
@@ -2276,14 +2493,25 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
mark_mft_record_dirty(ctx->ntfs_ino);
ntfs_attr_put_search_ctx(ctx);
unmap_mft_record(mft_ni);
+ if (reserve_start >= 0 && reserve_end > reserve_start) {
+ vol->mft_record_reserve_pos = reserve_start;
+ vol->mft_record_reserve_end = reserve_end;
+ ntfs_debug("Reserved MFT records [0x%llx, 0x%llx) for metadata.",
+ reserve_start, reserve_end);
+ }
read_lock_irqsave(&mft_ni->size_lock, flags);
ntfs_debug("Status of mft data after mft record initialization: allocated_size 0x%llx, data_size 0x%llx, initialized_size 0x%llx.",
mft_ni->allocated_size, i_size_read(vol->mft_ino),
mft_ni->initialized_size);
WARN_ON(i_size_read(vol->mft_ino) > mft_ni->allocated_size);
WARN_ON(mft_ni->initialized_size > i_size_read(vol->mft_ino));
+ nr_new_mft_records = (i_size_read(vol->mft_ino) - old_data_size) >>
+ vol->mft_record_size_bits;
read_unlock_irqrestore(&mft_ni->size_lock, flags);
mft_rec_already_initialized:
+ /* Account for newly visible MFT records before dropping the lock. */
+ if (nr_new_mft_records > 0)
+ ntfs_inc_free_mft_records(vol, nr_new_mft_records);
/*
* We can finally drop the mft bitmap lock as the mft data attribute
* has been fully updated. The only disparity left is that the
@@ -2315,8 +2543,8 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
/* If we just formatted the mft record no need to do it again. */
if (!record_formatted) {
/* Sanity check that the mft record is really not in use. */
- if (ntfs_is_file_record(m->magic) &&
- (m->flags & MFT_RECORD_IN_USE)) {
+ if (!forced_reserved_record && ntfs_is_file_record(m->magic) &&
+ (m->flags & MFT_RECORD_IN_USE)) {
ntfs_warning(vol->sb,
"Mft record 0x%llx was marked free in mft bitmap but is marked used itself. Unmount and run chkdsk.",
bit);
@@ -2389,9 +2617,13 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
ntfs_error(vol->sb, "Failed to map allocated extent mft record 0x%llx.",
bit);
err = PTR_ERR(m_tmp);
- /* Set the mft record itself not in use. */
- m->flags &= cpu_to_le16(
- ~le16_to_cpu(MFT_RECORD_IN_USE));
+ if (forced_reserved_record) {
+ m->base_mft_record = 0;
+ m->flags |= MFT_RECORD_IN_USE;
+ } else {
+ /* Set the mft record itself not in use. */
+ m->flags &= cpu_to_le16(~le16_to_cpu(MFT_RECORD_IN_USE));
+ }
/* Make sure the mft record is written out to disk. */
ntfs_mft_mark_dirty(folio);
folio_unlock(folio);
@@ -2464,7 +2696,8 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
(*ni)->mft_no = bit;
if (ni_mrec)
*ni_mrec = (*ni)->mrec;
- ntfs_dec_free_mft_records(vol, 1);
+ if (!forced_reserved_record)
+ ntfs_dec_free_mft_records(vol, 1);
return 0;
undo_data_init:
write_lock_irqsave(&mft_ni->size_lock, flags);
@@ -2476,10 +2709,13 @@ int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
if (!base_ni || base_ni->mft_no != FILE_MFT)
down_write(&vol->mftbmp_lock);
undo_mftbmp_alloc_nolock:
- if (ntfs_bitmap_clear_bit(vol->mftbmp_ino, bit)) {
+ if (!forced_reserved_record && ntfs_bitmap_clear_bit(vol->mftbmp_ino, bit)) {
ntfs_error(vol->sb, "Failed to clear bit in mft bitmap.%s", es);
NVolSetErrors(vol);
}
+ if ((from_reserve || reserve_created) &&
+ vol->mft_record_reserve_pos == bit + 1)
+ vol->mft_record_reserve_pos = bit;
if (!base_ni || base_ni->mft_no != FILE_MFT)
up_write(&vol->mftbmp_lock);
err_out:
@@ -2515,9 +2751,11 @@ int ntfs_mft_record_free(struct ntfs_volume *vol, struct ntfs_inode *ni)
int err;
u16 seq_no;
__le16 old_seq_no;
+ __le64 old_base_mft_record;
struct mft_record *ni_mrec;
unsigned int memalloc_flags;
struct ntfs_inode *base_ni;
+ bool keep_reserved;
if (!vol || !ni)
return -EINVAL;
@@ -2530,9 +2768,23 @@ int ntfs_mft_record_free(struct ntfs_volume *vol, struct ntfs_inode *ni)
/* Cache the mft reference for later. */
mft_no = ni->mft_no;
-
- /* Mark the mft record as not in use. */
- ni_mrec->flags &= ~MFT_RECORD_IN_USE;
+ if (likely(ni->nr_extents >= 0))
+ base_ni = ni;
+ else
+ base_ni = ni->ext.base_ntfs_ino;
+ keep_reserved = mft_no >= FILE_reserved12 &&
+ mft_no <= FILE_reserved15 &&
+ base_ni->mft_no == FILE_MFT;
+
+ old_base_mft_record = ni_mrec->base_mft_record;
+ if (keep_reserved) {
+ /* Restore the special, unnamed form used by reserved records. */
+ ni_mrec->base_mft_record = 0;
+ ni_mrec->flags |= MFT_RECORD_IN_USE;
+ } else {
+ /* Mark the mft record as not in use. */
+ ni_mrec->flags &= ~MFT_RECORD_IN_USE;
+ }
/* Increment the sequence number, skipping zero, if it is not zero. */
old_seq_no = ni_mrec->sequence_number;
@@ -2561,24 +2813,28 @@ int ntfs_mft_record_free(struct ntfs_volume *vol, struct ntfs_inode *ni)
if (err)
goto sync_rollback;
- if (likely(ni->nr_extents >= 0))
- base_ni = ni;
- else
- base_ni = ni->ext.base_ntfs_ino;
+ if (keep_reserved) {
+ unmap_mft_record(ni);
+ return 0;
+ }
/* Clear the bit in the $MFT/$BITMAP corresponding to this record. */
memalloc_flags = memalloc_nofs_save();
if (base_ni->mft_no != FILE_MFT)
down_write(&vol->mftbmp_lock);
err = ntfs_bitmap_clear_bit(vol->mftbmp_ino, mft_no);
+ if (!err)
+ ntfs_inc_free_mft_records(vol, 1);
+ if (!err && base_ni->mft_no == FILE_MFT &&
+ mft_no + 1 == vol->mft_record_reserve_pos &&
+ mft_no < vol->mft_record_reserve_end)
+ vol->mft_record_reserve_pos = mft_no;
if (base_ni->mft_no != FILE_MFT)
up_write(&vol->mftbmp_lock);
memalloc_nofs_restore(memalloc_flags);
if (err)
goto bitmap_rollback;
-
unmap_mft_record(ni);
- ntfs_inc_free_mft_records(vol, 1);
return 0;
/* Rollback what we did... */
@@ -2596,6 +2852,7 @@ int ntfs_mft_record_free(struct ntfs_volume *vol, struct ntfs_inode *ni)
"Eeek! Rollback failed in %s. Leaving inconsistent metadata!\n", __func__);
ni_mrec->flags |= MFT_RECORD_IN_USE;
ni_mrec->sequence_number = old_seq_no;
+ ni_mrec->base_mft_record = old_base_mft_record;
NInoSetDirty(ni);
write_mft_record(ni, ni_mrec, 0);
unmap_mft_record(ni);
diff --git a/fs/ntfs/mft.h b/fs/ntfs/mft.h
index 75a51a98d0f6..ed5c1d595c0d 100644
--- a/fs/ntfs/mft.h
+++ b/fs/ntfs/mft.h
@@ -78,7 +78,7 @@ static inline int write_mft_record(struct ntfs_inode *ni, struct mft_record *m,
int ntfs_mft_record_alloc(struct ntfs_volume *vol, const int mode,
struct ntfs_inode **ni, struct ntfs_inode *base_ni,
- struct mft_record **ni_mrec);
+ struct mft_record **ni_mrec, const s64 mft_data_vcn);
int ntfs_mft_record_free(struct ntfs_volume *vol, struct ntfs_inode *ni);
int ntfs_mft_records_write(const struct ntfs_volume *vol, const u64 mref,
const s64 count, struct mft_record *b);
diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c
index 96045face63f..dfd05e604f9c 100644
--- a/fs/ntfs/namei.c
+++ b/fs/ntfs/namei.c
@@ -480,7 +480,7 @@ static struct ntfs_inode *__ntfs_create(struct mnt_idmap *idmap, struct inode *d
mark_inode_dirty(dir);
err = ntfs_mft_record_alloc(dir_ni->vol, mode, &ni, NULL,
- &ni_mrec);
+ &ni_mrec, -1);
if (err) {
iput(vi);
return ERR_PTR(err);
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 63aa83ff77f5..b5371d269f74 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -2064,8 +2064,7 @@ static unsigned long __get_nr_free_mft_records(struct ntfs_volume *vol,
/* If errors occurred we may well have gone below zero, fix this. */
if (nr_free < 0)
nr_free = 0;
- else
- atomic64_set(&vol->free_mft_records, nr_free);
+ atomic64_set(&vol->free_mft_records, nr_free);
ntfs_debug("Exiting.");
return nr_free;
@@ -2131,7 +2130,14 @@ static int ntfs_statfs(struct dentry *dentry, struct kstatfs *sfs)
read_unlock_irqrestore(&mft_ni->size_lock, flags);
/* Free inodes in fs (based on current total count). */
- sfs->f_ffree = atomic64_read(&vol->free_mft_records);
+ size = atomic64_read(&vol->free_mft_records);
+ if (unlikely(size < 0 || size > (s64)sfs->f_files))
+ ntfs_warning(vol->sb, "Invalid free MFT record count %lld.", size);
+ if (size < 0)
+ size = 0;
+ else if (size > (s64)sfs->f_files)
+ size = sfs->f_files;
+ sfs->f_ffree = size;
/*
* File system id. This is extremely *nix flavour dependent and even
diff --git a/fs/ntfs/volume.h b/fs/ntfs/volume.h
index 65fd3908af26..bc85a9592245 100644
--- a/fs/ntfs/volume.h
+++ b/fs/ntfs/volume.h
@@ -55,6 +55,10 @@
* @attrdef_size: Size of the attribute definition table in bytes.
* @attrdef: Table of attribute definitions. Obtained from FILE_AttrDef.
* @mft_data_pos: Mft record number at which to allocate the next mft record.
+ * @mft_record_reserve_pos: First record in the in-memory MFT metadata reserve
+ * (protected by mftbmp_lock).
+ * @mft_record_reserve_end: First record beyond the MFT metadata reserve
+ * (protected by mftbmp_lock).
* @mft_zone_start: First cluster of the mft zone.
* @mft_zone_end: First cluster beyond the mft zone.
* @mft_zone_pos: Current position in the mft zone.
@@ -119,6 +123,8 @@ struct ntfs_volume {
s32 attrdef_size;
struct attr_def *attrdef;
s64 mft_data_pos;
+ s64 mft_record_reserve_pos;
+ s64 mft_record_reserve_end;
s64 mft_zone_start;
s64 mft_zone_end;
s64 mft_zone_pos;
@@ -252,17 +258,11 @@ static inline void ntfs_dec_free_clusters(struct ntfs_volume *vol, s64 nr)
static inline void ntfs_inc_free_mft_records(struct ntfs_volume *vol, s64 nr)
{
- if (!NVolFreeClusterKnown(vol))
- return;
-
atomic64_add(nr, &vol->free_mft_records);
}
static inline void ntfs_dec_free_mft_records(struct ntfs_volume *vol, s64 nr)
{
- if (!NVolFreeClusterKnown(vol))
- return;
-
atomic64_sub(nr, &vol->free_mft_records);
}
diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c
index a1da1ade8c10..6e3b6fbd9c55 100644
--- a/fs/smb/client/cifssmb.c
+++ b/fs/smb/client/cifssmb.c
@@ -3080,7 +3080,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 = smb_EIO2(smb_eio_trace_qreparse_data_area,
(unsigned long)start - (unsigned long)io_rsp,
(unsigned long)end - (unsigned long)io_rsp);
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index ba749ec25a59..b7ad267ac28b 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -174,6 +174,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);
}
@@ -182,11 +184,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);
}
/*
@@ -1067,6 +1073,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;
@@ -1823,6 +1830,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);
@@ -1926,6 +1934,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);
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
index 8886e9483c91..7294ccd4782f 100644
--- a/fs/smb/client/file.c
+++ b/fs/smb/client/file.c
@@ -3330,8 +3330,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 945194fe7a97..05168284f205 100644
--- a/fs/smb/client/misc.c
+++ b/fs/smb/client/misc.c
@@ -788,7 +788,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;
}
@@ -802,7 +806,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 8a1b9e8be5ba..3a27773186ae 100644
--- a/fs/smb/client/reparse.c
+++ b/fs/smb/client/reparse.c
@@ -3,6 +3,7 @@
* Copyright (c) 2024 Paulo Alcantara <pc@manguebit.com>
*/
+#include <linux/ctype.h>
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/slab.h>
@@ -159,15 +160,24 @@ static int create_native_symlink(const unsigned int xid, struct inode *inode,
convert_delimiter(sym, sep);
/*
- * For absolute NT symlinks it is required to pass also leading
- * backslash and to not mangle NT object prefix "\\??\\" and not to
- * mangle colon in drive letter. But cifs_convert_path_to_utf16()
- * removes leading backslash and replaces '?' and ':'. So temporary
- * mask these characters in NT object prefix by '_' and then change
- * them back.
+ * Absolute NT symlinks must retain the leading backslash, "\\??\\"
+ * prefix and drive-letter colon. cifs_convert_path_to_utf16() strips
+ * the leading backslash and maps '?' and ':', so temporarily mask
+ * these characters with '_' and restore them after conversion.
+ *
+ * When symlinkroot is unset, sym comes directly from the caller.
+ * Validate the complete "\\??\\X:" prefix before using fixed offsets
+ * or subtracting the NT prefix length below. Require an ASCII drive
+ * letter so the prefix occupies six characters in UTF-16 too.
*/
- if (!(sbflags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/')
+ if (!(sbflags & CIFS_MOUNT_POSIX_PATHS) && symname[0] == '/') {
+ if (!strstarts(sym, "\\??\\") || !isascii(sym[4]) ||
+ !isalpha(sym[4]) || sym[5] != ':') {
+ rc = -EINVAL;
+ goto out;
+ }
sym[0] = sym[1] = sym[2] = sym[5] = '_';
+ }
/*
* On a POSIX paths mount the symlink target is stored verbatim, so
@@ -1139,29 +1149,30 @@ static bool wsl_to_fattr(struct cifs_open_info_data *data,
u32 tag, struct cifs_fattr *fattr)
{
unsigned int sbflags = cifs_sb_flags(cifs_sb);
+ kuid_t uid = cifs_sb->ctx->linux_uid;
+ kgid_t gid = cifs_sb->ctx->linux_gid;
struct smb2_file_full_ea_info *ea;
bool have_xattr_dev = false;
+ dev_t rdev = 0;
+ umode_t mode;
u32 next = 0;
- fattr->cf_uid = cifs_sb->ctx->linux_uid;
- fattr->cf_gid = cifs_sb->ctx->linux_gid;
-
- fattr->cf_mode &= ~S_IFMT;
+ mode = fattr->cf_mode & ~S_IFMT;
switch (tag) {
case IO_REPARSE_TAG_LX_SYMLINK:
- fattr->cf_mode |= S_IFLNK;
+ mode |= S_IFLNK;
break;
case IO_REPARSE_TAG_LX_FIFO:
- fattr->cf_mode |= S_IFIFO;
+ mode |= S_IFIFO;
break;
case IO_REPARSE_TAG_AF_UNIX:
- fattr->cf_mode |= S_IFSOCK;
+ mode |= S_IFSOCK;
break;
case IO_REPARSE_TAG_LX_CHR:
- fattr->cf_mode |= S_IFCHR;
+ mode |= S_IFCHR;
break;
case IO_REPARSE_TAG_LX_BLK:
- fattr->cf_mode |= S_IFBLK;
+ mode |= S_IFBLK;
break;
}
@@ -1185,26 +1196,29 @@ static bool wsl_to_fattr(struct cifs_open_info_data *data,
if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen)) {
if (!(sbflags & CIFS_MOUNT_OVERR_UID))
- fattr->cf_uid = wsl_make_kuid(cifs_sb, v);
+ uid = wsl_make_kuid(cifs_sb, v);
} else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen)) {
if (!(sbflags & CIFS_MOUNT_OVERR_GID))
- fattr->cf_gid = wsl_make_kgid(cifs_sb, v);
+ 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(mode) != S_DT(get_unaligned_le32(v)))
return false;
- fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v);
+ mode = get_unaligned_le32(v);
} else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen)) {
- fattr->cf_rdev = reparse_mkdev(v);
+ rdev = reparse_mkdev(v);
have_xattr_dev = true;
}
} while (next);
out:
-
/* Major and minor numbers for char and block devices are mandatory. */
if (!have_xattr_dev && (tag == IO_REPARSE_TAG_LX_CHR || tag == IO_REPARSE_TAG_LX_BLK))
return false;
+ fattr->cf_uid = uid;
+ fattr->cf_gid = gid;
+ fattr->cf_mode = mode;
+ fattr->cf_rdev = rdev;
return true;
}
diff --git a/fs/smb/client/reparse.h b/fs/smb/client/reparse.h
index 0164dc47bdfd..0506d25eea5c 100644
--- a/fs/smb/client/reparse.h
+++ b/fs/smb/client/reparse.h
@@ -9,6 +9,7 @@
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/uidgid.h>
+#include <linux/unaligned.h>
#include "fs_context.h"
#include "cifsglob.h"
#include "../common/smbfsctl.h"
@@ -23,7 +24,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);
}
@@ -31,7 +32,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;
@@ -41,7 +42,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 7cf7dd104f7c..e095f41b5882 100644
--- a/fs/smb/client/sess.c
+++ b/fs/smb/client/sess.c
@@ -149,9 +149,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);
@@ -197,67 +197,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 457442af1222..441f107ed202 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -76,6 +76,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 5f616384c75c..0c8478d1d698 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -785,9 +785,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;
}
@@ -1053,8 +1053,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 */
@@ -2451,8 +2460,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
@@ -5362,11 +5377,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");
@@ -5374,8 +5391,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
@@ -5411,6 +5435,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 dea05aeb53a1..880ce12f50c4 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -189,18 +189,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 b442cccd1530..bb8d0197cb54 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/connection.c b/fs/smb/server/connection.c
index 39ac777fd452..4f042a8a2fdb 100644
--- a/fs/smb/server/connection.c
+++ b/fs/smb/server/connection.c
@@ -22,6 +22,8 @@
static DEFINE_MUTEX(init_lock);
static struct ksmbd_conn_ops default_conn_ops;
+static struct delayed_work session_expiration_work;
+static bool stopping_session_expiration_work;
DEFINE_HASHTABLE(conn_list, CONN_HASH_BITS);
DECLARE_RWSEM(conn_list_lock);
@@ -35,9 +37,9 @@ static int proc_show_clients(struct seq_file *m, void *v)
struct timespec64 now, t;
int i;
- seq_printf(m, "#%-20s %-10s %-10s %-10s %-10s %-10s\n",
- "<name>", "<dialect>", "<credits>", "<open files>",
- "<requests>", "<last active>");
+ seq_printf(m, "#%-40s %-10s %-10s %-12s %-10s %s\n",
+ "<client>", "<dialect>", "<credits>", "<open files>",
+ "<requests>", "<last active>");
down_read(&conn_list_lock);
hash_for_each(conn_list, i, conn, hlist) {
@@ -46,11 +48,11 @@ static int proc_show_clients(struct seq_file *m, void *v)
t = timespec64_sub(now, t);
#if IS_ENABLED(CONFIG_IPV6)
if (!conn->inet_addr)
- seq_printf(m, "%-20pI6c", &conn->inet6_addr);
+ seq_printf(m, " %-40pI6c", &conn->inet6_addr);
else
#endif
- seq_printf(m, "%-20pI4", &conn->inet_addr);
- seq_printf(m, " 0x%-10x %-10u %-12d %-10d %ptT\n",
+ seq_printf(m, " %-40pI4", &conn->inet_addr);
+ seq_printf(m, " 0x%-8x %-10u %-12d %-10d %ptT\n",
conn->dialect,
conn->total_credits,
atomic_read(&conn->stats.open_files_count),
@@ -84,18 +86,28 @@ static void delete_proc_clients(void) {}
static struct workqueue_struct *ksmbd_conn_wq;
+static void ksmbd_session_expiration_worker(struct work_struct *work);
+
int ksmbd_conn_wq_init(void)
{
ksmbd_conn_wq = alloc_workqueue("ksmbd-conn-release",
WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
if (!ksmbd_conn_wq)
return -ENOMEM;
+
+ WRITE_ONCE(stopping_session_expiration_work, false);
+ INIT_DELAYED_WORK(&session_expiration_work,
+ ksmbd_session_expiration_worker);
+ queue_delayed_work(ksmbd_conn_wq, &session_expiration_work,
+ KSMBD_SESSION_EXPIRATION_INTERVAL);
return 0;
}
void ksmbd_conn_wq_destroy(void)
{
if (ksmbd_conn_wq) {
+ WRITE_ONCE(stopping_session_expiration_work, true);
+ cancel_delayed_work_sync(&session_expiration_work);
destroy_workqueue(ksmbd_conn_wq);
ksmbd_conn_wq = NULL;
}
@@ -205,6 +217,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
return NULL;
conn->need_neg = true;
+ conn->creation_time = jiffies;
ksmbd_conn_set_new(conn);
conn->local_nls = load_nls("utf8");
if (!conn->local_nls)
@@ -487,6 +500,20 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
if (kthread_should_stop())
return false;
+ /*
+ * Stale connections that have not completed NEGOTIATE and SESSION_SETUP
+ * must be disconnected. Do not race a request that is currently
+ * completing authentication.
+ */
+ if (!atomic_read(&conn->req_running) &&
+ time_after(jiffies, conn->creation_time +
+ KSMBD_UNAUTHENTICATED_CONN_TIMEOUT) &&
+ (READ_ONCE(conn->need_neg) ||
+ !ksmbd_conn_has_valid_or_expired_session(conn))) {
+ ksmbd_debug(CONN, "Connection setup timed out\n");
+ return false;
+ }
+
if (atomic_read(&conn->stats.open_files_count) > 0)
return true;
@@ -504,6 +531,51 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
return true;
}
+static void ksmbd_session_expiration_worker(struct work_struct *work)
+{
+ struct ksmbd_conn *conn, *target;
+ int bkt;
+
+ if (!ksmbd_server_running())
+ goto reschedule;
+
+ ksmbd_expire_sessions();
+
+ /*
+ * An old connection without a Valid or Expired session must be
+ * disconnected. Process one connection at a time without holding
+ * conn_list_lock across transport shutdown.
+ */
+again:
+ target = NULL;
+ down_read(&conn_list_lock);
+ hash_for_each(conn_list, bkt, conn, hlist) {
+ if (ksmbd_conn_exiting(conn) || ksmbd_conn_releasing(conn) ||
+ atomic_read(&conn->req_running) ||
+ time_before_eq(jiffies, conn->creation_time +
+ KSMBD_UNAUTHENTICATED_CONN_TIMEOUT) ||
+ (!READ_ONCE(conn->need_neg) &&
+ ksmbd_conn_has_valid_or_expired_session(conn)))
+ continue;
+
+ target = ksmbd_conn_get(conn);
+ break;
+ }
+ up_read(&conn_list_lock);
+
+ if (target) {
+ ksmbd_debug(CONN, "Connection setup timed out\n");
+ ksmbd_conn_abort(target);
+ ksmbd_conn_put(target);
+ goto again;
+ }
+
+reschedule:
+ if (!READ_ONCE(stopping_session_expiration_work))
+ queue_delayed_work(ksmbd_conn_wq, &session_expiration_work,
+ KSMBD_SESSION_EXPIRATION_INTERVAL);
+}
+
/* "+2" for BCC field (ByteCount, 2 bytes) */
#define SMB1_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb_hdr) + 2)
#define SMB2_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb2_pdu))
diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h
index 242a9757eb0d..909f73c6e3c1 100644
--- a/fs/smb/server/connection.h
+++ b/fs/smb/server/connection.h
@@ -67,6 +67,7 @@ struct ksmbd_conn {
struct rw_semaphore session_lock;
/* smb session 1 per user */
struct xarray sessions;
+ unsigned long creation_time;
unsigned long last_active;
/* How many request are running currently */
atomic_t req_running;
@@ -160,6 +161,8 @@ struct ksmbd_transport {
#define KSMBD_TCP_RECV_TIMEOUT (7 * HZ)
#define KSMBD_TCP_SEND_TIMEOUT (5 * HZ)
+#define KSMBD_SESSION_EXPIRATION_INTERVAL (5 * HZ)
+#define KSMBD_UNAUTHENTICATED_CONN_TIMEOUT (45 * HZ)
#define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr))
#define CONN_HASH_BITS 12
diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
index 10b31df185a6..c3c0557dcc19 100644
--- a/fs/smb/server/mgmt/user_session.c
+++ b/fs/smb/server/mgmt/user_session.c
@@ -22,6 +22,7 @@
static DEFINE_IDA(session_ida);
#define SESSION_HASH_BITS 12
+#define KSMBD_MAX_PENDING_SESSIONS 1
static DEFINE_HASHTABLE(sessions_table, SESSION_HASH_BITS);
static DECLARE_RWSEM(sessions_table_lock);
@@ -90,9 +91,15 @@ static int show_proc_session(struct seq_file *m, void *v)
sess = (struct ksmbd_session *)m->private;
ksmbd_user_session_get(sess);
+ seq_printf(m, "%-20s\t%s\n", "user", session_user_name(sess));
+ seq_printf(m, "%-20s\t%llu\n", "id", sess->id);
+ seq_printf(m, "%-20s\t%s\n", "state", session_state_string(sess));
+
i = 0;
down_read(&sess->chann_lock);
xa_for_each(&sess->ksmbd_chann_list, id, chan) {
+ const char *name;
+
#if IS_ENABLED(CONFIG_IPV6)
if (chan->conn->inet_addr)
seq_printf(m, "%-20s\t%pI4\n", "client",
@@ -104,29 +111,37 @@ static int show_proc_session(struct seq_file *m, void *v)
seq_printf(m, "%-20s\t%pI4\n", "client",
&chan->conn->inet_addr);
#endif
- seq_printf(m, "%-20s\t%s\n", "user", session_user_name(sess));
- seq_printf(m, "%-20s\t%llu\n", "id", sess->id);
- seq_printf(m, "%-20s\t%s\n", "state",
- session_state_string(sess));
-
seq_printf(m, "%-20s\t", "capabilities");
ksmbd_proc_show_flag_names(m,
ksmbd_sess_cap_const_names,
ARRAY_SIZE(ksmbd_sess_cap_const_names),
chan->conn->vals->req_capabilities);
+ seq_putc(m, '\n');
if (sess->sign) {
- seq_printf(m, "%-20s\t", "signing");
- ksmbd_proc_show_const_name(m, "%s\t",
- ksmbd_signing_const_names,
- ARRAY_SIZE(ksmbd_signing_const_names),
- le16_to_cpu(chan->conn->signing_algorithm));
- } else if (sess->enc) {
- seq_printf(m, "%-20s\t", "encryption");
- ksmbd_proc_show_const_name(m, "%s\t",
- ksmbd_cipher_const_names,
- ARRAY_SIZE(ksmbd_cipher_const_names),
- le16_to_cpu(chan->conn->cipher_type));
+ unsigned int algorithm =
+ le16_to_cpu(chan->conn->signing_algorithm);
+
+ name = ksmbd_proc_const_name(ksmbd_signing_const_names,
+ ARRAY_SIZE(ksmbd_signing_const_names),
+ algorithm);
+ if (name)
+ seq_printf(m, "%-20s\t%s\n", "signing", name);
+ else
+ seq_printf(m, "%-20s\t0x%04x\n", "signing",
+ algorithm);
+ }
+ if (sess->enc) {
+ unsigned int cipher = le16_to_cpu(chan->conn->cipher_type);
+
+ name = ksmbd_proc_const_name(ksmbd_cipher_const_names,
+ ARRAY_SIZE(ksmbd_cipher_const_names),
+ cipher);
+ if (name)
+ seq_printf(m, "%-20s\t%s\n", "encryption", name);
+ else
+ seq_printf(m, "%-20s\t0x%04x\n", "encryption",
+ cipher);
}
i++;
}
@@ -152,35 +167,6 @@ static int show_proc_session(struct seq_file *m, void *v)
return 0;
}
-void ksmbd_proc_show_flag_names(struct seq_file *m,
- const struct ksmbd_const_name *table,
- int count,
- unsigned int flags)
-{
- int i;
-
- for (i = 0; i < count; i++) {
- if (table[i].const_value & flags)
- seq_printf(m, "0x%08x\t", table[i].const_value);
- }
- seq_putc(m, '\n');
-}
-
-void ksmbd_proc_show_const_name(struct seq_file *m,
- const char *format,
- const struct ksmbd_const_name *table,
- int count,
- unsigned int const_value)
-{
- int i;
-
- for (i = 0; i < count; i++) {
- if (table[i].const_value & const_value)
- seq_printf(m, format, table[i].name);
- }
- seq_putc(m, '\n');
-}
-
static int create_proc_session(struct ksmbd_session *sess)
{
char name[30];
@@ -416,26 +402,31 @@ struct ksmbd_session *__session_lookup(unsigned long long id)
return NULL;
}
-static void ksmbd_expire_session(struct ksmbd_conn *conn)
+static bool ksmbd_too_many_session_setups(struct ksmbd_conn *conn)
{
unsigned long id;
struct ksmbd_session *sess;
+ unsigned int pending = 0;
down_write(&sessions_table_lock);
down_write(&conn->session_lock);
xa_for_each(&conn->sessions, id, sess) {
+ if (READ_ONCE(sess->state) != SMB2_SESSION_IN_PROGRESS)
+ continue;
+
if (atomic_read(&sess->refcnt) <= 1 &&
- (sess->state != SMB2_SESSION_VALID ||
- time_after(jiffies,
- sess->last_active + SMB2_SESSION_TIMEOUT))) {
+ time_after(jiffies, sess->last_active +
+ KSMBD_UNAUTHENTICATED_CONN_TIMEOUT)) {
xa_erase(&conn->sessions, sess->id);
ksmbd_session_remove_from_table(sess);
ksmbd_session_destroy(sess);
continue;
}
+ pending++;
}
up_write(&conn->session_lock);
up_write(&sessions_table_lock);
+ return pending >= KSMBD_MAX_PENDING_SESSIONS;
}
int ksmbd_session_register(struct ksmbd_conn *conn,
@@ -445,9 +436,12 @@ int ksmbd_session_register(struct ksmbd_conn *conn,
sess->dialect = conn->dialect;
memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
- ksmbd_expire_session(conn);
- ret = xa_err(xa_store(&conn->sessions, sess->id, sess,
- KSMBD_DEFAULT_GFP));
+ /* Bound abandoned SessionId-zero authentication exchanges. */
+ if (ksmbd_too_many_session_setups(conn))
+ ret = -ENOSPC;
+ else
+ ret = xa_err(xa_store(&conn->sessions, sess->id, sess,
+ KSMBD_DEFAULT_GFP));
if (ret) {
down_write(&sessions_table_lock);
ksmbd_session_remove_from_table(sess);
@@ -458,6 +452,105 @@ int ksmbd_session_register(struct ksmbd_conn *conn,
return ret;
}
+void ksmbd_session_unregister(struct ksmbd_conn *conn,
+ struct ksmbd_session *sess)
+{
+ struct ksmbd_conn *session_conns[KSMBD_MAX_CHANNELS];
+ struct channel *chann;
+ unsigned long index;
+ unsigned int nr_conns = 0, i;
+ bool removed = false;
+
+ down_write(&sessions_table_lock);
+ if (!hlist_unhashed(&sess->hlist)) {
+ /* Keep each channel connection stable under sessions_table_lock. */
+ down_read(&sess->chann_lock);
+ xa_for_each(&sess->ksmbd_chann_list, index, chann) {
+ if (nr_conns == ARRAY_SIZE(session_conns))
+ break;
+ session_conns[nr_conns++] = chann->conn;
+ }
+ up_read(&sess->chann_lock);
+
+ ksmbd_session_remove_from_table(sess);
+ removed = true;
+ }
+
+ down_write(&conn->session_lock);
+ if (xa_load(&conn->sessions, sess->id) == sess)
+ xa_erase(&conn->sessions, sess->id);
+ up_write(&conn->session_lock);
+ for (i = 0; i < nr_conns; i++) {
+ if (session_conns[i] == conn)
+ continue;
+ down_write(&session_conns[i]->session_lock);
+ if (xa_load(&session_conns[i]->sessions, sess->id) == sess)
+ xa_erase(&session_conns[i]->sessions, sess->id);
+ up_write(&session_conns[i]->session_lock);
+ }
+ up_write(&sessions_table_lock);
+
+ if (removed)
+ ksmbd_user_session_put(sess);
+}
+
+bool ksmbd_conn_has_valid_or_expired_session(struct ksmbd_conn *conn)
+{
+ struct ksmbd_session *sess;
+ unsigned long id;
+ int state, bkt;
+ bool found = false;
+
+ down_read(&conn->session_lock);
+ xa_for_each(&conn->sessions, id, sess) {
+ state = READ_ONCE(sess->state);
+ if (state == SMB2_SESSION_VALID ||
+ state == SMB2_SESSION_EXPIRED) {
+ found = true;
+ break;
+ }
+ }
+ up_read(&conn->session_lock);
+ if (found)
+ return true;
+
+ /* A session bound through SMB3 multichannel is not in conn->sessions. */
+ down_read(&sessions_table_lock);
+ hash_for_each(sessions_table, bkt, sess, hlist) {
+ state = READ_ONCE(sess->state);
+ if (state != SMB2_SESSION_VALID &&
+ state != SMB2_SESSION_EXPIRED)
+ continue;
+
+ down_read(&sess->chann_lock);
+ found = xa_load(&sess->ksmbd_chann_list, (long)conn);
+ up_read(&sess->chann_lock);
+ if (found)
+ break;
+ }
+ up_read(&sessions_table_lock);
+ return found;
+}
+
+void ksmbd_expire_sessions(void)
+{
+ struct ksmbd_session *sess;
+ u64 now = ktime_get_real_seconds();
+ int bkt;
+
+ down_read(&sessions_table_lock);
+ hash_for_each(sessions_table, bkt, sess, hlist) {
+ if (READ_ONCE(sess->state) != SMB2_SESSION_VALID ||
+ !sess->kerberos_expiry || now < sess->kerberos_expiry)
+ continue;
+
+ if (cmpxchg(&sess->state, SMB2_SESSION_VALID,
+ SMB2_SESSION_EXPIRED) == SMB2_SESSION_VALID)
+ ksmbd_counter_inc(KSMBD_COUNTER_SESSION_TIMEOUTS);
+ }
+ up_read(&sessions_table_lock);
+}
+
static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
{
struct channel *chann;
@@ -472,7 +565,7 @@ static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
return 0;
}
-void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
+void ksmbd_conn_sessions_cleanup(struct ksmbd_conn *conn)
{
struct ksmbd_session *sess;
unsigned long id;
diff --git a/fs/smb/server/mgmt/user_session.h b/fs/smb/server/mgmt/user_session.h
index 3e52d4cc1324..217258551d6d 100644
--- a/fs/smb/server/mgmt/user_session.h
+++ b/fs/smb/server/mgmt/user_session.h
@@ -72,6 +72,8 @@ struct ksmbd_session {
struct rw_semaphore rpc_lock;
};
+#define KSMBD_MAX_CHANNELS 32
+
static inline int test_session_flag(struct ksmbd_session *sess, int bit)
{
return sess->flags & bit;
@@ -98,7 +100,11 @@ bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn,
unsigned long long id);
int ksmbd_session_register(struct ksmbd_conn *conn,
struct ksmbd_session *sess);
-void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
+void ksmbd_session_unregister(struct ksmbd_conn *conn,
+ struct ksmbd_session *sess);
+void ksmbd_conn_sessions_cleanup(struct ksmbd_conn *conn);
+bool ksmbd_conn_has_valid_or_expired_session(struct ksmbd_conn *conn);
+void ksmbd_expire_sessions(void);
struct ksmbd_session *__session_lookup(unsigned long long id);
struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
unsigned long long id);
diff --git a/fs/smb/server/misc.h b/fs/smb/server/misc.h
index c7b063f571a7..1faaddd0f5f7 100644
--- a/fs/smb/server/misc.h
+++ b/fs/smb/server/misc.h
@@ -53,11 +53,8 @@ void ksmbd_proc_show_flag_names(struct seq_file *m,
const struct ksmbd_const_name *table,
int count,
unsigned int flags);
-void ksmbd_proc_show_const_name(struct seq_file *m,
- const char *format,
- const struct ksmbd_const_name *table,
- int count,
- unsigned int const_value);
+const char *ksmbd_proc_const_name(const struct ksmbd_const_name *table,
+ int count, unsigned int const_value);
#else
static inline int ksmbd_proc_init(void) { return 0; }
static inline void ksmbd_proc_cleanup(void) {}
diff --git a/fs/smb/server/proc.c b/fs/smb/server/proc.c
index 5c9f3f314dbe..19f0f2cfbf54 100644
--- a/fs/smb/server/proc.c
+++ b/fs/smb/server/proc.c
@@ -11,10 +11,12 @@
#include <linux/seq_file.h>
#include "misc.h"
+#include "connection.h"
#include "server.h"
#include "stats.h"
#include "smb_common.h"
#include "smb2pdu.h"
+#include "vfs_cache.h"
static struct proc_dir_entry *ksmbd_proc_fs;
struct ksmbd_counters ksmbd_counters;
@@ -27,6 +29,42 @@ struct proc_dir_entry *ksmbd_proc_create(const char *name,
show, v);
}
+void ksmbd_proc_show_flag_names(struct seq_file *m,
+ const struct ksmbd_const_name *table,
+ int count, unsigned int flags)
+{
+ unsigned int remaining = flags;
+ bool separator = false;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ unsigned int flag = table[i].const_value;
+
+ if (!flag || (remaining & flag) != flag)
+ continue;
+ seq_printf(m, "%s%s", separator ? "," : "", table[i].name);
+ separator = true;
+ remaining &= ~flag;
+ }
+
+ if (remaining)
+ seq_printf(m, "%s0x%08x", separator ? "," : "", remaining);
+ else if (!separator)
+ seq_puts(m, "none");
+}
+
+const char *ksmbd_proc_const_name(const struct ksmbd_const_name *table,
+ int count, unsigned int const_value)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (table[i].const_value == const_value)
+ return table[i].name;
+ }
+ return NULL;
+}
+
struct ksmbd_const_smb2_process_req {
unsigned int const_value;
const char *name;
@@ -54,32 +92,129 @@ static const struct ksmbd_const_smb2_process_req smb2_process_req[KSMBD_COUNTER_
{le16_to_cpu(SMB2_OPLOCK_BREAK), "SMB2_OPLOCK_BREAK"},
};
+static const char *ksmbd_server_state_string(void)
+{
+ switch (READ_ONCE(server_conf.state)) {
+ case SERVER_STATE_STARTING_UP:
+ return "starting";
+ case SERVER_STATE_RUNNING:
+ return "running";
+ case SERVER_STATE_RESETTING:
+ return "resetting";
+ case SERVER_STATE_SHUTTING_DOWN:
+ return "shutdown";
+ default:
+ return "unknown";
+ }
+}
+
+static const char *ksmbd_signing_mode_string(void)
+{
+ switch (server_conf.signing) {
+ case KSMBD_CONFIG_OPT_DISABLED:
+ return "disabled";
+ case KSMBD_CONFIG_OPT_MANDATORY:
+ return "mandatory";
+ case KSMBD_CONFIG_OPT_AUTO:
+ return "auto";
+ default:
+ return "unknown";
+ }
+}
+
+static void proc_show_runtime_totals(struct seq_file *m)
+{
+ struct ksmbd_conn *conn;
+ unsigned int clients = 0;
+ unsigned int open_files = 0;
+ int i;
+
+ down_read(&conn_list_lock);
+ hash_for_each(conn_list, i, conn, hlist) {
+ clients++;
+ open_files += atomic_read(&conn->stats.open_files_count);
+ }
+ up_read(&conn_list_lock);
+
+ seq_printf(m, "clients:\t%u\n", clients);
+ seq_printf(m, "open_files:\t%u\n", open_files);
+}
+
static int proc_show_ksmbd_stats(struct seq_file *m, void *v)
{
int i;
seq_puts(m, "Server\n");
- seq_printf(m, "name: %s\n", ksmbd_server_string());
- seq_printf(m, "netbios: %s\n", ksmbd_netbios_name());
- seq_printf(m, "work group: %s\n", ksmbd_work_group());
- seq_printf(m, "min protocol: %s\n", ksmbd_get_protocol_string(server_conf.min_protocol));
- seq_printf(m, "max protocol: %s\n", ksmbd_get_protocol_string(server_conf.max_protocol));
- seq_printf(m, "flags: 0x%08x\n", server_conf.flags);
- seq_printf(m, "share_fake_fscaps: 0x%08x\n",
+ seq_printf(m, "state:\t%s\n", ksmbd_server_state_string());
+ seq_printf(m, "name:\t%s\n", ksmbd_server_string());
+ seq_printf(m, "netbios:\t%s\n", ksmbd_netbios_name());
+ seq_printf(m, "work_group:\t%s\n", ksmbd_work_group());
+ seq_printf(m, "min_protocol:\t%s\n", ksmbd_get_protocol_string(server_conf.min_protocol));
+ seq_printf(m, "max_protocol:\t%s\n", ksmbd_get_protocol_string(server_conf.max_protocol));
+ seq_printf(m, "flags:\t0x%08x\n", server_conf.flags);
+ seq_printf(m, "tcp_port:\t%u\n", server_conf.tcp_port);
+ seq_printf(m, "signing:\t%s\n", ksmbd_signing_mode_string());
+ seq_printf(m, "signing_enforced:\t%s\n",
+ server_conf.enforced_signing ? "yes" : "no");
+ seq_printf(m, "bind_interfaces_only:\t%s\n",
+ server_conf.bind_interfaces_only ? "yes" : "no");
+ seq_printf(m, "max_connections:\t%u\n", server_conf.max_connections);
+ seq_printf(m, "max_connections_per_ip:\t%u\n",
+ server_conf.max_ip_connections);
+ seq_printf(m, "max_inflight_requests:\t%u\n",
+ server_conf.max_inflight_req);
+ seq_printf(m, "deadtime_seconds:\t%lu\n", server_conf.deadtime / HZ);
+ seq_printf(m, "ipc_timeout_seconds:\t%u\n", server_conf.ipc_timeout / HZ);
+ if (server_conf.ipc_last_active)
+ seq_printf(m, "ipc_last_active_seconds:\t%lu\n",
+ jiffies_to_msecs(jiffies - server_conf.ipc_last_active) /
+ MSEC_PER_SEC);
+ else
+ seq_puts(m, "ipc_last_active_seconds:\tnever\n");
+ seq_printf(m, "durable_scavenger:\t%s\n",
+ ksmbd_durable_scavenger_active() ? "running" : "stopped");
+ seq_printf(m, "share_fake_fscaps:\t0x%08x\n",
server_conf.share_fake_fscaps);
- seq_printf(m, "sessions: %lld\n",
+ proc_show_runtime_totals(m);
+ seq_printf(m, "sessions:\t%lld\n",
ksmbd_counter_sum(KSMBD_COUNTER_SESSIONS));
- seq_printf(m, "tree connects: %lld\n",
+ seq_printf(m, "session_timeouts:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_SESSION_TIMEOUTS));
+ seq_printf(m, "tree_connects:\t%lld\n",
ksmbd_counter_sum(KSMBD_COUNTER_TREE_CONNS));
- seq_printf(m, "read bytes: %lld\n",
+ seq_printf(m, "requests:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_REQUESTS));
+ seq_printf(m, "read_bytes:\t%lld\n",
ksmbd_counter_sum(KSMBD_COUNTER_READ_BYTES));
- seq_printf(m, "written bytes: %lld\n",
+ seq_printf(m, "written_bytes:\t%lld\n",
ksmbd_counter_sum(KSMBD_COUNTER_WRITE_BYTES));
seq_puts(m, "\nSMB2\n");
for (i = 0; i < KSMBD_COUNTER_MAX_REQS; i++)
- seq_printf(m, "%-20s:\t%lld\n", smb2_process_req[i].name,
+ seq_printf(m, "%s:\t%lld\n", smb2_process_req[i].name,
ksmbd_counter_sum(KSMBD_COUNTER_FIRST_REQ + i));
+
+ seq_puts(m, "\nSMB2 status\n");
+ seq_printf(m, "success:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_STATUS_SUCCESS));
+ seq_printf(m, "informational:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_STATUS_INFORMATIONAL));
+ seq_printf(m, "warning:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_STATUS_WARNING));
+ seq_printf(m, "error:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_STATUS_ERROR));
+ seq_printf(m, "access_denied:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_ERROR_ACCESS_DENIED));
+ seq_printf(m, "not_found:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_ERROR_NOT_FOUND));
+ seq_printf(m, "invalid_parameter:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_ERROR_INVALID_PARAMETER));
+ seq_printf(m, "sharing_violation:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_ERROR_SHARING_VIOLATION));
+ seq_printf(m, "not_supported:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_ERROR_NOT_SUPPORTED));
+ seq_printf(m, "other:\t%lld\n",
+ ksmbd_counter_sum(KSMBD_COUNTER_ERROR_OTHER));
return 0;
}
diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
index 0b080972e908..e113b23d96f9 100644
--- a/fs/smb/server/server.c
+++ b/fs/smb/server/server.c
@@ -156,8 +156,11 @@ static int __process_request(struct ksmbd_work *work, struct ksmbd_conn *conn,
}
ret = cmds->proc(work);
- if (conn->ops->inc_reqs)
- conn->ops->inc_reqs(command);
+ if (conn->ops->inc_reqs) {
+ struct smb2_hdr *rsp = ksmbd_resp_buf_curr(work);
+
+ conn->ops->inc_reqs(command, rsp->Status);
+ }
if (ret < 0)
ksmbd_debug(CONN, "Failed to process %u [%d]\n", command, ret);
@@ -400,7 +403,7 @@ static int ksmbd_server_process_request(struct ksmbd_conn *conn)
static int ksmbd_server_terminate_conn(struct ksmbd_conn *conn)
{
- ksmbd_sessions_deregister(conn);
+ ksmbd_conn_sessions_cleanup(conn);
destroy_lease_table(conn);
return 0;
}
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 184b28072a6f..07de36aac0bf 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -83,8 +83,6 @@ struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn
return chann;
}
-#define KSMBD_MAX_CHANNELS 32
-
static int register_session_channel(struct ksmbd_session *sess,
struct ksmbd_conn *conn,
const char *sess_key)
@@ -914,8 +912,14 @@ static bool smb2_session_expired_cmd_allowed(struct ksmbd_work *work,
static bool smb2_session_kerberos_expired(struct ksmbd_session *sess)
{
- return sess->kerberos_expiry &&
- ktime_get_real_seconds() >= sess->kerberos_expiry;
+ if (!sess->kerberos_expiry ||
+ ktime_get_real_seconds() < sess->kerberos_expiry)
+ return false;
+
+ if (cmpxchg(&sess->state, SMB2_SESSION_VALID,
+ SMB2_SESSION_EXPIRED) == SMB2_SESSION_VALID)
+ ksmbd_counter_inc(KSMBD_COUNTER_SESSION_TIMEOUTS);
+ return true;
}
/**
@@ -950,9 +954,8 @@ int smb2_check_user_session(struct ksmbd_work *work)
if (!work->next_smb2_rcv_hdr_off && sess_id)
work->sess = ksmbd_session_lookup_all_states(conn, sess_id);
if (work->sess) {
- if (smb2_session_kerberos_expired(work->sess)) {
- work->sess->state = SMB2_SESSION_EXPIRED;
- } else if (work->sess->state != SMB2_SESSION_VALID) {
+ if (!smb2_session_kerberos_expired(work->sess) &&
+ work->sess->state != SMB2_SESSION_VALID) {
ksmbd_user_session_put(work->sess);
work->sess = NULL;
}
@@ -977,8 +980,7 @@ int smb2_check_user_session(struct ksmbd_work *work)
sess_id, work->sess->id);
return -EINVAL;
}
- if (smb2_session_kerberos_expired(work->sess))
- work->sess->state = SMB2_SESSION_EXPIRED;
+ smb2_session_kerberos_expired(work->sess);
if (work->sess->state != SMB2_SESSION_VALID) {
pr_err("compound request on a non-valid session (state %d)\n",
work->sess->state);
@@ -995,7 +997,6 @@ int smb2_check_user_session(struct ksmbd_work *work)
work->sess = ksmbd_session_lookup_all_states(conn, sess_id);
if (work->sess) {
if (smb2_session_kerberos_expired(work->sess)) {
- work->sess->state = SMB2_SESSION_EXPIRED;
return smb2_session_expired_cmd_allowed(work, cmd) ?
1 : -EKEYEXPIRED;
}
@@ -2192,7 +2193,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
struct ksmbd_conn *conn = work->conn;
struct smb2_sess_setup_req *req;
struct smb2_sess_setup_rsp *rsp;
- struct ksmbd_session *sess;
+ struct ksmbd_session *sess = NULL;
struct negotiate_message *negblob;
unsigned int negblob_len, negblob_off;
int rc = 0;
@@ -2333,6 +2334,9 @@ int smb2_sess_setup(struct ksmbd_work *work)
goto out_err;
}
+ if (work->session_setup_reauth)
+ WRITE_ONCE(sess->state, SMB2_SESSION_IN_PROGRESS);
+
conn->binding = false;
}
work->sess = sess;
@@ -2444,6 +2448,14 @@ int smb2_sess_setup(struct ksmbd_work *work)
}
if (rc < 0) {
+ bool setup_in_progress = sess &&
+ READ_ONCE(sess->state) == SMB2_SESSION_IN_PROGRESS &&
+ !(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING);
+
+ /* Authentication errors must not leave the new session published. */
+ if (setup_in_progress)
+ ksmbd_session_unregister(conn, sess);
+
if (sess && conn->dialect == SMB311_PROT_ID &&
(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
struct preauth_session *preauth_sess;
@@ -2477,7 +2489,8 @@ int smb2_sess_setup(struct ksmbd_work *work)
* For binding requests, session belongs to another
* connection. Do not expire it.
*/
- if (!(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
+ if (!(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) &&
+ !setup_in_progress) {
sess->last_active = jiffies;
sess->kerberos_expiry = 0;
sess->state = SMB2_SESSION_EXPIRED;
@@ -5609,26 +5622,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;
@@ -5643,8 +5661,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;
@@ -5658,8 +5675,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;
@@ -5684,14 +5700,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",
@@ -5973,7 +5991,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",
@@ -5986,10 +6003,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;
@@ -6080,7 +6096,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,
@@ -6090,10 +6105,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;
@@ -6406,13 +6419,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;
}
@@ -6509,9 +6522,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:
@@ -6532,6 +6562,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;
@@ -6566,6 +6597,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:
@@ -6618,6 +6650,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->FileSystemNameLen = cpu_to_le32(len);
sz = sizeof(FILE_SYSTEM_ATTRIBUTE_INFO) + len;
rsp->OutputBufferLength = cpu_to_le32(sz);
+ fixed_len = 16;
break;
}
case FS_VOLUME_INFORMATION:
@@ -6645,6 +6678,7 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
info->SupportsObjects = 0;
sz = sizeof(struct filesystem_vol_info) + len;
rsp->OutputBufferLength = cpu_to_le32(sz);
+ fixed_len = 24;
break;
}
case FS_SIZE_INFORMATION:
@@ -6657,6 +6691,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:
@@ -6672,6 +6707,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:
@@ -6692,6 +6728,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:
@@ -6713,6 +6750,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:
@@ -6733,6 +6771,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:
@@ -6753,6 +6792,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;
}
@@ -6761,7 +6801,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)
@@ -6862,7 +6903,8 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
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 1836259be897..bf30fa8544b7 100644
--- a/fs/smb/server/smb2pdu.h
+++ b/fs/smb/server/smb2pdu.h
@@ -61,8 +61,6 @@ struct preauth_integrity_info {
#define SMB2_SESSION_IN_PROGRESS BIT(0)
#define SMB2_SESSION_VALID BIT(1)
-#define SMB2_SESSION_TIMEOUT (10 * HZ)
-
/* Apple Defined Contexts */
#define SMB2_CREATE_AAPL "AAPL"
@@ -199,6 +197,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.h b/fs/smb/server/smb_common.h
index b090b56743c4..7b9c5cfcb63b 100644
--- a/fs/smb/server/smb_common.h
+++ b/fs/smb/server/smb_common.h
@@ -135,7 +135,7 @@ struct file_id_both_directory_info {
struct smb_version_ops {
u16 (*get_cmd_val)(struct ksmbd_work *swork);
- void (*inc_reqs)(unsigned int cmd);
+ void (*inc_reqs)(unsigned int cmd, __le32 status);
int (*init_rsp_hdr)(struct ksmbd_work *swork);
void (*set_rsp_status)(struct ksmbd_work *swork, __le32 err);
int (*allocate_rsp_buf)(struct ksmbd_work *work);
diff --git a/fs/smb/server/stats.h b/fs/smb/server/stats.h
index b60c30c69077..8b32b8b4e8be 100644
--- a/fs/smb/server/stats.h
+++ b/fs/smb/server/stats.h
@@ -9,12 +9,25 @@
#ifndef __KSMBD_STATS_H__
#define __KSMBD_STATS_H__
+#include "../common/smb2status.h"
+
#define KSMBD_COUNTER_MAX_REQS 19
enum {
KSMBD_COUNTER_SESSIONS = 0,
+ KSMBD_COUNTER_SESSION_TIMEOUTS,
KSMBD_COUNTER_TREE_CONNS,
KSMBD_COUNTER_REQUESTS,
+ KSMBD_COUNTER_STATUS_SUCCESS,
+ KSMBD_COUNTER_STATUS_INFORMATIONAL,
+ KSMBD_COUNTER_STATUS_WARNING,
+ KSMBD_COUNTER_STATUS_ERROR,
+ KSMBD_COUNTER_ERROR_ACCESS_DENIED,
+ KSMBD_COUNTER_ERROR_NOT_FOUND,
+ KSMBD_COUNTER_ERROR_INVALID_PARAMETER,
+ KSMBD_COUNTER_ERROR_SHARING_VIOLATION,
+ KSMBD_COUNTER_ERROR_NOT_SUPPORTED,
+ KSMBD_COUNTER_ERROR_OTHER,
KSMBD_COUNTER_READ_BYTES,
KSMBD_COUNTER_WRITE_BYTES,
KSMBD_COUNTER_FIRST_REQ,
@@ -50,10 +63,49 @@ static inline void ksmbd_counter_sub(int type, s64 value)
percpu_counter_sub(&ksmbd_counters.counters[type], value);
}
-static inline void ksmbd_counter_inc_reqs(unsigned int cmd)
+static inline void ksmbd_counter_inc_reqs(unsigned int cmd, __le32 status)
{
- if (cmd < KSMBD_COUNTER_MAX_REQS)
+ unsigned int severity = le32_to_cpu(status) >> 30;
+ int type;
+
+ switch (severity) {
+ case 0:
+ type = KSMBD_COUNTER_STATUS_SUCCESS;
+ break;
+ case 1:
+ type = KSMBD_COUNTER_STATUS_INFORMATIONAL;
+ break;
+ case 2:
+ type = KSMBD_COUNTER_STATUS_WARNING;
+ break;
+ default:
+ type = KSMBD_COUNTER_STATUS_ERROR;
+ break;
+ }
+ percpu_counter_inc(&ksmbd_counters.counters[type]);
+
+ if (severity == 3) {
+ if (status == STATUS_ACCESS_DENIED)
+ type = KSMBD_COUNTER_ERROR_ACCESS_DENIED;
+ else if (status == STATUS_OBJECT_NAME_NOT_FOUND ||
+ status == STATUS_NO_SUCH_FILE)
+ type = KSMBD_COUNTER_ERROR_NOT_FOUND;
+ else if (status == STATUS_INVALID_PARAMETER)
+ type = KSMBD_COUNTER_ERROR_INVALID_PARAMETER;
+ else if (status == STATUS_SHARING_VIOLATION)
+ type = KSMBD_COUNTER_ERROR_SHARING_VIOLATION;
+ else if (status == STATUS_NOT_SUPPORTED ||
+ status == STATUS_NOT_IMPLEMENTED)
+ type = KSMBD_COUNTER_ERROR_NOT_SUPPORTED;
+ else
+ type = KSMBD_COUNTER_ERROR_OTHER;
+ percpu_counter_inc(&ksmbd_counters.counters[type]);
+ }
+
+ if (cmd < KSMBD_COUNTER_MAX_REQS) {
+ percpu_counter_inc(&ksmbd_counters.counters[KSMBD_COUNTER_REQUESTS]);
percpu_counter_inc(&ksmbd_counters.counters[KSMBD_COUNTER_FIRST_REQ + cmd]);
+ }
}
static inline s64 ksmbd_counter_sum(int type)
@@ -66,7 +118,7 @@ static inline void ksmbd_counter_inc(int type) {}
static inline void ksmbd_counter_dec(int type) {}
static inline void ksmbd_counter_add(int type, s64 value) {}
static inline void ksmbd_counter_sub(int type, s64 value) {}
-static inline void ksmbd_counter_inc_reqs(unsigned int cmd) {}
+static inline void ksmbd_counter_inc_reqs(unsigned int cmd, __le32 status) {}
static inline s64 ksmbd_counter_sum(int type) { return 0; }
#endif
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
index a23bd9b1a68b..5eae49ed1c79 100644
--- a/fs/smb/server/vfs_cache.c
+++ b/fs/smb/server/vfs_cache.c
@@ -66,7 +66,7 @@ static const struct ksmbd_const_name ksmbd_lease_const_names[] = {
static const struct ksmbd_const_name ksmbd_oplock_const_names[] = {
{SMB2_OPLOCK_LEVEL_NONE, "OPLOCK_NONE"},
{SMB2_OPLOCK_LEVEL_II, "OPLOCK_II"},
- {SMB2_OPLOCK_LEVEL_EXCLUSIVE, "OPLOCK_EXECL"},
+ {SMB2_OPLOCK_LEVEL_EXCLUSIVE, "OPLOCK_EXCLUSIVE"},
{SMB2_OPLOCK_LEVEL_BATCH, "OPLOCK_BATCH"},
};
@@ -76,14 +76,14 @@ static int proc_show_files(struct seq_file *m, void *v)
unsigned int id;
struct oplock_info *opinfo;
- seq_printf(m, "#%-10s %-10s %-10s %-10s %-15s %-10s %-10s %s\n",
+ seq_printf(m, "#%-10s %-18s %-18s %-10s %-16s %-10s %-10s %s\n",
"<tree id>", "<pid>", "<vid>", "<refcnt>",
"<oplock>", "<daccess>", "<saccess>",
"<name>");
read_lock(&global_ft.lock);
idr_for_each_entry(global_ft.idr, fp, id) {
- seq_printf(m, "%#-10x %#-10llx %#-10llx %#-10x",
+ seq_printf(m, " %#-10x %#-18llx %#-18llx %#-10x",
fp->tcon ? fp->tcon->id : 0,
fp->persistent_id,
fp->volatile_id,
@@ -93,6 +93,7 @@ static int proc_show_files(struct seq_file *m, void *v)
opinfo = rcu_dereference(fp->f_opinfo);
if (opinfo) {
const struct ksmbd_const_name *const_names;
+ const char *name;
int count;
unsigned int level;
@@ -106,11 +107,14 @@ static int proc_show_files(struct seq_file *m, void *v)
level = opinfo->level;
}
rcu_read_unlock();
- ksmbd_proc_show_const_name(m, " %-15s",
- const_names, count, level);
+ name = ksmbd_proc_const_name(const_names, count, level);
+ if (name)
+ seq_printf(m, " %-16s", name);
+ else
+ seq_printf(m, " 0x%-14x", level);
} else {
rcu_read_unlock();
- seq_printf(m, " %-15s", " ");
+ seq_printf(m, " %-16s", " ");
}
seq_printf(m, " %#010x %#010x %s\n",
@@ -136,6 +140,16 @@ static bool durable_scavenger_running;
static DEFINE_MUTEX(durable_scavenger_lock);
static wait_queue_head_t dh_wq;
+bool ksmbd_durable_scavenger_active(void)
+{
+ bool active;
+
+ mutex_lock(&durable_scavenger_lock);
+ active = durable_scavenger_running;
+ mutex_unlock(&durable_scavenger_lock);
+ return active;
+}
+
void ksmbd_set_fd_limit(unsigned long limit)
{
limit = min(limit, get_max_files());
diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
index d6a9cd4b6d56..1c6fc4349b88 100644
--- a/fs/smb/server/vfs_cache.h
+++ b/fs/smb/server/vfs_cache.h
@@ -209,6 +209,7 @@ unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp);
void ksmbd_launch_ksmbd_durable_scavenger(void);
void ksmbd_stop_durable_scavenger(void);
+bool ksmbd_durable_scavenger_active(void);
void ksmbd_close_tree_conn_fds(struct ksmbd_work *work);
void ksmbd_close_session_fds(struct ksmbd_work *work);
void ksmbd_wake_session_blocked_works(struct ksmbd_session *sess);
diff --git a/fs/super.c b/fs/super.c
index 1159a73856db..a257b154f7f7 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -24,6 +24,7 @@
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/blkdev.h>
+#include <linux/memcontrol.h>
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/writeback.h> /* for the emergency remount stuff */
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/dma-fence.h b/include/linux/dma-fence.h
index b52ab692b22e..c4a76bc4006b 100644
--- a/include/linux/dma-fence.h
+++ b/include/linux/dma-fence.h
@@ -141,6 +141,9 @@ struct dma_fence_ops {
* compute the name at runtime, without having it to store permanently
* for each fence, or build a cache of some sort.
*
+ * The returned string is RCU protected and can be freed after the fence
+ * signaled and a RCU grace period passed.
+ *
* This callback is mandatory.
*/
const char * (*get_driver_name)(struct dma_fence *fence);
@@ -153,6 +156,9 @@ struct dma_fence_ops {
* having it to store permanently for each fence, or build a cache of
* some sort.
*
+ * The returned string is RCU protected and can be freed after the fence
+ * signaled and a RCU grace period passed.
+ *
* This callback is mandatory.
*/
const char * (*get_timeline_name)(struct dma_fence *fence);
diff --git a/include/linux/ieee80211-mesh.h b/include/linux/ieee80211-mesh.h
index 7eb15834531c..9e548b9173df 100644
--- a/include/linux/ieee80211-mesh.h
+++ b/include/linux/ieee80211-mesh.h
@@ -361,8 +361,7 @@ ieee80211_mesh_hwmp_perr_get_rcode(const u8 *ie, u8 dst_idx)
/* IEEE Std 802.11-2016 9.4.2.113 PREQ element */
static inline bool ieee80211_mesh_preq_size_ok(const u8 *pos, u8 elen)
{
- struct ieee80211_mesh_hwmp_preq_bottom *preq_elem_bottom =
- ieee80211_mesh_hwmp_preq_get_bottom(pos);
+ struct ieee80211_mesh_hwmp_preq_bottom *preq_elem_bottom;
u8 target_count;
int needed;
@@ -378,6 +377,7 @@ static inline bool ieee80211_mesh_preq_size_ok(const u8 *pos, u8 elen)
if (elen < needed)
return false;
+ preq_elem_bottom = ieee80211_mesh_hwmp_preq_get_bottom(pos);
target_count = preq_elem_bottom->target_count;
/* IEEE Std 802.11-2016 Table 14-10 to 14-16 */
if (target_count < 1)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 8840b126979f..14bcdcd44d1d 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -832,8 +832,13 @@ struct xps_dev_maps {
#define TC_BITMASK 15
/* HW offloaded queuing disciplines txq count and offset maps */
struct netdev_tc_txq {
- u16 count;
- u16 offset;
+ union {
+ struct {
+ u16 count;
+ u16 offset;
+ };
+ u32 combined;
+ };
};
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
@@ -894,6 +899,7 @@ struct net_device_path {
u8 h_dest[ETH_ALEN];
} encap;
struct {
+ struct dst_entry *dst;
union {
struct in_addr src_v4;
struct in6_addr src_v6;
@@ -3422,8 +3428,9 @@ void dev_remove_offload(struct packet_offload *po);
int dev_get_iflink(const struct net_device *dev);
int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
-int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
+int dev_fill_forward_path(struct net_device_path_ctx *ctx,
struct net_device_path_stack *stack);
+void dev_fill_forward_path_release(struct net_device_path_stack *stack);
struct net_device *dev_get_by_name(struct net *net, const char *name);
struct net_device *dev_get_by_name_rcu(struct net *net, const char *name);
struct net_device *__dev_get_by_name(struct net *net, const char *name);
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/codel.h b/include/net/codel.h
index aa80f744826c..183d43c2bd43 100644
--- a/include/net/codel.h
+++ b/include/net/codel.h
@@ -140,6 +140,11 @@ struct codel_vars {
/* needed shift to get a Q0.32 number from rec_inv_sqrt */
#define REC_INV_SQRT_SHIFT (32 - REC_INV_SQRT_BITS)
+/* Cap on drops per codel_dequeue() call: the loop's work depends on the
+ * idle gap and backlog, both outside our control; resync when exceeded.
+ */
+#define CODEL_MAX_DROPS_PER_DEQUEUE 256
+
/**
* struct codel_stats - contains codel shared variables and stats
* @maxpacket: largest packet we've seen so far
diff --git a/include/net/codel_impl.h b/include/net/codel_impl.h
index 2c1f0ec309e9..8f26132d45b7 100644
--- a/include/net/codel_impl.h
+++ b/include/net/codel_impl.h
@@ -93,12 +93,17 @@ static void codel_Newton_step(struct codel_vars *vars)
* CoDel control_law is t + interval/sqrt(count)
* We maintain in rec_inv_sqrt the reciprocal value of sqrt(count) to avoid
* both sqrt() and divide operation.
+ *
+ * Clamp the increment to at least 1 tick: a very small interval (or a
+ * large count) can truncate it to zero, stalling the dropping loop.
*/
static codel_time_t codel_control_law(codel_time_t t,
codel_time_t interval,
u32 rec_inv_sqrt)
{
- return t + reciprocal_scale(interval, rec_inv_sqrt << REC_INV_SQRT_SHIFT);
+ return t + max_t(u32, 1,
+ reciprocal_scale(interval,
+ rec_inv_sqrt << REC_INV_SQRT_SHIFT));
}
static bool codel_should_drop(const struct sk_buff *skb,
@@ -154,6 +159,7 @@ static struct sk_buff *codel_dequeue(void *ctx,
codel_skb_dequeue_t dequeue_func)
{
struct sk_buff *skb = dequeue_func(vars, ctx);
+ unsigned int drops = 0;
codel_time_t now;
bool drop;
@@ -180,6 +186,14 @@ static struct sk_buff *codel_dequeue(void *ctx,
*/
while (vars->dropping &&
codel_time_after_eq(now, vars->drop_next)) {
+ if (++drops > CODEL_MAX_DROPS_PER_DEQUEUE) {
+ /* fell far behind the schedule */
+ WRITE_ONCE(vars->drop_next,
+ codel_control_law(now,
+ params->interval,
+ vars->rec_inv_sqrt));
+ break;
+ }
/* dont care of possible wrap
* since there is no more divide.
*/
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 4f95da023746..36055d40172a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -7615,11 +7615,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/sock.h b/include/net/sock.h
index 51185222aac2..60ea55dc1885 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2312,6 +2312,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/rdma/uverbs_types.h b/include/rdma/uverbs_types.h
index 5a07f9a6dcd1..6f3622892c0c 100644
--- a/include/rdma/uverbs_types.h
+++ b/include/rdma/uverbs_types.h
@@ -180,8 +180,6 @@ struct ib_uverbs_file {
struct page *disassociate_page;
struct xarray idr;
-
- struct mutex disassociation_lock;
};
extern const struct uverbs_obj_type_class uverbs_idr_class;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 10ad80f930c2..1d2772758fb6 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -698,7 +698,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 79c21966220b..9b28e9aef4f1 100644
--- a/include/sound/soc_sdw_utils.h
+++ b/include/sound/soc_sdw_utils.h
@@ -44,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 *codec_name;
@@ -88,25 +100,13 @@ struct asoc_sdw_codec_info {
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;
@@ -182,7 +182,8 @@ struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks
const struct snd_soc_acpi_endpoint *new);
int asoc_sdw_get_dai_type(u32 type);
-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,
@@ -235,7 +236,7 @@ int asoc_sdw_es9356_amp_init(struct snd_soc_card *card,
int asoc_sdw_es9356_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
/* 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/include/trace/events/dma.h b/include/trace/events/dma.h
index 31c9ddf72c9d..daef2c176ecd 100644
--- a/include/trace/events/dma.h
+++ b/include/trace/events/dma.h
@@ -133,7 +133,7 @@ DECLARE_EVENT_CLASS(dma_alloc_class,
TP_fast_assign(
__assign_str(device);
__entry->virt_addr = virt_addr;
- __entry->dma_addr = dma_addr;
+ __entry->dma_addr = virt_addr ? dma_addr : 0;
__entry->size = size;
__entry->flags = flags;
__entry->dir = dir;
diff --git a/include/uapi/rdma/bnxt_re-abi.h b/include/uapi/rdma/bnxt_re-abi.h
index a4599d7b736a..0a125c2a8cc4 100644
--- a/include/uapi/rdma/bnxt_re-abi.h
+++ b/include/uapi/rdma/bnxt_re-abi.h
@@ -247,7 +247,7 @@ struct bnxt_re_query_device_ex_resp {
struct bnxt_re_db_region {
__u32 dpi;
__u32 reserved;
- __aligned_u64 umdbr;
+ __aligned_u64 reserved2;
};
enum bnxt_re_obj_dbr_alloc_attrs {
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index b5b461d4418b..1f0393ad0b18 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -5228,10 +5228,13 @@ struct task_struct *css_task_iter_next(struct css_task_iter *it)
if (it->flags & CSS_TASK_ITER_SKIPPED)
css_task_iter_advance(it);
- if (it->task_pos) {
+ while (it->task_pos && !it->cur_task) {
it->cur_task = list_entry(it->task_pos, struct task_struct,
cg_list);
- get_task_struct(it->cur_task);
+ /* a task on dying_tasks with zero refcount is only valid for
+ * RCU readers, not even interesting for
+ * CSS_TASK_ITER_WITH_DEAD, find another one */
+ it->cur_task = tryget_task_struct(it->cur_task);
css_task_iter_advance(it);
}
diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c
index bcdc0f76d2e8..b6fe902c6a6d 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 6e8db52866bf..bd5393133753 100644
--- a/kernel/dma/swiotlb.c
+++ b/kernel/dma/swiotlb.c
@@ -867,7 +867,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;
@@ -900,7 +899,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/events/core.c b/kernel/events/core.c
index bd8c1acf59e2..60e60809bedc 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -6350,6 +6350,9 @@ static DEFINE_MUTEX(perf_mediated_pmu_mutex);
/* !exclude_guest event of PMU with PERF_PMU_CAP_MEDIATED_VPMU */
static inline bool is_include_guest_event(struct perf_event *event)
{
+ if (!event->pmu)
+ return false;
+
if ((event->pmu->capabilities & PERF_PMU_CAP_MEDIATED_VPMU) &&
!event->attr.exclude_guest)
return true;
@@ -12977,6 +12980,7 @@ static void __pmu_detach_event(struct pmu *pmu, struct perf_event *event,
exclusive_event_destroy(event);
module_put(pmu->module);
+ mediated_pmu_unaccount_event(event);
event->pmu = NULL; /* force fault instead of UAF */
}
diff --git a/kernel/exit.c b/kernel/exit.c
index e4cd7232015d..0abce8edb28b 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -303,12 +303,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);
diff --git a/kernel/fork.c b/kernel/fork.c
index 3340dbaf2bb4..2c88568b0463 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1977,9 +1977,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 35d647c8c368..3d6c55598726 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3352,6 +3352,8 @@ void relax_compatible_cpus_allowed_ptr(struct task_struct *p)
void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
{
unsigned int state = READ_ONCE(p->__state);
+ bool proxy_migrated = sched_proxy_exec() && p->is_blocked &&
+ task_cpu(p) != p->wake_cpu;
/*
* We should never call set_task_cpu() on a blocked task,
@@ -3387,7 +3389,12 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
*/
WARN_ON_ONCE(!cpu_online(new_cpu));
- WARN_ON_ONCE(is_migration_disabled(p));
+ /*
+ * Proxy execution can move a blocked task's scheduling context to any
+ * CPU without moving its migration-disabled execution context. The
+ * wakeup path will return the task to a CPU where it can execute.
+ */
+ WARN_ON_ONCE(is_migration_disabled(p) && !proxy_migrated);
trace_sched_migrate_task(p, new_cpu);
diff --git a/kernel/sched/ext/ext.c b/kernel/sched/ext/ext.c
index 548f46a42788..906e4f08967f 100644
--- a/kernel/sched/ext/ext.c
+++ b/kernel/sched/ext/ext.c
@@ -7282,22 +7282,24 @@ static void scx_root_enable_workfn(struct kthread_work *work)
#ifdef CONFIG_EXT_SUB_SCHED
cgroup_get(cgrp);
#endif
+ /*
+ * Transition to ENABLING to arm the disable path. Allocation failure
+ * still unwinds locally. Full disabling on failure applies only after
+ * scx_alloc_and_add_sched() succeeds.
+ */
+ WARN_ON_ONCE(scx_set_enable_state(SCX_ENABLING) != SCX_DISABLED);
+ WARN_ON_ONCE(scx_root);
+
sch = scx_alloc_and_add_sched(cmd, cgrp, NULL);
if (IS_ERR(sch)) {
ret = PTR_ERR(sch);
+ WARN_ON_ONCE(scx_set_enable_state(SCX_DISABLED) != SCX_ENABLING);
goto err_free_tid_hash;
}
if (sch->is_cid_type)
static_branch_enable(&__scx_is_cid_type);
- /*
- * Transition to ENABLING and clear exit info to arm the disable path.
- * Failure triggers full disabling from here on.
- */
- WARN_ON_ONCE(scx_set_enable_state(SCX_ENABLING) != SCX_DISABLED);
- WARN_ON_ONCE(scx_root);
-
atomic_long_set(&scx_nr_rejected, 0);
for_each_possible_cpu(cpu) {
@@ -8964,10 +8966,17 @@ __bpf_kfunc void scx_bpf_dsq_insert_vtime(struct task_struct *p, u64 dsq_id,
#ifdef CONFIG_EXT_SUB_SCHED
/*
* Disallow if any sub-scheds are attached. There is no way to tell
- * which scheduler called us, just error out @p's scheduler.
+ * which scheduler called us, so error out @p's scheduler -- read it
+ * under RCU as @p's locks aren't necessarily held here. @p may be a
+ * task past sched_ext_dead() or an idle task, in which case its
+ * scheduler can't be determined and there is nothing obviously wrong
+ * to report; just refuse the call.
*/
if (unlikely(!list_empty(&sch->children))) {
- scx_error(scx_task_sched(p), "__scx_bpf_dsq_insert_vtime() must be used");
+ struct scx_sched *tsch = scx_task_sched_rcu(p);
+
+ if (tsch)
+ scx_error(tsch, "__scx_bpf_dsq_insert_vtime() must be used");
return;
}
#endif
diff --git a/kernel/sched/ext/idle.c b/kernel/sched/ext/idle.c
index 6f93cc32b650..fff48c164b10 100644
--- a/kernel/sched/ext/idle.c
+++ b/kernel/sched/ext/idle.c
@@ -1097,10 +1097,17 @@ __bpf_kfunc s32 scx_bpf_select_cpu_and(struct task_struct *p, s32 prev_cpu, u64
#ifdef CONFIG_EXT_SUB_SCHED
/*
* Disallow if any sub-scheds are attached. There is no way to tell
- * which scheduler called us, just error out @p's scheduler.
+ * which scheduler called us, so error out @p's scheduler -- read it
+ * under RCU as @p's locks aren't necessarily held here. @p may be a
+ * task past sched_ext_dead() or an idle task, in which case its
+ * scheduler can't be determined and there is nothing obviously wrong
+ * to report; just refuse the call.
*/
if (unlikely(!list_empty(&sch->children))) {
- scx_error(scx_task_sched(p), "__scx_bpf_select_cpu_and() must be used");
+ struct scx_sched *tsch = scx_task_sched_rcu(p);
+
+ if (tsch)
+ scx_error(tsch, "__scx_bpf_select_cpu_and() must be used");
return -EINVAL;
}
#endif
diff --git a/kernel/signal.c b/kernel/signal.c
index 5f34ee7b504e..808980d08371 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.
*/
@@ -1037,6 +1061,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)
{
@@ -1048,6 +1087,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;
@@ -1991,11 +2034,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;
@@ -2013,6 +2070,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().
@@ -2104,6 +2164,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);
}
@@ -2159,7 +2220,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
@@ -3143,42 +3204,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)) {
+ 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().
- */
- 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/jiffies.c b/kernel/time/jiffies.c
index d51428867a33..f4c43b9716f8 100644
--- a/kernel/time/jiffies.c
+++ b/kernel/time/jiffies.c
@@ -181,7 +181,7 @@ static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr,
int *k_ptr, int dir,
const struct ctl_table *tbl)
{
- return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, false,
+ return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, true,
sysctl_u2k_int_conv_ms, sysctl_k2u_int_conv_ms);
}
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index a7d3e8229c4b..8e3e3917a2f7 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 d721986d5f46..ebc51fabfcd8 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1616,7 +1616,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 0dbed3ba5c8a..a2ad4a96b193 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -92,7 +92,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;
@@ -118,6 +118,67 @@ static bool vma_is_special_huge(const struct vm_area_struct *vma)
return vma_test_any(vma, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT);
}
+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_test(vma, VMA_PFNMAP_BIT) && 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,
@@ -190,27 +251,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 6349c48154f4..a8d1992ba7a1 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -2823,14 +2823,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 405faa4b8472..7138ebc6efc3 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -3107,7 +3107,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 8c227fefa2df..2d8f26a1cf26 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 a7bd785e603f..ecd926209560 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -1344,12 +1344,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;
@@ -1390,10 +1389,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/shrinker.c b/mm/shrinker.c
index a70aab124a0e..7ec2a9704f6f 100644
--- a/mm/shrinker.c
+++ b/mm/shrinker.c
@@ -227,6 +227,8 @@ static int shrinker_memcg_alloc(struct shrinker *shrinker)
{
int id;
+ shrinker->id = -1;
+
if (mem_cgroup_disabled())
return -ENOSYS;
if (mem_cgroup_kmem_disabled() && !(shrinker->flags & SHRINKER_NONSLAB))
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 5bb24031e913..623b30e9c2df 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -156,7 +156,7 @@ static struct swap_info_struct *swap_entry_to_info(swp_entry_t entry)
* 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 9eea2850818a..98c163431e40 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -2754,10 +2754,12 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr,
map.check_ksm_early = can_set_ksm_flags_early(&map);
error = __mmap_setup(&map, &desc, uf);
- if (!error && have_mmap_prepare)
- error = call_mmap_prepare(&map, &desc);
if (error)
goto abort_munmap;
+ if (have_mmap_prepare)
+ error = call_mmap_prepare(&map, &desc);
+ 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 6da52d12df68..5214786e61d1 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));
@@ -317,23 +320,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))
@@ -346,6 +339,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);
@@ -355,13 +354,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_conn.c b/net/bluetooth/hci_conn.c
index 8de98af2fb58..fa72cf8aaa7a 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1023,6 +1023,19 @@ static struct hci_conn *__hci_conn_add(struct hci_dev *hdev, int type,
if (!hdev->le_mtu && hdev->acl_mtu < HCI_MIN_LE_MTU)
return ERR_PTR(-ECONNREFUSED);
irk = hci_get_irk(hdev, dst, dst_type);
+ /* An identity address only reaches a peer advertising an RPA
+ * if the controller translates it. Unless address resolution
+ * is enabled and this peer is programmed into the resolving
+ * list, keep the RPA the peer is on air with;
+ * le_conn_complete_evt() resolves it back once the link is
+ * up.
+ */
+ if (irk &&
+ (!hci_dev_test_flag(hdev, HCI_LL_RPA_RESOLUTION) ||
+ !hci_bdaddr_list_lookup_with_irk(&hdev->le_resolv_list,
+ &irk->bdaddr,
+ irk->addr_type)))
+ irk = NULL;
break;
case SCO_LINK:
case ESCO_LINK:
@@ -1505,7 +1518,15 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
}
if (conn) {
+ /* dst may just have been swapped for the peer's RPA above, and
+ * dst_type describes dst -- it has to travel with it. Leaving
+ * the identity type behind makes the pair describe a peer that
+ * does not exist, and nothing downstream repairs it:
+ * hci_bdaddr_is_rpa() tests the type before the address, so
+ * the RPA is never treated as one.
+ */
bacpy(&conn->dst, dst);
+ conn->dst_type = dst_type;
} else {
conn = hci_conn_add_unset(hdev, LE_LINK, dst, dst_type, role);
if (IS_ERR(conn))
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index f747492da5f6..3ea5ea7267d9 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2670,6 +2670,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);
@@ -3234,6 +3235,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;
@@ -3242,7 +3254,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 */
@@ -3267,7 +3279,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 */
@@ -3338,7 +3350,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 a8d2a3f076e9..9d9e270492f9 100644
--- a/net/bluetooth/hci_sync.c
+++ b/net/bluetooth/hci_sync.c
@@ -5587,7 +5587,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 75bfd5938b2e..eb99653f33f9 100644
--- a/net/bluetooth/iso.c
+++ b/net/bluetooth/iso.c
@@ -819,19 +819,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) {
@@ -1737,6 +1742,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);
@@ -1745,12 +1757,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;
@@ -1760,12 +1780,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;
}
@@ -2289,6 +2319,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 feb302a491fa..24b42483b3c0 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -241,9 +241,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)
@@ -904,6 +902,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);
@@ -914,9 +913,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/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 1e0e436629ec..92b3cb621a26 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -387,12 +387,12 @@ static int __vlan_add(struct net_bridge_vlan *v, u16 flags,
goto out;
}
-static int __vlan_del(struct net_bridge_vlan *v)
+static void __vlan_del(struct net_bridge_vlan *v)
{
struct net_bridge_vlan *masterv = v;
struct net_bridge_vlan_group *vg;
struct net_bridge_port *p = NULL;
- int err = 0;
+ int err;
if (br_vlan_is_master(v)) {
vg = br_vlan_group(v->br);
@@ -406,12 +406,16 @@ static int __vlan_del(struct net_bridge_vlan *v)
if (p) {
err = __vlan_vid_del(p->dev, p->br, v);
if (err)
- goto out;
+ br_warn(p->br,
+ "port %u(%s) failed to delete vlan %u from switchdev: %pe\n",
+ (unsigned int)p->port_no, p->dev->name,
+ v->vid, ERR_PTR(err));
} else {
err = br_switchdev_port_vlan_del(v->br->dev, v->vid);
if (err && err != -EOPNOTSUPP)
- goto out;
- err = 0;
+ br_warn(v->br,
+ "failed to delete bridge vlan %u from switchdev: %pe\n",
+ v->vid, ERR_PTR(err));
}
if (br_vlan_should_use(v)) {
@@ -431,8 +435,6 @@ static int __vlan_del(struct net_bridge_vlan *v)
}
br_vlan_put_master(masterv);
-out:
- return err;
}
static void __vlan_group_free(struct net_bridge_vlan_group *vg)
@@ -449,7 +451,6 @@ static void __vlan_flush(const struct net_bridge *br,
{
struct net_bridge_vlan *vlan, *tmp;
u16 v_start = 0, v_end = 0;
- int err;
__vlan_delete_pvid(vg, vg->pvid);
list_for_each_entry_safe(vlan, tmp, &vg->vlan_list, vlist) {
@@ -463,13 +464,7 @@ static void __vlan_flush(const struct net_bridge *br,
}
v_end = vlan->vid;
- err = __vlan_del(vlan);
- if (err) {
- br_err(br,
- "port %u(%s) failed to delete vlan %d: %pe\n",
- (unsigned int) p->port_no, p->dev->name,
- vlan->vid, ERR_PTR(err));
- }
+ __vlan_del(vlan);
}
/* notify about the last/whole vlan range */
@@ -837,8 +832,9 @@ int br_vlan_delete(struct net_bridge *br, u16 vid)
br_fdb_delete_by_port(br, NULL, vid, 0);
vlan_tunnel_info_del(vg, v);
+ __vlan_del(v);
- return __vlan_del(v);
+ return 0;
}
void br_vlan_flush(struct net_bridge *br)
@@ -1368,8 +1364,9 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid)
return -ENOENT;
br_fdb_find_delete_local(port->br, port, port->dev->dev_addr, vid);
br_fdb_delete_by_port(port->br, port, vid, 0);
+ __vlan_del(v);
- return __vlan_del(v);
+ return 0;
}
void nbp_vlan_flush(struct net_bridge_port *port)
diff --git a/net/core/dev.c b/net/core/dev.c
index 74dd9e25f4ff..65cdaf0c81f7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -742,51 +742,73 @@ EXPORT_SYMBOL_GPL(dev_fill_metadata_dst);
static struct net_device_path *dev_fwd_path(struct net_device_path_stack *stack)
{
- int k = stack->num_paths++;
-
- if (k >= NET_DEVICE_PATH_STACK_MAX)
+ if (stack->num_paths + 1 > NET_DEVICE_PATH_STACK_MAX)
return NULL;
- return &stack->path[k];
+ return &stack->path[stack->num_paths];
}
-int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
+void dev_fill_forward_path_release(struct net_device_path_stack *stack)
+{
+ struct net_device_path *path;
+ int k;
+
+ if (stack->num_paths == 0)
+ return;
+
+ for (k = stack->num_paths - 1; k >= 0; k--) {
+ path = &stack->path[k];
+ switch (path->type) {
+ case DEV_PATH_TUN:
+ dst_release(path->tun.dst);
+ break;
+ default:
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(dev_fill_forward_path_release);
+
+int dev_fill_forward_path(struct net_device_path_ctx *ctx,
struct net_device_path_stack *stack)
{
const struct net_device *last_dev;
- struct net_device_path_ctx ctx = {
- .dev = dev,
- };
struct net_device_path *path;
int ret = 0;
- memcpy(ctx.daddr, daddr, sizeof(ctx.daddr));
stack->num_paths = 0;
- while (ctx.dev && ctx.dev->netdev_ops->ndo_fill_forward_path) {
- last_dev = ctx.dev;
+ while (ctx->dev && ctx->dev->netdev_ops->ndo_fill_forward_path) {
+ last_dev = ctx->dev;
path = dev_fwd_path(stack);
if (!path)
- return -1;
+ goto err_out;
memset(path, 0, sizeof(struct net_device_path));
- ret = ctx.dev->netdev_ops->ndo_fill_forward_path(&ctx, path);
+ ret = ctx->dev->netdev_ops->ndo_fill_forward_path(ctx, path);
if (ret < 0)
- return -1;
+ goto err_out;
- if (WARN_ON_ONCE(last_dev == ctx.dev))
- return -1;
+ stack->num_paths++;
+ if (last_dev == ctx->dev)
+ goto err_out;
}
- if (!ctx.dev)
+ if (!ctx->dev)
return ret;
path = dev_fwd_path(stack);
if (!path)
- return -1;
+ goto err_out;
+
path->type = DEV_PATH_ETHERNET;
- path->dev = ctx.dev;
+ path->dev = ctx->dev;
+ stack->num_paths++;
- return ret;
+ return 0;
+err_out:
+ dev_fill_forward_path_release(stack);
+
+ return -1;
}
EXPORT_SYMBOL_GPL(dev_fill_forward_path);
@@ -2627,11 +2649,13 @@ EXPORT_SYMBOL_GPL(dev_queue_xmit_nit);
*/
static void netif_setup_tc(struct net_device *dev, unsigned int txq)
{
+ struct netdev_tc_txq res;
int i;
- struct netdev_tc_txq *tc = &dev->tc_to_txq[0];
+
+ res.combined = READ_ONCE(dev->tc_to_txq[0].combined);
/* If TC0 is invalidated disable TC mapping */
- if (tc->offset + tc->count > txq) {
+ if (res.offset + res.count > txq) {
netdev_warn(dev, "Number of in use tx queues changed invalidating tc mappings. Priority traffic classification disabled!\n");
dev->num_tc = 0;
return;
@@ -2641,8 +2665,8 @@ static void netif_setup_tc(struct net_device *dev, unsigned int txq)
for (i = 1; i < TC_BITMASK + 1; i++) {
int q = netdev_get_prio_tc_map(dev, i);
- tc = &dev->tc_to_txq[q];
- if (tc->offset + tc->count > txq) {
+ res.combined = READ_ONCE(dev->tc_to_txq[q].combined);
+ if (res.offset + res.count > txq) {
netdev_warn(dev, "Number of in use tx queues changed. Priority %i to tc mapping %i is no longer valid. Setting map to 0\n",
i, q);
netdev_set_prio_tc_map(dev, i, 0);
@@ -2658,7 +2682,10 @@ int netdev_txq_to_tc(struct net_device *dev, unsigned int txq)
/* walk through the TCs and see if it falls into any of them */
for (i = 0; i < TC_MAX_QUEUE; i++, tc++) {
- if ((txq - tc->offset) < tc->count)
+ struct netdev_tc_txq res;
+
+ res.combined = READ_ONCE(tc->combined);
+ if ((txq - res.offset) < res.count)
return i;
}
@@ -3078,6 +3105,8 @@ static void netdev_unbind_all_sb_channels(struct net_device *dev)
void netdev_reset_tc(struct net_device *dev)
{
+ int i;
+
#ifdef CONFIG_XPS
netif_reset_xps_queues_gt(dev, 0);
#endif
@@ -3085,21 +3114,26 @@ void netdev_reset_tc(struct net_device *dev)
/* Reset TC configuration of device */
dev->num_tc = 0;
- memset(dev->tc_to_txq, 0, sizeof(dev->tc_to_txq));
+ for (i = 0; i < TC_MAX_QUEUE; i++)
+ WRITE_ONCE(dev->tc_to_txq[i].combined, 0);
memset(dev->prio_tc_map, 0, sizeof(dev->prio_tc_map));
}
EXPORT_SYMBOL(netdev_reset_tc);
int netdev_set_tc_queue(struct net_device *dev, u8 tc, u16 count, u16 offset)
{
+ struct netdev_tc_txq res = {
+ .count = count,
+ .offset = offset,
+ };
+
if (tc >= dev->num_tc)
return -EINVAL;
#ifdef CONFIG_XPS
netif_reset_xps_queues(dev, offset, count);
#endif
- dev->tc_to_txq[tc].count = count;
- dev->tc_to_txq[tc].offset = offset;
+ WRITE_ONCE(dev->tc_to_txq[tc].combined, res.combined);
return 0;
}
EXPORT_SYMBOL(netdev_set_tc_queue);
@@ -3123,11 +3157,13 @@ void netdev_unbind_sb_channel(struct net_device *dev,
struct net_device *sb_dev)
{
struct netdev_queue *txq = &dev->_tx[dev->num_tx_queues];
+ int i;
#ifdef CONFIG_XPS
netif_reset_xps_queues_gt(sb_dev, 0);
#endif
- memset(sb_dev->tc_to_txq, 0, sizeof(sb_dev->tc_to_txq));
+ for (i = 0; i < TC_MAX_QUEUE; i++)
+ WRITE_ONCE(sb_dev->tc_to_txq[i].combined, 0);
memset(sb_dev->prio_tc_map, 0, sizeof(sb_dev->prio_tc_map));
while (txq-- != &dev->_tx[0]) {
@@ -3150,8 +3186,12 @@ int netdev_bind_sb_channel_queue(struct net_device *dev,
return -EINVAL;
/* Record the mapping */
- sb_dev->tc_to_txq[tc].count = count;
- sb_dev->tc_to_txq[tc].offset = offset;
+ struct netdev_tc_txq res = {
+ .count = count,
+ .offset = offset,
+ };
+
+ WRITE_ONCE(sb_dev->tc_to_txq[tc].combined, res.combined);
/* Provide a way for Tx queue to find the tc_to_txq map or
* XPS map for itself.
@@ -3517,9 +3557,11 @@ static u16 skb_tx_hash(const struct net_device *dev,
if (dev->num_tc) {
u8 tc = netdev_get_prio_tc_map(dev, skb->priority);
+ struct netdev_tc_txq res;
- qoffset = sb_dev->tc_to_txq[tc].offset;
- qcount = sb_dev->tc_to_txq[tc].count;
+ res.combined = READ_ONCE(sb_dev->tc_to_txq[tc].combined);
+ qoffset = res.offset;
+ qcount = res.count;
if (unlikely(!qcount)) {
net_warn_ratelimited("%s: invalid qcount, qoffset %u for tc %u\n",
sb_dev->name, qoffset, tc);
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
index abaf108ac4db..edc660778408 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;
@@ -448,7 +447,7 @@ net_dm_hw_trap_summary_probe(void *ignore, const struct devlink *devlink,
if (metadata->trap_type == DEVLINK_TRAP_TYPE_CONTROL)
return;
- hw_data = this_cpu_ptr(&dm_hw_cpu_data);
+ hw_data = raw_cpu_ptr(&dm_hw_cpu_data);
raw_spin_lock_irqsave(&hw_data->lock, flags);
hw_entries = hw_data->hw_entries;
@@ -516,7 +515,7 @@ static void net_dm_packet_trace_kfree_skb_hit(void *ignore,
*/
nskb->tstamp = tstamp;
- data = this_cpu_ptr(&dm_cpu_data);
+ data = raw_cpu_ptr(&dm_cpu_data);
spin_lock_irqsave(&data->drop_queue.lock, flags);
if (skb_queue_len(&data->drop_queue) < net_dm_queue_len)
@@ -983,7 +982,7 @@ net_dm_hw_trap_packet_probe(void *ignore, const struct devlink *devlink,
NET_DM_SKB_CB(nskb)->hw_metadata = n_hw_metadata;
nskb->tstamp = tstamp;
- hw_data = this_cpu_ptr(&dm_hw_cpu_data);
+ hw_data = raw_cpu_ptr(&dm_hw_cpu_data);
spin_lock_irqsave(&hw_data->drop_queue.lock, flags);
if (skb_queue_len(&hw_data->drop_queue) < net_dm_queue_len)
@@ -1083,7 +1082,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;
@@ -1117,7 +1116,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;
@@ -1173,12 +1172,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);
@@ -1206,7 +1206,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 1349c0eedb64..7448320f7ad5 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2359,6 +2359,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 },
@@ -2375,7 +2382,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,
@@ -2579,9 +2587,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) {
@@ -2605,17 +2614,21 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
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_rcu(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 || p->dev == blackhole_netdev)
+ continue;
+
if (nidx < neigh_skip)
goto next;
@@ -2630,12 +2643,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;
}
@@ -3669,12 +3685,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);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 0e964c67a721..c485be081aea 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -6820,6 +6820,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)
@@ -6875,7 +6903,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;
@@ -7015,7 +7043,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 1ad41904db25..4395509ab9dc 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -142,6 +142,7 @@
#include <trace/events/sock.h>
+#include <net/psp.h>
#include <net/tcp.h>
#include <net/busy_poll.h>
#include <net/phonet/phonet.h>
@@ -2667,6 +2668,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.
*/
@@ -3908,7 +3915,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 dfc81ee969ae..faa48f5b9739 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -441,6 +441,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 0caedfc7ca92..90c0e22c29be 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -581,16 +581,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 5168d546ea2f..bab42b9e277f 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 ca1180dba1de..e921cb381b53 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -51,6 +51,8 @@ static int tcp_ecn_mode_max = 5;
static u32 icmp_errors_extension_mask_all =
GENMASK_U8(ICMP_ERR_EXT_COUNT - 1, 0);
+static int tcp_min_rcvbuf = 4096;
+
/* obsolete */
static int sysctl_tcp_low_latency __read_mostly;
@@ -1462,7 +1464,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 0f60a1dbf927..92bc60716f33 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6490,6 +6490,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.
@@ -6539,7 +6540,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/ipv6/esp6.c b/net/ipv6/esp6.c
index 296b57926abb..a3a3857eed98 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -470,6 +470,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/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 df9c29eb5c1f..7fa4ed2fd4f1 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1604,7 +1604,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_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/cfg.c b/net/mac80211/cfg.c
index 43f142624d33..33334b978462 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -115,6 +115,10 @@ static int ieee80211_set_mon_options(struct ieee80211_sub_if_data *sdata,
return -EBUSY;
}
+ /* TXQs are reserved in ieee80211_if_add() and cannot be added later */
+ if ((params->flags & MONITOR_FLAG_ACTIVE) && !sdata->vif.txq)
+ return -EOPNOTSUPP;
+
/* validate whether MU-MIMO can be configured */
if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
@@ -1929,6 +1933,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;
@@ -3320,7 +3327,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)
@@ -3475,7 +3486,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)
@@ -4113,6 +4124,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 a4d5461f6480..f36cc2590305 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -388,7 +388,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 f3c6a41e4911..6aba22493670 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -657,6 +657,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);
@@ -670,6 +673,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);
@@ -729,6 +735,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 34a9ea8b6f85..0564370419fb 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2433,7 +2433,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 43460a705a6b..889c32fd8de1 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -616,6 +616,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:
@@ -924,9 +926,33 @@ static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
}
}
+/*
+ * 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,
@@ -935,6 +961,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);
}
@@ -964,7 +993,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);
@@ -1603,8 +1632,12 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
err_del_interface:
drv_remove_interface(local, sdata);
err_stop:
- if (!local->open_count)
+ if (!local->open_count) {
+ ieee80211_led_radio(local, false);
+ ieee80211_mod_tpt_led_trig(local, 0,
+ IEEE80211_TPT_LEDTRIG_FL_RADIO);
drv_stop(local, false);
+ }
if (sdata->vif.type == NL80211_IFTYPE_NAN_DATA)
RCU_INIT_POINTER(sdata->u.nan_data.nmi, NULL);
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index eb1eaaf34612..8edfef2b57f8 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1454,6 +1454,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 d4507e4e6ec1..8f8814125375 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -1196,6 +1196,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;
@@ -1204,6 +1219,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);
@@ -1510,19 +1530,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;
@@ -1555,7 +1566,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/offchannel.c b/net/mac80211/offchannel.c
index 2bceb73717c6..6f8de5d4a20d 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -460,6 +460,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 eeff230bd909..8e950ef6d1ea 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -1242,7 +1242,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 ffd575a8d188..9e721d3735e7 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -1142,6 +1142,7 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_local *local = sdata->local;
enum ieee80211_smps_mode smps_mode =
sdata->deflink.u.mgd.driver_smps_mode;
+ struct sta_info *sta;
int ret;
/* don't support setup with forced SMPS mode that's not off */
@@ -1168,14 +1169,10 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
* Allow error packets to be sent - sometimes we don't even add a STA
* before failing the setup.
*/
- if (status_code == 0) {
- rcu_read_lock();
- if (!sta_info_get(sdata, peer)) {
- rcu_read_unlock();
- ret = -ENOLINK;
- goto out_unlock;
- }
- rcu_read_unlock();
+ sta = sta_info_get(sdata, peer);
+ if ((status_code == 0 && !sta) || (sta && !sta->sta.tdls)) {
+ ret = -ENOLINK;
+ goto out_unlock;
}
ieee80211_flush_queues(local, sdata, false);
@@ -1284,6 +1281,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
@@ -1292,7 +1307,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,
@@ -1442,6 +1456,10 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
*/
tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer);
+ sta = sta_info_get(sdata, peer);
+ if (!sta || !sta->sta.tdls)
+ return -ENOLINK;
+
switch (oper) {
case NL80211_TDLS_ENABLE_LINK:
if (sdata->vif.bss_conf.csa_active) {
@@ -1449,10 +1467,6 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
return -EBUSY;
}
- sta = sta_info_get(sdata, peer);
- if (!sta || !sta->sta.tdls)
- return -ENOLINK;
-
iee80211_tdls_recalc_chanctx(sdata, sta);
iee80211_tdls_recalc_ht_protection(sdata, sta);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index fd4c379b3f20..e26412120873 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2096,8 +2096,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;
@@ -2271,6 +2292,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++) {
@@ -2470,7 +2494,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 */
@@ -2950,10 +2974,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;
@@ -2992,10 +3029,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;
}
}
@@ -3022,16 +3057,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);
@@ -3055,16 +3080,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);
}
@@ -5063,10 +5089,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
@@ -5075,6 +5109,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;
@@ -5156,25 +5194,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/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index 8b1165f2b5a4..254063fca078 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -258,6 +258,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) {
@@ -267,8 +275,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);
@@ -852,6 +859,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);
kmem_cache_destroy(flow_offload_cachep);
diff --git a/net/netfilter/nf_flow_table_path.c b/net/netfilter/nf_flow_table_path.c
index 98c03b487f52..b9df7453f762 100644
--- a/net/netfilter/nf_flow_table_path.c
+++ b/net/netfilter/nf_flow_table_path.c
@@ -50,6 +50,9 @@ static int nft_dev_fill_forward_path(const struct nf_flow_route *route,
{
const void *daddr = &ct->tuplehash[!dir].tuple.src.u3;
struct net_device *dev = dst_cache->dev;
+ struct net_device_path_ctx ctx = {
+ .dev = dev,
+ };
struct neighbour *n;
u8 nud_state;
@@ -72,7 +75,9 @@ static int nft_dev_fill_forward_path(const struct nf_flow_route *route,
return -1;
out:
- return dev_fill_forward_path(dev, ha, stack);
+ ether_addr_copy(ctx.daddr, ha);
+
+ return dev_fill_forward_path(&ctx, stack);
}
struct nft_forward_info {
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
index 63ff6b4d5d21..be021d8ecc41 100644
--- a/net/netfilter/nf_nat_core.c
+++ b/net/netfilter/nf_nat_core.c
@@ -1230,31 +1230,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 63003a3b8bab..245fe7b2f673 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -2435,11 +2435,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))) {
if (hook->flags & NFT_HOOK_REMOVE)
@@ -2481,7 +2484,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;
@@ -2938,7 +2941,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;
@@ -2951,7 +2954,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;
}
@@ -3252,7 +3256,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;
@@ -9031,7 +9035,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;
}
@@ -9108,7 +9112,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;
@@ -9121,7 +9125,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;
}
@@ -9341,7 +9345,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/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 5202fe0b0867..7288de715341 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -922,9 +922,9 @@ netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions)
static int netlink_realloc_groups(struct sock *sk)
{
+ unsigned long *new_groups, *old_groups = NULL;
struct netlink_sock *nlk = nlk_sk(sk);
unsigned int groups;
- unsigned long *new_groups;
int err = 0;
netlink_table_grab();
@@ -938,18 +938,37 @@ static int netlink_realloc_groups(struct sock *sk)
if (nlk->ngroups >= groups)
goto out_unlock;
- new_groups = krealloc(nlk->groups, NLGRPSZ(groups), GFP_ATOMIC);
- if (new_groups == NULL) {
+ /* Can not use krealloc(), because the old buffer might be freed
+ * immediately, while lockless readers (netlink diag dump and
+ * /proc/net/netlink) can still be looking at it.
+ */
+ new_groups = kzalloc(NLGRPSZ(groups), GFP_ATOMIC);
+ if (!new_groups) {
err = -ENOMEM;
goto out_unlock;
}
- memset((char *)new_groups + NLGRPSZ(nlk->ngroups), 0,
- NLGRPSZ(groups) - NLGRPSZ(nlk->ngroups));
+ old_groups = nlk->groups;
+ if (old_groups)
+ memcpy(new_groups, old_groups, NLGRPSZ(nlk->ngroups));
+
+ /* Publish the new bitmap and its content: pairs with the address
+ * dependency in lockless readers, which can pick up the new pointer
+ * while still seeing the old (smaller) nlk->ngroups.
+ */
+ smp_store_release(&nlk->groups, new_groups);
+
+ /* Then publish the new size: pairs with smp_load_acquire() from
+ * lockless readers, so that they can not read NLGRPSZ(new ngroups)
+ * bytes from the old buffer.
+ */
+ smp_store_release(&nlk->ngroups, groups);
- nlk->groups = new_groups;
- nlk->ngroups = groups;
out_unlock:
netlink_table_ungrab();
+
+ if (old_groups)
+ kfree_rcu_mightsleep(old_groups);
+
return err;
}
@@ -2705,12 +2724,19 @@ static int netlink_native_seq_show(struct seq_file *seq, void *v)
} else {
struct sock *s = v;
struct netlink_sock *nlk = nlk_sk(s);
+ const unsigned long *groups;
+
+ /* Lockless read : netlink_realloc_groups() can change
+ * nlk->groups under us. The old buffer is freed after an
+ * RCU grace period, and this walk is RCU protected.
+ */
+ groups = READ_ONCE(nlk->groups);
seq_printf(seq, "%pK %-3d %-10u %08x %-8d %-8d %-5d %-8d %-8u %-8llu\n",
s,
s->sk_protocol,
nlk->portid,
- nlk->groups ? (u32)nlk->groups[0] : 0,
+ groups ? (u32)groups[0] : 0,
sk_rmem_alloc_get(s),
sk_wmem_alloc_get(s),
READ_ONCE(nlk->cb_running),
diff --git a/net/netlink/diag.c b/net/netlink/diag.c
index 0b3e021bd0ed..7979bd9b2606 100644
--- a/net/netlink/diag.c
+++ b/net/netlink/diag.c
@@ -12,12 +12,24 @@
static int sk_diag_dump_groups(struct sock *sk, struct sk_buff *nlskb)
{
struct netlink_sock *nlk = nlk_sk(sk);
-
- if (nlk->groups == NULL)
+ unsigned long *groups;
+ unsigned int ngroups;
+
+ /* Hashed sockets are dumped from the rhashtable walk, which only
+ * holds rcu_read_lock(), while netlink_realloc_groups() can replace
+ * nlk->groups and nlk->ngroups at any time.
+ *
+ * Read nlk->ngroups first : this pairs with smp_store_release()
+ * from netlink_realloc_groups(), so that we can not use the new
+ * (bigger) size with the old (smaller) buffer. The old buffer is
+ * freed after an RCU grace period.
+ */
+ ngroups = smp_load_acquire(&nlk->ngroups);
+ groups = READ_ONCE(nlk->groups);
+ if (!groups)
return 0;
- return nla_put(nlskb, NETLINK_DIAG_GROUPS, NLGRPSZ(nlk->ngroups),
- nlk->groups);
+ return nla_put(nlskb, NETLINK_DIAG_GROUPS, NLGRPSZ(ngroups), groups);
}
static int sk_diag_put_flags(struct sock *sk, struct sk_buff *skb)
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index 37c90580ecb8..757cce7a658e 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 76bde7906d49..50cae32ae269 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2384,7 +2384,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 07dc4cf741f3..ce423d14ad26 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 d46146887ba4..2909da8363f3 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 19501dc99464..3f653721c45f 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 fc72f825fbd9..5dec1ed969ad 100644
--- a/net/sched/sch_hhf.c
+++ b/net/sched/sch_hhf.c
@@ -527,7 +527,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 },
@@ -546,7 +546,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;
@@ -624,6 +624,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/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
index ae991fc25b43..6ced7008ef5c 100644
--- a/net/sched/sch_mqprio.c
+++ b/net/sched/sch_mqprio.c
@@ -679,12 +679,14 @@ static int mqprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
rcu_read_lock();
if (cl >= TC_H_MIN_PRIORITY) {
struct net_device *dev = qdisc_dev(sch);
- struct netdev_tc_txq tc = dev->tc_to_txq[cl & TC_BITMASK];
+ struct netdev_tc_txq tc;
struct gnet_stats_queue qstats = {0};
struct gnet_stats_basic_sync bstats;
u32 qlen = 0;
int i;
+ tc.combined = READ_ONCE(dev->tc_to_txq[cl & TC_BITMASK].combined);
+
gnet_stats_basic_sync_init(&bstats);
for (i = tc.offset; i < tc.offset + tc.count; i++) {
diff --git a/net/sched/sch_mqprio_lib.c b/net/sched/sch_mqprio_lib.c
index b3a5572c167b..b60e130c7078 100644
--- a/net/sched/sch_mqprio_lib.c
+++ b/net/sched/sch_mqprio_lib.c
@@ -108,8 +108,11 @@ void mqprio_qopt_reconstruct(struct net_device *dev, struct tc_mqprio_qopt *qopt
memcpy(qopt->prio_tc_map, dev->prio_tc_map, sizeof(qopt->prio_tc_map));
for (tc = 0; tc < num_tc; tc++) {
- qopt->count[tc] = dev->tc_to_txq[tc].count;
- qopt->offset[tc] = dev->tc_to_txq[tc].offset;
+ struct netdev_tc_txq res;
+
+ res.combined = READ_ONCE(dev->tc_to_txq[tc].combined);
+ qopt->count[tc] = res.count;
+ qopt->offset[tc] = res.offset;
}
}
EXPORT_SYMBOL_GPL(mqprio_qopt_reconstruct);
diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c
index 299234a5f0fe..7d5fe93a4c12 100644
--- a/net/sched/sch_taprio.c
+++ b/net/sched/sch_taprio.c
@@ -762,12 +762,13 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq,
static void taprio_next_tc_txq(struct net_device *dev, int tc, int *txq)
{
- int offset = dev->tc_to_txq[tc].offset;
- int count = dev->tc_to_txq[tc].count;
+ struct netdev_tc_txq res;
+
+ res.combined = READ_ONCE(dev->tc_to_txq[tc].combined);
(*txq)++;
- if (*txq == offset + count)
- *txq = offset;
+ if (*txq == res.offset + res.count)
+ *txq = res.offset;
}
/* Prioritize higher traffic classes, and select among TXQs belonging to the
@@ -1441,15 +1442,14 @@ static u32 tc_map_to_queue_mask(struct net_device *dev, u32 tc_mask)
u32 i, queue_mask = 0;
for (i = 0; i < dev->num_tc; i++) {
- u32 offset, count;
+ struct netdev_tc_txq res;
if (!(tc_mask & BIT(i)))
continue;
- offset = dev->tc_to_txq[i].offset;
- count = dev->tc_to_txq[i].count;
+ res.combined = READ_ONCE(dev->tc_to_txq[i].combined);
- queue_mask |= GENMASK(offset + count - 1, offset);
+ queue_mask |= GENMASK(res.offset + res.count - 1, res.offset);
}
return queue_mask;
@@ -1802,10 +1802,14 @@ static int taprio_mqprio_cmp(const struct net_device *dev,
if (!mqprio || mqprio->num_tc != dev->num_tc)
return -1;
- for (i = 0; i < mqprio->num_tc; i++)
- if (dev->tc_to_txq[i].count != mqprio->count[i] ||
- dev->tc_to_txq[i].offset != mqprio->offset[i])
+ for (i = 0; i < mqprio->num_tc; i++) {
+ struct netdev_tc_txq res;
+
+ res.combined = READ_ONCE(dev->tc_to_txq[i].combined);
+ if (res.count != mqprio->count[i] ||
+ res.offset != mqprio->offset[i])
return -1;
+ }
for (i = 0; i <= TC_BITMASK; i++)
if (dev->prio_tc_map[i] != mqprio->prio_tc_map[i])
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index 9fcaaf55cba5..da774f56ca64 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -374,7 +374,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;
@@ -386,10 +386,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);
}
@@ -521,6 +517,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.
@@ -530,7 +527,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/core.c b/net/wireless/core.c
index d13310fef691..bc7e2c50cc72 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -153,68 +153,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)
@@ -244,9 +269,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);
}
@@ -1758,9 +1782,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);
}
@@ -1868,7 +1892,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 ac6ce9f967ec..81e595247b93 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;
};
@@ -280,8 +290,7 @@ struct cfg80211_event {
bool locally_generated;
} dc;
struct {
- u8 bssid[ETH_ALEN];
- struct ieee80211_channel *channel;
+ struct cfg80211_bss *bss;
} ij;
struct {
u8 peer_addr[ETH_ALEN];
@@ -344,8 +353,7 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool nowext);
-void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
- struct ieee80211_channel *channel);
+void __cfg80211_ibss_joined(struct net_device *dev, struct cfg80211_bss *bss);
int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev);
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index b1d748bdb504..7f6779d326b8 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -16,26 +16,18 @@
#include "rdev-ops.h"
-void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
- struct ieee80211_channel *channel)
+void __cfg80211_ibss_joined(struct net_device *dev, struct cfg80211_bss *bss)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
- struct cfg80211_bss *bss;
#ifdef CONFIG_CFG80211_WEXT
union iwreq_data wrqu;
#endif
if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
- return;
+ goto put_bss;
if (!wdev->u.ibss.ssid_len)
- return;
-
- bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
- IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY);
-
- if (WARN_ON(!bss))
- return;
+ goto put_bss;
if (wdev->u.ibss.current_bss) {
cfg80211_unhold_bss(wdev->u.ibss.current_bss);
@@ -43,17 +35,22 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
}
cfg80211_hold_bss(bss_from_pub(bss));
+ /* the reference from the event is transferred to current_bss */
wdev->u.ibss.current_bss = bss_from_pub(bss);
cfg80211_upload_connect_keys(wdev);
- nl80211_send_ibss_bssid(wiphy_to_rdev(wdev->wiphy), dev, bssid,
+ nl80211_send_ibss_bssid(wiphy_to_rdev(wdev->wiphy), dev, bss->bssid,
GFP_KERNEL);
#ifdef CONFIG_CFG80211_WEXT
memset(&wrqu, 0, sizeof(wrqu));
- memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
+ memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN);
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
#endif
+ return;
+
+put_bss:
+ cfg80211_put_bss(wdev->wiphy, bss);
}
void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
@@ -62,6 +59,7 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
struct cfg80211_event *ev;
+ struct cfg80211_bss *bss;
unsigned long flags;
trace_cfg80211_ibss_joined(dev, bssid, channel);
@@ -69,13 +67,19 @@ void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
if (WARN_ON(!channel))
return;
+ bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
+ IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY);
+ if (WARN_ON(!bss))
+ return;
+
ev = kzalloc_obj(*ev, gfp);
- if (!ev)
+ if (!ev) {
+ cfg80211_put_bss(wdev->wiphy, bss);
return;
+ }
ev->type = EVENT_IBSS_JOINED;
- memcpy(ev->ij.bssid, bssid, ETH_ALEN);
- ev->ij.channel = channel;
+ ev->ij.bss = bss;
spin_lock_irqsave(&wdev->event_lock, flags);
list_add_tail(&ev->list, &wdev->event_list);
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 63c26e8b1139..8f466e1ab1d7 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/reg.c b/net/wireless/reg.c
index 1e8214d6b6d8..3454afa038bf 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2345,7 +2345,7 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
iftype = wdev->iftype;
/* make sure the interface is active */
- if (!wdev->netdev || !netif_running(wdev->netdev))
+ if (!wdev_running(wdev))
return true;
/* NAN doesn't have links, handle it separately */
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 071083cc3367..4a1ec7e3547d 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -1114,6 +1114,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)
{
@@ -1173,10 +1188,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)
@@ -1199,6 +1214,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);
@@ -2022,6 +2049,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,
@@ -3443,11 +3477,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 24527bf321b2..12285bbd2973 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -988,12 +988,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;
@@ -1166,8 +1184,7 @@ void cfg80211_process_wdev_events(struct wireless_dev *wdev)
!ev->dc.locally_generated);
break;
case EVENT_IBSS_JOINED:
- __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid,
- ev->ij.channel);
+ __cfg80211_ibss_joined(wdev->netdev, ev->ij.bss);
break;
case EVENT_STOPPED:
/*
@@ -2426,16 +2443,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 674aedc5af5a..3e72b9f067b9 100644
--- a/net/xfrm/espintcp.c
+++ b/net/xfrm/espintcp.c
@@ -30,7 +30,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 eecab337bd0a..5ed87d51392a 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -474,6 +474,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
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;
@@ -485,6 +486,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)
@@ -592,11 +594,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);
@@ -604,6 +608,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;
}
@@ -728,7 +733,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
} while (!err);
rcu_read_lock();
- err = xfrm_rcv_cb(skb, family, x->type->proto, 0);
+ err = xfrm_rcv_cb(skb, family, xfrm_proto, 0);
if (err) {
rcu_read_unlock();
goto drop;
@@ -753,7 +758,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
xfrm_gro = xo->flags & XFRM_GRO;
err = -EAFNOSUPPORT;
- 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);
if (xfrm_gro) {
@@ -776,7 +781,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
drop:
if (async)
dev_put(dev);
- xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
+ xfrm_rcv_cb(skb, family, xfrm_proto, -1);
kfree_skb(skb);
return 0;
}
@@ -800,12 +805,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();
}
@@ -821,12 +831,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 597aedeac26e..6920940a35b4 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_policy.c b/net/xfrm/xfrm_policy.c
index 932a313b9460..513c9f228334 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2770,9 +2770,12 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
xdst0->path = dst;
err = -ENODEV;
- dev = dst->dev;
- if (!dev)
+ rcu_read_lock();
+ dev = dst_dev_rcu(dst);
+ if (!dev) {
+ rcu_read_unlock();
goto free_dst;
+ }
xfrm_init_path(xdst0, dst, nfheader_len);
xfrm_init_pmtu(bundle, nx);
@@ -2780,8 +2783,10 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
for (xdst_prev = xdst0; xdst_prev != (struct xfrm_dst *)dst;
xdst_prev = (struct xfrm_dst *) xfrm_dst_child(&xdst_prev->u.dst)) {
err = xfrm_fill_dst(xdst_prev, dev, fl);
- if (err)
+ if (err) {
+ rcu_read_unlock();
goto free_dst;
+ }
xdst_prev->u.dst.header_len = header_len;
xdst_prev->u.dst.trailer_len = trailer_len;
@@ -2789,6 +2794,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
trailer_len -= xdst_prev->u.dst.xfrm->props.trailer_len;
}
+ rcu_read_unlock();
return &xdst0->u.dst;
put_states:
@@ -3058,11 +3064,15 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
xfrm_init_path((struct xfrm_dst *)dst1, dst, 0);
err = -ENODEV;
- dev = dst->dev;
- if (!dev)
+ rcu_read_lock();
+ dev = dst_dev_rcu(dst);
+ if (!dev) {
+ rcu_read_unlock();
goto free_dst;
+ }
err = xfrm_fill_dst(xdst, dev, fl);
+ rcu_read_unlock();
if (err)
goto free_dst;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 36a4f6793ede..e45aa1ed5b96 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 6266a92cf302..a2587c7e796b 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -1877,7 +1877,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;
@@ -1943,17 +1942,6 @@ 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(xfrm_net_nlsk(net, skb), resp_skb, NETLINK_CB(skb).portid);
out:
@@ -3337,7 +3325,11 @@ static int xfrm_send_migrate_state(struct net *net,
return err;
}
- return xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MIGRATE);
+ rcu_read_lock();
+ err = xfrm_nlmsg_multicast(net, skb, 0, XFRMNLGRP_MIGRATE);
+ rcu_read_unlock();
+
+ return err;
}
static int xfrm_do_migrate_state(struct sk_buff *skb, struct nlmsghdr *nlh,
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 3ca99db5cccf..b5f1ada8e02e 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 3bf296581a88..7687b0dd5474 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 59cb77b237b3..e07092ea301a 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -19,6 +19,7 @@
#include <linux/parser.h>
#include <linux/string.h>
#include <linux/err.h>
+#include <linux/overflow.h>
#include <keys/user-type.h>
#include <keys/trusted-type.h>
#include <keys/encrypted-type.h>
@@ -579,6 +580,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;
@@ -632,16 +634,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 282e09d8fa46..ed6f55b9cdd9 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -9,6 +9,8 @@
#include <linux/sched.h>
#include <linux/err.h>
+#include <linux/pid.h>
+#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -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 6340823f8b53..e8c129396b8b 100644
--- a/security/keys/trusted-keys/trusted_tpm2.c
+++ b/security/keys/trusted-keys/trusted_tpm2.c
@@ -100,7 +100,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;
@@ -121,6 +121,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);
@@ -381,10 +382,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: */
@@ -396,17 +398,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/selinux/avc.c b/security/selinux/avc.c
index 813e82bcfc27..221c41978dc5 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -1150,8 +1150,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 18dd28b2bb13..5832131f29c4 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1672,26 +1672,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. */
@@ -3841,17 +3847,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.
@@ -3969,6 +4032,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)
@@ -4002,14 +4112,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;
@@ -4104,6 +4210,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;
@@ -4147,6 +4254,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)
@@ -4159,6 +4270,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;
@@ -7628,6 +7743,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 3c0a16ec978b..2f21568251ff 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 57733852624a..cd21c6f520e9 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -310,7 +310,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;
@@ -601,6 +601,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 afec5c5546ec..18dae022b324 100644
--- a/sound/hda/common/controller.c
+++ b/sound/hda/common/controller.c
@@ -586,11 +586,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 e8b6819cc4b4..9e3d5d3ed1d7 100644
--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -205,9 +205,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;
@@ -215,7 +225,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;
@@ -432,7 +442,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card)
if (!soc_aux)
return -ENOMEM;
- ret = asoc_sdw_parse_sdw_endpoints(card, soc_aux, soc_dais, soc_ends, &num_confs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, soc_aux, soc_dais, soc_ends, &num_confs);
if (ret < 0)
return ret;
diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c
index a423853f3a97..13885ca20168 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;
@@ -277,6 +286,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
int num_devs = 0;
int num_ends = 0;
int num_aux = 0;
+ int num_confs;
int num_links;
int be_id = 0;
int ret;
@@ -287,6 +297,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
return ret;
}
+ num_confs = num_ends;
/* One per DAI link, worst case is a DAI link for every endpoint */
struct asoc_sdw_dailink *sof_dais __free(kfree) =
kzalloc_objs(*sof_dais, num_ends);
@@ -303,7 +314,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
if (!sof_aux)
return -ENOMEM;
- ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_devs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs);
if (ret < 0)
return ret;
@@ -315,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;
@@ -326,7 +337,7 @@ 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;
diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c
index 371e99205b58..58b06e6878b9 100644
--- a/sound/soc/codecs/cs-amp-lib.c
+++ b/sound/soc/codecs/cs-amp-lib.c
@@ -314,6 +314,8 @@ static void *cs_amp_alloc_get_efi_variable(efi_char16_t *name,
unsigned long size = 0;
status = cs_amp_get_efi_variable(name, guid, NULL, &size, NULL);
+ if (status == EFI_SUCCESS)
+ return ERR_PTR(-ENOENT);
if (status != EFI_BUFFER_TOO_SMALL)
return ERR_PTR(cs_amp_convert_efi_status(status));
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 13ae9e83bc21..2db9cf8ec6e9 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 85779547653e..ccc5e54f5fd7 100644
--- a/sound/soc/codecs/rt712-sdca-dmic.c
+++ b/sound/soc/codecs/rt712-sdca-dmic.c
@@ -13,6 +13,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/sdw.h>
#include <sound/tlv.h>
#include "rt712-sdca.h"
#include "rt712-sdca-dmic.h"
@@ -632,10 +633,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);
@@ -647,13 +648,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 c527d575d1ed..1013e07052a3 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -1288,7 +1288,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card)
goto err_dai;
}
- ret = asoc_sdw_parse_sdw_endpoints(card, sof_aux, sof_dais, sof_ends, &num_confs);
+ ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs);
if (ret < 0)
goto err_end;
diff --git a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
index e0e32a279787..129a437ae397 100644
--- a/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
+++ b/sound/soc/sdw_utils/soc_sdw_bridge_cs35l56.c
@@ -99,11 +99,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 d8db8fc5313e..befcad08135e 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -1541,7 +1541,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;
}
@@ -1976,14 +1976,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;
@@ -2045,7 +2044,7 @@ int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
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;
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 0e49290a8c90..3137c091bdb8 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1206,7 +1206,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,
@@ -1228,9 +1230,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);
@@ -1264,7 +1272,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 d3b7cab85699..510d310824e9 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_obj(struct comm_runtime);
@@ -153,14 +165,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;
@@ -175,13 +191,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)
@@ -189,14 +207,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 6b0bb096f27a..279b449936e7 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;
@@ -148,8 +161,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;
@@ -160,15 +179,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");
@@ -182,6 +199,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)
@@ -189,14 +210,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 d2e274b731fe..0285d79ace0f 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 e34d92d576a2..8299ac241c60 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -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 a1d449f2a342..a0ec51cc56ac 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -492,9 +492,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;
+ ctx->packets = min_t(int, packet->packets,
+ ep->max_urb_packs);
memcpy(ctx->packet_size, packet->packet_size,
- packet->packets * sizeof(packet->packet_size[0]));
+ ctx->packets * sizeof(packet->packet_size[0]));
}
/* call the data handler to fill in playback data */
@@ -1239,15 +1240,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 647190f4d5af..6f35276416fe 100644
--- a/sound/virtio/virtio_card.c
+++ b/sound/virtio/virtio_card.c
@@ -354,8 +354,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];
@@ -383,8 +383,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/objtool/Makefile b/tools/objtool/Makefile
index a4484fd22a96..4cc2e756af84 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -89,9 +89,11 @@ LIBOPCODES_LIBS := $(shell \
"-lopcodes -lbfd" \
"-lopcodes -lbfd -liberty" \
"-lopcodes -lbfd -liberty -lz"; do \
- echo 'extern void disassemble_init_for_target(void *);' \
- 'int main(void) { disassemble_init_for_target(0); return 0; }' | \
- $(HOSTCC) -xc - -o /dev/null $$libs 2>/dev/null && \
+ printf '%s\n' \
+ '$(pound)include <bfd.h>' \
+ '$(pound)include <dis-asm.h>' \
+ 'int main(void) { disassemble_init_for_target(0); return 0; }' | \
+ $(HOSTCC) $(HOSTCFLAGS) -DPACKAGE='"objtool"' -xc - -o /dev/null $$libs 2>/dev/null && \
echo "$$libs" && break; \
done)
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/fs_test.c b/tools/testing/selftests/landlock/fs_test.c
index 86e08aa6e0a7..a9130ed70af5 100644
--- a/tools/testing/selftests/landlock/fs_test.c
+++ b/tools/testing/selftests/landlock/fs_test.c
@@ -2247,6 +2247,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[] = {
@@ -3270,6 +3434,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. */
@@ -7436,7 +7612,7 @@ TEST_F(audit_layout1, make_char)
enforce_fs(_metadata, ACCESS_ALL, NULL);
- 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));
@@ -7446,6 +7622,25 @@ 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));
+
+ enforce_fs(_metadata, ACCESS_ALL, NULL);
+
+ /* 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;
prev parent reply other threads:[~2026-09-25 14:46 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-25 14:46 Greg Kroah-Hartman
2026-09-25 14:46 ` Greg Kroah-Hartman [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2026092502-yippee-sedation-7579@gregkh \
--to=gregkh@linuxfoundation.org \
--cc=akpm@linux-foundation.org \
--cc=jslaby@suse.cz \
--cc=linux-kernel@vger.kernel.org \
--cc=lwn@lwn.net \
--cc=stable@vger.kernel.org \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®