mirror of
https://github.com/armbian/build.git
synced 2025-08-15 23:56:57 +02:00
6503 lines
201 KiB
Diff
6503 lines
201 KiB
Diff
diff --git a/Documentation/networking/strparser.rst b/Documentation/networking/strparser.rst
|
|
index 6cab1f74ae05a3..7f623d1db72aae 100644
|
|
--- a/Documentation/networking/strparser.rst
|
|
+++ b/Documentation/networking/strparser.rst
|
|
@@ -112,7 +112,7 @@ Functions
|
|
Callbacks
|
|
=========
|
|
|
|
-There are six callbacks:
|
|
+There are seven callbacks:
|
|
|
|
::
|
|
|
|
@@ -182,6 +182,13 @@ There are six callbacks:
|
|
the length of the message. skb->len - offset may be greater
|
|
then full_len since strparser does not trim the skb.
|
|
|
|
+ ::
|
|
+
|
|
+ int (*read_sock)(struct strparser *strp, read_descriptor_t *desc,
|
|
+ sk_read_actor_t recv_actor);
|
|
+
|
|
+ The read_sock callback is used by strparser instead of
|
|
+ sock->ops->read_sock, if provided.
|
|
::
|
|
|
|
int (*read_sock_done)(struct strparser *strp, int err);
|
|
diff --git a/Makefile b/Makefile
|
|
index de16ab06861410..67c5799f259e2e 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -1,7 +1,7 @@
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
VERSION = 6
|
|
PATCHLEVEL = 6
|
|
-SUBLEVEL = 79
|
|
+SUBLEVEL = 80
|
|
EXTRAVERSION =
|
|
NAME = Pinguïn Aangedreven
|
|
|
|
diff --git a/arch/arm64/boot/dts/mediatek/mt8183.dtsi b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
|
|
index d1b6355148620b..f3a1b96f1ee4db 100644
|
|
--- a/arch/arm64/boot/dts/mediatek/mt8183.dtsi
|
|
+++ b/arch/arm64/boot/dts/mediatek/mt8183.dtsi
|
|
@@ -1828,6 +1828,7 @@ dsi0: dsi@14014000 {
|
|
resets = <&mmsys MT8183_MMSYS_SW0_RST_B_DISP_DSI0>;
|
|
phys = <&mipi_tx0>;
|
|
phy-names = "dphy";
|
|
+ status = "disabled";
|
|
};
|
|
|
|
mutex: mutex@14016000 {
|
|
diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
|
|
index 2a49a29713752b..3b4d7882300897 100644
|
|
--- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
|
|
+++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
|
|
@@ -2135,6 +2135,7 @@ fastrpc {
|
|
compatible = "qcom,fastrpc";
|
|
qcom,glink-channels = "fastrpcglink-apps-dsp";
|
|
label = "sdsp";
|
|
+ qcom,non-secure-domain;
|
|
#address-cells = <1>;
|
|
#size-cells = <0>;
|
|
|
|
@@ -2160,6 +2161,112 @@ compute-cb@3 {
|
|
};
|
|
};
|
|
|
|
+ remoteproc_adsp: remoteproc@3000000 {
|
|
+ compatible = "qcom,sm8450-adsp-pas";
|
|
+ reg = <0x0 0x03000000 0x0 0x10000>;
|
|
+
|
|
+ interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>,
|
|
+ <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>,
|
|
+ <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>,
|
|
+ <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>,
|
|
+ <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>;
|
|
+ interrupt-names = "wdog", "fatal", "ready",
|
|
+ "handover", "stop-ack";
|
|
+
|
|
+ clocks = <&rpmhcc RPMH_CXO_CLK>;
|
|
+ clock-names = "xo";
|
|
+
|
|
+ power-domains = <&rpmhpd RPMHPD_LCX>,
|
|
+ <&rpmhpd RPMHPD_LMX>;
|
|
+ power-domain-names = "lcx", "lmx";
|
|
+
|
|
+ memory-region = <&adsp_mem>;
|
|
+
|
|
+ qcom,qmp = <&aoss_qmp>;
|
|
+
|
|
+ qcom,smem-states = <&smp2p_adsp_out 0>;
|
|
+ qcom,smem-state-names = "stop";
|
|
+
|
|
+ status = "disabled";
|
|
+
|
|
+ remoteproc_adsp_glink: glink-edge {
|
|
+ interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
|
|
+ IPCC_MPROC_SIGNAL_GLINK_QMP
|
|
+ IRQ_TYPE_EDGE_RISING>;
|
|
+ mboxes = <&ipcc IPCC_CLIENT_LPASS
|
|
+ IPCC_MPROC_SIGNAL_GLINK_QMP>;
|
|
+
|
|
+ label = "lpass";
|
|
+ qcom,remote-pid = <2>;
|
|
+
|
|
+ gpr {
|
|
+ compatible = "qcom,gpr";
|
|
+ qcom,glink-channels = "adsp_apps";
|
|
+ qcom,domain = <GPR_DOMAIN_ID_ADSP>;
|
|
+ qcom,intents = <512 20>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ q6apm: service@1 {
|
|
+ compatible = "qcom,q6apm";
|
|
+ reg = <GPR_APM_MODULE_IID>;
|
|
+ #sound-dai-cells = <0>;
|
|
+ qcom,protection-domain = "avs/audio",
|
|
+ "msm/adsp/audio_pd";
|
|
+
|
|
+ q6apmdai: dais {
|
|
+ compatible = "qcom,q6apm-dais";
|
|
+ iommus = <&apps_smmu 0x1801 0x0>;
|
|
+ };
|
|
+
|
|
+ q6apmbedai: bedais {
|
|
+ compatible = "qcom,q6apm-lpass-dais";
|
|
+ #sound-dai-cells = <1>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ q6prm: service@2 {
|
|
+ compatible = "qcom,q6prm";
|
|
+ reg = <GPR_PRM_MODULE_IID>;
|
|
+ qcom,protection-domain = "avs/audio",
|
|
+ "msm/adsp/audio_pd";
|
|
+
|
|
+ q6prmcc: clock-controller {
|
|
+ compatible = "qcom,q6prm-lpass-clocks";
|
|
+ #clock-cells = <2>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
+ fastrpc {
|
|
+ compatible = "qcom,fastrpc";
|
|
+ qcom,glink-channels = "fastrpcglink-apps-dsp";
|
|
+ label = "adsp";
|
|
+ qcom,non-secure-domain;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ compute-cb@3 {
|
|
+ compatible = "qcom,fastrpc-compute-cb";
|
|
+ reg = <3>;
|
|
+ iommus = <&apps_smmu 0x1803 0x0>;
|
|
+ };
|
|
+
|
|
+ compute-cb@4 {
|
|
+ compatible = "qcom,fastrpc-compute-cb";
|
|
+ reg = <4>;
|
|
+ iommus = <&apps_smmu 0x1804 0x0>;
|
|
+ };
|
|
+
|
|
+ compute-cb@5 {
|
|
+ compatible = "qcom,fastrpc-compute-cb";
|
|
+ reg = <5>;
|
|
+ iommus = <&apps_smmu 0x1805 0x0>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
wsa2macro: codec@31e0000 {
|
|
compatible = "qcom,sm8450-lpass-wsa-macro";
|
|
reg = <0 0x031e0000 0 0x1000>;
|
|
@@ -2368,111 +2475,6 @@ vamacro: codec@33f0000 {
|
|
status = "disabled";
|
|
};
|
|
|
|
- remoteproc_adsp: remoteproc@30000000 {
|
|
- compatible = "qcom,sm8450-adsp-pas";
|
|
- reg = <0 0x30000000 0 0x100>;
|
|
-
|
|
- interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>,
|
|
- <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>,
|
|
- <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>,
|
|
- <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>,
|
|
- <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>;
|
|
- interrupt-names = "wdog", "fatal", "ready",
|
|
- "handover", "stop-ack";
|
|
-
|
|
- clocks = <&rpmhcc RPMH_CXO_CLK>;
|
|
- clock-names = "xo";
|
|
-
|
|
- power-domains = <&rpmhpd RPMHPD_LCX>,
|
|
- <&rpmhpd RPMHPD_LMX>;
|
|
- power-domain-names = "lcx", "lmx";
|
|
-
|
|
- memory-region = <&adsp_mem>;
|
|
-
|
|
- qcom,qmp = <&aoss_qmp>;
|
|
-
|
|
- qcom,smem-states = <&smp2p_adsp_out 0>;
|
|
- qcom,smem-state-names = "stop";
|
|
-
|
|
- status = "disabled";
|
|
-
|
|
- remoteproc_adsp_glink: glink-edge {
|
|
- interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
|
|
- IPCC_MPROC_SIGNAL_GLINK_QMP
|
|
- IRQ_TYPE_EDGE_RISING>;
|
|
- mboxes = <&ipcc IPCC_CLIENT_LPASS
|
|
- IPCC_MPROC_SIGNAL_GLINK_QMP>;
|
|
-
|
|
- label = "lpass";
|
|
- qcom,remote-pid = <2>;
|
|
-
|
|
- gpr {
|
|
- compatible = "qcom,gpr";
|
|
- qcom,glink-channels = "adsp_apps";
|
|
- qcom,domain = <GPR_DOMAIN_ID_ADSP>;
|
|
- qcom,intents = <512 20>;
|
|
- #address-cells = <1>;
|
|
- #size-cells = <0>;
|
|
-
|
|
- q6apm: service@1 {
|
|
- compatible = "qcom,q6apm";
|
|
- reg = <GPR_APM_MODULE_IID>;
|
|
- #sound-dai-cells = <0>;
|
|
- qcom,protection-domain = "avs/audio",
|
|
- "msm/adsp/audio_pd";
|
|
-
|
|
- q6apmdai: dais {
|
|
- compatible = "qcom,q6apm-dais";
|
|
- iommus = <&apps_smmu 0x1801 0x0>;
|
|
- };
|
|
-
|
|
- q6apmbedai: bedais {
|
|
- compatible = "qcom,q6apm-lpass-dais";
|
|
- #sound-dai-cells = <1>;
|
|
- };
|
|
- };
|
|
-
|
|
- q6prm: service@2 {
|
|
- compatible = "qcom,q6prm";
|
|
- reg = <GPR_PRM_MODULE_IID>;
|
|
- qcom,protection-domain = "avs/audio",
|
|
- "msm/adsp/audio_pd";
|
|
-
|
|
- q6prmcc: clock-controller {
|
|
- compatible = "qcom,q6prm-lpass-clocks";
|
|
- #clock-cells = <2>;
|
|
- };
|
|
- };
|
|
- };
|
|
-
|
|
- fastrpc {
|
|
- compatible = "qcom,fastrpc";
|
|
- qcom,glink-channels = "fastrpcglink-apps-dsp";
|
|
- label = "adsp";
|
|
- #address-cells = <1>;
|
|
- #size-cells = <0>;
|
|
-
|
|
- compute-cb@3 {
|
|
- compatible = "qcom,fastrpc-compute-cb";
|
|
- reg = <3>;
|
|
- iommus = <&apps_smmu 0x1803 0x0>;
|
|
- };
|
|
-
|
|
- compute-cb@4 {
|
|
- compatible = "qcom,fastrpc-compute-cb";
|
|
- reg = <4>;
|
|
- iommus = <&apps_smmu 0x1804 0x0>;
|
|
- };
|
|
-
|
|
- compute-cb@5 {
|
|
- compatible = "qcom,fastrpc-compute-cb";
|
|
- reg = <5>;
|
|
- iommus = <&apps_smmu 0x1805 0x0>;
|
|
- };
|
|
- };
|
|
- };
|
|
- };
|
|
-
|
|
remoteproc_cdsp: remoteproc@32300000 {
|
|
compatible = "qcom,sm8450-cdsp-pas";
|
|
reg = <0 0x32300000 0 0x10000>;
|
|
@@ -2515,6 +2517,7 @@ fastrpc {
|
|
compatible = "qcom,fastrpc";
|
|
qcom,glink-channels = "fastrpcglink-apps-dsp";
|
|
label = "cdsp";
|
|
+ qcom,non-secure-domain;
|
|
#address-cells = <1>;
|
|
#size-cells = <0>;
|
|
|
|
diff --git a/arch/arm64/boot/dts/qcom/sm8550.dtsi b/arch/arm64/boot/dts/qcom/sm8550.dtsi
|
|
index f3a0e1fe333c4d..bc9a1fca2db3ae 100644
|
|
--- a/arch/arm64/boot/dts/qcom/sm8550.dtsi
|
|
+++ b/arch/arm64/boot/dts/qcom/sm8550.dtsi
|
|
@@ -2026,6 +2026,137 @@ IPCC_MPROC_SIGNAL_GLINK_QMP
|
|
};
|
|
};
|
|
|
|
+ remoteproc_adsp: remoteproc@6800000 {
|
|
+ compatible = "qcom,sm8550-adsp-pas";
|
|
+ reg = <0x0 0x06800000 0x0 0x10000>;
|
|
+
|
|
+ interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>,
|
|
+ <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>,
|
|
+ <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>,
|
|
+ <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>,
|
|
+ <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>;
|
|
+ interrupt-names = "wdog", "fatal", "ready",
|
|
+ "handover", "stop-ack";
|
|
+
|
|
+ clocks = <&rpmhcc RPMH_CXO_CLK>;
|
|
+ clock-names = "xo";
|
|
+
|
|
+ power-domains = <&rpmhpd RPMHPD_LCX>,
|
|
+ <&rpmhpd RPMHPD_LMX>;
|
|
+ power-domain-names = "lcx", "lmx";
|
|
+
|
|
+ interconnects = <&lpass_lpicx_noc MASTER_LPASS_PROC 0 &mc_virt SLAVE_EBI1 0>;
|
|
+
|
|
+ memory-region = <&adspslpi_mem>, <&q6_adsp_dtb_mem>;
|
|
+
|
|
+ qcom,qmp = <&aoss_qmp>;
|
|
+
|
|
+ qcom,smem-states = <&smp2p_adsp_out 0>;
|
|
+ qcom,smem-state-names = "stop";
|
|
+
|
|
+ status = "disabled";
|
|
+
|
|
+ remoteproc_adsp_glink: glink-edge {
|
|
+ interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
|
|
+ IPCC_MPROC_SIGNAL_GLINK_QMP
|
|
+ IRQ_TYPE_EDGE_RISING>;
|
|
+ mboxes = <&ipcc IPCC_CLIENT_LPASS
|
|
+ IPCC_MPROC_SIGNAL_GLINK_QMP>;
|
|
+
|
|
+ label = "lpass";
|
|
+ qcom,remote-pid = <2>;
|
|
+
|
|
+ fastrpc {
|
|
+ compatible = "qcom,fastrpc";
|
|
+ qcom,glink-channels = "fastrpcglink-apps-dsp";
|
|
+ label = "adsp";
|
|
+ qcom,non-secure-domain;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ compute-cb@3 {
|
|
+ compatible = "qcom,fastrpc-compute-cb";
|
|
+ reg = <3>;
|
|
+ iommus = <&apps_smmu 0x1003 0x80>,
|
|
+ <&apps_smmu 0x1063 0x0>;
|
|
+ dma-coherent;
|
|
+ };
|
|
+
|
|
+ compute-cb@4 {
|
|
+ compatible = "qcom,fastrpc-compute-cb";
|
|
+ reg = <4>;
|
|
+ iommus = <&apps_smmu 0x1004 0x80>,
|
|
+ <&apps_smmu 0x1064 0x0>;
|
|
+ dma-coherent;
|
|
+ };
|
|
+
|
|
+ compute-cb@5 {
|
|
+ compatible = "qcom,fastrpc-compute-cb";
|
|
+ reg = <5>;
|
|
+ iommus = <&apps_smmu 0x1005 0x80>,
|
|
+ <&apps_smmu 0x1065 0x0>;
|
|
+ dma-coherent;
|
|
+ };
|
|
+
|
|
+ compute-cb@6 {
|
|
+ compatible = "qcom,fastrpc-compute-cb";
|
|
+ reg = <6>;
|
|
+ iommus = <&apps_smmu 0x1006 0x80>,
|
|
+ <&apps_smmu 0x1066 0x0>;
|
|
+ dma-coherent;
|
|
+ };
|
|
+
|
|
+ compute-cb@7 {
|
|
+ compatible = "qcom,fastrpc-compute-cb";
|
|
+ reg = <7>;
|
|
+ iommus = <&apps_smmu 0x1007 0x80>,
|
|
+ <&apps_smmu 0x1067 0x0>;
|
|
+ dma-coherent;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ gpr {
|
|
+ compatible = "qcom,gpr";
|
|
+ qcom,glink-channels = "adsp_apps";
|
|
+ qcom,domain = <GPR_DOMAIN_ID_ADSP>;
|
|
+ qcom,intents = <512 20>;
|
|
+ #address-cells = <1>;
|
|
+ #size-cells = <0>;
|
|
+
|
|
+ q6apm: service@1 {
|
|
+ compatible = "qcom,q6apm";
|
|
+ reg = <GPR_APM_MODULE_IID>;
|
|
+ #sound-dai-cells = <0>;
|
|
+ qcom,protection-domain = "avs/audio",
|
|
+ "msm/adsp/audio_pd";
|
|
+
|
|
+ q6apmdai: dais {
|
|
+ compatible = "qcom,q6apm-dais";
|
|
+ iommus = <&apps_smmu 0x1001 0x80>,
|
|
+ <&apps_smmu 0x1061 0x0>;
|
|
+ };
|
|
+
|
|
+ q6apmbedai: bedais {
|
|
+ compatible = "qcom,q6apm-lpass-dais";
|
|
+ #sound-dai-cells = <1>;
|
|
+ };
|
|
+ };
|
|
+
|
|
+ q6prm: service@2 {
|
|
+ compatible = "qcom,q6prm";
|
|
+ reg = <GPR_PRM_MODULE_IID>;
|
|
+ qcom,protection-domain = "avs/audio",
|
|
+ "msm/adsp/audio_pd";
|
|
+
|
|
+ q6prmcc: clock-controller {
|
|
+ compatible = "qcom,q6prm-lpass-clocks";
|
|
+ #clock-cells = <2>;
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+ };
|
|
+
|
|
lpass_wsa2macro: codec@6aa0000 {
|
|
compatible = "qcom,sm8550-lpass-wsa-macro";
|
|
reg = <0 0x06aa0000 0 0x1000>;
|
|
@@ -3954,131 +4085,6 @@ system-cache-controller@25000000 {
|
|
interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
|
|
};
|
|
|
|
- remoteproc_adsp: remoteproc@30000000 {
|
|
- compatible = "qcom,sm8550-adsp-pas";
|
|
- reg = <0x0 0x30000000 0x0 0x100>;
|
|
-
|
|
- interrupts-extended = <&pdc 6 IRQ_TYPE_EDGE_RISING>,
|
|
- <&smp2p_adsp_in 0 IRQ_TYPE_EDGE_RISING>,
|
|
- <&smp2p_adsp_in 1 IRQ_TYPE_EDGE_RISING>,
|
|
- <&smp2p_adsp_in 2 IRQ_TYPE_EDGE_RISING>,
|
|
- <&smp2p_adsp_in 3 IRQ_TYPE_EDGE_RISING>;
|
|
- interrupt-names = "wdog", "fatal", "ready",
|
|
- "handover", "stop-ack";
|
|
-
|
|
- clocks = <&rpmhcc RPMH_CXO_CLK>;
|
|
- clock-names = "xo";
|
|
-
|
|
- power-domains = <&rpmhpd RPMHPD_LCX>,
|
|
- <&rpmhpd RPMHPD_LMX>;
|
|
- power-domain-names = "lcx", "lmx";
|
|
-
|
|
- interconnects = <&lpass_lpicx_noc MASTER_LPASS_PROC 0 &mc_virt SLAVE_EBI1 0>;
|
|
-
|
|
- memory-region = <&adspslpi_mem>, <&q6_adsp_dtb_mem>;
|
|
-
|
|
- qcom,qmp = <&aoss_qmp>;
|
|
-
|
|
- qcom,smem-states = <&smp2p_adsp_out 0>;
|
|
- qcom,smem-state-names = "stop";
|
|
-
|
|
- status = "disabled";
|
|
-
|
|
- remoteproc_adsp_glink: glink-edge {
|
|
- interrupts-extended = <&ipcc IPCC_CLIENT_LPASS
|
|
- IPCC_MPROC_SIGNAL_GLINK_QMP
|
|
- IRQ_TYPE_EDGE_RISING>;
|
|
- mboxes = <&ipcc IPCC_CLIENT_LPASS
|
|
- IPCC_MPROC_SIGNAL_GLINK_QMP>;
|
|
-
|
|
- label = "lpass";
|
|
- qcom,remote-pid = <2>;
|
|
-
|
|
- fastrpc {
|
|
- compatible = "qcom,fastrpc";
|
|
- qcom,glink-channels = "fastrpcglink-apps-dsp";
|
|
- label = "adsp";
|
|
- #address-cells = <1>;
|
|
- #size-cells = <0>;
|
|
-
|
|
- compute-cb@3 {
|
|
- compatible = "qcom,fastrpc-compute-cb";
|
|
- reg = <3>;
|
|
- iommus = <&apps_smmu 0x1003 0x80>,
|
|
- <&apps_smmu 0x1063 0x0>;
|
|
- };
|
|
-
|
|
- compute-cb@4 {
|
|
- compatible = "qcom,fastrpc-compute-cb";
|
|
- reg = <4>;
|
|
- iommus = <&apps_smmu 0x1004 0x80>,
|
|
- <&apps_smmu 0x1064 0x0>;
|
|
- };
|
|
-
|
|
- compute-cb@5 {
|
|
- compatible = "qcom,fastrpc-compute-cb";
|
|
- reg = <5>;
|
|
- iommus = <&apps_smmu 0x1005 0x80>,
|
|
- <&apps_smmu 0x1065 0x0>;
|
|
- };
|
|
-
|
|
- compute-cb@6 {
|
|
- compatible = "qcom,fastrpc-compute-cb";
|
|
- reg = <6>;
|
|
- iommus = <&apps_smmu 0x1006 0x80>,
|
|
- <&apps_smmu 0x1066 0x0>;
|
|
- };
|
|
-
|
|
- compute-cb@7 {
|
|
- compatible = "qcom,fastrpc-compute-cb";
|
|
- reg = <7>;
|
|
- iommus = <&apps_smmu 0x1007 0x80>,
|
|
- <&apps_smmu 0x1067 0x0>;
|
|
- };
|
|
- };
|
|
-
|
|
- gpr {
|
|
- compatible = "qcom,gpr";
|
|
- qcom,glink-channels = "adsp_apps";
|
|
- qcom,domain = <GPR_DOMAIN_ID_ADSP>;
|
|
- qcom,intents = <512 20>;
|
|
- #address-cells = <1>;
|
|
- #size-cells = <0>;
|
|
-
|
|
- q6apm: service@1 {
|
|
- compatible = "qcom,q6apm";
|
|
- reg = <GPR_APM_MODULE_IID>;
|
|
- #sound-dai-cells = <0>;
|
|
- qcom,protection-domain = "avs/audio",
|
|
- "msm/adsp/audio_pd";
|
|
-
|
|
- q6apmdai: dais {
|
|
- compatible = "qcom,q6apm-dais";
|
|
- iommus = <&apps_smmu 0x1001 0x80>,
|
|
- <&apps_smmu 0x1061 0x0>;
|
|
- };
|
|
-
|
|
- q6apmbedai: bedais {
|
|
- compatible = "qcom,q6apm-lpass-dais";
|
|
- #sound-dai-cells = <1>;
|
|
- };
|
|
- };
|
|
-
|
|
- q6prm: service@2 {
|
|
- compatible = "qcom,q6prm";
|
|
- reg = <GPR_PRM_MODULE_IID>;
|
|
- qcom,protection-domain = "avs/audio",
|
|
- "msm/adsp/audio_pd";
|
|
-
|
|
- q6prmcc: clock-controller {
|
|
- compatible = "qcom,q6prm-lpass-clocks";
|
|
- #clock-cells = <2>;
|
|
- };
|
|
- };
|
|
- };
|
|
- };
|
|
- };
|
|
-
|
|
nsp_noc: interconnect@320c0000 {
|
|
compatible = "qcom,sm8550-nsp-noc";
|
|
reg = <0 0x320c0000 0 0xe080>;
|
|
@@ -4131,6 +4137,7 @@ fastrpc {
|
|
compatible = "qcom,fastrpc";
|
|
qcom,glink-channels = "fastrpcglink-apps-dsp";
|
|
label = "cdsp";
|
|
+ qcom,non-secure-domain;
|
|
#address-cells = <1>;
|
|
#size-cells = <0>;
|
|
|
|
@@ -4140,6 +4147,7 @@ compute-cb@1 {
|
|
iommus = <&apps_smmu 0x1961 0x0>,
|
|
<&apps_smmu 0x0c01 0x20>,
|
|
<&apps_smmu 0x19c1 0x10>;
|
|
+ dma-coherent;
|
|
};
|
|
|
|
compute-cb@2 {
|
|
@@ -4148,6 +4156,7 @@ compute-cb@2 {
|
|
iommus = <&apps_smmu 0x1962 0x0>,
|
|
<&apps_smmu 0x0c02 0x20>,
|
|
<&apps_smmu 0x19c2 0x10>;
|
|
+ dma-coherent;
|
|
};
|
|
|
|
compute-cb@3 {
|
|
@@ -4156,6 +4165,7 @@ compute-cb@3 {
|
|
iommus = <&apps_smmu 0x1963 0x0>,
|
|
<&apps_smmu 0x0c03 0x20>,
|
|
<&apps_smmu 0x19c3 0x10>;
|
|
+ dma-coherent;
|
|
};
|
|
|
|
compute-cb@4 {
|
|
@@ -4164,6 +4174,7 @@ compute-cb@4 {
|
|
iommus = <&apps_smmu 0x1964 0x0>,
|
|
<&apps_smmu 0x0c04 0x20>,
|
|
<&apps_smmu 0x19c4 0x10>;
|
|
+ dma-coherent;
|
|
};
|
|
|
|
compute-cb@5 {
|
|
@@ -4172,6 +4183,7 @@ compute-cb@5 {
|
|
iommus = <&apps_smmu 0x1965 0x0>,
|
|
<&apps_smmu 0x0c05 0x20>,
|
|
<&apps_smmu 0x19c5 0x10>;
|
|
+ dma-coherent;
|
|
};
|
|
|
|
compute-cb@6 {
|
|
@@ -4180,6 +4192,7 @@ compute-cb@6 {
|
|
iommus = <&apps_smmu 0x1966 0x0>,
|
|
<&apps_smmu 0x0c06 0x20>,
|
|
<&apps_smmu 0x19c6 0x10>;
|
|
+ dma-coherent;
|
|
};
|
|
|
|
compute-cb@7 {
|
|
@@ -4188,6 +4201,7 @@ compute-cb@7 {
|
|
iommus = <&apps_smmu 0x1967 0x0>,
|
|
<&apps_smmu 0x0c07 0x20>,
|
|
<&apps_smmu 0x19c7 0x10>;
|
|
+ dma-coherent;
|
|
};
|
|
|
|
compute-cb@8 {
|
|
@@ -4196,6 +4210,7 @@ compute-cb@8 {
|
|
iommus = <&apps_smmu 0x1968 0x0>,
|
|
<&apps_smmu 0x0c08 0x20>,
|
|
<&apps_smmu 0x19c8 0x10>;
|
|
+ dma-coherent;
|
|
};
|
|
|
|
/* note: secure cb9 in downstream */
|
|
diff --git a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts
|
|
index 4237f2ee8fee33..f57d4acd9807cb 100644
|
|
--- a/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts
|
|
+++ b/arch/arm64/boot/dts/rockchip/rk3328-orangepi-r1-plus-lts.dts
|
|
@@ -15,9 +15,11 @@ / {
|
|
};
|
|
|
|
&gmac2io {
|
|
+ /delete-property/ tx_delay;
|
|
+ /delete-property/ rx_delay;
|
|
+
|
|
phy-handle = <&yt8531c>;
|
|
- tx_delay = <0x19>;
|
|
- rx_delay = <0x05>;
|
|
+ phy-mode = "rgmii-id";
|
|
|
|
mdio {
|
|
/delete-node/ ethernet-phy@1;
|
|
diff --git a/arch/arm64/include/asm/mman.h b/arch/arm64/include/asm/mman.h
|
|
index ef35c52aabd66d..101771c60d80d2 100644
|
|
--- a/arch/arm64/include/asm/mman.h
|
|
+++ b/arch/arm64/include/asm/mman.h
|
|
@@ -31,9 +31,12 @@ static inline unsigned long arch_calc_vm_flag_bits(struct file *file,
|
|
* backed by tags-capable memory. The vm_flags may be overridden by a
|
|
* filesystem supporting MTE (RAM-based).
|
|
*/
|
|
- if (system_supports_mte() &&
|
|
- ((flags & MAP_ANONYMOUS) || shmem_file(file)))
|
|
- return VM_MTE_ALLOWED;
|
|
+ if (system_supports_mte()) {
|
|
+ if ((flags & MAP_ANONYMOUS) && !(flags & MAP_HUGETLB))
|
|
+ return VM_MTE_ALLOWED;
|
|
+ if (shmem_file(file))
|
|
+ return VM_MTE_ALLOWED;
|
|
+ }
|
|
|
|
return 0;
|
|
}
|
|
diff --git a/arch/powerpc/include/asm/book3s/64/hash-4k.h b/arch/powerpc/include/asm/book3s/64/hash-4k.h
|
|
index 6472b08fa1b0cd..2a2649e0f91dff 100644
|
|
--- a/arch/powerpc/include/asm/book3s/64/hash-4k.h
|
|
+++ b/arch/powerpc/include/asm/book3s/64/hash-4k.h
|
|
@@ -89,6 +89,34 @@ static inline int hash__hugepd_ok(hugepd_t hpd)
|
|
}
|
|
#endif
|
|
|
|
+/*
|
|
+ * With 4K page size the real_pte machinery is all nops.
|
|
+ */
|
|
+static inline real_pte_t __real_pte(pte_t pte, pte_t *ptep, int offset)
|
|
+{
|
|
+ return (real_pte_t){pte};
|
|
+}
|
|
+
|
|
+#define __rpte_to_pte(r) ((r).pte)
|
|
+
|
|
+static inline unsigned long __rpte_to_hidx(real_pte_t rpte, unsigned long index)
|
|
+{
|
|
+ return pte_val(__rpte_to_pte(rpte)) >> H_PAGE_F_GIX_SHIFT;
|
|
+}
|
|
+
|
|
+#define pte_iterate_hashed_subpages(rpte, psize, va, index, shift) \
|
|
+ do { \
|
|
+ index = 0; \
|
|
+ shift = mmu_psize_defs[psize].shift; \
|
|
+
|
|
+#define pte_iterate_hashed_end() } while(0)
|
|
+
|
|
+/*
|
|
+ * We expect this to be called only for user addresses or kernel virtual
|
|
+ * addresses other than the linear mapping.
|
|
+ */
|
|
+#define pte_pagesize_index(mm, addr, pte) MMU_PAGE_4K
|
|
+
|
|
/*
|
|
* 4K PTE format is different from 64K PTE format. Saving the hash_slot is just
|
|
* a matter of returning the PTE bits that need to be modified. On 64K PTE,
|
|
diff --git a/arch/powerpc/include/asm/book3s/64/pgtable.h b/arch/powerpc/include/asm/book3s/64/pgtable.h
|
|
index 5c497c862d757e..8a6e6b6daa9065 100644
|
|
--- a/arch/powerpc/include/asm/book3s/64/pgtable.h
|
|
+++ b/arch/powerpc/include/asm/book3s/64/pgtable.h
|
|
@@ -319,32 +319,6 @@ extern unsigned long pci_io_base;
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
-/*
|
|
- * This is the default implementation of various PTE accessors, it's
|
|
- * used in all cases except Book3S with 64K pages where we have a
|
|
- * concept of sub-pages
|
|
- */
|
|
-#ifndef __real_pte
|
|
-
|
|
-#define __real_pte(e, p, o) ((real_pte_t){(e)})
|
|
-#define __rpte_to_pte(r) ((r).pte)
|
|
-#define __rpte_to_hidx(r,index) (pte_val(__rpte_to_pte(r)) >> H_PAGE_F_GIX_SHIFT)
|
|
-
|
|
-#define pte_iterate_hashed_subpages(rpte, psize, va, index, shift) \
|
|
- do { \
|
|
- index = 0; \
|
|
- shift = mmu_psize_defs[psize].shift; \
|
|
-
|
|
-#define pte_iterate_hashed_end() } while(0)
|
|
-
|
|
-/*
|
|
- * We expect this to be called only for user addresses or kernel virtual
|
|
- * addresses other than the linear mapping.
|
|
- */
|
|
-#define pte_pagesize_index(mm, addr, pte) MMU_PAGE_4K
|
|
-
|
|
-#endif /* __real_pte */
|
|
-
|
|
static inline unsigned long pte_update(struct mm_struct *mm, unsigned long addr,
|
|
pte_t *ptep, unsigned long clr,
|
|
unsigned long set, int huge)
|
|
diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c
|
|
index b00112d7ad467d..4426a77c8f063b 100644
|
|
--- a/arch/powerpc/lib/code-patching.c
|
|
+++ b/arch/powerpc/lib/code-patching.c
|
|
@@ -105,7 +105,7 @@ static int text_area_cpu_up(unsigned int cpu)
|
|
unsigned long addr;
|
|
int err;
|
|
|
|
- area = get_vm_area(PAGE_SIZE, VM_ALLOC);
|
|
+ area = get_vm_area(PAGE_SIZE, 0);
|
|
if (!area) {
|
|
WARN_ONCE(1, "Failed to create text area for cpu %d\n",
|
|
cpu);
|
|
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
|
|
index 05c82fd5d0f60b..989d432b58345d 100644
|
|
--- a/arch/x86/Kconfig
|
|
+++ b/arch/x86/Kconfig
|
|
@@ -2514,7 +2514,8 @@ config CPU_IBPB_ENTRY
|
|
depends on CPU_SUP_AMD && X86_64
|
|
default y
|
|
help
|
|
- Compile the kernel with support for the retbleed=ibpb mitigation.
|
|
+ Compile the kernel with support for the retbleed=ibpb and
|
|
+ spec_rstack_overflow={ibpb,ibpb-vmexit} mitigations.
|
|
|
|
config CPU_IBRS_ENTRY
|
|
bool "Enable IBRS on kernel entry"
|
|
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
|
|
index df286789c94f18..61ac094e26bd78 100644
|
|
--- a/arch/x86/events/intel/core.c
|
|
+++ b/arch/x86/events/intel/core.c
|
|
@@ -4643,16 +4643,19 @@ static void intel_pmu_check_num_counters(int *num_counters,
|
|
|
|
static void update_pmu_cap(struct x86_hybrid_pmu *pmu)
|
|
{
|
|
- unsigned int sub_bitmaps = cpuid_eax(ARCH_PERFMON_EXT_LEAF);
|
|
- unsigned int eax, ebx, ecx, edx;
|
|
+ unsigned int cntr, fixed_cntr, ecx, edx;
|
|
+ union cpuid35_eax eax;
|
|
+ union cpuid35_ebx ebx;
|
|
|
|
- if (sub_bitmaps & ARCH_PERFMON_NUM_COUNTER_LEAF_BIT) {
|
|
+ cpuid(ARCH_PERFMON_EXT_LEAF, &eax.full, &ebx.full, &ecx, &edx);
|
|
+
|
|
+ if (eax.split.cntr_subleaf) {
|
|
cpuid_count(ARCH_PERFMON_EXT_LEAF, ARCH_PERFMON_NUM_COUNTER_LEAF,
|
|
- &eax, &ebx, &ecx, &edx);
|
|
- pmu->num_counters = fls(eax);
|
|
- pmu->num_counters_fixed = fls(ebx);
|
|
+ &cntr, &fixed_cntr, &ecx, &edx);
|
|
+ pmu->num_counters = fls(cntr);
|
|
+ pmu->num_counters_fixed = fls(fixed_cntr);
|
|
intel_pmu_check_num_counters(&pmu->num_counters, &pmu->num_counters_fixed,
|
|
- &pmu->intel_ctrl, ebx);
|
|
+ &pmu->intel_ctrl, fixed_cntr);
|
|
}
|
|
}
|
|
|
|
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
|
|
index 85a9fd5a3ec331..384e8a7db4827b 100644
|
|
--- a/arch/x86/include/asm/perf_event.h
|
|
+++ b/arch/x86/include/asm/perf_event.h
|
|
@@ -177,9 +177,33 @@ union cpuid10_edx {
|
|
* detection/enumeration details:
|
|
*/
|
|
#define ARCH_PERFMON_EXT_LEAF 0x00000023
|
|
-#define ARCH_PERFMON_NUM_COUNTER_LEAF_BIT 0x1
|
|
#define ARCH_PERFMON_NUM_COUNTER_LEAF 0x1
|
|
|
|
+union cpuid35_eax {
|
|
+ struct {
|
|
+ unsigned int leaf0:1;
|
|
+ /* Counters Sub-Leaf */
|
|
+ unsigned int cntr_subleaf:1;
|
|
+ /* Auto Counter Reload Sub-Leaf */
|
|
+ unsigned int acr_subleaf:1;
|
|
+ /* Events Sub-Leaf */
|
|
+ unsigned int events_subleaf:1;
|
|
+ unsigned int reserved:28;
|
|
+ } split;
|
|
+ unsigned int full;
|
|
+};
|
|
+
|
|
+union cpuid35_ebx {
|
|
+ struct {
|
|
+ /* UnitMask2 Supported */
|
|
+ unsigned int umask2:1;
|
|
+ /* EQ-bit Supported */
|
|
+ unsigned int eq:1;
|
|
+ unsigned int reserved:30;
|
|
+ } split;
|
|
+ unsigned int full;
|
|
+};
|
|
+
|
|
/*
|
|
* Intel Architectural LBR CPUID detection/enumeration details:
|
|
*/
|
|
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
|
|
index 7b5ba5b8592a25..7df458a6553eb2 100644
|
|
--- a/arch/x86/kernel/cpu/bugs.c
|
|
+++ b/arch/x86/kernel/cpu/bugs.c
|
|
@@ -1113,6 +1113,8 @@ static void __init retbleed_select_mitigation(void)
|
|
|
|
case RETBLEED_MITIGATION_IBPB:
|
|
setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB);
|
|
+ setup_force_cpu_cap(X86_FEATURE_IBPB_ON_VMEXIT);
|
|
+ mitigate_smt = true;
|
|
|
|
/*
|
|
* IBPB on entry already obviates the need for
|
|
@@ -1122,9 +1124,6 @@ static void __init retbleed_select_mitigation(void)
|
|
setup_clear_cpu_cap(X86_FEATURE_UNRET);
|
|
setup_clear_cpu_cap(X86_FEATURE_RETHUNK);
|
|
|
|
- setup_force_cpu_cap(X86_FEATURE_IBPB_ON_VMEXIT);
|
|
- mitigate_smt = true;
|
|
-
|
|
/*
|
|
* There is no need for RSB filling: entry_ibpb() ensures
|
|
* all predictions, including the RSB, are invalidated,
|
|
@@ -2626,6 +2625,7 @@ static void __init srso_select_mitigation(void)
|
|
if (IS_ENABLED(CONFIG_CPU_IBPB_ENTRY)) {
|
|
if (has_microcode) {
|
|
setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB);
|
|
+ setup_force_cpu_cap(X86_FEATURE_IBPB_ON_VMEXIT);
|
|
srso_mitigation = SRSO_MITIGATION_IBPB;
|
|
|
|
/*
|
|
@@ -2635,6 +2635,13 @@ static void __init srso_select_mitigation(void)
|
|
*/
|
|
setup_clear_cpu_cap(X86_FEATURE_UNRET);
|
|
setup_clear_cpu_cap(X86_FEATURE_RETHUNK);
|
|
+
|
|
+ /*
|
|
+ * There is no need for RSB filling: entry_ibpb() ensures
|
|
+ * all predictions, including the RSB, are invalidated,
|
|
+ * regardless of IBPB implementation.
|
|
+ */
|
|
+ setup_clear_cpu_cap(X86_FEATURE_RSB_VMEXIT);
|
|
}
|
|
} else {
|
|
pr_err("WARNING: kernel not compiled with CPU_IBPB_ENTRY.\n");
|
|
@@ -2643,8 +2650,8 @@ static void __init srso_select_mitigation(void)
|
|
break;
|
|
|
|
case SRSO_CMD_IBPB_ON_VMEXIT:
|
|
- if (IS_ENABLED(CONFIG_CPU_SRSO)) {
|
|
- if (!boot_cpu_has(X86_FEATURE_ENTRY_IBPB) && has_microcode) {
|
|
+ if (IS_ENABLED(CONFIG_CPU_IBPB_ENTRY)) {
|
|
+ if (has_microcode) {
|
|
setup_force_cpu_cap(X86_FEATURE_IBPB_ON_VMEXIT);
|
|
srso_mitigation = SRSO_MITIGATION_IBPB_ON_VMEXIT;
|
|
|
|
@@ -2656,9 +2663,9 @@ static void __init srso_select_mitigation(void)
|
|
setup_clear_cpu_cap(X86_FEATURE_RSB_VMEXIT);
|
|
}
|
|
} else {
|
|
- pr_err("WARNING: kernel not compiled with CPU_SRSO.\n");
|
|
+ pr_err("WARNING: kernel not compiled with CPU_IBPB_ENTRY.\n");
|
|
goto pred_cmd;
|
|
- }
|
|
+ }
|
|
break;
|
|
|
|
default:
|
|
diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c
|
|
index 35fb26cbf22941..892e2540f008ae 100644
|
|
--- a/drivers/bluetooth/btqca.c
|
|
+++ b/drivers/bluetooth/btqca.c
|
|
@@ -289,6 +289,39 @@ int qca_send_pre_shutdown_cmd(struct hci_dev *hdev)
|
|
}
|
|
EXPORT_SYMBOL_GPL(qca_send_pre_shutdown_cmd);
|
|
|
|
+static bool qca_filename_has_extension(const char *filename)
|
|
+{
|
|
+ const char *suffix = strrchr(filename, '.');
|
|
+
|
|
+ /* File extensions require a dot, but not as the first or last character */
|
|
+ if (!suffix || suffix == filename || *(suffix + 1) == '\0')
|
|
+ return 0;
|
|
+
|
|
+ /* Avoid matching directories with names that look like files with extensions */
|
|
+ return !strchr(suffix, '/');
|
|
+}
|
|
+
|
|
+static bool qca_get_alt_nvm_file(char *filename, size_t max_size)
|
|
+{
|
|
+ char fwname[64];
|
|
+ const char *suffix;
|
|
+
|
|
+ /* nvm file name has an extension, replace with .bin */
|
|
+ if (qca_filename_has_extension(filename)) {
|
|
+ suffix = strrchr(filename, '.');
|
|
+ strscpy(fwname, filename, suffix - filename + 1);
|
|
+ snprintf(fwname + (suffix - filename),
|
|
+ sizeof(fwname) - (suffix - filename), ".bin");
|
|
+ /* If nvm file is already the default one, return false to skip the retry. */
|
|
+ if (strcmp(fwname, filename) == 0)
|
|
+ return false;
|
|
+
|
|
+ snprintf(filename, max_size, "%s", fwname);
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
static int qca_tlv_check_data(struct hci_dev *hdev,
|
|
struct qca_fw_config *config,
|
|
u8 *fw_data, size_t fw_size,
|
|
@@ -586,6 +619,19 @@ static int qca_download_firmware(struct hci_dev *hdev,
|
|
config->fwname, ret);
|
|
return ret;
|
|
}
|
|
+ }
|
|
+ /* If the board-specific file is missing, try loading the default
|
|
+ * one, unless that was attempted already.
|
|
+ */
|
|
+ else if (config->type == TLV_TYPE_NVM &&
|
|
+ qca_get_alt_nvm_file(config->fwname, sizeof(config->fwname))) {
|
|
+ bt_dev_info(hdev, "QCA Downloading %s", config->fwname);
|
|
+ ret = request_firmware(&fw, config->fwname, &hdev->dev);
|
|
+ if (ret) {
|
|
+ bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
|
|
+ config->fwname, ret);
|
|
+ return ret;
|
|
+ }
|
|
} else {
|
|
bt_dev_err(hdev, "QCA Failed to request file: %s (%d)",
|
|
config->fwname, ret);
|
|
@@ -722,21 +768,38 @@ static int qca_check_bdaddr(struct hci_dev *hdev, const struct qca_fw_config *co
|
|
return 0;
|
|
}
|
|
|
|
-static void qca_generate_hsp_nvm_name(char *fwname, size_t max_size,
|
|
+static void qca_get_nvm_name_by_board(char *fwname, size_t max_size,
|
|
+ const char *stem, enum qca_btsoc_type soc_type,
|
|
struct qca_btsoc_version ver, u8 rom_ver, u16 bid)
|
|
{
|
|
const char *variant;
|
|
+ const char *prefix;
|
|
|
|
- /* hsp gf chip */
|
|
- if ((le32_to_cpu(ver.soc_id) & QCA_HSP_GF_SOC_MASK) == QCA_HSP_GF_SOC_ID)
|
|
- variant = "g";
|
|
- else
|
|
- variant = "";
|
|
+ /* Set the default value to variant and prefix */
|
|
+ variant = "";
|
|
+ prefix = "b";
|
|
|
|
- if (bid == 0x0)
|
|
- snprintf(fwname, max_size, "qca/hpnv%02x%s.bin", rom_ver, variant);
|
|
- else
|
|
- snprintf(fwname, max_size, "qca/hpnv%02x%s.%x", rom_ver, variant, bid);
|
|
+ if (soc_type == QCA_QCA2066)
|
|
+ prefix = "";
|
|
+
|
|
+ if (soc_type == QCA_WCN6855 || soc_type == QCA_QCA2066) {
|
|
+ /* If the chip is manufactured by GlobalFoundries */
|
|
+ if ((le32_to_cpu(ver.soc_id) & QCA_HSP_GF_SOC_MASK) == QCA_HSP_GF_SOC_ID)
|
|
+ variant = "g";
|
|
+ }
|
|
+
|
|
+ if (rom_ver != 0) {
|
|
+ if (bid == 0x0 || bid == 0xffff)
|
|
+ snprintf(fwname, max_size, "qca/%s%02x%s.bin", stem, rom_ver, variant);
|
|
+ else
|
|
+ snprintf(fwname, max_size, "qca/%s%02x%s.%s%02x", stem, rom_ver,
|
|
+ variant, prefix, bid);
|
|
+ } else {
|
|
+ if (bid == 0x0 || bid == 0xffff)
|
|
+ snprintf(fwname, max_size, "qca/%s%s.bin", stem, variant);
|
|
+ else
|
|
+ snprintf(fwname, max_size, "qca/%s%s.%s%02x", stem, variant, prefix, bid);
|
|
+ }
|
|
}
|
|
|
|
int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|
@@ -819,14 +882,20 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|
/* Give the controller some time to get ready to receive the NVM */
|
|
msleep(10);
|
|
|
|
- if (soc_type == QCA_QCA2066)
|
|
+ if (soc_type == QCA_QCA2066 || soc_type == QCA_WCN7850)
|
|
qca_read_fw_board_id(hdev, &boardid);
|
|
|
|
/* Download NVM configuration */
|
|
config.type = TLV_TYPE_NVM;
|
|
if (firmware_name) {
|
|
- snprintf(config.fwname, sizeof(config.fwname),
|
|
- "qca/%s", firmware_name);
|
|
+ /* The firmware name has an extension, use it directly */
|
|
+ if (qca_filename_has_extension(firmware_name)) {
|
|
+ snprintf(config.fwname, sizeof(config.fwname), "qca/%s", firmware_name);
|
|
+ } else {
|
|
+ qca_read_fw_board_id(hdev, &boardid);
|
|
+ qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
|
|
+ firmware_name, soc_type, ver, 0, boardid);
|
|
+ }
|
|
} else {
|
|
switch (soc_type) {
|
|
case QCA_WCN3990:
|
|
@@ -845,8 +914,9 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|
"qca/apnv%02x.bin", rom_ver);
|
|
break;
|
|
case QCA_QCA2066:
|
|
- qca_generate_hsp_nvm_name(config.fwname,
|
|
- sizeof(config.fwname), ver, rom_ver, boardid);
|
|
+ qca_get_nvm_name_by_board(config.fwname,
|
|
+ sizeof(config.fwname), "hpnv", soc_type, ver,
|
|
+ rom_ver, boardid);
|
|
break;
|
|
case QCA_QCA6390:
|
|
snprintf(config.fwname, sizeof(config.fwname),
|
|
@@ -857,14 +927,14 @@ int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate,
|
|
"qca/msnv%02x.bin", rom_ver);
|
|
break;
|
|
case QCA_WCN6855:
|
|
- snprintf(config.fwname, sizeof(config.fwname),
|
|
- "qca/hpnv%02x.bin", rom_ver);
|
|
+ qca_read_fw_board_id(hdev, &boardid);
|
|
+ qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
|
|
+ "hpnv", soc_type, ver, rom_ver, boardid);
|
|
break;
|
|
case QCA_WCN7850:
|
|
- snprintf(config.fwname, sizeof(config.fwname),
|
|
- "qca/hmtnv%02x.bin", rom_ver);
|
|
+ qca_get_nvm_name_by_board(config.fwname, sizeof(config.fwname),
|
|
+ "hmtnv", soc_type, ver, rom_ver, boardid);
|
|
break;
|
|
-
|
|
default:
|
|
snprintf(config.fwname, sizeof(config.fwname),
|
|
"qca/nvm_%08x.bin", soc_ver);
|
|
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
|
|
index f429b9b37b76c7..7e773c47a4fcd2 100644
|
|
--- a/drivers/cpufreq/Kconfig
|
|
+++ b/drivers/cpufreq/Kconfig
|
|
@@ -218,7 +218,7 @@ config CPUFREQ_DT
|
|
If in doubt, say N.
|
|
|
|
config CPUFREQ_DT_PLATDEV
|
|
- tristate "Generic DT based cpufreq platdev driver"
|
|
+ bool "Generic DT based cpufreq platdev driver"
|
|
depends on OF
|
|
help
|
|
This adds a generic DT based cpufreq platdev driver for frequency
|
|
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
|
|
index fb2875ce1fdd57..09becf14653b58 100644
|
|
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
|
|
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
|
|
@@ -225,4 +225,3 @@ static int __init cpufreq_dt_platdev_init(void)
|
|
sizeof(struct cpufreq_dt_platform_data)));
|
|
}
|
|
core_initcall(cpufreq_dt_platdev_init);
|
|
-MODULE_LICENSE("GPL");
|
|
diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c
|
|
index b2db545c681031..345cae059c029a 100644
|
|
--- a/drivers/edac/qcom_edac.c
|
|
+++ b/drivers/edac/qcom_edac.c
|
|
@@ -95,7 +95,7 @@ static int qcom_llcc_core_setup(struct llcc_drv_data *drv, struct regmap *llcc_b
|
|
* Configure interrupt enable registers such that Tag, Data RAM related
|
|
* interrupts are propagated to interrupt controller for servicing
|
|
*/
|
|
- ret = regmap_update_bits(llcc_bcast_regmap, drv->edac_reg_offset->cmn_interrupt_2_enable,
|
|
+ ret = regmap_update_bits(llcc_bcast_regmap, drv->edac_reg_offset->cmn_interrupt_0_enable,
|
|
TRP0_INTERRUPT_ENABLE,
|
|
TRP0_INTERRUPT_ENABLE);
|
|
if (ret)
|
|
@@ -113,7 +113,7 @@ static int qcom_llcc_core_setup(struct llcc_drv_data *drv, struct regmap *llcc_b
|
|
if (ret)
|
|
return ret;
|
|
|
|
- ret = regmap_update_bits(llcc_bcast_regmap, drv->edac_reg_offset->cmn_interrupt_2_enable,
|
|
+ ret = regmap_update_bits(llcc_bcast_regmap, drv->edac_reg_offset->cmn_interrupt_0_enable,
|
|
DRP0_INTERRUPT_ENABLE,
|
|
DRP0_INTERRUPT_ENABLE);
|
|
if (ret)
|
|
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
|
|
index 7af59985f1c1f9..4c5c2b73d42c21 100644
|
|
--- a/drivers/firmware/qcom_scm.c
|
|
+++ b/drivers/firmware/qcom_scm.c
|
|
@@ -1339,7 +1339,8 @@ static int qcom_scm_find_dload_address(struct device *dev, u64 *addr)
|
|
*/
|
|
bool qcom_scm_is_available(void)
|
|
{
|
|
- return !!READ_ONCE(__scm);
|
|
+ /* Paired with smp_store_release() in qcom_scm_probe */
|
|
+ return !!smp_load_acquire(&__scm);
|
|
}
|
|
EXPORT_SYMBOL_GPL(qcom_scm_is_available);
|
|
|
|
@@ -1457,7 +1458,7 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
|
if (ret)
|
|
return ret;
|
|
|
|
- /* Let all above stores be available after this */
|
|
+ /* Paired with smp_load_acquire() in qcom_scm_is_available(). */
|
|
smp_store_release(&__scm, scm);
|
|
|
|
irq = platform_get_irq_optional(pdev, 0);
|
|
diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
|
|
index 1a59fca40252cd..347527885ffd75 100644
|
|
--- a/drivers/gpu/drm/i915/display/intel_display.c
|
|
+++ b/drivers/gpu/drm/i915/display/intel_display.c
|
|
@@ -6141,12 +6141,30 @@ static int intel_async_flip_check_hw(struct intel_atomic_state *state, struct in
|
|
static int intel_bigjoiner_add_affected_crtcs(struct intel_atomic_state *state)
|
|
{
|
|
struct drm_i915_private *i915 = to_i915(state->base.dev);
|
|
+ const struct intel_plane_state *plane_state;
|
|
struct intel_crtc_state *crtc_state;
|
|
+ struct intel_plane *plane;
|
|
struct intel_crtc *crtc;
|
|
u8 affected_pipes = 0;
|
|
u8 modeset_pipes = 0;
|
|
int i;
|
|
|
|
+ /*
|
|
+ * Any plane which is in use by the joiner needs its crtc.
|
|
+ * Pull those in first as this will not have happened yet
|
|
+ * if the plane remains disabled according to uapi.
|
|
+ */
|
|
+ for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
|
|
+ crtc = to_intel_crtc(plane_state->hw.crtc);
|
|
+ if (!crtc)
|
|
+ continue;
|
|
+
|
|
+ crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
|
|
+ if (IS_ERR(crtc_state))
|
|
+ return PTR_ERR(crtc_state);
|
|
+ }
|
|
+
|
|
+ /* Now pull in all joined crtcs */
|
|
for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
|
|
affected_pipes |= crtc_state->bigjoiner_pipes;
|
|
if (intel_crtc_needs_modeset(crtc_state))
|
|
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
|
|
index eb5559e1a20024..f79809a48672ed 100644
|
|
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
|
|
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
|
|
@@ -1364,7 +1364,7 @@ intel_dp_128b132b_link_train(struct intel_dp *intel_dp,
|
|
|
|
if (wait_for(intel_dp_128b132b_intra_hop(intel_dp, crtc_state) == 0, 500)) {
|
|
lt_err(intel_dp, DP_PHY_DPRX, "128b/132b intra-hop not clear\n");
|
|
- return false;
|
|
+ goto out;
|
|
}
|
|
|
|
if (intel_dp_128b132b_lane_eq(intel_dp, crtc_state) &&
|
|
@@ -1376,6 +1376,19 @@ intel_dp_128b132b_link_train(struct intel_dp *intel_dp,
|
|
passed ? "passed" : "failed",
|
|
crtc_state->port_clock, crtc_state->lane_count);
|
|
|
|
+out:
|
|
+ /*
|
|
+ * Ensure that the training pattern does get set to TPS2 even in case
|
|
+ * of a failure, as is the case at the end of a passing link training
|
|
+ * and what is expected by the transcoder. Leaving TPS1 set (and
|
|
+ * disabling the link train mode in DP_TP_CTL later from TPS1 directly)
|
|
+ * would result in a stuck transcoder HW state and flip-done timeouts
|
|
+ * later in the modeset sequence.
|
|
+ */
|
|
+ if (!passed)
|
|
+ intel_dp_program_link_training_pattern(intel_dp, crtc_state,
|
|
+ DP_PHY_DPRX, DP_TRAINING_PATTERN_2);
|
|
+
|
|
return passed;
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
|
|
index 10c68de1bf22ca..35cf9080168b12 100644
|
|
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
|
|
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c
|
|
@@ -2075,6 +2075,9 @@ void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc)
|
|
}
|
|
}
|
|
|
|
+ if (phys_enc->hw_pp && phys_enc->hw_pp->ops.setup_dither)
|
|
+ phys_enc->hw_pp->ops.setup_dither(phys_enc->hw_pp, NULL);
|
|
+
|
|
/* reset the merge 3D HW block */
|
|
if (phys_enc->hw_pp && phys_enc->hw_pp->merge_3d) {
|
|
phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d,
|
|
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
|
|
index 48e1a8c6942c9f..223bf904235a81 100644
|
|
--- a/drivers/gpu/drm/msm/msm_drv.h
|
|
+++ b/drivers/gpu/drm/msm/msm_drv.h
|
|
@@ -533,15 +533,12 @@ static inline int align_pitch(int width, int bpp)
|
|
static inline unsigned long timeout_to_jiffies(const ktime_t *timeout)
|
|
{
|
|
ktime_t now = ktime_get();
|
|
- s64 remaining_jiffies;
|
|
|
|
- if (ktime_compare(*timeout, now) < 0) {
|
|
- remaining_jiffies = 0;
|
|
- } else {
|
|
- ktime_t rem = ktime_sub(*timeout, now);
|
|
- remaining_jiffies = ktime_divns(rem, NSEC_PER_SEC / HZ);
|
|
- }
|
|
+ if (ktime_compare(*timeout, now) <= 0)
|
|
+ return 0;
|
|
|
|
+ ktime_t rem = ktime_sub(*timeout, now);
|
|
+ s64 remaining_jiffies = ktime_divns(rem, NSEC_PER_SEC / HZ);
|
|
return clamp(remaining_jiffies, 1LL, (s64)INT_MAX);
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
|
|
index db1e748daa753f..1113e6b2ec8ec9 100644
|
|
--- a/drivers/gpu/drm/msm/msm_gem.c
|
|
+++ b/drivers/gpu/drm/msm/msm_gem.c
|
|
@@ -226,9 +226,9 @@ static struct page **msm_gem_pin_pages_locked(struct drm_gem_object *obj,
|
|
|
|
msm_gem_assert_locked(obj);
|
|
|
|
- if (GEM_WARN_ON(msm_obj->madv > madv)) {
|
|
- DRM_DEV_ERROR(obj->dev->dev, "Invalid madv state: %u vs %u\n",
|
|
- msm_obj->madv, madv);
|
|
+ if (msm_obj->madv > madv) {
|
|
+ DRM_DEV_DEBUG_DRIVER(obj->dev->dev, "Invalid madv state: %u vs %u\n",
|
|
+ msm_obj->madv, madv);
|
|
return ERR_PTR(-EBUSY);
|
|
}
|
|
|
|
diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c
|
|
index 99744de6c05a1b..018b39546fc1dd 100644
|
|
--- a/drivers/gpu/drm/msm/msm_gem_submit.c
|
|
+++ b/drivers/gpu/drm/msm/msm_gem_submit.c
|
|
@@ -17,6 +17,12 @@
|
|
#include "msm_gem.h"
|
|
#include "msm_gpu_trace.h"
|
|
|
|
+/* For userspace errors, use DRM_UT_DRIVER.. so that userspace can enable
|
|
+ * error msgs for debugging, but we don't spam dmesg by default
|
|
+ */
|
|
+#define SUBMIT_ERROR(submit, fmt, ...) \
|
|
+ DRM_DEV_DEBUG_DRIVER((submit)->dev->dev, fmt, ##__VA_ARGS__)
|
|
+
|
|
/*
|
|
* Cmdstream submission:
|
|
*/
|
|
@@ -136,7 +142,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
|
|
|
|
if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) ||
|
|
!(submit_bo.flags & MANDATORY_FLAGS)) {
|
|
- DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
|
|
+ SUBMIT_ERROR(submit, "invalid flags: %x\n", submit_bo.flags);
|
|
ret = -EINVAL;
|
|
i = 0;
|
|
goto out;
|
|
@@ -158,7 +164,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
|
|
*/
|
|
obj = idr_find(&file->object_idr, submit->bos[i].handle);
|
|
if (!obj) {
|
|
- DRM_ERROR("invalid handle %u at index %u\n", submit->bos[i].handle, i);
|
|
+ SUBMIT_ERROR(submit, "invalid handle %u at index %u\n", submit->bos[i].handle, i);
|
|
ret = -EINVAL;
|
|
goto out_unlock;
|
|
}
|
|
@@ -202,13 +208,13 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit,
|
|
case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
|
|
break;
|
|
default:
|
|
- DRM_ERROR("invalid type: %08x\n", submit_cmd.type);
|
|
+ SUBMIT_ERROR(submit, "invalid type: %08x\n", submit_cmd.type);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (submit_cmd.size % 4) {
|
|
- DRM_ERROR("non-aligned cmdstream buffer size: %u\n",
|
|
- submit_cmd.size);
|
|
+ SUBMIT_ERROR(submit, "non-aligned cmdstream buffer size: %u\n",
|
|
+ submit_cmd.size);
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
@@ -306,8 +312,8 @@ static int submit_lock_objects(struct msm_gem_submit *submit)
|
|
|
|
fail:
|
|
if (ret == -EALREADY) {
|
|
- DRM_ERROR("handle %u at index %u already on submit list\n",
|
|
- submit->bos[i].handle, i);
|
|
+ SUBMIT_ERROR(submit, "handle %u at index %u already on submit list\n",
|
|
+ submit->bos[i].handle, i);
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
@@ -448,8 +454,8 @@ static int submit_bo(struct msm_gem_submit *submit, uint32_t idx,
|
|
struct drm_gem_object **obj, uint64_t *iova, bool *valid)
|
|
{
|
|
if (idx >= submit->nr_bos) {
|
|
- DRM_ERROR("invalid buffer index: %u (out of %u)\n",
|
|
- idx, submit->nr_bos);
|
|
+ SUBMIT_ERROR(submit, "invalid buffer index: %u (out of %u)\n",
|
|
+ idx, submit->nr_bos);
|
|
return -EINVAL;
|
|
}
|
|
|
|
@@ -475,7 +481,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob
|
|
return 0;
|
|
|
|
if (offset % 4) {
|
|
- DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
|
|
+ SUBMIT_ERROR(submit, "non-aligned cmdstream buffer: %u\n", offset);
|
|
return -EINVAL;
|
|
}
|
|
|
|
@@ -497,8 +503,8 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob
|
|
bool valid;
|
|
|
|
if (submit_reloc.submit_offset % 4) {
|
|
- DRM_ERROR("non-aligned reloc offset: %u\n",
|
|
- submit_reloc.submit_offset);
|
|
+ SUBMIT_ERROR(submit, "non-aligned reloc offset: %u\n",
|
|
+ submit_reloc.submit_offset);
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
@@ -508,7 +514,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct drm_gem_object *ob
|
|
|
|
if ((off >= (obj->size / 4)) ||
|
|
(off < last_offset)) {
|
|
- DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
|
|
+ SUBMIT_ERROR(submit, "invalid offset %u at reloc %u\n", off, i);
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
@@ -879,9 +885,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
|
goto out;
|
|
|
|
if (!submit->cmd[i].size ||
|
|
- ((submit->cmd[i].size + submit->cmd[i].offset) >
|
|
- obj->size / 4)) {
|
|
- DRM_ERROR("invalid cmdstream size: %u\n", submit->cmd[i].size * 4);
|
|
+ (size_add(submit->cmd[i].size, submit->cmd[i].offset) > obj->size / 4)) {
|
|
+ SUBMIT_ERROR(submit, "invalid cmdstream size: %u\n", submit->cmd[i].size * 4);
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
@@ -893,7 +898,7 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
|
|
|
|
if (!gpu->allow_relocs) {
|
|
if (submit->cmd[i].nr_relocs) {
|
|
- DRM_ERROR("relocs not allowed\n");
|
|
+ SUBMIT_ERROR(submit, "relocs not allowed\n");
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c
|
|
index ec9f307370fa8a..6c71f6738ca510 100644
|
|
--- a/drivers/gpu/drm/nouveau/nouveau_svm.c
|
|
+++ b/drivers/gpu/drm/nouveau/nouveau_svm.c
|
|
@@ -593,6 +593,7 @@ static int nouveau_atomic_range_fault(struct nouveau_svmm *svmm,
|
|
unsigned long timeout =
|
|
jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
|
|
struct mm_struct *mm = svmm->notifier.mm;
|
|
+ struct folio *folio;
|
|
struct page *page;
|
|
unsigned long start = args->p.addr;
|
|
unsigned long notifier_seq;
|
|
@@ -619,12 +620,16 @@ static int nouveau_atomic_range_fault(struct nouveau_svmm *svmm,
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
+ folio = page_folio(page);
|
|
|
|
mutex_lock(&svmm->mutex);
|
|
if (!mmu_interval_read_retry(¬ifier->notifier,
|
|
notifier_seq))
|
|
break;
|
|
mutex_unlock(&svmm->mutex);
|
|
+
|
|
+ folio_unlock(folio);
|
|
+ folio_put(folio);
|
|
}
|
|
|
|
/* Map the page on the GPU. */
|
|
@@ -640,8 +645,8 @@ static int nouveau_atomic_range_fault(struct nouveau_svmm *svmm,
|
|
ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, size, NULL);
|
|
mutex_unlock(&svmm->mutex);
|
|
|
|
- unlock_page(page);
|
|
- put_page(page);
|
|
+ folio_unlock(folio);
|
|
+ folio_put(folio);
|
|
|
|
out:
|
|
mmu_interval_notifier_remove(¬ifier->notifier);
|
|
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c
|
|
index a6f410ba60bc94..d393bc540f8628 100644
|
|
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c
|
|
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gp10b.c
|
|
@@ -75,7 +75,7 @@ gp10b_pmu_acr = {
|
|
.bootstrap_multiple_falcons = gp10b_pmu_acr_bootstrap_multiple_falcons,
|
|
};
|
|
|
|
-#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)
|
|
+#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC)
|
|
MODULE_FIRMWARE("nvidia/gp10b/pmu/desc.bin");
|
|
MODULE_FIRMWARE("nvidia/gp10b/pmu/image.bin");
|
|
MODULE_FIRMWARE("nvidia/gp10b/pmu/sig.bin");
|
|
diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c b/drivers/gpu/drm/tidss/tidss_dispc.c
|
|
index ee3531bbccd7df..355c64bafb82b8 100644
|
|
--- a/drivers/gpu/drm/tidss/tidss_dispc.c
|
|
+++ b/drivers/gpu/drm/tidss/tidss_dispc.c
|
|
@@ -2704,14 +2704,32 @@ static void dispc_init_errata(struct dispc_device *dispc)
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+ * K2G display controller does not support soft reset, so we do a basic manual
|
|
+ * reset here: make sure the IRQs are masked and VPs are disabled.
|
|
+ */
|
|
+static void dispc_softreset_k2g(struct dispc_device *dispc)
|
|
+{
|
|
+ unsigned long flags;
|
|
+
|
|
+ spin_lock_irqsave(&dispc->tidss->wait_lock, flags);
|
|
+ dispc_set_irqenable(dispc, 0);
|
|
+ dispc_read_and_clear_irqstatus(dispc);
|
|
+ spin_unlock_irqrestore(&dispc->tidss->wait_lock, flags);
|
|
+
|
|
+ for (unsigned int vp_idx = 0; vp_idx < dispc->feat->num_vps; ++vp_idx)
|
|
+ VP_REG_FLD_MOD(dispc, vp_idx, DISPC_VP_CONTROL, 0, 0, 0);
|
|
+}
|
|
+
|
|
static int dispc_softreset(struct dispc_device *dispc)
|
|
{
|
|
u32 val;
|
|
int ret = 0;
|
|
|
|
- /* K2G display controller does not support soft reset */
|
|
- if (dispc->feat->subrev == DISPC_K2G)
|
|
+ if (dispc->feat->subrev == DISPC_K2G) {
|
|
+ dispc_softreset_k2g(dispc);
|
|
return 0;
|
|
+ }
|
|
|
|
/* Soft reset */
|
|
REG_FLD_MOD(dispc, DSS_SYSCONFIG, 1, 1, 1);
|
|
diff --git a/drivers/gpu/drm/tidss/tidss_irq.c b/drivers/gpu/drm/tidss/tidss_irq.c
|
|
index 0c681c7600bcb2..f13c7e434f8ede 100644
|
|
--- a/drivers/gpu/drm/tidss/tidss_irq.c
|
|
+++ b/drivers/gpu/drm/tidss/tidss_irq.c
|
|
@@ -60,7 +60,9 @@ static irqreturn_t tidss_irq_handler(int irq, void *arg)
|
|
unsigned int id;
|
|
dispc_irq_t irqstatus;
|
|
|
|
+ spin_lock(&tidss->wait_lock);
|
|
irqstatus = dispc_read_and_clear_irqstatus(tidss->dispc);
|
|
+ spin_unlock(&tidss->wait_lock);
|
|
|
|
for (id = 0; id < tidss->num_crtcs; id++) {
|
|
struct drm_crtc *crtc = tidss->crtcs[id];
|
|
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
|
|
index cff3393f0dd000..26677432ac8361 100644
|
|
--- a/drivers/input/mouse/synaptics.c
|
|
+++ b/drivers/input/mouse/synaptics.c
|
|
@@ -667,23 +667,50 @@ static void synaptics_pt_stop(struct serio *serio)
|
|
serio_continue_rx(parent->ps2dev.serio);
|
|
}
|
|
|
|
+static int synaptics_pt_open(struct serio *serio)
|
|
+{
|
|
+ struct psmouse *parent = psmouse_from_serio(serio->parent);
|
|
+ struct synaptics_data *priv = parent->private;
|
|
+
|
|
+ guard(serio_pause_rx)(parent->ps2dev.serio);
|
|
+ priv->pt_port_open = true;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void synaptics_pt_close(struct serio *serio)
|
|
+{
|
|
+ struct psmouse *parent = psmouse_from_serio(serio->parent);
|
|
+ struct synaptics_data *priv = parent->private;
|
|
+
|
|
+ guard(serio_pause_rx)(parent->ps2dev.serio);
|
|
+ priv->pt_port_open = false;
|
|
+}
|
|
+
|
|
static int synaptics_is_pt_packet(u8 *buf)
|
|
{
|
|
return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
|
|
}
|
|
|
|
-static void synaptics_pass_pt_packet(struct serio *ptport, u8 *packet)
|
|
+static void synaptics_pass_pt_packet(struct synaptics_data *priv, u8 *packet)
|
|
{
|
|
- struct psmouse *child = psmouse_from_serio(ptport);
|
|
+ struct serio *ptport;
|
|
|
|
- if (child && child->state == PSMOUSE_ACTIVATED) {
|
|
- serio_interrupt(ptport, packet[1], 0);
|
|
- serio_interrupt(ptport, packet[4], 0);
|
|
- serio_interrupt(ptport, packet[5], 0);
|
|
- if (child->pktsize == 4)
|
|
- serio_interrupt(ptport, packet[2], 0);
|
|
- } else {
|
|
- serio_interrupt(ptport, packet[1], 0);
|
|
+ ptport = priv->pt_port;
|
|
+ if (!ptport)
|
|
+ return;
|
|
+
|
|
+ serio_interrupt(ptport, packet[1], 0);
|
|
+
|
|
+ if (priv->pt_port_open) {
|
|
+ struct psmouse *child = psmouse_from_serio(ptport);
|
|
+
|
|
+ if (child->state == PSMOUSE_ACTIVATED) {
|
|
+ serio_interrupt(ptport, packet[4], 0);
|
|
+ serio_interrupt(ptport, packet[5], 0);
|
|
+ if (child->pktsize == 4)
|
|
+ serio_interrupt(ptport, packet[2], 0);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -722,6 +749,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
|
|
serio->write = synaptics_pt_write;
|
|
serio->start = synaptics_pt_start;
|
|
serio->stop = synaptics_pt_stop;
|
|
+ serio->open = synaptics_pt_open;
|
|
+ serio->close = synaptics_pt_close;
|
|
serio->parent = psmouse->ps2dev.serio;
|
|
|
|
psmouse->pt_activate = synaptics_pt_activate;
|
|
@@ -1218,11 +1247,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
|
|
|
|
if (SYN_CAP_PASS_THROUGH(priv->info.capabilities) &&
|
|
synaptics_is_pt_packet(psmouse->packet)) {
|
|
- if (priv->pt_port)
|
|
- synaptics_pass_pt_packet(priv->pt_port,
|
|
- psmouse->packet);
|
|
- } else
|
|
+ synaptics_pass_pt_packet(priv, psmouse->packet);
|
|
+ } else {
|
|
synaptics_process_packet(psmouse);
|
|
+ }
|
|
|
|
return PSMOUSE_FULL_PACKET;
|
|
}
|
|
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
|
|
index 08533d1b1b16fc..4b34f13b9f7616 100644
|
|
--- a/drivers/input/mouse/synaptics.h
|
|
+++ b/drivers/input/mouse/synaptics.h
|
|
@@ -188,6 +188,7 @@ struct synaptics_data {
|
|
bool disable_gesture; /* disable gestures */
|
|
|
|
struct serio *pt_port; /* Pass-through serio port */
|
|
+ bool pt_port_open;
|
|
|
|
/*
|
|
* Last received Advanced Gesture Mode (AGM) packet. An AGM packet
|
|
diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
|
|
index 2085b1705f144f..deb40a8ba39995 100644
|
|
--- a/drivers/md/md-bitmap.c
|
|
+++ b/drivers/md/md-bitmap.c
|
|
@@ -2112,33 +2112,29 @@ int md_bitmap_copy_from_slot(struct mddev *mddev, int slot,
|
|
}
|
|
EXPORT_SYMBOL_GPL(md_bitmap_copy_from_slot);
|
|
|
|
-
|
|
-void md_bitmap_status(struct seq_file *seq, struct bitmap *bitmap)
|
|
+int md_bitmap_get_stats(struct bitmap *bitmap, struct md_bitmap_stats *stats)
|
|
{
|
|
- unsigned long chunk_kb;
|
|
struct bitmap_counts *counts;
|
|
+ bitmap_super_t *sb;
|
|
|
|
if (!bitmap)
|
|
- return;
|
|
+ return -ENOENT;
|
|
+ if (bitmap->mddev->bitmap_info.external)
|
|
+ return -ENOENT;
|
|
+ if (!bitmap->storage.sb_page) /* no superblock */
|
|
+ return -EINVAL;
|
|
+ sb = kmap_local_page(bitmap->storage.sb_page);
|
|
+ stats->sync_size = le64_to_cpu(sb->sync_size);
|
|
+ kunmap_local(sb);
|
|
|
|
counts = &bitmap->counts;
|
|
+ stats->missing_pages = counts->missing_pages;
|
|
+ stats->pages = counts->pages;
|
|
+ stats->file = bitmap->storage.file;
|
|
|
|
- chunk_kb = bitmap->mddev->bitmap_info.chunksize >> 10;
|
|
- seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], "
|
|
- "%lu%s chunk",
|
|
- counts->pages - counts->missing_pages,
|
|
- counts->pages,
|
|
- (counts->pages - counts->missing_pages)
|
|
- << (PAGE_SHIFT - 10),
|
|
- chunk_kb ? chunk_kb : bitmap->mddev->bitmap_info.chunksize,
|
|
- chunk_kb ? "KB" : "B");
|
|
- if (bitmap->storage.file) {
|
|
- seq_printf(seq, ", file: ");
|
|
- seq_file_path(seq, bitmap->storage.file, " \t\n");
|
|
- }
|
|
-
|
|
- seq_printf(seq, "\n");
|
|
+ return 0;
|
|
}
|
|
+EXPORT_SYMBOL_GPL(md_bitmap_get_stats);
|
|
|
|
int md_bitmap_resize(struct bitmap *bitmap, sector_t blocks,
|
|
int chunksize, int init)
|
|
diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h
|
|
index 8b89e260a93b71..840efd1b8a01cd 100644
|
|
--- a/drivers/md/md-bitmap.h
|
|
+++ b/drivers/md/md-bitmap.h
|
|
@@ -234,6 +234,13 @@ struct bitmap {
|
|
int cluster_slot; /* Slot offset for clustered env */
|
|
};
|
|
|
|
+struct md_bitmap_stats {
|
|
+ unsigned long missing_pages;
|
|
+ unsigned long sync_size;
|
|
+ unsigned long pages;
|
|
+ struct file *file;
|
|
+};
|
|
+
|
|
/* the bitmap API */
|
|
|
|
/* these are used only by md/bitmap */
|
|
@@ -244,7 +251,7 @@ void md_bitmap_destroy(struct mddev *mddev);
|
|
|
|
void md_bitmap_print_sb(struct bitmap *bitmap);
|
|
void md_bitmap_update_sb(struct bitmap *bitmap);
|
|
-void md_bitmap_status(struct seq_file *seq, struct bitmap *bitmap);
|
|
+int md_bitmap_get_stats(struct bitmap *bitmap, struct md_bitmap_stats *stats);
|
|
|
|
int md_bitmap_setallbits(struct bitmap *bitmap);
|
|
void md_bitmap_write_all(struct bitmap *bitmap);
|
|
diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
|
|
index 1e26eb22334950..6a89f6b5d64f98 100644
|
|
--- a/drivers/md/md-cluster.c
|
|
+++ b/drivers/md/md-cluster.c
|
|
@@ -1190,18 +1190,21 @@ static int resize_bitmaps(struct mddev *mddev, sector_t newsize, sector_t oldsiz
|
|
*/
|
|
static int cluster_check_sync_size(struct mddev *mddev)
|
|
{
|
|
- int i, rv;
|
|
- bitmap_super_t *sb;
|
|
- unsigned long my_sync_size, sync_size = 0;
|
|
- int node_num = mddev->bitmap_info.nodes;
|
|
int current_slot = md_cluster_ops->slot_number(mddev);
|
|
+ int node_num = mddev->bitmap_info.nodes;
|
|
struct bitmap *bitmap = mddev->bitmap;
|
|
- char str[64];
|
|
struct dlm_lock_resource *bm_lockres;
|
|
+ struct md_bitmap_stats stats;
|
|
+ unsigned long sync_size = 0;
|
|
+ unsigned long my_sync_size;
|
|
+ char str[64];
|
|
+ int i, rv;
|
|
|
|
- sb = kmap_atomic(bitmap->storage.sb_page);
|
|
- my_sync_size = sb->sync_size;
|
|
- kunmap_atomic(sb);
|
|
+ rv = md_bitmap_get_stats(bitmap, &stats);
|
|
+ if (rv)
|
|
+ return rv;
|
|
+
|
|
+ my_sync_size = stats.sync_size;
|
|
|
|
for (i = 0; i < node_num; i++) {
|
|
if (i == current_slot)
|
|
@@ -1230,15 +1233,18 @@ static int cluster_check_sync_size(struct mddev *mddev)
|
|
md_bitmap_update_sb(bitmap);
|
|
lockres_free(bm_lockres);
|
|
|
|
- sb = kmap_atomic(bitmap->storage.sb_page);
|
|
- if (sync_size == 0)
|
|
- sync_size = sb->sync_size;
|
|
- else if (sync_size != sb->sync_size) {
|
|
- kunmap_atomic(sb);
|
|
+ rv = md_bitmap_get_stats(bitmap, &stats);
|
|
+ if (rv) {
|
|
+ md_bitmap_free(bitmap);
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
+ if (sync_size == 0) {
|
|
+ sync_size = stats.sync_size;
|
|
+ } else if (sync_size != stats.sync_size) {
|
|
md_bitmap_free(bitmap);
|
|
return -1;
|
|
}
|
|
- kunmap_atomic(sb);
|
|
md_bitmap_free(bitmap);
|
|
}
|
|
|
|
diff --git a/drivers/md/md.c b/drivers/md/md.c
|
|
index 9bc19a5a4119bd..a8ac4afc51d91d 100644
|
|
--- a/drivers/md/md.c
|
|
+++ b/drivers/md/md.c
|
|
@@ -633,28 +633,33 @@ static inline struct mddev *mddev_get(struct mddev *mddev)
|
|
|
|
static void mddev_delayed_delete(struct work_struct *ws);
|
|
|
|
+static void __mddev_put(struct mddev *mddev)
|
|
+{
|
|
+ if (mddev->raid_disks || !list_empty(&mddev->disks) ||
|
|
+ mddev->ctime || mddev->hold_active)
|
|
+ return;
|
|
+
|
|
+ /* Array is not configured at all, and not held active, so destroy it */
|
|
+ set_bit(MD_DELETED, &mddev->flags);
|
|
+
|
|
+ /*
|
|
+ * Call queue_work inside the spinlock so that flush_workqueue() after
|
|
+ * mddev_find will succeed in waiting for the work to be done.
|
|
+ */
|
|
+ queue_work(md_misc_wq, &mddev->del_work);
|
|
+}
|
|
+
|
|
void mddev_put(struct mddev *mddev)
|
|
{
|
|
if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock))
|
|
return;
|
|
- if (!mddev->raid_disks && list_empty(&mddev->disks) &&
|
|
- mddev->ctime == 0 && !mddev->hold_active) {
|
|
- /* Array is not configured at all, and not held active,
|
|
- * so destroy it */
|
|
- set_bit(MD_DELETED, &mddev->flags);
|
|
|
|
- /*
|
|
- * Call queue_work inside the spinlock so that
|
|
- * flush_workqueue() after mddev_find will succeed in waiting
|
|
- * for the work to be done.
|
|
- */
|
|
- INIT_WORK(&mddev->del_work, mddev_delayed_delete);
|
|
- queue_work(md_misc_wq, &mddev->del_work);
|
|
- }
|
|
+ __mddev_put(mddev);
|
|
spin_unlock(&all_mddevs_lock);
|
|
}
|
|
|
|
static void md_safemode_timeout(struct timer_list *t);
|
|
+static void md_start_sync(struct work_struct *ws);
|
|
|
|
void mddev_init(struct mddev *mddev)
|
|
{
|
|
@@ -679,6 +684,9 @@ void mddev_init(struct mddev *mddev)
|
|
mddev->resync_min = 0;
|
|
mddev->resync_max = MaxSector;
|
|
mddev->level = LEVEL_NONE;
|
|
+
|
|
+ INIT_WORK(&mddev->sync_work, md_start_sync);
|
|
+ INIT_WORK(&mddev->del_work, mddev_delayed_delete);
|
|
}
|
|
EXPORT_SYMBOL_GPL(mddev_init);
|
|
|
|
@@ -4828,7 +4836,7 @@ static void stop_sync_thread(struct mddev *mddev)
|
|
return;
|
|
}
|
|
|
|
- if (work_pending(&mddev->del_work))
|
|
+ if (work_pending(&mddev->sync_work))
|
|
flush_workqueue(md_misc_wq);
|
|
|
|
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
|
|
@@ -6285,7 +6293,7 @@ static void md_clean(struct mddev *mddev)
|
|
static void __md_stop_writes(struct mddev *mddev)
|
|
{
|
|
set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
|
|
- if (work_pending(&mddev->del_work))
|
|
+ if (work_pending(&mddev->sync_work))
|
|
flush_workqueue(md_misc_wq);
|
|
if (mddev->sync_thread) {
|
|
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
|
|
@@ -8113,6 +8121,19 @@ static void status_unused(struct seq_file *seq)
|
|
seq_printf(seq, "\n");
|
|
}
|
|
|
|
+static void status_personalities(struct seq_file *seq)
|
|
+{
|
|
+ struct md_personality *pers;
|
|
+
|
|
+ seq_puts(seq, "Personalities : ");
|
|
+ spin_lock(&pers_lock);
|
|
+ list_for_each_entry(pers, &pers_list, list)
|
|
+ seq_printf(seq, "[%s] ", pers->name);
|
|
+
|
|
+ spin_unlock(&pers_lock);
|
|
+ seq_puts(seq, "\n");
|
|
+}
|
|
+
|
|
static int status_resync(struct seq_file *seq, struct mddev *mddev)
|
|
{
|
|
sector_t max_sectors, resync, res;
|
|
@@ -8252,104 +8273,73 @@ static int status_resync(struct seq_file *seq, struct mddev *mddev)
|
|
}
|
|
|
|
static void *md_seq_start(struct seq_file *seq, loff_t *pos)
|
|
+ __acquires(&all_mddevs_lock)
|
|
{
|
|
- struct list_head *tmp;
|
|
- loff_t l = *pos;
|
|
- struct mddev *mddev;
|
|
-
|
|
- if (l == 0x10000) {
|
|
- ++*pos;
|
|
- return (void *)2;
|
|
- }
|
|
- if (l > 0x10000)
|
|
- return NULL;
|
|
- if (!l--)
|
|
- /* header */
|
|
- return (void*)1;
|
|
-
|
|
+ seq->poll_event = atomic_read(&md_event_count);
|
|
spin_lock(&all_mddevs_lock);
|
|
- list_for_each(tmp,&all_mddevs)
|
|
- if (!l--) {
|
|
- mddev = list_entry(tmp, struct mddev, all_mddevs);
|
|
- if (!mddev_get(mddev))
|
|
- continue;
|
|
- spin_unlock(&all_mddevs_lock);
|
|
- return mddev;
|
|
- }
|
|
- spin_unlock(&all_mddevs_lock);
|
|
- if (!l--)
|
|
- return (void*)2;/* tail */
|
|
- return NULL;
|
|
+
|
|
+ return seq_list_start_head(&all_mddevs, *pos);
|
|
}
|
|
|
|
static void *md_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
|
{
|
|
- struct list_head *tmp;
|
|
- struct mddev *next_mddev, *mddev = v;
|
|
- struct mddev *to_put = NULL;
|
|
+ return seq_list_next(v, &all_mddevs, pos);
|
|
+}
|
|
|
|
- ++*pos;
|
|
- if (v == (void*)2)
|
|
- return NULL;
|
|
+static void md_seq_stop(struct seq_file *seq, void *v)
|
|
+ __releases(&all_mddevs_lock)
|
|
+{
|
|
+ spin_unlock(&all_mddevs_lock);
|
|
+}
|
|
|
|
- spin_lock(&all_mddevs_lock);
|
|
- if (v == (void*)1) {
|
|
- tmp = all_mddevs.next;
|
|
- } else {
|
|
- to_put = mddev;
|
|
- tmp = mddev->all_mddevs.next;
|
|
- }
|
|
+static void md_bitmap_status(struct seq_file *seq, struct mddev *mddev)
|
|
+{
|
|
+ struct md_bitmap_stats stats;
|
|
+ unsigned long used_pages;
|
|
+ unsigned long chunk_kb;
|
|
+ int err;
|
|
|
|
- for (;;) {
|
|
- if (tmp == &all_mddevs) {
|
|
- next_mddev = (void*)2;
|
|
- *pos = 0x10000;
|
|
- break;
|
|
- }
|
|
- next_mddev = list_entry(tmp, struct mddev, all_mddevs);
|
|
- if (mddev_get(next_mddev))
|
|
- break;
|
|
- mddev = next_mddev;
|
|
- tmp = mddev->all_mddevs.next;
|
|
- }
|
|
- spin_unlock(&all_mddevs_lock);
|
|
+ err = md_bitmap_get_stats(mddev->bitmap, &stats);
|
|
+ if (err)
|
|
+ return;
|
|
|
|
- if (to_put)
|
|
- mddev_put(to_put);
|
|
- return next_mddev;
|
|
+ chunk_kb = mddev->bitmap_info.chunksize >> 10;
|
|
+ used_pages = stats.pages - stats.missing_pages;
|
|
|
|
-}
|
|
+ seq_printf(seq, "bitmap: %lu/%lu pages [%luKB], %lu%s chunk",
|
|
+ used_pages, stats.pages, used_pages << (PAGE_SHIFT - 10),
|
|
+ chunk_kb ? chunk_kb : mddev->bitmap_info.chunksize,
|
|
+ chunk_kb ? "KB" : "B");
|
|
|
|
-static void md_seq_stop(struct seq_file *seq, void *v)
|
|
-{
|
|
- struct mddev *mddev = v;
|
|
+ if (stats.file) {
|
|
+ seq_puts(seq, ", file: ");
|
|
+ seq_file_path(seq, stats.file, " \t\n");
|
|
+ }
|
|
|
|
- if (mddev && v != (void*)1 && v != (void*)2)
|
|
- mddev_put(mddev);
|
|
+ seq_putc(seq, '\n');
|
|
}
|
|
|
|
static int md_seq_show(struct seq_file *seq, void *v)
|
|
{
|
|
- struct mddev *mddev = v;
|
|
+ struct mddev *mddev;
|
|
sector_t sectors;
|
|
struct md_rdev *rdev;
|
|
|
|
- if (v == (void*)1) {
|
|
- struct md_personality *pers;
|
|
- seq_printf(seq, "Personalities : ");
|
|
- spin_lock(&pers_lock);
|
|
- list_for_each_entry(pers, &pers_list, list)
|
|
- seq_printf(seq, "[%s] ", pers->name);
|
|
-
|
|
- spin_unlock(&pers_lock);
|
|
- seq_printf(seq, "\n");
|
|
- seq->poll_event = atomic_read(&md_event_count);
|
|
+ if (v == &all_mddevs) {
|
|
+ status_personalities(seq);
|
|
+ if (list_empty(&all_mddevs))
|
|
+ status_unused(seq);
|
|
return 0;
|
|
}
|
|
- if (v == (void*)2) {
|
|
- status_unused(seq);
|
|
+
|
|
+ mddev = list_entry(v, struct mddev, all_mddevs);
|
|
+ if (!mddev_get(mddev))
|
|
return 0;
|
|
- }
|
|
+
|
|
+ spin_unlock(&all_mddevs_lock);
|
|
+
|
|
+ /* prevent bitmap to be freed after checking */
|
|
+ mutex_lock(&mddev->bitmap_info.mutex);
|
|
|
|
spin_lock(&mddev->lock);
|
|
if (mddev->pers || mddev->raid_disks || !list_empty(&mddev->disks)) {
|
|
@@ -8416,11 +8406,19 @@ static int md_seq_show(struct seq_file *seq, void *v)
|
|
} else
|
|
seq_printf(seq, "\n ");
|
|
|
|
- md_bitmap_status(seq, mddev->bitmap);
|
|
+ md_bitmap_status(seq, mddev);
|
|
|
|
seq_printf(seq, "\n");
|
|
}
|
|
spin_unlock(&mddev->lock);
|
|
+ mutex_unlock(&mddev->bitmap_info.mutex);
|
|
+ spin_lock(&all_mddevs_lock);
|
|
+
|
|
+ if (mddev == list_last_entry(&all_mddevs, struct mddev, all_mddevs))
|
|
+ status_unused(seq);
|
|
+
|
|
+ if (atomic_dec_and_test(&mddev->active))
|
|
+ __mddev_put(mddev);
|
|
|
|
return 0;
|
|
}
|
|
@@ -9333,7 +9331,7 @@ static int remove_and_add_spares(struct mddev *mddev,
|
|
|
|
static void md_start_sync(struct work_struct *ws)
|
|
{
|
|
- struct mddev *mddev = container_of(ws, struct mddev, del_work);
|
|
+ struct mddev *mddev = container_of(ws, struct mddev, sync_work);
|
|
|
|
rcu_assign_pointer(mddev->sync_thread,
|
|
md_register_thread(md_do_sync, mddev, "resync"));
|
|
@@ -9546,8 +9544,7 @@ void md_check_recovery(struct mddev *mddev)
|
|
*/
|
|
md_bitmap_write_all(mddev->bitmap);
|
|
}
|
|
- INIT_WORK(&mddev->del_work, md_start_sync);
|
|
- queue_work(md_misc_wq, &mddev->del_work);
|
|
+ queue_work(md_misc_wq, &mddev->sync_work);
|
|
goto unlock;
|
|
}
|
|
not_running:
|
|
diff --git a/drivers/md/md.h b/drivers/md/md.h
|
|
index f29fa8650cd0f0..46995558d3bd91 100644
|
|
--- a/drivers/md/md.h
|
|
+++ b/drivers/md/md.h
|
|
@@ -453,7 +453,10 @@ struct mddev {
|
|
struct kernfs_node *sysfs_degraded; /*handle for 'degraded' */
|
|
struct kernfs_node *sysfs_level; /*handle for 'level' */
|
|
|
|
- struct work_struct del_work; /* used for delayed sysfs removal */
|
|
+ /* used for delayed sysfs removal */
|
|
+ struct work_struct del_work;
|
|
+ /* used for register new sync thread */
|
|
+ struct work_struct sync_work;
|
|
|
|
/* "lock" protects:
|
|
* flush_bio transition from NULL to !NULL
|
|
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
|
|
index ce70e96b8fb52e..028c4a5049af97 100644
|
|
--- a/drivers/media/usb/uvc/uvc_ctrl.c
|
|
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
|
|
@@ -1532,6 +1532,40 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain,
|
|
uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
|
|
}
|
|
|
|
+static void uvc_ctrl_set_handle(struct uvc_fh *handle, struct uvc_control *ctrl,
|
|
+ struct uvc_fh *new_handle)
|
|
+{
|
|
+ lockdep_assert_held(&handle->chain->ctrl_mutex);
|
|
+
|
|
+ if (new_handle) {
|
|
+ if (ctrl->handle)
|
|
+ dev_warn_ratelimited(&handle->stream->dev->udev->dev,
|
|
+ "UVC non compliance: Setting an async control with a pending operation.");
|
|
+
|
|
+ if (new_handle == ctrl->handle)
|
|
+ return;
|
|
+
|
|
+ if (ctrl->handle) {
|
|
+ WARN_ON(!ctrl->handle->pending_async_ctrls);
|
|
+ if (ctrl->handle->pending_async_ctrls)
|
|
+ ctrl->handle->pending_async_ctrls--;
|
|
+ }
|
|
+
|
|
+ ctrl->handle = new_handle;
|
|
+ handle->pending_async_ctrls++;
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Cannot clear the handle for a control not owned by us.*/
|
|
+ if (WARN_ON(ctrl->handle != handle))
|
|
+ return;
|
|
+
|
|
+ ctrl->handle = NULL;
|
|
+ if (WARN_ON(!handle->pending_async_ctrls))
|
|
+ return;
|
|
+ handle->pending_async_ctrls--;
|
|
+}
|
|
+
|
|
void uvc_ctrl_status_event(struct uvc_video_chain *chain,
|
|
struct uvc_control *ctrl, const u8 *data)
|
|
{
|
|
@@ -1542,7 +1576,8 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
|
|
mutex_lock(&chain->ctrl_mutex);
|
|
|
|
handle = ctrl->handle;
|
|
- ctrl->handle = NULL;
|
|
+ if (handle)
|
|
+ uvc_ctrl_set_handle(handle, ctrl, NULL);
|
|
|
|
list_for_each_entry(mapping, &ctrl->info.mappings, list) {
|
|
s32 value = __uvc_ctrl_get_value(mapping, data);
|
|
@@ -1762,7 +1797,10 @@ int uvc_ctrl_begin(struct uvc_video_chain *chain)
|
|
}
|
|
|
|
static int uvc_ctrl_commit_entity(struct uvc_device *dev,
|
|
- struct uvc_entity *entity, int rollback, struct uvc_control **err_ctrl)
|
|
+ struct uvc_fh *handle,
|
|
+ struct uvc_entity *entity,
|
|
+ int rollback,
|
|
+ struct uvc_control **err_ctrl)
|
|
{
|
|
struct uvc_control *ctrl;
|
|
unsigned int i;
|
|
@@ -1810,6 +1848,10 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
|
|
*err_ctrl = ctrl;
|
|
return ret;
|
|
}
|
|
+
|
|
+ if (!rollback && handle &&
|
|
+ ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
|
|
+ uvc_ctrl_set_handle(handle, ctrl, handle);
|
|
}
|
|
|
|
return 0;
|
|
@@ -1846,18 +1888,20 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
|
|
|
|
/* Find the control. */
|
|
list_for_each_entry(entity, &chain->entities, chain) {
|
|
- ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback,
|
|
- &err_ctrl);
|
|
- if (ret < 0)
|
|
+ ret = uvc_ctrl_commit_entity(chain->dev, handle, entity,
|
|
+ rollback, &err_ctrl);
|
|
+ if (ret < 0) {
|
|
+ if (ctrls)
|
|
+ ctrls->error_idx =
|
|
+ uvc_ctrl_find_ctrl_idx(entity, ctrls,
|
|
+ err_ctrl);
|
|
goto done;
|
|
+ }
|
|
}
|
|
|
|
if (!rollback)
|
|
uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
|
|
done:
|
|
- if (ret < 0 && ctrls)
|
|
- ctrls->error_idx = uvc_ctrl_find_ctrl_idx(entity, ctrls,
|
|
- err_ctrl);
|
|
mutex_unlock(&chain->ctrl_mutex);
|
|
return ret;
|
|
}
|
|
@@ -1995,9 +2039,6 @@ int uvc_ctrl_set(struct uvc_fh *handle,
|
|
mapping->set(mapping, value,
|
|
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
|
|
|
|
- if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
|
|
- ctrl->handle = handle;
|
|
-
|
|
ctrl->dirty = 1;
|
|
ctrl->modified = 1;
|
|
return 0;
|
|
@@ -2170,7 +2211,7 @@ static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev,
|
|
int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
|
|
struct uvc_xu_control_query *xqry)
|
|
{
|
|
- struct uvc_entity *entity;
|
|
+ struct uvc_entity *entity, *iter;
|
|
struct uvc_control *ctrl;
|
|
unsigned int i;
|
|
bool found;
|
|
@@ -2180,16 +2221,16 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
|
|
int ret;
|
|
|
|
/* Find the extension unit. */
|
|
- found = false;
|
|
- list_for_each_entry(entity, &chain->entities, chain) {
|
|
- if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT &&
|
|
- entity->id == xqry->unit) {
|
|
- found = true;
|
|
+ entity = NULL;
|
|
+ list_for_each_entry(iter, &chain->entities, chain) {
|
|
+ if (UVC_ENTITY_TYPE(iter) == UVC_VC_EXTENSION_UNIT &&
|
|
+ iter->id == xqry->unit) {
|
|
+ entity = iter;
|
|
break;
|
|
}
|
|
}
|
|
|
|
- if (!found) {
|
|
+ if (!entity) {
|
|
uvc_dbg(chain->dev, CONTROL, "Extension unit %u not found\n",
|
|
xqry->unit);
|
|
return -ENOENT;
|
|
@@ -2326,7 +2367,7 @@ int uvc_ctrl_restore_values(struct uvc_device *dev)
|
|
ctrl->dirty = 1;
|
|
}
|
|
|
|
- ret = uvc_ctrl_commit_entity(dev, entity, 0, NULL);
|
|
+ ret = uvc_ctrl_commit_entity(dev, NULL, entity, 0, NULL);
|
|
if (ret < 0)
|
|
return ret;
|
|
}
|
|
@@ -2748,6 +2789,26 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
|
|
return 0;
|
|
}
|
|
|
|
+void uvc_ctrl_cleanup_fh(struct uvc_fh *handle)
|
|
+{
|
|
+ struct uvc_entity *entity;
|
|
+
|
|
+ guard(mutex)(&handle->chain->ctrl_mutex);
|
|
+
|
|
+ if (!handle->pending_async_ctrls)
|
|
+ return;
|
|
+
|
|
+ list_for_each_entry(entity, &handle->chain->dev->entities, list) {
|
|
+ for (unsigned int i = 0; i < entity->ncontrols; ++i) {
|
|
+ if (entity->controls[i].handle != handle)
|
|
+ continue;
|
|
+ uvc_ctrl_set_handle(handle, &entity->controls[i], NULL);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ WARN_ON(handle->pending_async_ctrls);
|
|
+}
|
|
+
|
|
/*
|
|
* Cleanup device controls.
|
|
*/
|
|
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
|
|
index f4988f03640aec..7bcd706281daf3 100644
|
|
--- a/drivers/media/usb/uvc/uvc_v4l2.c
|
|
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
|
|
@@ -659,6 +659,8 @@ static int uvc_v4l2_release(struct file *file)
|
|
|
|
uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
|
|
|
|
+ uvc_ctrl_cleanup_fh(handle);
|
|
+
|
|
/* Only free resources if this is a privileged handle. */
|
|
if (uvc_has_privileges(handle))
|
|
uvc_queue_release(&stream->queue);
|
|
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
|
|
index 30fd056b2aec9d..e99bfaa622669b 100644
|
|
--- a/drivers/media/usb/uvc/uvcvideo.h
|
|
+++ b/drivers/media/usb/uvc/uvcvideo.h
|
|
@@ -334,7 +334,11 @@ struct uvc_video_chain {
|
|
struct uvc_entity *processing; /* Processing unit */
|
|
struct uvc_entity *selector; /* Selector unit */
|
|
|
|
- struct mutex ctrl_mutex; /* Protects ctrl.info */
|
|
+ struct mutex ctrl_mutex; /*
|
|
+ * Protects ctrl.info,
|
|
+ * ctrl.handle and
|
|
+ * uvc_fh.pending_async_ctrls
|
|
+ */
|
|
|
|
struct v4l2_prio_state prio; /* V4L2 priority state */
|
|
u32 caps; /* V4L2 chain-wide caps */
|
|
@@ -609,6 +613,7 @@ struct uvc_fh {
|
|
struct uvc_video_chain *chain;
|
|
struct uvc_streaming *stream;
|
|
enum uvc_handle_state state;
|
|
+ unsigned int pending_async_ctrls;
|
|
};
|
|
|
|
struct uvc_driver {
|
|
@@ -794,6 +799,8 @@ int uvc_ctrl_is_accessible(struct uvc_video_chain *chain, u32 v4l2_id,
|
|
int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
|
|
struct uvc_xu_control_query *xqry);
|
|
|
|
+void uvc_ctrl_cleanup_fh(struct uvc_fh *handle);
|
|
+
|
|
/* Utility functions */
|
|
struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
|
|
u8 epaddr);
|
|
diff --git a/drivers/mtd/nand/raw/cadence-nand-controller.c b/drivers/mtd/nand/raw/cadence-nand-controller.c
|
|
index 034ec564c2edb0..4f37ca894d18a1 100644
|
|
--- a/drivers/mtd/nand/raw/cadence-nand-controller.c
|
|
+++ b/drivers/mtd/nand/raw/cadence-nand-controller.c
|
|
@@ -469,6 +469,8 @@ struct cdns_nand_ctrl {
|
|
struct {
|
|
void __iomem *virt;
|
|
dma_addr_t dma;
|
|
+ dma_addr_t iova_dma;
|
|
+ u32 size;
|
|
} io;
|
|
|
|
int irq;
|
|
@@ -1838,11 +1840,11 @@ static int cadence_nand_slave_dma_transfer(struct cdns_nand_ctrl *cdns_ctrl,
|
|
}
|
|
|
|
if (dir == DMA_FROM_DEVICE) {
|
|
- src_dma = cdns_ctrl->io.dma;
|
|
+ src_dma = cdns_ctrl->io.iova_dma;
|
|
dst_dma = buf_dma;
|
|
} else {
|
|
src_dma = buf_dma;
|
|
- dst_dma = cdns_ctrl->io.dma;
|
|
+ dst_dma = cdns_ctrl->io.iova_dma;
|
|
}
|
|
|
|
tx = dmaengine_prep_dma_memcpy(cdns_ctrl->dmac, dst_dma, src_dma, len,
|
|
@@ -1864,12 +1866,12 @@ static int cadence_nand_slave_dma_transfer(struct cdns_nand_ctrl *cdns_ctrl,
|
|
dma_async_issue_pending(cdns_ctrl->dmac);
|
|
wait_for_completion(&finished);
|
|
|
|
- dma_unmap_single(cdns_ctrl->dev, buf_dma, len, dir);
|
|
+ dma_unmap_single(dma_dev->dev, buf_dma, len, dir);
|
|
|
|
return 0;
|
|
|
|
err_unmap:
|
|
- dma_unmap_single(cdns_ctrl->dev, buf_dma, len, dir);
|
|
+ dma_unmap_single(dma_dev->dev, buf_dma, len, dir);
|
|
|
|
err:
|
|
dev_dbg(cdns_ctrl->dev, "Fall back to CPU I/O\n");
|
|
@@ -2874,6 +2876,7 @@ cadence_nand_irq_cleanup(int irqnum, struct cdns_nand_ctrl *cdns_ctrl)
|
|
static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
|
|
{
|
|
dma_cap_mask_t mask;
|
|
+ struct dma_device *dma_dev = cdns_ctrl->dmac->device;
|
|
int ret;
|
|
|
|
cdns_ctrl->cdma_desc = dma_alloc_coherent(cdns_ctrl->dev,
|
|
@@ -2909,15 +2912,24 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
|
|
dma_cap_set(DMA_MEMCPY, mask);
|
|
|
|
if (cdns_ctrl->caps1->has_dma) {
|
|
- cdns_ctrl->dmac = dma_request_channel(mask, NULL, NULL);
|
|
- if (!cdns_ctrl->dmac) {
|
|
- dev_err(cdns_ctrl->dev,
|
|
- "Unable to get a DMA channel\n");
|
|
- ret = -EBUSY;
|
|
+ cdns_ctrl->dmac = dma_request_chan_by_mask(&mask);
|
|
+ if (IS_ERR(cdns_ctrl->dmac)) {
|
|
+ ret = dev_err_probe(cdns_ctrl->dev, PTR_ERR(cdns_ctrl->dmac),
|
|
+ "%d: Failed to get a DMA channel\n", ret);
|
|
goto disable_irq;
|
|
}
|
|
}
|
|
|
|
+ cdns_ctrl->io.iova_dma = dma_map_resource(dma_dev->dev, cdns_ctrl->io.dma,
|
|
+ cdns_ctrl->io.size,
|
|
+ DMA_BIDIRECTIONAL, 0);
|
|
+
|
|
+ ret = dma_mapping_error(dma_dev->dev, cdns_ctrl->io.iova_dma);
|
|
+ if (ret) {
|
|
+ dev_err(cdns_ctrl->dev, "Failed to map I/O resource to DMA\n");
|
|
+ goto dma_release_chnl;
|
|
+ }
|
|
+
|
|
nand_controller_init(&cdns_ctrl->controller);
|
|
INIT_LIST_HEAD(&cdns_ctrl->chips);
|
|
|
|
@@ -2928,18 +2940,22 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
|
|
if (ret) {
|
|
dev_err(cdns_ctrl->dev, "Failed to register MTD: %d\n",
|
|
ret);
|
|
- goto dma_release_chnl;
|
|
+ goto unmap_dma_resource;
|
|
}
|
|
|
|
kfree(cdns_ctrl->buf);
|
|
cdns_ctrl->buf = kzalloc(cdns_ctrl->buf_size, GFP_KERNEL);
|
|
if (!cdns_ctrl->buf) {
|
|
ret = -ENOMEM;
|
|
- goto dma_release_chnl;
|
|
+ goto unmap_dma_resource;
|
|
}
|
|
|
|
return 0;
|
|
|
|
+unmap_dma_resource:
|
|
+ dma_unmap_resource(dma_dev->dev, cdns_ctrl->io.iova_dma,
|
|
+ cdns_ctrl->io.size, DMA_BIDIRECTIONAL, 0);
|
|
+
|
|
dma_release_chnl:
|
|
if (cdns_ctrl->dmac)
|
|
dma_release_channel(cdns_ctrl->dmac);
|
|
@@ -2961,6 +2977,8 @@ static int cadence_nand_init(struct cdns_nand_ctrl *cdns_ctrl)
|
|
static void cadence_nand_remove(struct cdns_nand_ctrl *cdns_ctrl)
|
|
{
|
|
cadence_nand_chips_cleanup(cdns_ctrl);
|
|
+ dma_unmap_resource(cdns_ctrl->dmac->device->dev, cdns_ctrl->io.iova_dma,
|
|
+ cdns_ctrl->io.size, DMA_BIDIRECTIONAL, 0);
|
|
cadence_nand_irq_cleanup(cdns_ctrl->irq, cdns_ctrl);
|
|
kfree(cdns_ctrl->buf);
|
|
dma_free_coherent(cdns_ctrl->dev, sizeof(struct cadence_nand_cdma_desc),
|
|
@@ -3029,7 +3047,9 @@ static int cadence_nand_dt_probe(struct platform_device *ofdev)
|
|
cdns_ctrl->io.virt = devm_platform_get_and_ioremap_resource(ofdev, 1, &res);
|
|
if (IS_ERR(cdns_ctrl->io.virt))
|
|
return PTR_ERR(cdns_ctrl->io.virt);
|
|
+
|
|
cdns_ctrl->io.dma = res->start;
|
|
+ cdns_ctrl->io.size = resource_size(res);
|
|
|
|
dt->clk = devm_clk_get(cdns_ctrl->dev, "nf_clk");
|
|
if (IS_ERR(dt->clk))
|
|
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
|
|
index 61685c3053ad7e..4f18addc191b85 100644
|
|
--- a/drivers/net/ethernet/ibm/ibmvnic.c
|
|
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
|
|
@@ -117,6 +117,7 @@ static void free_long_term_buff(struct ibmvnic_adapter *adapter,
|
|
struct ibmvnic_long_term_buff *ltb);
|
|
static void ibmvnic_disable_irqs(struct ibmvnic_adapter *adapter);
|
|
static void flush_reset_queue(struct ibmvnic_adapter *adapter);
|
|
+static void print_subcrq_error(struct device *dev, int rc, const char *func);
|
|
|
|
struct ibmvnic_stat {
|
|
char name[ETH_GSTRING_LEN];
|
|
@@ -2325,7 +2326,7 @@ static void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter,
|
|
tx_buff = &tx_pool->tx_buff[index];
|
|
adapter->netdev->stats.tx_packets--;
|
|
adapter->netdev->stats.tx_bytes -= tx_buff->skb->len;
|
|
- adapter->tx_stats_buffers[queue_num].packets--;
|
|
+ adapter->tx_stats_buffers[queue_num].batched_packets--;
|
|
adapter->tx_stats_buffers[queue_num].bytes -=
|
|
tx_buff->skb->len;
|
|
dev_kfree_skb_any(tx_buff->skb);
|
|
@@ -2350,8 +2351,29 @@ static void ibmvnic_tx_scrq_clean_buffer(struct ibmvnic_adapter *adapter,
|
|
}
|
|
}
|
|
|
|
+static int send_subcrq_direct(struct ibmvnic_adapter *adapter,
|
|
+ u64 remote_handle, u64 *entry)
|
|
+{
|
|
+ unsigned int ua = adapter->vdev->unit_address;
|
|
+ struct device *dev = &adapter->vdev->dev;
|
|
+ int rc;
|
|
+
|
|
+ /* Make sure the hypervisor sees the complete request */
|
|
+ dma_wmb();
|
|
+ rc = plpar_hcall_norets(H_SEND_SUB_CRQ, ua,
|
|
+ cpu_to_be64(remote_handle),
|
|
+ cpu_to_be64(entry[0]), cpu_to_be64(entry[1]),
|
|
+ cpu_to_be64(entry[2]), cpu_to_be64(entry[3]));
|
|
+
|
|
+ if (rc)
|
|
+ print_subcrq_error(dev, rc, __func__);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
static int ibmvnic_tx_scrq_flush(struct ibmvnic_adapter *adapter,
|
|
- struct ibmvnic_sub_crq_queue *tx_scrq)
|
|
+ struct ibmvnic_sub_crq_queue *tx_scrq,
|
|
+ bool indirect)
|
|
{
|
|
struct ibmvnic_ind_xmit_queue *ind_bufp;
|
|
u64 dma_addr;
|
|
@@ -2366,12 +2388,18 @@ static int ibmvnic_tx_scrq_flush(struct ibmvnic_adapter *adapter,
|
|
|
|
if (!entries)
|
|
return 0;
|
|
- rc = send_subcrq_indirect(adapter, handle, dma_addr, entries);
|
|
+
|
|
+ if (indirect)
|
|
+ rc = send_subcrq_indirect(adapter, handle, dma_addr, entries);
|
|
+ else
|
|
+ rc = send_subcrq_direct(adapter, handle,
|
|
+ (u64 *)ind_bufp->indir_arr);
|
|
+
|
|
if (rc)
|
|
ibmvnic_tx_scrq_clean_buffer(adapter, tx_scrq);
|
|
else
|
|
ind_bufp->index = 0;
|
|
- return 0;
|
|
+ return rc;
|
|
}
|
|
|
|
static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|
@@ -2390,11 +2418,13 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|
unsigned int tx_map_failed = 0;
|
|
union sub_crq indir_arr[16];
|
|
unsigned int tx_dropped = 0;
|
|
- unsigned int tx_packets = 0;
|
|
+ unsigned int tx_dpackets = 0;
|
|
+ unsigned int tx_bpackets = 0;
|
|
unsigned int tx_bytes = 0;
|
|
dma_addr_t data_dma_addr;
|
|
struct netdev_queue *txq;
|
|
unsigned long lpar_rc;
|
|
+ unsigned int skblen;
|
|
union sub_crq tx_crq;
|
|
unsigned int offset;
|
|
int num_entries = 1;
|
|
@@ -2424,7 +2454,9 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|
tx_dropped++;
|
|
tx_send_failed++;
|
|
ret = NETDEV_TX_OK;
|
|
- ibmvnic_tx_scrq_flush(adapter, tx_scrq);
|
|
+ lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq, true);
|
|
+ if (lpar_rc != H_SUCCESS)
|
|
+ goto tx_err;
|
|
goto out;
|
|
}
|
|
|
|
@@ -2439,8 +2471,10 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|
dev_kfree_skb_any(skb);
|
|
tx_send_failed++;
|
|
tx_dropped++;
|
|
- ibmvnic_tx_scrq_flush(adapter, tx_scrq);
|
|
ret = NETDEV_TX_OK;
|
|
+ lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq, true);
|
|
+ if (lpar_rc != H_SUCCESS)
|
|
+ goto tx_err;
|
|
goto out;
|
|
}
|
|
|
|
@@ -2493,6 +2527,7 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|
tx_buff->skb = skb;
|
|
tx_buff->index = bufidx;
|
|
tx_buff->pool_index = queue_num;
|
|
+ skblen = skb->len;
|
|
|
|
memset(&tx_crq, 0, sizeof(tx_crq));
|
|
tx_crq.v1.first = IBMVNIC_CRQ_CMD;
|
|
@@ -2536,6 +2571,17 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|
tx_crq.v1.flags1 |= IBMVNIC_TX_LSO;
|
|
tx_crq.v1.mss = cpu_to_be16(skb_shinfo(skb)->gso_size);
|
|
hdrs += 2;
|
|
+ } else if (!ind_bufp->index && !netdev_xmit_more()) {
|
|
+ ind_bufp->indir_arr[0] = tx_crq;
|
|
+ ind_bufp->index = 1;
|
|
+ tx_buff->num_entries = 1;
|
|
+ netdev_tx_sent_queue(txq, skb->len);
|
|
+ lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq, false);
|
|
+ if (lpar_rc != H_SUCCESS)
|
|
+ goto tx_err;
|
|
+
|
|
+ tx_dpackets++;
|
|
+ goto early_exit;
|
|
}
|
|
|
|
if ((*hdrs >> 7) & 1)
|
|
@@ -2545,7 +2591,7 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|
tx_buff->num_entries = num_entries;
|
|
/* flush buffer if current entry can not fit */
|
|
if (num_entries + ind_bufp->index > IBMVNIC_MAX_IND_DESCS) {
|
|
- lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq);
|
|
+ lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq, true);
|
|
if (lpar_rc != H_SUCCESS)
|
|
goto tx_flush_err;
|
|
}
|
|
@@ -2553,23 +2599,26 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|
indir_arr[0] = tx_crq;
|
|
memcpy(&ind_bufp->indir_arr[ind_bufp->index], &indir_arr[0],
|
|
num_entries * sizeof(struct ibmvnic_generic_scrq));
|
|
+
|
|
ind_bufp->index += num_entries;
|
|
if (__netdev_tx_sent_queue(txq, skb->len,
|
|
netdev_xmit_more() &&
|
|
ind_bufp->index < IBMVNIC_MAX_IND_DESCS)) {
|
|
- lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq);
|
|
+ lpar_rc = ibmvnic_tx_scrq_flush(adapter, tx_scrq, true);
|
|
if (lpar_rc != H_SUCCESS)
|
|
goto tx_err;
|
|
}
|
|
|
|
+ tx_bpackets++;
|
|
+
|
|
+early_exit:
|
|
if (atomic_add_return(num_entries, &tx_scrq->used)
|
|
>= adapter->req_tx_entries_per_subcrq) {
|
|
netdev_dbg(netdev, "Stopping queue %d\n", queue_num);
|
|
netif_stop_subqueue(netdev, queue_num);
|
|
}
|
|
|
|
- tx_packets++;
|
|
- tx_bytes += skb->len;
|
|
+ tx_bytes += skblen;
|
|
txq_trans_cond_update(txq);
|
|
ret = NETDEV_TX_OK;
|
|
goto out;
|
|
@@ -2598,10 +2647,11 @@ static netdev_tx_t ibmvnic_xmit(struct sk_buff *skb, struct net_device *netdev)
|
|
rcu_read_unlock();
|
|
netdev->stats.tx_dropped += tx_dropped;
|
|
netdev->stats.tx_bytes += tx_bytes;
|
|
- netdev->stats.tx_packets += tx_packets;
|
|
+ netdev->stats.tx_packets += tx_bpackets + tx_dpackets;
|
|
adapter->tx_send_failed += tx_send_failed;
|
|
adapter->tx_map_failed += tx_map_failed;
|
|
- adapter->tx_stats_buffers[queue_num].packets += tx_packets;
|
|
+ adapter->tx_stats_buffers[queue_num].batched_packets += tx_bpackets;
|
|
+ adapter->tx_stats_buffers[queue_num].direct_packets += tx_dpackets;
|
|
adapter->tx_stats_buffers[queue_num].bytes += tx_bytes;
|
|
adapter->tx_stats_buffers[queue_num].dropped_packets += tx_dropped;
|
|
|
|
@@ -3767,7 +3817,10 @@ static void ibmvnic_get_strings(struct net_device *dev, u32 stringset, u8 *data)
|
|
memcpy(data, ibmvnic_stats[i].name, ETH_GSTRING_LEN);
|
|
|
|
for (i = 0; i < adapter->req_tx_queues; i++) {
|
|
- snprintf(data, ETH_GSTRING_LEN, "tx%d_packets", i);
|
|
+ snprintf(data, ETH_GSTRING_LEN, "tx%d_batched_packets", i);
|
|
+ data += ETH_GSTRING_LEN;
|
|
+
|
|
+ snprintf(data, ETH_GSTRING_LEN, "tx%d_direct_packets", i);
|
|
data += ETH_GSTRING_LEN;
|
|
|
|
snprintf(data, ETH_GSTRING_LEN, "tx%d_bytes", i);
|
|
@@ -3832,7 +3885,9 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev,
|
|
(adapter, ibmvnic_stats[i].offset));
|
|
|
|
for (j = 0; j < adapter->req_tx_queues; j++) {
|
|
- data[i] = adapter->tx_stats_buffers[j].packets;
|
|
+ data[i] = adapter->tx_stats_buffers[j].batched_packets;
|
|
+ i++;
|
|
+ data[i] = adapter->tx_stats_buffers[j].direct_packets;
|
|
i++;
|
|
data[i] = adapter->tx_stats_buffers[j].bytes;
|
|
i++;
|
|
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
|
|
index 4e18b4cefa972c..b3fc18db4f4c39 100644
|
|
--- a/drivers/net/ethernet/ibm/ibmvnic.h
|
|
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
|
|
@@ -213,7 +213,8 @@ struct ibmvnic_statistics {
|
|
|
|
#define NUM_TX_STATS 3
|
|
struct ibmvnic_tx_queue_stats {
|
|
- u64 packets;
|
|
+ u64 batched_packets;
|
|
+ u64 direct_packets;
|
|
u64 bytes;
|
|
u64 dropped_packets;
|
|
};
|
|
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
|
|
index 6e431f587c233a..b34f57ab9755ce 100644
|
|
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
|
|
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
|
|
@@ -6110,7 +6110,9 @@ static void mlx5e_remove(struct auxiliary_device *adev)
|
|
mlx5e_dcbnl_delete_app(priv);
|
|
unregister_netdev(priv->netdev);
|
|
mlx5e_suspend(adev, state);
|
|
- priv->profile->cleanup(priv);
|
|
+ /* Avoid cleanup if profile rollback failed. */
|
|
+ if (priv->profile)
|
|
+ priv->profile->cleanup(priv);
|
|
mlx5e_destroy_netdev(priv);
|
|
mlx5e_devlink_port_unregister(mlx5e_dev);
|
|
mlx5e_destroy_devlink(mlx5e_dev);
|
|
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
|
|
index 2ec62c8d86e1c1..59486fe2ad18c2 100644
|
|
--- a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
|
|
+++ b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
|
|
@@ -20,6 +20,8 @@ nfp_bpf_cmsg_alloc(struct nfp_app_bpf *bpf, unsigned int size)
|
|
struct sk_buff *skb;
|
|
|
|
skb = nfp_app_ctrl_msg_alloc(bpf->app, size, GFP_KERNEL);
|
|
+ if (!skb)
|
|
+ return NULL;
|
|
skb_put(skb, size);
|
|
|
|
return skb;
|
|
diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
|
|
index 02e11827440b5c..3517a2275821ff 100644
|
|
--- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
|
|
+++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c
|
|
@@ -2161,6 +2161,7 @@ static int axienet_probe(struct platform_device *pdev)
|
|
|
|
lp->phylink_config.dev = &ndev->dev;
|
|
lp->phylink_config.type = PHYLINK_NETDEV;
|
|
+ lp->phylink_config.mac_managed_pm = true;
|
|
lp->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
|
|
MAC_10FD | MAC_100FD | MAC_1000FD;
|
|
|
|
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
|
|
index b939d4711c59b6..27761334e1bff7 100644
|
|
--- a/drivers/net/geneve.c
|
|
+++ b/drivers/net/geneve.c
|
|
@@ -1961,21 +1961,9 @@ static void geneve_destroy_tunnels(struct net *net, struct list_head *head)
|
|
{
|
|
struct geneve_net *gn = net_generic(net, geneve_net_id);
|
|
struct geneve_dev *geneve, *next;
|
|
- struct net_device *dev, *aux;
|
|
|
|
- /* gather any geneve devices that were moved into this ns */
|
|
- for_each_netdev_safe(net, dev, aux)
|
|
- if (dev->rtnl_link_ops == &geneve_link_ops)
|
|
- unregister_netdevice_queue(dev, head);
|
|
-
|
|
- /* now gather any other geneve devices that were created in this ns */
|
|
- list_for_each_entry_safe(geneve, next, &gn->geneve_list, next) {
|
|
- /* If geneve->dev is in the same netns, it was already added
|
|
- * to the list by the previous loop.
|
|
- */
|
|
- if (!net_eq(dev_net(geneve->dev), net))
|
|
- unregister_netdevice_queue(geneve->dev, head);
|
|
- }
|
|
+ list_for_each_entry_safe(geneve, next, &gn->geneve_list, next)
|
|
+ geneve_dellink(geneve->dev, head);
|
|
}
|
|
|
|
static void __net_exit geneve_exit_batch_net(struct list_head *net_list)
|
|
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
|
|
index 47238c3ec82e75..55160a5fc90fc6 100644
|
|
--- a/drivers/net/gtp.c
|
|
+++ b/drivers/net/gtp.c
|
|
@@ -1895,11 +1895,6 @@ static void __net_exit gtp_net_exit_batch_rtnl(struct list_head *net_list,
|
|
list_for_each_entry(net, net_list, exit_list) {
|
|
struct gtp_net *gn = net_generic(net, gtp_net_id);
|
|
struct gtp_dev *gtp, *gtp_next;
|
|
- struct net_device *dev;
|
|
-
|
|
- for_each_netdev(net, dev)
|
|
- if (dev->rtnl_link_ops == >p_link_ops)
|
|
- gtp_dellink(dev, dev_to_kill);
|
|
|
|
list_for_each_entry_safe(gtp, gtp_next, &gn->gtp_dev_list, list)
|
|
gtp_dellink(gtp->dev, dev_to_kill);
|
|
diff --git a/drivers/nvme/host/ioctl.c b/drivers/nvme/host/ioctl.c
|
|
index 19a7f0160618d1..4ce31f9f069475 100644
|
|
--- a/drivers/nvme/host/ioctl.c
|
|
+++ b/drivers/nvme/host/ioctl.c
|
|
@@ -336,8 +336,7 @@ static bool nvme_validate_passthru_nsid(struct nvme_ctrl *ctrl,
|
|
{
|
|
if (ns && nsid != ns->head->ns_id) {
|
|
dev_err(ctrl->device,
|
|
- "%s: nsid (%u) in cmd does not match nsid (%u)"
|
|
- "of namespace\n",
|
|
+ "%s: nsid (%u) in cmd does not match nsid (%u) of namespace\n",
|
|
current->comm, nsid, ns->head->ns_id);
|
|
return false;
|
|
}
|
|
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
|
|
index fd11d3825cf854..3ea94bc26e8003 100644
|
|
--- a/drivers/nvmem/core.c
|
|
+++ b/drivers/nvmem/core.c
|
|
@@ -19,29 +19,7 @@
|
|
#include <linux/of.h>
|
|
#include <linux/slab.h>
|
|
|
|
-struct nvmem_device {
|
|
- struct module *owner;
|
|
- struct device dev;
|
|
- int stride;
|
|
- int word_size;
|
|
- int id;
|
|
- struct kref refcnt;
|
|
- size_t size;
|
|
- bool read_only;
|
|
- bool root_only;
|
|
- int flags;
|
|
- enum nvmem_type type;
|
|
- struct bin_attribute eeprom;
|
|
- struct device *base_dev;
|
|
- struct list_head cells;
|
|
- const struct nvmem_keepout *keepout;
|
|
- unsigned int nkeepout;
|
|
- nvmem_reg_read_t reg_read;
|
|
- nvmem_reg_write_t reg_write;
|
|
- struct gpio_desc *wp_gpio;
|
|
- struct nvmem_layout *layout;
|
|
- void *priv;
|
|
-};
|
|
+#include "internals.h"
|
|
|
|
#define to_nvmem_device(d) container_of(d, struct nvmem_device, dev)
|
|
|
|
@@ -696,7 +674,6 @@ static int nvmem_validate_keepouts(struct nvmem_device *nvmem)
|
|
|
|
static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_node *np)
|
|
{
|
|
- struct nvmem_layout *layout = nvmem->layout;
|
|
struct device *dev = &nvmem->dev;
|
|
struct device_node *child;
|
|
const __be32 *addr;
|
|
@@ -726,8 +703,8 @@ static int nvmem_add_cells_from_dt(struct nvmem_device *nvmem, struct device_nod
|
|
|
|
info.np = of_node_get(child);
|
|
|
|
- if (layout && layout->fixup_cell_info)
|
|
- layout->fixup_cell_info(nvmem, layout, &info);
|
|
+ if (nvmem->fixup_dt_cell_info)
|
|
+ nvmem->fixup_dt_cell_info(nvmem, &info);
|
|
|
|
ret = nvmem_add_one_cell(nvmem, &info);
|
|
kfree(info.name);
|
|
@@ -837,7 +814,7 @@ static int nvmem_add_cells_from_layout(struct nvmem_device *nvmem)
|
|
int ret;
|
|
|
|
if (layout && layout->add_cells) {
|
|
- ret = layout->add_cells(&nvmem->dev, nvmem, layout);
|
|
+ ret = layout->add_cells(&nvmem->dev, nvmem);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
@@ -924,6 +901,7 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config)
|
|
|
|
kref_init(&nvmem->refcnt);
|
|
INIT_LIST_HEAD(&nvmem->cells);
|
|
+ nvmem->fixup_dt_cell_info = config->fixup_dt_cell_info;
|
|
|
|
nvmem->owner = config->owner;
|
|
if (!nvmem->owner && config->dev->driver)
|
|
diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c
|
|
index dfc925edfc83e0..1356ec93bfd00c 100644
|
|
--- a/drivers/nvmem/imx-ocotp-ele.c
|
|
+++ b/drivers/nvmem/imx-ocotp-ele.c
|
|
@@ -107,6 +107,26 @@ static int imx_ocotp_reg_read(void *context, unsigned int offset, void *val, siz
|
|
return 0;
|
|
};
|
|
|
|
+static int imx_ocotp_cell_pp(void *context, const char *id, int index,
|
|
+ unsigned int offset, void *data, size_t bytes)
|
|
+{
|
|
+ u8 *buf = data;
|
|
+ int i;
|
|
+
|
|
+ /* Deal with some post processing of nvmem cell data */
|
|
+ if (id && !strcmp(id, "mac-address"))
|
|
+ for (i = 0; i < bytes / 2; i++)
|
|
+ swap(buf[i], buf[bytes - i - 1]);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem,
|
|
+ struct nvmem_cell_info *cell)
|
|
+{
|
|
+ cell->read_post_process = imx_ocotp_cell_pp;
|
|
+}
|
|
+
|
|
static int imx_ele_ocotp_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
@@ -133,6 +153,8 @@ static int imx_ele_ocotp_probe(struct platform_device *pdev)
|
|
priv->config.stride = 1;
|
|
priv->config.priv = priv;
|
|
priv->config.read_only = true;
|
|
+ priv->config.add_legacy_fixed_of_cells = true;
|
|
+ priv->config.fixup_dt_cell_info = imx_ocotp_fixup_dt_cell_info;
|
|
mutex_init(&priv->lock);
|
|
|
|
nvmem = devm_nvmem_register(dev, &priv->config);
|
|
diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c
|
|
index f1e202efaa4970..79dd4fda03295a 100644
|
|
--- a/drivers/nvmem/imx-ocotp.c
|
|
+++ b/drivers/nvmem/imx-ocotp.c
|
|
@@ -583,17 +583,12 @@ static const struct of_device_id imx_ocotp_dt_ids[] = {
|
|
};
|
|
MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids);
|
|
|
|
-static void imx_ocotp_fixup_cell_info(struct nvmem_device *nvmem,
|
|
- struct nvmem_layout *layout,
|
|
- struct nvmem_cell_info *cell)
|
|
+static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem,
|
|
+ struct nvmem_cell_info *cell)
|
|
{
|
|
cell->read_post_process = imx_ocotp_cell_pp;
|
|
}
|
|
|
|
-static struct nvmem_layout imx_ocotp_layout = {
|
|
- .fixup_cell_info = imx_ocotp_fixup_cell_info,
|
|
-};
|
|
-
|
|
static int imx_ocotp_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
@@ -619,7 +614,7 @@ static int imx_ocotp_probe(struct platform_device *pdev)
|
|
imx_ocotp_nvmem_config.size = 4 * priv->params->nregs;
|
|
imx_ocotp_nvmem_config.dev = dev;
|
|
imx_ocotp_nvmem_config.priv = priv;
|
|
- imx_ocotp_nvmem_config.layout = &imx_ocotp_layout;
|
|
+ imx_ocotp_nvmem_config.fixup_dt_cell_info = &imx_ocotp_fixup_dt_cell_info;
|
|
|
|
priv->config = &imx_ocotp_nvmem_config;
|
|
|
|
diff --git a/drivers/nvmem/internals.h b/drivers/nvmem/internals.h
|
|
new file mode 100644
|
|
index 00000000000000..893553fbdf51aa
|
|
--- /dev/null
|
|
+++ b/drivers/nvmem/internals.h
|
|
@@ -0,0 +1,37 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+
|
|
+#ifndef _LINUX_NVMEM_INTERNALS_H
|
|
+#define _LINUX_NVMEM_INTERNALS_H
|
|
+
|
|
+#include <linux/device.h>
|
|
+#include <linux/nvmem-consumer.h>
|
|
+#include <linux/nvmem-provider.h>
|
|
+
|
|
+struct nvmem_device {
|
|
+ struct module *owner;
|
|
+ struct device dev;
|
|
+ struct list_head node;
|
|
+ int stride;
|
|
+ int word_size;
|
|
+ int id;
|
|
+ struct kref refcnt;
|
|
+ size_t size;
|
|
+ bool read_only;
|
|
+ bool root_only;
|
|
+ int flags;
|
|
+ enum nvmem_type type;
|
|
+ struct bin_attribute eeprom;
|
|
+ struct device *base_dev;
|
|
+ struct list_head cells;
|
|
+ void (*fixup_dt_cell_info)(struct nvmem_device *nvmem,
|
|
+ struct nvmem_cell_info *cell);
|
|
+ const struct nvmem_keepout *keepout;
|
|
+ unsigned int nkeepout;
|
|
+ nvmem_reg_read_t reg_read;
|
|
+ nvmem_reg_write_t reg_write;
|
|
+ struct gpio_desc *wp_gpio;
|
|
+ struct nvmem_layout *layout;
|
|
+ void *priv;
|
|
+};
|
|
+
|
|
+#endif /* ifndef _LINUX_NVMEM_INTERNALS_H */
|
|
diff --git a/drivers/nvmem/layouts/onie-tlv.c b/drivers/nvmem/layouts/onie-tlv.c
|
|
index 59fc87ccfcffeb..defd42d4375cc1 100644
|
|
--- a/drivers/nvmem/layouts/onie-tlv.c
|
|
+++ b/drivers/nvmem/layouts/onie-tlv.c
|
|
@@ -182,8 +182,7 @@ static bool onie_tlv_crc_is_valid(struct device *dev, size_t table_len, u8 *tabl
|
|
return true;
|
|
}
|
|
|
|
-static int onie_tlv_parse_table(struct device *dev, struct nvmem_device *nvmem,
|
|
- struct nvmem_layout *layout)
|
|
+static int onie_tlv_parse_table(struct device *dev, struct nvmem_device *nvmem)
|
|
{
|
|
struct onie_tlv_hdr hdr;
|
|
size_t table_len, data_len, hdr_len;
|
|
diff --git a/drivers/nvmem/layouts/sl28vpd.c b/drivers/nvmem/layouts/sl28vpd.c
|
|
index 05671371f63166..26c7cf21b52336 100644
|
|
--- a/drivers/nvmem/layouts/sl28vpd.c
|
|
+++ b/drivers/nvmem/layouts/sl28vpd.c
|
|
@@ -80,8 +80,7 @@ static int sl28vpd_v1_check_crc(struct device *dev, struct nvmem_device *nvmem)
|
|
return 0;
|
|
}
|
|
|
|
-static int sl28vpd_add_cells(struct device *dev, struct nvmem_device *nvmem,
|
|
- struct nvmem_layout *layout)
|
|
+static int sl28vpd_add_cells(struct device *dev, struct nvmem_device *nvmem)
|
|
{
|
|
const struct nvmem_cell_info *pinfo;
|
|
struct nvmem_cell_info info = {0};
|
|
diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c
|
|
index 87c94686cfd216..84f05b40a4112e 100644
|
|
--- a/drivers/nvmem/mtk-efuse.c
|
|
+++ b/drivers/nvmem/mtk-efuse.c
|
|
@@ -45,9 +45,8 @@ static int mtk_efuse_gpu_speedbin_pp(void *context, const char *id, int index,
|
|
return 0;
|
|
}
|
|
|
|
-static void mtk_efuse_fixup_cell_info(struct nvmem_device *nvmem,
|
|
- struct nvmem_layout *layout,
|
|
- struct nvmem_cell_info *cell)
|
|
+static void mtk_efuse_fixup_dt_cell_info(struct nvmem_device *nvmem,
|
|
+ struct nvmem_cell_info *cell)
|
|
{
|
|
size_t sz = strlen(cell->name);
|
|
|
|
@@ -61,10 +60,6 @@ static void mtk_efuse_fixup_cell_info(struct nvmem_device *nvmem,
|
|
cell->read_post_process = mtk_efuse_gpu_speedbin_pp;
|
|
}
|
|
|
|
-static struct nvmem_layout mtk_efuse_layout = {
|
|
- .fixup_cell_info = mtk_efuse_fixup_cell_info,
|
|
-};
|
|
-
|
|
static int mtk_efuse_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
@@ -91,7 +86,7 @@ static int mtk_efuse_probe(struct platform_device *pdev)
|
|
econfig.priv = priv;
|
|
econfig.dev = dev;
|
|
if (pdata->uses_post_processing)
|
|
- econfig.layout = &mtk_efuse_layout;
|
|
+ econfig.fixup_dt_cell_info = &mtk_efuse_fixup_dt_cell_info;
|
|
nvmem = devm_nvmem_register(dev, &econfig);
|
|
|
|
return PTR_ERR_OR_ZERO(nvmem);
|
|
diff --git a/drivers/power/supply/da9150-fg.c b/drivers/power/supply/da9150-fg.c
|
|
index 652c1f213af1c2..4f28ef1bba1a3c 100644
|
|
--- a/drivers/power/supply/da9150-fg.c
|
|
+++ b/drivers/power/supply/da9150-fg.c
|
|
@@ -247,9 +247,9 @@ static int da9150_fg_current_avg(struct da9150_fg *fg,
|
|
DA9150_QIF_SD_GAIN_SIZE);
|
|
da9150_fg_read_sync_end(fg);
|
|
|
|
- div = (u64) (sd_gain * shunt_val * 65536ULL);
|
|
+ div = 65536ULL * sd_gain * shunt_val;
|
|
do_div(div, 1000000);
|
|
- res = (u64) (iavg * 1000000ULL);
|
|
+ res = 1000000ULL * iavg;
|
|
do_div(res, div);
|
|
|
|
val->intval = (int) res;
|
|
diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c
|
|
index f6a0626a6b3ec6..af0d90beba6380 100644
|
|
--- a/drivers/s390/net/ism_drv.c
|
|
+++ b/drivers/s390/net/ism_drv.c
|
|
@@ -611,6 +611,15 @@ static int ism_dev_init(struct ism_dev *ism)
|
|
return ret;
|
|
}
|
|
|
|
+static void ism_dev_release(struct device *dev)
|
|
+{
|
|
+ struct ism_dev *ism;
|
|
+
|
|
+ ism = container_of(dev, struct ism_dev, dev);
|
|
+
|
|
+ kfree(ism);
|
|
+}
|
|
+
|
|
static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
{
|
|
struct ism_dev *ism;
|
|
@@ -624,6 +633,7 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
dev_set_drvdata(&pdev->dev, ism);
|
|
ism->pdev = pdev;
|
|
ism->dev.parent = &pdev->dev;
|
|
+ ism->dev.release = ism_dev_release;
|
|
device_initialize(&ism->dev);
|
|
dev_set_name(&ism->dev, dev_name(&pdev->dev));
|
|
ret = device_add(&ism->dev);
|
|
@@ -660,7 +670,7 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|
device_del(&ism->dev);
|
|
err_dev:
|
|
dev_set_drvdata(&pdev->dev, NULL);
|
|
- kfree(ism);
|
|
+ put_device(&ism->dev);
|
|
|
|
return ret;
|
|
}
|
|
@@ -706,7 +716,7 @@ static void ism_remove(struct pci_dev *pdev)
|
|
pci_disable_device(pdev);
|
|
device_del(&ism->dev);
|
|
dev_set_drvdata(&pdev->dev, NULL);
|
|
- kfree(ism);
|
|
+ put_device(&ism->dev);
|
|
}
|
|
|
|
static struct pci_driver ism_driver = {
|
|
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
|
|
index 97def2619ecf2a..f026377f1cf1c4 100644
|
|
--- a/drivers/scsi/scsi_lib.c
|
|
+++ b/drivers/scsi/scsi_lib.c
|
|
@@ -774,12 +774,18 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
|
|
case 0x1a: /* start stop unit in progress */
|
|
case 0x1b: /* sanitize in progress */
|
|
case 0x1d: /* configuration in progress */
|
|
- case 0x24: /* depopulation in progress */
|
|
action = ACTION_DELAYED_RETRY;
|
|
break;
|
|
case 0x0a: /* ALUA state transition */
|
|
action = ACTION_DELAYED_REPREP;
|
|
break;
|
|
+ /*
|
|
+ * Depopulation might take many hours,
|
|
+ * thus it is not worthwhile to retry.
|
|
+ */
|
|
+ case 0x24: /* depopulation in progress */
|
|
+ case 0x25: /* depopulation restore in progress */
|
|
+ fallthrough;
|
|
default:
|
|
action = ACTION_FAIL;
|
|
break;
|
|
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
|
|
index 2c627deedc1fa2..fe694fec16b516 100644
|
|
--- a/drivers/scsi/sd.c
|
|
+++ b/drivers/scsi/sd.c
|
|
@@ -2309,6 +2309,10 @@ sd_spinup_disk(struct scsi_disk *sdkp)
|
|
break; /* unavailable */
|
|
if (sshdr.asc == 4 && sshdr.ascq == 0x1b)
|
|
break; /* sanitize in progress */
|
|
+ if (sshdr.asc == 4 && sshdr.ascq == 0x24)
|
|
+ break; /* depopulation in progress */
|
|
+ if (sshdr.asc == 4 && sshdr.ascq == 0x25)
|
|
+ break; /* depopulation restoration in progress */
|
|
/*
|
|
* Issue command to spin up drive when not ready
|
|
*/
|
|
diff --git a/drivers/soc/loongson/loongson2_guts.c b/drivers/soc/loongson/loongson2_guts.c
|
|
index 9a469779eea75b..2d7045ee4ac87d 100644
|
|
--- a/drivers/soc/loongson/loongson2_guts.c
|
|
+++ b/drivers/soc/loongson/loongson2_guts.c
|
|
@@ -114,8 +114,11 @@ static int loongson2_guts_probe(struct platform_device *pdev)
|
|
if (of_property_read_string(root, "model", &machine))
|
|
of_property_read_string_index(root, "compatible", 0, &machine);
|
|
of_node_put(root);
|
|
- if (machine)
|
|
+ if (machine) {
|
|
soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
|
|
+ if (!soc_dev_attr.machine)
|
|
+ return -ENOMEM;
|
|
+ }
|
|
|
|
svr = loongson2_guts_get_svr();
|
|
soc_die = loongson2_soc_die_match(svr, loongson2_soc_die);
|
|
diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
|
|
index 0dfc1da9471cba..d83a46334adbbe 100644
|
|
--- a/drivers/soc/mediatek/mtk-devapc.c
|
|
+++ b/drivers/soc/mediatek/mtk-devapc.c
|
|
@@ -300,18 +300,17 @@ static int mtk_devapc_probe(struct platform_device *pdev)
|
|
return ret;
|
|
}
|
|
|
|
-static int mtk_devapc_remove(struct platform_device *pdev)
|
|
+static void mtk_devapc_remove(struct platform_device *pdev)
|
|
{
|
|
struct mtk_devapc_context *ctx = platform_get_drvdata(pdev);
|
|
|
|
stop_devapc(ctx);
|
|
-
|
|
- return 0;
|
|
+ iounmap(ctx->infra_base);
|
|
}
|
|
|
|
static struct platform_driver mtk_devapc_driver = {
|
|
.probe = mtk_devapc_probe,
|
|
- .remove = mtk_devapc_remove,
|
|
+ .remove_new = mtk_devapc_remove,
|
|
.driver = {
|
|
.name = "mtk-devapc",
|
|
.of_match_table = mtk_devapc_dt_match,
|
|
diff --git a/drivers/tee/optee/supp.c b/drivers/tee/optee/supp.c
|
|
index 322a543b8c278a..d0f397c9024201 100644
|
|
--- a/drivers/tee/optee/supp.c
|
|
+++ b/drivers/tee/optee/supp.c
|
|
@@ -80,7 +80,6 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
|
|
struct optee *optee = tee_get_drvdata(ctx->teedev);
|
|
struct optee_supp *supp = &optee->supp;
|
|
struct optee_supp_req *req;
|
|
- bool interruptable;
|
|
u32 ret;
|
|
|
|
/*
|
|
@@ -111,36 +110,18 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
|
|
/*
|
|
* Wait for supplicant to process and return result, once we've
|
|
* returned from wait_for_completion(&req->c) successfully we have
|
|
- * exclusive access again.
|
|
+ * exclusive access again. Allow the wait to be killable such that
|
|
+ * the wait doesn't turn into an indefinite state if the supplicant
|
|
+ * gets hung for some reason.
|
|
*/
|
|
- while (wait_for_completion_interruptible(&req->c)) {
|
|
+ if (wait_for_completion_killable(&req->c)) {
|
|
mutex_lock(&supp->mutex);
|
|
- interruptable = !supp->ctx;
|
|
- if (interruptable) {
|
|
- /*
|
|
- * There's no supplicant available and since the
|
|
- * supp->mutex currently is held none can
|
|
- * become available until the mutex released
|
|
- * again.
|
|
- *
|
|
- * Interrupting an RPC to supplicant is only
|
|
- * allowed as a way of slightly improving the user
|
|
- * experience in case the supplicant hasn't been
|
|
- * started yet. During normal operation the supplicant
|
|
- * will serve all requests in a timely manner and
|
|
- * interrupting then wouldn't make sense.
|
|
- */
|
|
- if (req->in_queue) {
|
|
- list_del(&req->link);
|
|
- req->in_queue = false;
|
|
- }
|
|
+ if (req->in_queue) {
|
|
+ list_del(&req->link);
|
|
+ req->in_queue = false;
|
|
}
|
|
mutex_unlock(&supp->mutex);
|
|
-
|
|
- if (interruptable) {
|
|
- req->ret = TEEC_ERROR_COMMUNICATION;
|
|
- break;
|
|
- }
|
|
+ req->ret = TEEC_ERROR_COMMUNICATION;
|
|
}
|
|
|
|
ret = req->ret;
|
|
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
|
|
index 49946af11a9058..6d91d7d7a23f85 100644
|
|
--- a/drivers/usb/gadget/function/f_midi.c
|
|
+++ b/drivers/usb/gadget/function/f_midi.c
|
|
@@ -282,7 +282,7 @@ f_midi_complete(struct usb_ep *ep, struct usb_request *req)
|
|
/* Our transmit completed. See if there's more to go.
|
|
* f_midi_transmit eats req, don't queue it again. */
|
|
req->length = 0;
|
|
- f_midi_transmit(midi);
|
|
+ queue_work(system_highpri_wq, &midi->work);
|
|
return;
|
|
}
|
|
break;
|
|
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
|
|
index 33979f61dc4dd7..a4120a25428e5d 100644
|
|
--- a/drivers/usb/gadget/udc/core.c
|
|
+++ b/drivers/usb/gadget/udc/core.c
|
|
@@ -1419,8 +1419,16 @@ int usb_add_gadget(struct usb_gadget *gadget)
|
|
if (ret)
|
|
goto err_free_id;
|
|
|
|
+ ret = sysfs_create_link(&udc->dev.kobj,
|
|
+ &gadget->dev.kobj, "gadget");
|
|
+ if (ret)
|
|
+ goto err_del_gadget;
|
|
+
|
|
return 0;
|
|
|
|
+ err_del_gadget:
|
|
+ device_del(&gadget->dev);
|
|
+
|
|
err_free_id:
|
|
ida_free(&gadget_id_numbers, gadget->id_number);
|
|
|
|
@@ -1529,8 +1537,9 @@ void usb_del_gadget(struct usb_gadget *gadget)
|
|
mutex_unlock(&udc_lock);
|
|
|
|
kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
|
|
- flush_work(&gadget->work);
|
|
+ sysfs_remove_link(&udc->dev.kobj, "gadget");
|
|
device_del(&gadget->dev);
|
|
+ flush_work(&gadget->work);
|
|
ida_free(&gadget_id_numbers, gadget->id_number);
|
|
cancel_work_sync(&udc->vbus_work);
|
|
device_unregister(&udc->dev);
|
|
diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c
|
|
index 652279c8b1680a..49ca762baa8f15 100644
|
|
--- a/fs/nilfs2/dir.c
|
|
+++ b/fs/nilfs2/dir.c
|
|
@@ -64,12 +64,6 @@ static inline unsigned int nilfs_chunk_size(struct inode *inode)
|
|
return inode->i_sb->s_blocksize;
|
|
}
|
|
|
|
-static inline void nilfs_put_page(struct page *page)
|
|
-{
|
|
- kunmap(page);
|
|
- put_page(page);
|
|
-}
|
|
-
|
|
/*
|
|
* Return the offset into page `page_nr' of the last valid
|
|
* byte in that page, plus one.
|
|
@@ -450,8 +444,7 @@ int nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr, ino_t *ino)
|
|
return 0;
|
|
}
|
|
|
|
-/* Releases the page */
|
|
-void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
|
|
+int nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
|
|
struct page *page, struct inode *inode)
|
|
{
|
|
unsigned int from = (char *)de - (char *)page_address(page);
|
|
@@ -461,12 +454,15 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
|
|
|
|
lock_page(page);
|
|
err = nilfs_prepare_chunk(page, from, to);
|
|
- BUG_ON(err);
|
|
+ if (unlikely(err)) {
|
|
+ unlock_page(page);
|
|
+ return err;
|
|
+ }
|
|
de->inode = cpu_to_le64(inode->i_ino);
|
|
nilfs_set_de_type(de, inode);
|
|
nilfs_commit_chunk(page, mapping, from, to);
|
|
- nilfs_put_page(page);
|
|
dir->i_mtime = inode_set_ctime_current(dir);
|
|
+ return 0;
|
|
}
|
|
|
|
/*
|
|
@@ -569,7 +565,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode)
|
|
|
|
/*
|
|
* nilfs_delete_entry deletes a directory entry by merging it with the
|
|
- * previous entry. Page is up-to-date. Releases the page.
|
|
+ * previous entry. Page is up-to-date.
|
|
*/
|
|
int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
|
|
{
|
|
@@ -598,14 +594,16 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
|
|
from = (char *)pde - (char *)page_address(page);
|
|
lock_page(page);
|
|
err = nilfs_prepare_chunk(page, from, to);
|
|
- BUG_ON(err);
|
|
+ if (unlikely(err)) {
|
|
+ unlock_page(page);
|
|
+ goto out;
|
|
+ }
|
|
if (pde)
|
|
pde->rec_len = nilfs_rec_len_to_disk(to - from);
|
|
dir->inode = 0;
|
|
nilfs_commit_chunk(page, mapping, from, to);
|
|
inode->i_mtime = inode_set_ctime_current(inode);
|
|
out:
|
|
- nilfs_put_page(page);
|
|
return err;
|
|
}
|
|
|
|
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
|
|
index ac0adeb58e4104..43f01fe556fe17 100644
|
|
--- a/fs/nilfs2/namei.c
|
|
+++ b/fs/nilfs2/namei.c
|
|
@@ -297,6 +297,7 @@ static int nilfs_do_unlink(struct inode *dir, struct dentry *dentry)
|
|
set_nlink(inode, 1);
|
|
}
|
|
err = nilfs_delete_entry(de, page);
|
|
+ nilfs_put_page(page);
|
|
if (err)
|
|
goto out;
|
|
|
|
@@ -405,7 +406,10 @@ static int nilfs_rename(struct mnt_idmap *idmap,
|
|
err = PTR_ERR(new_de);
|
|
goto out_dir;
|
|
}
|
|
- nilfs_set_link(new_dir, new_de, new_page, old_inode);
|
|
+ err = nilfs_set_link(new_dir, new_de, new_page, old_inode);
|
|
+ nilfs_put_page(new_page);
|
|
+ if (unlikely(err))
|
|
+ goto out_dir;
|
|
nilfs_mark_inode_dirty(new_dir);
|
|
inode_set_ctime_current(new_inode);
|
|
if (dir_de)
|
|
@@ -428,28 +432,27 @@ static int nilfs_rename(struct mnt_idmap *idmap,
|
|
*/
|
|
inode_set_ctime_current(old_inode);
|
|
|
|
- nilfs_delete_entry(old_de, old_page);
|
|
-
|
|
- if (dir_de) {
|
|
- nilfs_set_link(old_inode, dir_de, dir_page, new_dir);
|
|
- drop_nlink(old_dir);
|
|
+ err = nilfs_delete_entry(old_de, old_page);
|
|
+ if (likely(!err)) {
|
|
+ if (dir_de) {
|
|
+ err = nilfs_set_link(old_inode, dir_de, dir_page,
|
|
+ new_dir);
|
|
+ drop_nlink(old_dir);
|
|
+ }
|
|
+ nilfs_mark_inode_dirty(old_dir);
|
|
}
|
|
- nilfs_mark_inode_dirty(old_dir);
|
|
nilfs_mark_inode_dirty(old_inode);
|
|
|
|
- err = nilfs_transaction_commit(old_dir->i_sb);
|
|
- return err;
|
|
-
|
|
out_dir:
|
|
- if (dir_de) {
|
|
- kunmap(dir_page);
|
|
- put_page(dir_page);
|
|
- }
|
|
+ if (dir_de)
|
|
+ nilfs_put_page(dir_page);
|
|
out_old:
|
|
- kunmap(old_page);
|
|
- put_page(old_page);
|
|
+ nilfs_put_page(old_page);
|
|
out:
|
|
- nilfs_transaction_abort(old_dir->i_sb);
|
|
+ if (likely(!err))
|
|
+ err = nilfs_transaction_commit(old_dir->i_sb);
|
|
+ else
|
|
+ nilfs_transaction_abort(old_dir->i_sb);
|
|
return err;
|
|
}
|
|
|
|
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h
|
|
index e2c5376b56cd8e..4c4b7686548434 100644
|
|
--- a/fs/nilfs2/nilfs.h
|
|
+++ b/fs/nilfs2/nilfs.h
|
|
@@ -240,8 +240,14 @@ nilfs_find_entry(struct inode *, const struct qstr *, struct page **);
|
|
extern int nilfs_delete_entry(struct nilfs_dir_entry *, struct page *);
|
|
extern int nilfs_empty_dir(struct inode *);
|
|
extern struct nilfs_dir_entry *nilfs_dotdot(struct inode *, struct page **);
|
|
-extern void nilfs_set_link(struct inode *, struct nilfs_dir_entry *,
|
|
- struct page *, struct inode *);
|
|
+int nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
|
|
+ struct page *page, struct inode *inode);
|
|
+
|
|
+static inline void nilfs_put_page(struct page *page)
|
|
+{
|
|
+ kunmap(page);
|
|
+ put_page(page);
|
|
+}
|
|
|
|
/* file.c */
|
|
extern int nilfs_sync_file(struct file *, loff_t, loff_t, int);
|
|
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
|
|
index 8d3fa2a3b8a956..b809a616728f27 100644
|
|
--- a/fs/smb/client/smb2ops.c
|
|
+++ b/fs/smb/client/smb2ops.c
|
|
@@ -4905,6 +4905,10 @@ receive_encrypted_standard(struct TCP_Server_Info *server,
|
|
next_buffer = (char *)cifs_buf_get();
|
|
else
|
|
next_buffer = (char *)cifs_small_buf_get();
|
|
+ if (!next_buffer) {
|
|
+ cifs_server_dbg(VFS, "No memory for (large) SMB response\n");
|
|
+ return -1;
|
|
+ }
|
|
memcpy(next_buffer, buf + next_cmd, pdu_length - next_cmd);
|
|
}
|
|
|
|
diff --git a/fs/xfs/libxfs/xfs_ag.c b/fs/xfs/libxfs/xfs_ag.c
|
|
index 1531bd0ee359c9..ea0e9492b37402 100644
|
|
--- a/fs/xfs/libxfs/xfs_ag.c
|
|
+++ b/fs/xfs/libxfs/xfs_ag.c
|
|
@@ -357,31 +357,37 @@ xfs_free_unused_perag_range(
|
|
}
|
|
}
|
|
|
|
+int
|
|
+xfs_update_last_ag_size(
|
|
+ struct xfs_mount *mp,
|
|
+ xfs_agnumber_t prev_agcount)
|
|
+{
|
|
+ struct xfs_perag *pag = xfs_perag_grab(mp, prev_agcount - 1);
|
|
+
|
|
+ if (!pag)
|
|
+ return -EFSCORRUPTED;
|
|
+ pag->block_count = __xfs_ag_block_count(mp, prev_agcount - 1,
|
|
+ mp->m_sb.sb_agcount, mp->m_sb.sb_dblocks);
|
|
+ __xfs_agino_range(mp, pag->block_count, &pag->agino_min,
|
|
+ &pag->agino_max);
|
|
+ xfs_perag_rele(pag);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int
|
|
xfs_initialize_perag(
|
|
struct xfs_mount *mp,
|
|
- xfs_agnumber_t agcount,
|
|
+ xfs_agnumber_t old_agcount,
|
|
+ xfs_agnumber_t new_agcount,
|
|
xfs_rfsblock_t dblocks,
|
|
xfs_agnumber_t *maxagi)
|
|
{
|
|
struct xfs_perag *pag;
|
|
xfs_agnumber_t index;
|
|
- xfs_agnumber_t first_initialised = NULLAGNUMBER;
|
|
int error;
|
|
|
|
- /*
|
|
- * Walk the current per-ag tree so we don't try to initialise AGs
|
|
- * that already exist (growfs case). Allocate and insert all the
|
|
- * AGs we don't find ready for initialisation.
|
|
- */
|
|
- for (index = 0; index < agcount; index++) {
|
|
- pag = xfs_perag_get(mp, index);
|
|
- if (pag) {
|
|
- xfs_perag_put(pag);
|
|
- continue;
|
|
- }
|
|
-
|
|
- pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
|
|
+ for (index = old_agcount; index < new_agcount; index++) {
|
|
+ pag = kmem_zalloc(sizeof(*pag), 0);
|
|
if (!pag) {
|
|
error = -ENOMEM;
|
|
goto out_unwind_new_pags;
|
|
@@ -425,21 +431,17 @@ xfs_initialize_perag(
|
|
/* Active ref owned by mount indicates AG is online. */
|
|
atomic_set(&pag->pag_active_ref, 1);
|
|
|
|
- /* first new pag is fully initialized */
|
|
- if (first_initialised == NULLAGNUMBER)
|
|
- first_initialised = index;
|
|
-
|
|
/*
|
|
* Pre-calculated geometry
|
|
*/
|
|
- pag->block_count = __xfs_ag_block_count(mp, index, agcount,
|
|
+ pag->block_count = __xfs_ag_block_count(mp, index, new_agcount,
|
|
dblocks);
|
|
pag->min_block = XFS_AGFL_BLOCK(mp);
|
|
__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
|
|
&pag->agino_max);
|
|
}
|
|
|
|
- index = xfs_set_inode_alloc(mp, agcount);
|
|
+ index = xfs_set_inode_alloc(mp, new_agcount);
|
|
|
|
if (maxagi)
|
|
*maxagi = index;
|
|
@@ -455,8 +457,7 @@ xfs_initialize_perag(
|
|
out_free_pag:
|
|
kmem_free(pag);
|
|
out_unwind_new_pags:
|
|
- /* unwind any prior newly initialized pags */
|
|
- xfs_free_unused_perag_range(mp, first_initialised, agcount);
|
|
+ xfs_free_unused_perag_range(mp, old_agcount, index);
|
|
return error;
|
|
}
|
|
|
|
diff --git a/fs/xfs/libxfs/xfs_ag.h b/fs/xfs/libxfs/xfs_ag.h
|
|
index 40d7b6427afb5d..423c489fec5832 100644
|
|
--- a/fs/xfs/libxfs/xfs_ag.h
|
|
+++ b/fs/xfs/libxfs/xfs_ag.h
|
|
@@ -135,10 +135,12 @@ __XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET)
|
|
|
|
void xfs_free_unused_perag_range(struct xfs_mount *mp, xfs_agnumber_t agstart,
|
|
xfs_agnumber_t agend);
|
|
-int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
|
|
- xfs_rfsblock_t dcount, xfs_agnumber_t *maxagi);
|
|
+int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t old_agcount,
|
|
+ xfs_agnumber_t agcount, xfs_rfsblock_t dcount,
|
|
+ xfs_agnumber_t *maxagi);
|
|
int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
|
|
void xfs_free_perag(struct xfs_mount *mp);
|
|
+int xfs_update_last_ag_size(struct xfs_mount *mp, xfs_agnumber_t prev_agcount);
|
|
|
|
/* Passive AG references */
|
|
struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);
|
|
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
|
|
index 100ab5931b3132..ad2fa3c26f8a94 100644
|
|
--- a/fs/xfs/libxfs/xfs_alloc.c
|
|
+++ b/fs/xfs/libxfs/xfs_alloc.c
|
|
@@ -1783,7 +1783,7 @@ xfs_alloc_ag_vextent_size(
|
|
error = -EFSCORRUPTED;
|
|
goto error0;
|
|
}
|
|
- if (flen < bestrlen)
|
|
+ if (flen <= bestrlen)
|
|
break;
|
|
busy = xfs_alloc_compute_aligned(args, fbno, flen,
|
|
&rbno, &rlen, &busy_gen);
|
|
@@ -2581,7 +2581,6 @@ __xfs_free_extent_later(
|
|
return 0;
|
|
}
|
|
|
|
-#ifdef DEBUG
|
|
/*
|
|
* Check if an AGF has a free extent record whose length is equal to
|
|
* args->minlen.
|
|
@@ -2620,7 +2619,6 @@ xfs_exact_minlen_extent_available(
|
|
|
|
return error;
|
|
}
|
|
-#endif
|
|
|
|
/*
|
|
* Decide whether to use this allocation group for this allocation.
|
|
@@ -2694,15 +2692,14 @@ xfs_alloc_fix_freelist(
|
|
if (!xfs_alloc_space_available(args, need, alloc_flags))
|
|
goto out_agbp_relse;
|
|
|
|
-#ifdef DEBUG
|
|
- if (args->alloc_minlen_only) {
|
|
+ if (IS_ENABLED(CONFIG_XFS_DEBUG) && args->alloc_minlen_only) {
|
|
int stat;
|
|
|
|
error = xfs_exact_minlen_extent_available(args, agbp, &stat);
|
|
if (error || !stat)
|
|
goto out_agbp_relse;
|
|
}
|
|
-#endif
|
|
+
|
|
/*
|
|
* Make the freelist shorter if it's too long.
|
|
*
|
|
diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h
|
|
index 6bb8d295c321d2..a12294cb83bbaf 100644
|
|
--- a/fs/xfs/libxfs/xfs_alloc.h
|
|
+++ b/fs/xfs/libxfs/xfs_alloc.h
|
|
@@ -53,11 +53,9 @@ typedef struct xfs_alloc_arg {
|
|
int datatype; /* mask defining data type treatment */
|
|
char wasdel; /* set if allocation was prev delayed */
|
|
char wasfromfl; /* set if allocation is from freelist */
|
|
+ bool alloc_minlen_only; /* allocate exact minlen extent */
|
|
struct xfs_owner_info oinfo; /* owner of blocks being allocated */
|
|
enum xfs_ag_resv_type resv; /* block reservation to use */
|
|
-#ifdef DEBUG
|
|
- bool alloc_minlen_only; /* allocate exact minlen extent */
|
|
-#endif
|
|
} xfs_alloc_arg_t;
|
|
|
|
/*
|
|
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
|
|
index 33edf047e0ad2f..50172bb8026fd9 100644
|
|
--- a/fs/xfs/libxfs/xfs_attr.c
|
|
+++ b/fs/xfs/libxfs/xfs_attr.c
|
|
@@ -50,7 +50,6 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
|
|
STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
|
|
STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
|
|
STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
|
|
-STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args);
|
|
|
|
/*
|
|
* Internal routines when attribute list is more than one block.
|
|
@@ -401,6 +400,33 @@ xfs_attr_sf_addname(
|
|
return error;
|
|
}
|
|
|
|
+/* Save the current remote block info and clear the current pointers. */
|
|
+static void
|
|
+xfs_attr_save_rmt_blk(
|
|
+ struct xfs_da_args *args)
|
|
+{
|
|
+ args->blkno2 = args->blkno;
|
|
+ args->index2 = args->index;
|
|
+ args->rmtblkno2 = args->rmtblkno;
|
|
+ args->rmtblkcnt2 = args->rmtblkcnt;
|
|
+ args->rmtvaluelen2 = args->rmtvaluelen;
|
|
+ args->rmtblkno = 0;
|
|
+ args->rmtblkcnt = 0;
|
|
+ args->rmtvaluelen = 0;
|
|
+}
|
|
+
|
|
+/* Set stored info about a remote block */
|
|
+static void
|
|
+xfs_attr_restore_rmt_blk(
|
|
+ struct xfs_da_args *args)
|
|
+{
|
|
+ args->blkno = args->blkno2;
|
|
+ args->index = args->index2;
|
|
+ args->rmtblkno = args->rmtblkno2;
|
|
+ args->rmtblkcnt = args->rmtblkcnt2;
|
|
+ args->rmtvaluelen = args->rmtvaluelen2;
|
|
+}
|
|
+
|
|
/*
|
|
* Handle the state change on completion of a multi-state attr operation.
|
|
*
|
|
@@ -428,48 +454,73 @@ xfs_attr_complete_op(
|
|
return XFS_DAS_DONE;
|
|
}
|
|
|
|
+/*
|
|
+ * Try to add an attribute to an inode in leaf form.
|
|
+ */
|
|
static int
|
|
xfs_attr_leaf_addname(
|
|
struct xfs_attr_intent *attr)
|
|
{
|
|
struct xfs_da_args *args = attr->xattri_da_args;
|
|
+ struct xfs_buf *bp;
|
|
int error;
|
|
|
|
ASSERT(xfs_attr_is_leaf(args->dp));
|
|
|
|
+ error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
|
|
+ if (error)
|
|
+ return error;
|
|
+
|
|
/*
|
|
- * Use the leaf buffer we may already hold locked as a result of
|
|
- * a sf-to-leaf conversion.
|
|
+ * Look up the xattr name to set the insertion point for the new xattr.
|
|
*/
|
|
- error = xfs_attr_leaf_try_add(args);
|
|
-
|
|
- if (error == -ENOSPC) {
|
|
- error = xfs_attr3_leaf_to_node(args);
|
|
- if (error)
|
|
- return error;
|
|
+ error = xfs_attr3_leaf_lookup_int(bp, args);
|
|
+ switch (error) {
|
|
+ case -ENOATTR:
|
|
+ if (args->op_flags & XFS_DA_OP_REPLACE)
|
|
+ goto out_brelse;
|
|
+ break;
|
|
+ case -EEXIST:
|
|
+ if (!(args->op_flags & XFS_DA_OP_REPLACE))
|
|
+ goto out_brelse;
|
|
|
|
+ trace_xfs_attr_leaf_replace(args);
|
|
/*
|
|
- * We're not in leaf format anymore, so roll the transaction and
|
|
- * retry the add to the newly allocated node block.
|
|
+ * Save the existing remote attr state so that the current
|
|
+ * values reflect the state of the new attribute we are about to
|
|
+ * add, not the attribute we just found and will remove later.
|
|
*/
|
|
- attr->xattri_dela_state = XFS_DAS_NODE_ADD;
|
|
- goto out;
|
|
+ xfs_attr_save_rmt_blk(args);
|
|
+ break;
|
|
+ case 0:
|
|
+ break;
|
|
+ default:
|
|
+ goto out_brelse;
|
|
}
|
|
- if (error)
|
|
- return error;
|
|
|
|
/*
|
|
* We need to commit and roll if we need to allocate remote xattr blocks
|
|
* or perform more xattr manipulations. Otherwise there is nothing more
|
|
* to do and we can return success.
|
|
*/
|
|
- if (args->rmtblkno)
|
|
+ if (!xfs_attr3_leaf_add(bp, args)) {
|
|
+ error = xfs_attr3_leaf_to_node(args);
|
|
+ if (error)
|
|
+ return error;
|
|
+
|
|
+ attr->xattri_dela_state = XFS_DAS_NODE_ADD;
|
|
+ } else if (args->rmtblkno) {
|
|
attr->xattri_dela_state = XFS_DAS_LEAF_SET_RMT;
|
|
- else
|
|
- attr->xattri_dela_state = xfs_attr_complete_op(attr,
|
|
- XFS_DAS_LEAF_REPLACE);
|
|
-out:
|
|
+ } else {
|
|
+ attr->xattri_dela_state =
|
|
+ xfs_attr_complete_op(attr, XFS_DAS_LEAF_REPLACE);
|
|
+ }
|
|
+
|
|
trace_xfs_attr_leaf_addname_return(attr->xattri_dela_state, args->dp);
|
|
+ return 0;
|
|
+
|
|
+out_brelse:
|
|
+ xfs_trans_brelse(args->trans, bp);
|
|
return error;
|
|
}
|
|
|
|
@@ -492,7 +543,7 @@ xfs_attr_node_addname(
|
|
return error;
|
|
|
|
error = xfs_attr_node_try_addname(attr);
|
|
- if (error == -ENOSPC) {
|
|
+ if (error == 1) {
|
|
error = xfs_attr3_leaf_to_node(args);
|
|
if (error)
|
|
return error;
|
|
@@ -1164,88 +1215,6 @@ xfs_attr_shortform_addname(
|
|
* External routines when attribute list is one block
|
|
*========================================================================*/
|
|
|
|
-/* Save the current remote block info and clear the current pointers. */
|
|
-static void
|
|
-xfs_attr_save_rmt_blk(
|
|
- struct xfs_da_args *args)
|
|
-{
|
|
- args->blkno2 = args->blkno;
|
|
- args->index2 = args->index;
|
|
- args->rmtblkno2 = args->rmtblkno;
|
|
- args->rmtblkcnt2 = args->rmtblkcnt;
|
|
- args->rmtvaluelen2 = args->rmtvaluelen;
|
|
- args->rmtblkno = 0;
|
|
- args->rmtblkcnt = 0;
|
|
- args->rmtvaluelen = 0;
|
|
-}
|
|
-
|
|
-/* Set stored info about a remote block */
|
|
-static void
|
|
-xfs_attr_restore_rmt_blk(
|
|
- struct xfs_da_args *args)
|
|
-{
|
|
- args->blkno = args->blkno2;
|
|
- args->index = args->index2;
|
|
- args->rmtblkno = args->rmtblkno2;
|
|
- args->rmtblkcnt = args->rmtblkcnt2;
|
|
- args->rmtvaluelen = args->rmtvaluelen2;
|
|
-}
|
|
-
|
|
-/*
|
|
- * Tries to add an attribute to an inode in leaf form
|
|
- *
|
|
- * This function is meant to execute as part of a delayed operation and leaves
|
|
- * the transaction handling to the caller. On success the attribute is added
|
|
- * and the inode and transaction are left dirty. If there is not enough space,
|
|
- * the attr data is converted to node format and -ENOSPC is returned. Caller is
|
|
- * responsible for handling the dirty inode and transaction or adding the attr
|
|
- * in node format.
|
|
- */
|
|
-STATIC int
|
|
-xfs_attr_leaf_try_add(
|
|
- struct xfs_da_args *args)
|
|
-{
|
|
- struct xfs_buf *bp;
|
|
- int error;
|
|
-
|
|
- error = xfs_attr3_leaf_read(args->trans, args->dp, 0, &bp);
|
|
- if (error)
|
|
- return error;
|
|
-
|
|
- /*
|
|
- * Look up the xattr name to set the insertion point for the new xattr.
|
|
- */
|
|
- error = xfs_attr3_leaf_lookup_int(bp, args);
|
|
- switch (error) {
|
|
- case -ENOATTR:
|
|
- if (args->op_flags & XFS_DA_OP_REPLACE)
|
|
- goto out_brelse;
|
|
- break;
|
|
- case -EEXIST:
|
|
- if (!(args->op_flags & XFS_DA_OP_REPLACE))
|
|
- goto out_brelse;
|
|
-
|
|
- trace_xfs_attr_leaf_replace(args);
|
|
- /*
|
|
- * Save the existing remote attr state so that the current
|
|
- * values reflect the state of the new attribute we are about to
|
|
- * add, not the attribute we just found and will remove later.
|
|
- */
|
|
- xfs_attr_save_rmt_blk(args);
|
|
- break;
|
|
- case 0:
|
|
- break;
|
|
- default:
|
|
- goto out_brelse;
|
|
- }
|
|
-
|
|
- return xfs_attr3_leaf_add(bp, args);
|
|
-
|
|
-out_brelse:
|
|
- xfs_trans_brelse(args->trans, bp);
|
|
- return error;
|
|
-}
|
|
-
|
|
/*
|
|
* Return EEXIST if attr is found, or ENOATTR if not
|
|
*/
|
|
@@ -1411,9 +1380,12 @@ xfs_attr_node_addname_find_attr(
|
|
/*
|
|
* Add a name to a Btree-format attribute list.
|
|
*
|
|
- * This will involve walking down the Btree, and may involve splitting
|
|
- * leaf nodes and even splitting intermediate nodes up to and including
|
|
- * the root node (a special case of an intermediate node).
|
|
+ * This will involve walking down the Btree, and may involve splitting leaf
|
|
+ * nodes and even splitting intermediate nodes up to and including the root
|
|
+ * node (a special case of an intermediate node).
|
|
+ *
|
|
+ * If the tree was still in single leaf format and needs to converted to
|
|
+ * real node format return 1 and let the caller handle that.
|
|
*/
|
|
static int
|
|
xfs_attr_node_try_addname(
|
|
@@ -1421,21 +1393,21 @@ xfs_attr_node_try_addname(
|
|
{
|
|
struct xfs_da_state *state = attr->xattri_da_state;
|
|
struct xfs_da_state_blk *blk;
|
|
- int error;
|
|
+ int error = 0;
|
|
|
|
trace_xfs_attr_node_addname(state->args);
|
|
|
|
blk = &state->path.blk[state->path.active-1];
|
|
ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
|
|
|
|
- error = xfs_attr3_leaf_add(blk->bp, state->args);
|
|
- if (error == -ENOSPC) {
|
|
+ if (!xfs_attr3_leaf_add(blk->bp, state->args)) {
|
|
if (state->path.active == 1) {
|
|
/*
|
|
* Its really a single leaf node, but it had
|
|
* out-of-line values so it looked like it *might*
|
|
* have been a b-tree. Let the caller deal with this.
|
|
*/
|
|
+ error = 1;
|
|
goto out;
|
|
}
|
|
|
|
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
|
|
index 51ff4406867539..4e5ede2a296a58 100644
|
|
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
|
|
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
|
|
@@ -46,7 +46,7 @@
|
|
*/
|
|
STATIC int xfs_attr3_leaf_create(struct xfs_da_args *args,
|
|
xfs_dablk_t which_block, struct xfs_buf **bpp);
|
|
-STATIC int xfs_attr3_leaf_add_work(struct xfs_buf *leaf_buffer,
|
|
+STATIC void xfs_attr3_leaf_add_work(struct xfs_buf *leaf_buffer,
|
|
struct xfs_attr3_icleaf_hdr *ichdr,
|
|
struct xfs_da_args *args, int freemap_index);
|
|
STATIC void xfs_attr3_leaf_compact(struct xfs_da_args *args,
|
|
@@ -990,10 +990,8 @@ xfs_attr_shortform_to_leaf(
|
|
}
|
|
error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */
|
|
ASSERT(error == -ENOATTR);
|
|
- error = xfs_attr3_leaf_add(bp, &nargs);
|
|
- ASSERT(error != -ENOSPC);
|
|
- if (error)
|
|
- goto out;
|
|
+ if (!xfs_attr3_leaf_add(bp, &nargs))
|
|
+ ASSERT(0);
|
|
sfe = xfs_attr_sf_nextentry(sfe);
|
|
}
|
|
error = 0;
|
|
@@ -1342,6 +1340,9 @@ xfs_attr3_leaf_create(
|
|
|
|
/*
|
|
* Split the leaf node, rebalance, then add the new entry.
|
|
+ *
|
|
+ * Returns 0 if the entry was added, 1 if a further split is needed or a
|
|
+ * negative error number otherwise.
|
|
*/
|
|
int
|
|
xfs_attr3_leaf_split(
|
|
@@ -1349,8 +1350,9 @@ xfs_attr3_leaf_split(
|
|
struct xfs_da_state_blk *oldblk,
|
|
struct xfs_da_state_blk *newblk)
|
|
{
|
|
- xfs_dablk_t blkno;
|
|
- int error;
|
|
+ bool added;
|
|
+ xfs_dablk_t blkno;
|
|
+ int error;
|
|
|
|
trace_xfs_attr_leaf_split(state->args);
|
|
|
|
@@ -1385,10 +1387,10 @@ xfs_attr3_leaf_split(
|
|
*/
|
|
if (state->inleaf) {
|
|
trace_xfs_attr_leaf_add_old(state->args);
|
|
- error = xfs_attr3_leaf_add(oldblk->bp, state->args);
|
|
+ added = xfs_attr3_leaf_add(oldblk->bp, state->args);
|
|
} else {
|
|
trace_xfs_attr_leaf_add_new(state->args);
|
|
- error = xfs_attr3_leaf_add(newblk->bp, state->args);
|
|
+ added = xfs_attr3_leaf_add(newblk->bp, state->args);
|
|
}
|
|
|
|
/*
|
|
@@ -1396,13 +1398,15 @@ xfs_attr3_leaf_split(
|
|
*/
|
|
oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL);
|
|
newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL);
|
|
- return error;
|
|
+ if (!added)
|
|
+ return 1;
|
|
+ return 0;
|
|
}
|
|
|
|
/*
|
|
* Add a name to the leaf attribute list structure.
|
|
*/
|
|
-int
|
|
+bool
|
|
xfs_attr3_leaf_add(
|
|
struct xfs_buf *bp,
|
|
struct xfs_da_args *args)
|
|
@@ -1411,6 +1415,7 @@ xfs_attr3_leaf_add(
|
|
struct xfs_attr3_icleaf_hdr ichdr;
|
|
int tablesize;
|
|
int entsize;
|
|
+ bool added = true;
|
|
int sum;
|
|
int tmp;
|
|
int i;
|
|
@@ -1439,7 +1444,7 @@ xfs_attr3_leaf_add(
|
|
if (ichdr.freemap[i].base < ichdr.firstused)
|
|
tmp += sizeof(xfs_attr_leaf_entry_t);
|
|
if (ichdr.freemap[i].size >= tmp) {
|
|
- tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, i);
|
|
+ xfs_attr3_leaf_add_work(bp, &ichdr, args, i);
|
|
goto out_log_hdr;
|
|
}
|
|
sum += ichdr.freemap[i].size;
|
|
@@ -1451,7 +1456,7 @@ xfs_attr3_leaf_add(
|
|
* no good and we should just give up.
|
|
*/
|
|
if (!ichdr.holes && sum < entsize)
|
|
- return -ENOSPC;
|
|
+ return false;
|
|
|
|
/*
|
|
* Compact the entries to coalesce free space.
|
|
@@ -1464,24 +1469,24 @@ xfs_attr3_leaf_add(
|
|
* free region, in freemap[0]. If it is not big enough, give up.
|
|
*/
|
|
if (ichdr.freemap[0].size < (entsize + sizeof(xfs_attr_leaf_entry_t))) {
|
|
- tmp = -ENOSPC;
|
|
+ added = false;
|
|
goto out_log_hdr;
|
|
}
|
|
|
|
- tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, 0);
|
|
+ xfs_attr3_leaf_add_work(bp, &ichdr, args, 0);
|
|
|
|
out_log_hdr:
|
|
xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr);
|
|
xfs_trans_log_buf(args->trans, bp,
|
|
XFS_DA_LOGRANGE(leaf, &leaf->hdr,
|
|
xfs_attr3_leaf_hdr_size(leaf)));
|
|
- return tmp;
|
|
+ return added;
|
|
}
|
|
|
|
/*
|
|
* Add a name to a leaf attribute list structure.
|
|
*/
|
|
-STATIC int
|
|
+STATIC void
|
|
xfs_attr3_leaf_add_work(
|
|
struct xfs_buf *bp,
|
|
struct xfs_attr3_icleaf_hdr *ichdr,
|
|
@@ -1599,7 +1604,6 @@ xfs_attr3_leaf_add_work(
|
|
}
|
|
}
|
|
ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index);
|
|
- return 0;
|
|
}
|
|
|
|
/*
|
|
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
|
|
index 368f4d9fa1d596..d15cc5b6f4a943 100644
|
|
--- a/fs/xfs/libxfs/xfs_attr_leaf.h
|
|
+++ b/fs/xfs/libxfs/xfs_attr_leaf.h
|
|
@@ -78,7 +78,7 @@ int xfs_attr3_leaf_split(struct xfs_da_state *state,
|
|
int xfs_attr3_leaf_lookup_int(struct xfs_buf *leaf,
|
|
struct xfs_da_args *args);
|
|
int xfs_attr3_leaf_getvalue(struct xfs_buf *bp, struct xfs_da_args *args);
|
|
-int xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer,
|
|
+bool xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer,
|
|
struct xfs_da_args *args);
|
|
int xfs_attr3_leaf_remove(struct xfs_buf *leaf_buffer,
|
|
struct xfs_da_args *args);
|
|
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
|
|
index e6ea35098e07f8..c111f691ea51a1 100644
|
|
--- a/fs/xfs/libxfs/xfs_bmap.c
|
|
+++ b/fs/xfs/libxfs/xfs_bmap.c
|
|
@@ -3388,31 +3388,19 @@ xfs_bmap_process_allocated_extent(
|
|
xfs_bmap_btalloc_accounting(ap, args);
|
|
}
|
|
|
|
-#ifdef DEBUG
|
|
static int
|
|
xfs_bmap_exact_minlen_extent_alloc(
|
|
- struct xfs_bmalloca *ap)
|
|
+ struct xfs_bmalloca *ap,
|
|
+ struct xfs_alloc_arg *args)
|
|
{
|
|
- struct xfs_mount *mp = ap->ip->i_mount;
|
|
- struct xfs_alloc_arg args = { .tp = ap->tp, .mp = mp };
|
|
- xfs_fileoff_t orig_offset;
|
|
- xfs_extlen_t orig_length;
|
|
- int error;
|
|
-
|
|
- ASSERT(ap->length);
|
|
-
|
|
if (ap->minlen != 1) {
|
|
- ap->blkno = NULLFSBLOCK;
|
|
- ap->length = 0;
|
|
+ args->fsbno = NULLFSBLOCK;
|
|
return 0;
|
|
}
|
|
|
|
- orig_offset = ap->offset;
|
|
- orig_length = ap->length;
|
|
-
|
|
- args.alloc_minlen_only = 1;
|
|
-
|
|
- xfs_bmap_compute_alignments(ap, &args);
|
|
+ args->alloc_minlen_only = 1;
|
|
+ args->minlen = args->maxlen = ap->minlen;
|
|
+ args->total = ap->total;
|
|
|
|
/*
|
|
* Unlike the longest extent available in an AG, we don't track
|
|
@@ -3422,39 +3410,16 @@ xfs_bmap_exact_minlen_extent_alloc(
|
|
* we need not be concerned about a drop in performance in
|
|
* "debug only" code paths.
|
|
*/
|
|
- ap->blkno = XFS_AGB_TO_FSB(mp, 0, 0);
|
|
+ ap->blkno = XFS_AGB_TO_FSB(ap->ip->i_mount, 0, 0);
|
|
|
|
- args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE;
|
|
- args.minlen = args.maxlen = ap->minlen;
|
|
- args.total = ap->total;
|
|
-
|
|
- args.alignment = 1;
|
|
- args.minalignslop = 0;
|
|
-
|
|
- args.minleft = ap->minleft;
|
|
- args.wasdel = ap->wasdel;
|
|
- args.resv = XFS_AG_RESV_NONE;
|
|
- args.datatype = ap->datatype;
|
|
-
|
|
- error = xfs_alloc_vextent_first_ag(&args, ap->blkno);
|
|
- if (error)
|
|
- return error;
|
|
-
|
|
- if (args.fsbno != NULLFSBLOCK) {
|
|
- xfs_bmap_process_allocated_extent(ap, &args, orig_offset,
|
|
- orig_length);
|
|
- } else {
|
|
- ap->blkno = NULLFSBLOCK;
|
|
- ap->length = 0;
|
|
- }
|
|
-
|
|
- return 0;
|
|
+ /*
|
|
+ * Call xfs_bmap_btalloc_low_space here as it first does a "normal" AG
|
|
+ * iteration and then drops args->total to args->minlen, which might be
|
|
+ * required to find an allocation for the transaction reservation when
|
|
+ * the file system is very full.
|
|
+ */
|
|
+ return xfs_bmap_btalloc_low_space(ap, args);
|
|
}
|
|
-#else
|
|
-
|
|
-#define xfs_bmap_exact_minlen_extent_alloc(bma) (-EFSCORRUPTED)
|
|
-
|
|
-#endif
|
|
|
|
/*
|
|
* If we are not low on available data blocks and we are allocating at
|
|
@@ -3712,8 +3677,11 @@ xfs_bmap_btalloc(
|
|
/* Trim the allocation back to the maximum an AG can fit. */
|
|
args.maxlen = min(ap->length, mp->m_ag_max_usable);
|
|
|
|
- if ((ap->datatype & XFS_ALLOC_USERDATA) &&
|
|
- xfs_inode_is_filestream(ap->ip))
|
|
+ if (unlikely(XFS_TEST_ERROR(false, mp,
|
|
+ XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
|
|
+ error = xfs_bmap_exact_minlen_extent_alloc(ap, &args);
|
|
+ else if ((ap->datatype & XFS_ALLOC_USERDATA) &&
|
|
+ xfs_inode_is_filestream(ap->ip))
|
|
error = xfs_bmap_btalloc_filestreams(ap, &args, stripe_align);
|
|
else
|
|
error = xfs_bmap_btalloc_best_length(ap, &args, stripe_align);
|
|
@@ -4077,43 +4045,6 @@ xfs_bmapi_reserve_delalloc(
|
|
return error;
|
|
}
|
|
|
|
-static int
|
|
-xfs_bmap_alloc_userdata(
|
|
- struct xfs_bmalloca *bma)
|
|
-{
|
|
- struct xfs_mount *mp = bma->ip->i_mount;
|
|
- int whichfork = xfs_bmapi_whichfork(bma->flags);
|
|
- int error;
|
|
-
|
|
- /*
|
|
- * Set the data type being allocated. For the data fork, the first data
|
|
- * in the file is treated differently to all other allocations. For the
|
|
- * attribute fork, we only need to ensure the allocated range is not on
|
|
- * the busy list.
|
|
- */
|
|
- bma->datatype = XFS_ALLOC_NOBUSY;
|
|
- if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK) {
|
|
- bma->datatype |= XFS_ALLOC_USERDATA;
|
|
- if (bma->offset == 0)
|
|
- bma->datatype |= XFS_ALLOC_INITIAL_USER_DATA;
|
|
-
|
|
- if (mp->m_dalign && bma->length >= mp->m_dalign) {
|
|
- error = xfs_bmap_isaeof(bma, whichfork);
|
|
- if (error)
|
|
- return error;
|
|
- }
|
|
-
|
|
- if (XFS_IS_REALTIME_INODE(bma->ip))
|
|
- return xfs_bmap_rtalloc(bma);
|
|
- }
|
|
-
|
|
- if (unlikely(XFS_TEST_ERROR(false, mp,
|
|
- XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
|
|
- return xfs_bmap_exact_minlen_extent_alloc(bma);
|
|
-
|
|
- return xfs_bmap_btalloc(bma);
|
|
-}
|
|
-
|
|
static int
|
|
xfs_bmapi_allocate(
|
|
struct xfs_bmalloca *bma)
|
|
@@ -4147,15 +4078,32 @@ xfs_bmapi_allocate(
|
|
else
|
|
bma->minlen = 1;
|
|
|
|
- if (bma->flags & XFS_BMAPI_METADATA) {
|
|
- if (unlikely(XFS_TEST_ERROR(false, mp,
|
|
- XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
|
|
- error = xfs_bmap_exact_minlen_extent_alloc(bma);
|
|
- else
|
|
- error = xfs_bmap_btalloc(bma);
|
|
- } else {
|
|
- error = xfs_bmap_alloc_userdata(bma);
|
|
+ if (!(bma->flags & XFS_BMAPI_METADATA)) {
|
|
+ /*
|
|
+ * For the data and COW fork, the first data in the file is
|
|
+ * treated differently to all other allocations. For the
|
|
+ * attribute fork, we only need to ensure the allocated range
|
|
+ * is not on the busy list.
|
|
+ */
|
|
+ bma->datatype = XFS_ALLOC_NOBUSY;
|
|
+ if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK) {
|
|
+ bma->datatype |= XFS_ALLOC_USERDATA;
|
|
+ if (bma->offset == 0)
|
|
+ bma->datatype |= XFS_ALLOC_INITIAL_USER_DATA;
|
|
+
|
|
+ if (mp->m_dalign && bma->length >= mp->m_dalign) {
|
|
+ error = xfs_bmap_isaeof(bma, whichfork);
|
|
+ if (error)
|
|
+ return error;
|
|
+ }
|
|
+ }
|
|
}
|
|
+
|
|
+ if ((bma->datatype & XFS_ALLOC_USERDATA) &&
|
|
+ XFS_IS_REALTIME_INODE(bma->ip))
|
|
+ error = xfs_bmap_rtalloc(bma);
|
|
+ else
|
|
+ error = xfs_bmap_btalloc(bma);
|
|
if (error)
|
|
return error;
|
|
if (bma->blkno == NULLFSBLOCK)
|
|
diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
|
|
index 12e3cca804b7ec..28bbfc31039c0e 100644
|
|
--- a/fs/xfs/libxfs/xfs_da_btree.c
|
|
+++ b/fs/xfs/libxfs/xfs_da_btree.c
|
|
@@ -522,9 +522,8 @@ xfs_da3_split(
|
|
switch (oldblk->magic) {
|
|
case XFS_ATTR_LEAF_MAGIC:
|
|
error = xfs_attr3_leaf_split(state, oldblk, newblk);
|
|
- if ((error != 0) && (error != -ENOSPC)) {
|
|
+ if (error < 0)
|
|
return error; /* GROT: attr is inconsistent */
|
|
- }
|
|
if (!error) {
|
|
addblk = newblk;
|
|
break;
|
|
@@ -546,6 +545,8 @@ xfs_da3_split(
|
|
error = xfs_attr3_leaf_split(state, newblk,
|
|
&state->extrablk);
|
|
}
|
|
+ if (error == 1)
|
|
+ return -ENOSPC;
|
|
if (error)
|
|
return error; /* GROT: attr inconsistent */
|
|
addblk = newblk;
|
|
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
|
|
index 5a2e7ddfa76d63..25b86ffc2ce327 100644
|
|
--- a/fs/xfs/libxfs/xfs_inode_fork.c
|
|
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
|
|
@@ -449,15 +449,15 @@ xfs_iroot_realloc(
|
|
}
|
|
|
|
/*
|
|
- * Only copy the records and pointers if there are any.
|
|
+ * Only copy the keys and pointers if there are any.
|
|
*/
|
|
if (new_max > 0) {
|
|
/*
|
|
- * First copy the records.
|
|
+ * First copy the keys.
|
|
*/
|
|
- op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1);
|
|
- np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1);
|
|
- memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t));
|
|
+ op = (char *)XFS_BMBT_KEY_ADDR(mp, ifp->if_broot, 1);
|
|
+ np = (char *)XFS_BMBT_KEY_ADDR(mp, new_broot, 1);
|
|
+ memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_key_t));
|
|
|
|
/*
|
|
* Then copy the pointers.
|
|
diff --git a/fs/xfs/libxfs/xfs_rtbitmap.c b/fs/xfs/libxfs/xfs_rtbitmap.c
|
|
index 760172a65aff31..d7d06dc89eb7e3 100644
|
|
--- a/fs/xfs/libxfs/xfs_rtbitmap.c
|
|
+++ b/fs/xfs/libxfs/xfs_rtbitmap.c
|
|
@@ -288,6 +288,8 @@ xfs_rtfind_forw(
|
|
xfs_rtword_t wdiff; /* difference from wanted value */
|
|
int word; /* word number in the buffer */
|
|
|
|
+ ASSERT(start <= limit);
|
|
+
|
|
/*
|
|
* Compute and read in starting bitmap block for starting block.
|
|
*/
|
|
diff --git a/fs/xfs/xfs_buf_item_recover.c b/fs/xfs/xfs_buf_item_recover.c
|
|
index 43167f543afc33..c12dee0cb7fc96 100644
|
|
--- a/fs/xfs/xfs_buf_item_recover.c
|
|
+++ b/fs/xfs/xfs_buf_item_recover.c
|
|
@@ -22,6 +22,9 @@
|
|
#include "xfs_inode.h"
|
|
#include "xfs_dir2.h"
|
|
#include "xfs_quota.h"
|
|
+#include "xfs_alloc.h"
|
|
+#include "xfs_ag.h"
|
|
+#include "xfs_sb.h"
|
|
|
|
/*
|
|
* This is the number of entries in the l_buf_cancel_table used during
|
|
@@ -684,6 +687,67 @@ xlog_recover_do_inode_buffer(
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+ * Update the in-memory superblock and perag structures from the primary SB
|
|
+ * buffer.
|
|
+ *
|
|
+ * This is required because transactions running after growfs may require the
|
|
+ * updated values to be set in a previous fully commit transaction.
|
|
+ */
|
|
+static int
|
|
+xlog_recover_do_primary_sb_buffer(
|
|
+ struct xfs_mount *mp,
|
|
+ struct xlog_recover_item *item,
|
|
+ struct xfs_buf *bp,
|
|
+ struct xfs_buf_log_format *buf_f,
|
|
+ xfs_lsn_t current_lsn)
|
|
+{
|
|
+ struct xfs_dsb *dsb = bp->b_addr;
|
|
+ xfs_agnumber_t orig_agcount = mp->m_sb.sb_agcount;
|
|
+ int error;
|
|
+
|
|
+ xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
|
|
+
|
|
+ if (orig_agcount == 0) {
|
|
+ xfs_alert(mp, "Trying to grow file system without AGs");
|
|
+ return -EFSCORRUPTED;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Update the in-core super block from the freshly recovered on-disk one.
|
|
+ */
|
|
+ xfs_sb_from_disk(&mp->m_sb, dsb);
|
|
+
|
|
+ if (mp->m_sb.sb_agcount < orig_agcount) {
|
|
+ xfs_alert(mp, "Shrinking AG count in log recovery not supported");
|
|
+ return -EFSCORRUPTED;
|
|
+ }
|
|
+
|
|
+ /*
|
|
+ * Growfs can also grow the last existing AG. In this case we also need
|
|
+ * to update the length in the in-core perag structure and values
|
|
+ * depending on it.
|
|
+ */
|
|
+ error = xfs_update_last_ag_size(mp, orig_agcount);
|
|
+ if (error)
|
|
+ return error;
|
|
+
|
|
+ /*
|
|
+ * Initialize the new perags, and also update various block and inode
|
|
+ * allocator setting based off the number of AGs or total blocks.
|
|
+ * Because of the latter this also needs to happen if the agcount did
|
|
+ * not change.
|
|
+ */
|
|
+ error = xfs_initialize_perag(mp, orig_agcount, mp->m_sb.sb_agcount,
|
|
+ mp->m_sb.sb_dblocks, &mp->m_maxagi);
|
|
+ if (error) {
|
|
+ xfs_warn(mp, "Failed recovery per-ag init: %d", error);
|
|
+ return error;
|
|
+ }
|
|
+ mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
/*
|
|
* V5 filesystems know the age of the buffer on disk being recovered. We can
|
|
* have newer objects on disk than we are replaying, and so for these cases we
|
|
@@ -967,6 +1031,12 @@ xlog_recover_buf_commit_pass2(
|
|
dirty = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f);
|
|
if (!dirty)
|
|
goto out_release;
|
|
+ } else if ((xfs_blft_from_flags(buf_f) & XFS_BLFT_SB_BUF) &&
|
|
+ xfs_buf_daddr(bp) == 0) {
|
|
+ error = xlog_recover_do_primary_sb_buffer(mp, item, bp, buf_f,
|
|
+ current_lsn);
|
|
+ if (error)
|
|
+ goto out_release;
|
|
} else {
|
|
xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn);
|
|
}
|
|
diff --git a/fs/xfs/xfs_filestream.c b/fs/xfs/xfs_filestream.c
|
|
index f62b023f274e96..4e1e8356121851 100644
|
|
--- a/fs/xfs/xfs_filestream.c
|
|
+++ b/fs/xfs/xfs_filestream.c
|
|
@@ -67,22 +67,28 @@ xfs_filestream_pick_ag(
|
|
xfs_extlen_t minfree, maxfree = 0;
|
|
xfs_agnumber_t agno;
|
|
bool first_pass = true;
|
|
- int err;
|
|
|
|
/* 2% of an AG's blocks must be free for it to be chosen. */
|
|
minfree = mp->m_sb.sb_agblocks / 50;
|
|
|
|
restart:
|
|
for_each_perag_wrap(mp, start_agno, agno, pag) {
|
|
+ int err;
|
|
+
|
|
trace_xfs_filestream_scan(pag, pino);
|
|
+
|
|
*longest = 0;
|
|
err = xfs_bmap_longest_free_extent(pag, NULL, longest);
|
|
if (err) {
|
|
- if (err != -EAGAIN)
|
|
- break;
|
|
- /* Couldn't lock the AGF, skip this AG. */
|
|
- err = 0;
|
|
- continue;
|
|
+ if (err == -EAGAIN) {
|
|
+ /* Couldn't lock the AGF, skip this AG. */
|
|
+ err = 0;
|
|
+ continue;
|
|
+ }
|
|
+ xfs_perag_rele(pag);
|
|
+ if (max_pag)
|
|
+ xfs_perag_rele(max_pag);
|
|
+ return err;
|
|
}
|
|
|
|
/* Keep track of the AG with the most free blocks. */
|
|
@@ -107,7 +113,9 @@ xfs_filestream_pick_ag(
|
|
!(flags & XFS_PICK_USERDATA) ||
|
|
(flags & XFS_PICK_LOWSPACE))) {
|
|
/* Break out, retaining the reference on the AG. */
|
|
- break;
|
|
+ if (max_pag)
|
|
+ xfs_perag_rele(max_pag);
|
|
+ goto done;
|
|
}
|
|
}
|
|
|
|
@@ -115,56 +123,44 @@ xfs_filestream_pick_ag(
|
|
atomic_dec(&pag->pagf_fstrms);
|
|
}
|
|
|
|
- if (err) {
|
|
- xfs_perag_rele(pag);
|
|
- if (max_pag)
|
|
- xfs_perag_rele(max_pag);
|
|
- return err;
|
|
+ /*
|
|
+ * Allow a second pass to give xfs_bmap_longest_free_extent() another
|
|
+ * attempt at locking AGFs that it might have skipped over before we
|
|
+ * fail.
|
|
+ */
|
|
+ if (first_pass) {
|
|
+ first_pass = false;
|
|
+ goto restart;
|
|
}
|
|
|
|
- if (!pag) {
|
|
- /*
|
|
- * Allow a second pass to give xfs_bmap_longest_free_extent()
|
|
- * another attempt at locking AGFs that it might have skipped
|
|
- * over before we fail.
|
|
- */
|
|
- if (first_pass) {
|
|
- first_pass = false;
|
|
- goto restart;
|
|
- }
|
|
-
|
|
- /*
|
|
- * We must be low on data space, so run a final lowspace
|
|
- * optimised selection pass if we haven't already.
|
|
- */
|
|
- if (!(flags & XFS_PICK_LOWSPACE)) {
|
|
- flags |= XFS_PICK_LOWSPACE;
|
|
- goto restart;
|
|
- }
|
|
-
|
|
- /*
|
|
- * No unassociated AGs are available, so select the AG with the
|
|
- * most free space, regardless of whether it's already in use by
|
|
- * another filestream. It none suit, just use whatever AG we can
|
|
- * grab.
|
|
- */
|
|
- if (!max_pag) {
|
|
- for_each_perag_wrap(args->mp, 0, start_agno, pag) {
|
|
- max_pag = pag;
|
|
- break;
|
|
- }
|
|
+ /*
|
|
+ * We must be low on data space, so run a final lowspace optimised
|
|
+ * selection pass if we haven't already.
|
|
+ */
|
|
+ if (!(flags & XFS_PICK_LOWSPACE)) {
|
|
+ flags |= XFS_PICK_LOWSPACE;
|
|
+ goto restart;
|
|
+ }
|
|
|
|
- /* Bail if there are no AGs at all to select from. */
|
|
- if (!max_pag)
|
|
- return -ENOSPC;
|
|
+ /*
|
|
+ * No unassociated AGs are available, so select the AG with the most
|
|
+ * free space, regardless of whether it's already in use by another
|
|
+ * filestream. It none suit, just use whatever AG we can grab.
|
|
+ */
|
|
+ if (!max_pag) {
|
|
+ for_each_perag_wrap(args->mp, 0, start_agno, pag) {
|
|
+ max_pag = pag;
|
|
+ break;
|
|
}
|
|
|
|
- pag = max_pag;
|
|
- atomic_inc(&pag->pagf_fstrms);
|
|
- } else if (max_pag) {
|
|
- xfs_perag_rele(max_pag);
|
|
+ /* Bail if there are no AGs at all to select from. */
|
|
+ if (!max_pag)
|
|
+ return -ENOSPC;
|
|
}
|
|
|
|
+ pag = max_pag;
|
|
+ atomic_inc(&pag->pagf_fstrms);
|
|
+done:
|
|
trace_xfs_filestream_pick(pag, pino);
|
|
args->pag = pag;
|
|
return 0;
|
|
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
|
|
index c3f0e3cae87e56..a2c1eab5fa4af8 100644
|
|
--- a/fs/xfs/xfs_fsops.c
|
|
+++ b/fs/xfs/xfs_fsops.c
|
|
@@ -87,6 +87,7 @@ xfs_growfs_data_private(
|
|
struct xfs_mount *mp, /* mount point for filesystem */
|
|
struct xfs_growfs_data *in) /* growfs data input struct */
|
|
{
|
|
+ xfs_agnumber_t oagcount = mp->m_sb.sb_agcount;
|
|
struct xfs_buf *bp;
|
|
int error;
|
|
xfs_agnumber_t nagcount;
|
|
@@ -94,7 +95,6 @@ xfs_growfs_data_private(
|
|
xfs_rfsblock_t nb, nb_div, nb_mod;
|
|
int64_t delta;
|
|
bool lastag_extended = false;
|
|
- xfs_agnumber_t oagcount;
|
|
struct xfs_trans *tp;
|
|
struct aghdr_init_data id = {};
|
|
struct xfs_perag *last_pag;
|
|
@@ -138,16 +138,14 @@ xfs_growfs_data_private(
|
|
if (delta == 0)
|
|
return 0;
|
|
|
|
- oagcount = mp->m_sb.sb_agcount;
|
|
- /* allocate the new per-ag structures */
|
|
- if (nagcount > oagcount) {
|
|
- error = xfs_initialize_perag(mp, nagcount, nb, &nagimax);
|
|
- if (error)
|
|
- return error;
|
|
- } else if (nagcount < oagcount) {
|
|
- /* TODO: shrinking the entire AGs hasn't yet completed */
|
|
+ /* TODO: shrinking the entire AGs hasn't yet completed */
|
|
+ if (nagcount < oagcount)
|
|
return -EINVAL;
|
|
- }
|
|
+
|
|
+ /* allocate the new per-ag structures */
|
|
+ error = xfs_initialize_perag(mp, oagcount, nagcount, nb, &nagimax);
|
|
+ if (error)
|
|
+ return error;
|
|
|
|
if (delta > 0)
|
|
error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata,
|
|
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
|
|
index 57a9f23175250a..c54a7c60e06332 100644
|
|
--- a/fs/xfs/xfs_icache.c
|
|
+++ b/fs/xfs/xfs_icache.c
|
|
@@ -748,7 +748,7 @@ xfs_iget(
|
|
ASSERT((lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED)) == 0);
|
|
|
|
/* reject inode numbers outside existing AGs */
|
|
- if (!ino || XFS_INO_TO_AGNO(mp, ino) >= mp->m_sb.sb_agcount)
|
|
+ if (!xfs_verify_ino(mp, ino))
|
|
return -EINVAL;
|
|
|
|
XFS_STATS_INC(mp, xs_ig_attempts);
|
|
@@ -1234,14 +1234,17 @@ xfs_inode_clear_eofblocks_tag(
|
|
}
|
|
|
|
/*
|
|
- * Set ourselves up to free CoW blocks from this file. If it's already clean
|
|
- * then we can bail out quickly, but otherwise we must back off if the file
|
|
- * is undergoing some kind of write.
|
|
+ * Prepare to free COW fork blocks from an inode.
|
|
*/
|
|
static bool
|
|
xfs_prep_free_cowblocks(
|
|
- struct xfs_inode *ip)
|
|
+ struct xfs_inode *ip,
|
|
+ struct xfs_icwalk *icw)
|
|
{
|
|
+ bool sync;
|
|
+
|
|
+ sync = icw && (icw->icw_flags & XFS_ICWALK_FLAG_SYNC);
|
|
+
|
|
/*
|
|
* Just clear the tag if we have an empty cow fork or none at all. It's
|
|
* possible the inode was fully unshared since it was originally tagged.
|
|
@@ -1253,16 +1256,22 @@ xfs_prep_free_cowblocks(
|
|
}
|
|
|
|
/*
|
|
- * If the mapping is dirty or under writeback we cannot touch the
|
|
- * CoW fork. Leave it alone if we're in the midst of a directio.
|
|
+ * A cowblocks trim of an inode can have a significant effect on
|
|
+ * fragmentation even when a reasonable COW extent size hint is set.
|
|
+ * Therefore, we prefer to not process cowblocks unless they are clean
|
|
+ * and idle. We can never process a cowblocks inode that is dirty or has
|
|
+ * in-flight I/O under any circumstances, because outstanding writeback
|
|
+ * or dio expects targeted COW fork blocks exist through write
|
|
+ * completion where they can be remapped into the data fork.
|
|
+ *
|
|
+ * Therefore, the heuristic used here is to never process inodes
|
|
+ * currently opened for write from background (i.e. non-sync) scans. For
|
|
+ * sync scans, use the pagecache/dio state of the inode to ensure we
|
|
+ * never free COW fork blocks out from under pending I/O.
|
|
*/
|
|
- if ((VFS_I(ip)->i_state & I_DIRTY_PAGES) ||
|
|
- mapping_tagged(VFS_I(ip)->i_mapping, PAGECACHE_TAG_DIRTY) ||
|
|
- mapping_tagged(VFS_I(ip)->i_mapping, PAGECACHE_TAG_WRITEBACK) ||
|
|
- atomic_read(&VFS_I(ip)->i_dio_count))
|
|
+ if (!sync && inode_is_open_for_write(VFS_I(ip)))
|
|
return false;
|
|
-
|
|
- return true;
|
|
+ return xfs_can_free_cowblocks(ip);
|
|
}
|
|
|
|
/*
|
|
@@ -1291,7 +1300,7 @@ xfs_inode_free_cowblocks(
|
|
if (!xfs_iflags_test(ip, XFS_ICOWBLOCKS))
|
|
return 0;
|
|
|
|
- if (!xfs_prep_free_cowblocks(ip))
|
|
+ if (!xfs_prep_free_cowblocks(ip, icw))
|
|
return 0;
|
|
|
|
if (!xfs_icwalk_match(ip, icw))
|
|
@@ -1320,7 +1329,7 @@ xfs_inode_free_cowblocks(
|
|
* Check again, nobody else should be able to dirty blocks or change
|
|
* the reflink iflag now that we have the first two locks held.
|
|
*/
|
|
- if (xfs_prep_free_cowblocks(ip))
|
|
+ if (xfs_prep_free_cowblocks(ip, icw))
|
|
ret = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF, false);
|
|
return ret;
|
|
}
|
|
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
|
|
index b9784348ebc5c4..e1adad91dba666 100644
|
|
--- a/fs/xfs/xfs_inode.c
|
|
+++ b/fs/xfs/xfs_inode.c
|
|
@@ -1758,7 +1758,7 @@ xfs_inactive(
|
|
|
|
if (S_ISREG(VFS_I(ip)->i_mode) &&
|
|
(ip->i_disk_size != 0 || XFS_ISIZE(ip) != 0 ||
|
|
- ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0))
|
|
+ xfs_inode_has_filedata(ip)))
|
|
truncate = 1;
|
|
|
|
if (xfs_iflags_test(ip, XFS_IQUOTAUNCHECKED)) {
|
|
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
|
|
index 0f2999b84e7d96..4820c4699f7d0f 100644
|
|
--- a/fs/xfs/xfs_inode.h
|
|
+++ b/fs/xfs/xfs_inode.h
|
|
@@ -286,6 +286,11 @@ static inline bool xfs_is_metadata_inode(struct xfs_inode *ip)
|
|
xfs_is_quota_inode(&mp->m_sb, ip->i_ino);
|
|
}
|
|
|
|
+static inline bool xfs_inode_has_filedata(const struct xfs_inode *ip)
|
|
+{
|
|
+ return ip->i_df.if_nextents > 0 || ip->i_delayed_blks > 0;
|
|
+}
|
|
+
|
|
/*
|
|
* Check if an inode has any data in the COW fork. This might be often false
|
|
* even for inodes with the reflink flag when there is no pending COW operation.
|
|
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
|
|
index 32e718043e0e2e..d22285a7453940 100644
|
|
--- a/fs/xfs/xfs_ioctl.c
|
|
+++ b/fs/xfs/xfs_ioctl.c
|
|
@@ -1126,7 +1126,7 @@ xfs_ioctl_setattr_xflags(
|
|
|
|
if (rtflag != XFS_IS_REALTIME_INODE(ip)) {
|
|
/* Can't change realtime flag if any extents are allocated. */
|
|
- if (ip->i_df.if_nextents || ip->i_delayed_blks)
|
|
+ if (xfs_inode_has_filedata(ip))
|
|
return -EINVAL;
|
|
|
|
/*
|
|
@@ -1247,7 +1247,7 @@ xfs_ioctl_setattr_check_extsize(
|
|
if (!fa->fsx_valid)
|
|
return 0;
|
|
|
|
- if (S_ISREG(VFS_I(ip)->i_mode) && ip->i_df.if_nextents &&
|
|
+ if (S_ISREG(VFS_I(ip)->i_mode) && xfs_inode_has_filedata(ip) &&
|
|
XFS_FSB_TO_B(mp, ip->i_extsize) != fa->fsx_extsize)
|
|
return -EINVAL;
|
|
|
|
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
|
|
index 2728886c296390..8e0f52599d8db5 100644
|
|
--- a/fs/xfs/xfs_log.h
|
|
+++ b/fs/xfs/xfs_log.h
|
|
@@ -161,6 +161,5 @@ bool xlog_force_shutdown(struct xlog *log, uint32_t shutdown_flags);
|
|
|
|
void xlog_use_incompat_feat(struct xlog *log);
|
|
void xlog_drop_incompat_feat(struct xlog *log);
|
|
-int xfs_attr_use_log_assist(struct xfs_mount *mp);
|
|
|
|
#endif /* __XFS_LOG_H__ */
|
|
diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c
|
|
index 67a99d94701e5b..d152d0945dab1c 100644
|
|
--- a/fs/xfs/xfs_log_cil.c
|
|
+++ b/fs/xfs/xfs_log_cil.c
|
|
@@ -156,7 +156,6 @@ xlog_cil_insert_pcp_aggregate(
|
|
struct xfs_cil *cil,
|
|
struct xfs_cil_ctx *ctx)
|
|
{
|
|
- struct xlog_cil_pcp *cilpcp;
|
|
int cpu;
|
|
int count = 0;
|
|
|
|
@@ -171,13 +170,11 @@ xlog_cil_insert_pcp_aggregate(
|
|
* structures that could have a nonzero space_used.
|
|
*/
|
|
for_each_cpu(cpu, &ctx->cil_pcpmask) {
|
|
- int old, prev;
|
|
+ struct xlog_cil_pcp *cilpcp = per_cpu_ptr(cil->xc_pcp, cpu);
|
|
+ int old = READ_ONCE(cilpcp->space_used);
|
|
|
|
- cilpcp = per_cpu_ptr(cil->xc_pcp, cpu);
|
|
- do {
|
|
- old = cilpcp->space_used;
|
|
- prev = cmpxchg(&cilpcp->space_used, old, 0);
|
|
- } while (old != prev);
|
|
+ while (!try_cmpxchg(&cilpcp->space_used, &old, 0))
|
|
+ ;
|
|
count += old;
|
|
}
|
|
atomic_add(count, &ctx->space_used);
|
|
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
|
|
index d11de0fa5c5f80..60382eb4996105 100644
|
|
--- a/fs/xfs/xfs_log_recover.c
|
|
+++ b/fs/xfs/xfs_log_recover.c
|
|
@@ -1820,7 +1820,7 @@ xlog_find_item_ops(
|
|
* from the transaction. However, we can't do that until after we've
|
|
* replayed all the other items because they may be dependent on the
|
|
* cancelled buffer and replaying the cancelled buffer can remove it
|
|
- * form the cancelled buffer table. Hence they have tobe done last.
|
|
+ * form the cancelled buffer table. Hence they have to be done last.
|
|
*
|
|
* 3. Inode allocation buffers must be replayed before inode items that
|
|
* read the buffer and replay changes into it. For filesystems using the
|
|
@@ -3365,13 +3365,6 @@ xlog_do_recover(
|
|
/* re-initialise in-core superblock and geometry structures */
|
|
mp->m_features |= xfs_sb_version_to_features(sbp);
|
|
xfs_reinit_percpu_counters(mp);
|
|
- error = xfs_initialize_perag(mp, sbp->sb_agcount, sbp->sb_dblocks,
|
|
- &mp->m_maxagi);
|
|
- if (error) {
|
|
- xfs_warn(mp, "Failed post-recovery per-ag init: %d", error);
|
|
- return error;
|
|
- }
|
|
- mp->m_alloc_set_aside = xfs_alloc_set_aside(mp);
|
|
|
|
/* Normal transactions can now occur */
|
|
clear_bit(XLOG_ACTIVE_RECOVERY, &log->l_opstate);
|
|
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
|
|
index 0a0fd19573d8ce..747db90731e894 100644
|
|
--- a/fs/xfs/xfs_mount.c
|
|
+++ b/fs/xfs/xfs_mount.c
|
|
@@ -797,8 +797,8 @@ xfs_mountfs(
|
|
/*
|
|
* Allocate and initialize the per-ag data.
|
|
*/
|
|
- error = xfs_initialize_perag(mp, sbp->sb_agcount, mp->m_sb.sb_dblocks,
|
|
- &mp->m_maxagi);
|
|
+ error = xfs_initialize_perag(mp, 0, sbp->sb_agcount,
|
|
+ mp->m_sb.sb_dblocks, &mp->m_maxagi);
|
|
if (error) {
|
|
xfs_warn(mp, "Failed per-ag init: %d", error);
|
|
goto out_free_dir;
|
|
diff --git a/fs/xfs/xfs_qm_bhv.c b/fs/xfs/xfs_qm_bhv.c
|
|
index b77673dd05581e..26b2c449f3c665 100644
|
|
--- a/fs/xfs/xfs_qm_bhv.c
|
|
+++ b/fs/xfs/xfs_qm_bhv.c
|
|
@@ -19,28 +19,41 @@
|
|
STATIC void
|
|
xfs_fill_statvfs_from_dquot(
|
|
struct kstatfs *statp,
|
|
+ struct xfs_inode *ip,
|
|
struct xfs_dquot *dqp)
|
|
{
|
|
+ struct xfs_dquot_res *blkres = &dqp->q_blk;
|
|
uint64_t limit;
|
|
|
|
- limit = dqp->q_blk.softlimit ?
|
|
- dqp->q_blk.softlimit :
|
|
- dqp->q_blk.hardlimit;
|
|
- if (limit && statp->f_blocks > limit) {
|
|
- statp->f_blocks = limit;
|
|
- statp->f_bfree = statp->f_bavail =
|
|
- (statp->f_blocks > dqp->q_blk.reserved) ?
|
|
- (statp->f_blocks - dqp->q_blk.reserved) : 0;
|
|
+ if (XFS_IS_REALTIME_MOUNT(ip->i_mount) &&
|
|
+ (ip->i_diflags & (XFS_DIFLAG_RTINHERIT | XFS_DIFLAG_REALTIME)))
|
|
+ blkres = &dqp->q_rtb;
|
|
+
|
|
+ limit = blkres->softlimit ?
|
|
+ blkres->softlimit :
|
|
+ blkres->hardlimit;
|
|
+ if (limit) {
|
|
+ uint64_t remaining = 0;
|
|
+
|
|
+ if (limit > blkres->reserved)
|
|
+ remaining = limit - blkres->reserved;
|
|
+
|
|
+ statp->f_blocks = min(statp->f_blocks, limit);
|
|
+ statp->f_bfree = min(statp->f_bfree, remaining);
|
|
+ statp->f_bavail = min(statp->f_bavail, remaining);
|
|
}
|
|
|
|
limit = dqp->q_ino.softlimit ?
|
|
dqp->q_ino.softlimit :
|
|
dqp->q_ino.hardlimit;
|
|
- if (limit && statp->f_files > limit) {
|
|
- statp->f_files = limit;
|
|
- statp->f_ffree =
|
|
- (statp->f_files > dqp->q_ino.reserved) ?
|
|
- (statp->f_files - dqp->q_ino.reserved) : 0;
|
|
+ if (limit) {
|
|
+ uint64_t remaining = 0;
|
|
+
|
|
+ if (limit > dqp->q_ino.reserved)
|
|
+ remaining = limit - dqp->q_ino.reserved;
|
|
+
|
|
+ statp->f_files = min(statp->f_files, limit);
|
|
+ statp->f_ffree = min(statp->f_ffree, remaining);
|
|
}
|
|
}
|
|
|
|
@@ -61,7 +74,7 @@ xfs_qm_statvfs(
|
|
struct xfs_dquot *dqp;
|
|
|
|
if (!xfs_qm_dqget(mp, ip->i_projid, XFS_DQTYPE_PROJ, false, &dqp)) {
|
|
- xfs_fill_statvfs_from_dquot(statp, dqp);
|
|
+ xfs_fill_statvfs_from_dquot(statp, ip, dqp);
|
|
xfs_qm_dqput(dqp);
|
|
}
|
|
}
|
|
diff --git a/fs/xfs/xfs_reflink.c b/fs/xfs/xfs_reflink.c
|
|
index 3431d0d8b6f3a1..4058cf361d2153 100644
|
|
--- a/fs/xfs/xfs_reflink.c
|
|
+++ b/fs/xfs/xfs_reflink.c
|
|
@@ -1600,6 +1600,9 @@ xfs_reflink_clear_inode_flag(
|
|
|
|
ASSERT(xfs_is_reflink_inode(ip));
|
|
|
|
+ if (!xfs_can_free_cowblocks(ip))
|
|
+ return 0;
|
|
+
|
|
error = xfs_reflink_inode_has_shared_extents(*tpp, ip, &needs_flag);
|
|
if (error || needs_flag)
|
|
return error;
|
|
diff --git a/fs/xfs/xfs_reflink.h b/fs/xfs/xfs_reflink.h
|
|
index 65c5dfe17ecf7f..67a335b247b157 100644
|
|
--- a/fs/xfs/xfs_reflink.h
|
|
+++ b/fs/xfs/xfs_reflink.h
|
|
@@ -16,6 +16,25 @@ static inline bool xfs_is_cow_inode(struct xfs_inode *ip)
|
|
return xfs_is_reflink_inode(ip) || xfs_is_always_cow_inode(ip);
|
|
}
|
|
|
|
+/*
|
|
+ * Check whether it is safe to free COW fork blocks from an inode. It is unsafe
|
|
+ * to do so when an inode has dirty cache or I/O in-flight, even if no shared
|
|
+ * extents exist in the data fork, because outstanding I/O may target blocks
|
|
+ * that were speculatively allocated to the COW fork.
|
|
+ */
|
|
+static inline bool
|
|
+xfs_can_free_cowblocks(struct xfs_inode *ip)
|
|
+{
|
|
+ struct inode *inode = VFS_I(ip);
|
|
+
|
|
+ if ((inode->i_state & I_DIRTY_PAGES) ||
|
|
+ mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY) ||
|
|
+ mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK) ||
|
|
+ atomic_read(&inode->i_dio_count))
|
|
+ return false;
|
|
+ return true;
|
|
+}
|
|
+
|
|
extern int xfs_reflink_trim_around_shared(struct xfs_inode *ip,
|
|
struct xfs_bmbt_irec *irec, bool *shared);
|
|
int xfs_bmap_trim_cow(struct xfs_inode *ip, struct xfs_bmbt_irec *imap,
|
|
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
|
|
index 13007b6bc9f337..a726fbba49e40a 100644
|
|
--- a/fs/xfs/xfs_super.c
|
|
+++ b/fs/xfs/xfs_super.c
|
|
@@ -878,12 +878,6 @@ xfs_fs_statfs(
|
|
ffree = statp->f_files - (icount - ifree);
|
|
statp->f_ffree = max_t(int64_t, ffree, 0);
|
|
|
|
-
|
|
- if ((ip->i_diflags & XFS_DIFLAG_PROJINHERIT) &&
|
|
- ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))) ==
|
|
- (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))
|
|
- xfs_qm_statvfs(ip, statp);
|
|
-
|
|
if (XFS_IS_REALTIME_MOUNT(mp) &&
|
|
(ip->i_diflags & (XFS_DIFLAG_RTINHERIT | XFS_DIFLAG_REALTIME))) {
|
|
s64 freertx;
|
|
@@ -893,6 +887,11 @@ xfs_fs_statfs(
|
|
statp->f_bavail = statp->f_bfree = freertx * sbp->sb_rextsize;
|
|
}
|
|
|
|
+ if ((ip->i_diflags & XFS_DIFLAG_PROJINHERIT) &&
|
|
+ ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))) ==
|
|
+ (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))
|
|
+ xfs_qm_statvfs(ip, statp);
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
|
|
index 95ee88dfe0b9c6..337a9d1c558f3c 100644
|
|
--- a/include/linux/netdevice.h
|
|
+++ b/include/linux/netdevice.h
|
|
@@ -3072,6 +3072,8 @@ static inline struct net_device *first_net_device_rcu(struct net *net)
|
|
}
|
|
|
|
int netdev_boot_setup_check(struct net_device *dev);
|
|
+struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type,
|
|
+ const char *hwaddr);
|
|
struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type,
|
|
const char *hwaddr);
|
|
struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type);
|
|
diff --git a/include/linux/nvmem-provider.h b/include/linux/nvmem-provider.h
|
|
index 1b81adebdb8beb..9a015e4d428ccb 100644
|
|
--- a/include/linux/nvmem-provider.h
|
|
+++ b/include/linux/nvmem-provider.h
|
|
@@ -83,6 +83,8 @@ struct nvmem_cell_info {
|
|
* @cells: Optional array of pre-defined NVMEM cells.
|
|
* @ncells: Number of elements in cells.
|
|
* @add_legacy_fixed_of_cells: Read fixed NVMEM cells from old OF syntax.
|
|
+ * @fixup_dt_cell_info: Will be called before a cell is added. Can be
|
|
+ * used to modify the nvmem_cell_info.
|
|
* @keepout: Optional array of keepout ranges (sorted ascending by start).
|
|
* @nkeepout: Number of elements in the keepout array.
|
|
* @type: Type of the nvmem storage
|
|
@@ -114,6 +116,8 @@ struct nvmem_config {
|
|
const struct nvmem_cell_info *cells;
|
|
int ncells;
|
|
bool add_legacy_fixed_of_cells;
|
|
+ void (*fixup_dt_cell_info)(struct nvmem_device *nvmem,
|
|
+ struct nvmem_cell_info *cell);
|
|
const struct nvmem_keepout *keepout;
|
|
unsigned int nkeepout;
|
|
enum nvmem_type type;
|
|
@@ -158,11 +162,8 @@ struct nvmem_cell_table {
|
|
*
|
|
* @name: Layout name.
|
|
* @of_match_table: Open firmware match table.
|
|
- * @add_cells: Will be called if a nvmem device is found which
|
|
- * has this layout. The function will add layout
|
|
- * specific cells with nvmem_add_one_cell().
|
|
- * @fixup_cell_info: Will be called before a cell is added. Can be
|
|
- * used to modify the nvmem_cell_info.
|
|
+ * @add_cells: Called to populate the layout using
|
|
+ * nvmem_add_one_cell().
|
|
* @owner: Pointer to struct module.
|
|
* @node: List node.
|
|
*
|
|
@@ -174,11 +175,7 @@ struct nvmem_cell_table {
|
|
struct nvmem_layout {
|
|
const char *name;
|
|
const struct of_device_id *of_match_table;
|
|
- int (*add_cells)(struct device *dev, struct nvmem_device *nvmem,
|
|
- struct nvmem_layout *layout);
|
|
- void (*fixup_cell_info)(struct nvmem_device *nvmem,
|
|
- struct nvmem_layout *layout,
|
|
- struct nvmem_cell_info *cell);
|
|
+ int (*add_cells)(struct device *dev, struct nvmem_device *nvmem);
|
|
|
|
/* private */
|
|
struct module *owner;
|
|
diff --git a/include/linux/serio.h b/include/linux/serio.h
|
|
index 6c27d413da921d..e105ff2ee651a6 100644
|
|
--- a/include/linux/serio.h
|
|
+++ b/include/linux/serio.h
|
|
@@ -6,6 +6,7 @@
|
|
#define _SERIO_H
|
|
|
|
|
|
+#include <linux/cleanup.h>
|
|
#include <linux/types.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/list.h>
|
|
@@ -161,4 +162,6 @@ static inline void serio_continue_rx(struct serio *serio)
|
|
spin_unlock_irq(&serio->lock);
|
|
}
|
|
|
|
+DEFINE_GUARD(serio_pause_rx, struct serio *, serio_pause_rx(_T), serio_continue_rx(_T))
|
|
+
|
|
#endif
|
|
diff --git a/include/linux/skmsg.h b/include/linux/skmsg.h
|
|
index 6ccfd9236387c6..32bbebf5b71e3c 100644
|
|
--- a/include/linux/skmsg.h
|
|
+++ b/include/linux/skmsg.h
|
|
@@ -87,6 +87,8 @@ struct sk_psock {
|
|
struct sk_psock_progs progs;
|
|
#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)
|
|
struct strparser strp;
|
|
+ u32 copied_seq;
|
|
+ u32 ingress_bytes;
|
|
#endif
|
|
struct sk_buff_head ingress_skb;
|
|
struct list_head ingress_msg;
|
|
diff --git a/include/net/strparser.h b/include/net/strparser.h
|
|
index 41e2ce9e9e10ff..0a83010b3a64a9 100644
|
|
--- a/include/net/strparser.h
|
|
+++ b/include/net/strparser.h
|
|
@@ -43,6 +43,8 @@ struct strparser;
|
|
struct strp_callbacks {
|
|
int (*parse_msg)(struct strparser *strp, struct sk_buff *skb);
|
|
void (*rcv_msg)(struct strparser *strp, struct sk_buff *skb);
|
|
+ int (*read_sock)(struct strparser *strp, read_descriptor_t *desc,
|
|
+ sk_read_actor_t recv_actor);
|
|
int (*read_sock_done)(struct strparser *strp, int err);
|
|
void (*abort_parser)(struct strparser *strp, int err);
|
|
void (*lock)(struct strparser *strp);
|
|
diff --git a/include/net/tcp.h b/include/net/tcp.h
|
|
index b3917af309e0f1..a6def0aab3ed31 100644
|
|
--- a/include/net/tcp.h
|
|
+++ b/include/net/tcp.h
|
|
@@ -40,6 +40,7 @@
|
|
#include <net/inet_ecn.h>
|
|
#include <net/dst.h>
|
|
#include <net/mptcp.h>
|
|
+#include <net/xfrm.h>
|
|
|
|
#include <linux/seq_file.h>
|
|
#include <linux/memcontrol.h>
|
|
@@ -630,6 +631,19 @@ void tcp_fin(struct sock *sk);
|
|
void tcp_check_space(struct sock *sk);
|
|
void tcp_sack_compress_send_ack(struct sock *sk);
|
|
|
|
+static inline void tcp_cleanup_skb(struct sk_buff *skb)
|
|
+{
|
|
+ skb_dst_drop(skb);
|
|
+ secpath_reset(skb);
|
|
+}
|
|
+
|
|
+static inline void tcp_add_receive_queue(struct sock *sk, struct sk_buff *skb)
|
|
+{
|
|
+ DEBUG_NET_WARN_ON_ONCE(skb_dst(skb));
|
|
+ DEBUG_NET_WARN_ON_ONCE(secpath_exists(skb));
|
|
+ __skb_queue_tail(&sk->sk_receive_queue, skb);
|
|
+}
|
|
+
|
|
/* tcp_timer.c */
|
|
void tcp_init_xmit_timers(struct sock *);
|
|
static inline void tcp_clear_xmit_timers(struct sock *sk)
|
|
@@ -676,6 +690,9 @@ void tcp_get_info(struct sock *, struct tcp_info *);
|
|
/* Read 'sendfile()'-style from a TCP socket */
|
|
int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|
sk_read_actor_t recv_actor);
|
|
+int tcp_read_sock_noack(struct sock *sk, read_descriptor_t *desc,
|
|
+ sk_read_actor_t recv_actor, bool noack,
|
|
+ u32 *copied_seq);
|
|
int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor);
|
|
struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off);
|
|
void tcp_read_done(struct sock *sk, size_t len);
|
|
@@ -2390,6 +2407,11 @@ struct sk_psock;
|
|
#ifdef CONFIG_BPF_SYSCALL
|
|
int tcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore);
|
|
void tcp_bpf_clone(const struct sock *sk, struct sock *newsk);
|
|
+#ifdef CONFIG_BPF_STREAM_PARSER
|
|
+struct strparser;
|
|
+int tcp_bpf_strp_read_sock(struct strparser *strp, read_descriptor_t *desc,
|
|
+ sk_read_actor_t recv_actor);
|
|
+#endif /* CONFIG_BPF_STREAM_PARSER */
|
|
#endif /* CONFIG_BPF_SYSCALL */
|
|
|
|
#ifdef CONFIG_INET
|
|
diff --git a/include/trace/events/oom.h b/include/trace/events/oom.h
|
|
index 26a11e4a2c361d..b799f3bcba8233 100644
|
|
--- a/include/trace/events/oom.h
|
|
+++ b/include/trace/events/oom.h
|
|
@@ -7,6 +7,8 @@
|
|
#include <linux/tracepoint.h>
|
|
#include <trace/events/mmflags.h>
|
|
|
|
+#define PG_COUNT_TO_KB(x) ((x) << (PAGE_SHIFT - 10))
|
|
+
|
|
TRACE_EVENT(oom_score_adj_update,
|
|
|
|
TP_PROTO(struct task_struct *task),
|
|
@@ -72,19 +74,45 @@ TRACE_EVENT(reclaim_retry_zone,
|
|
);
|
|
|
|
TRACE_EVENT(mark_victim,
|
|
- TP_PROTO(int pid),
|
|
+ TP_PROTO(struct task_struct *task, uid_t uid),
|
|
|
|
- TP_ARGS(pid),
|
|
+ TP_ARGS(task, uid),
|
|
|
|
TP_STRUCT__entry(
|
|
__field(int, pid)
|
|
+ __string(comm, task->comm)
|
|
+ __field(unsigned long, total_vm)
|
|
+ __field(unsigned long, anon_rss)
|
|
+ __field(unsigned long, file_rss)
|
|
+ __field(unsigned long, shmem_rss)
|
|
+ __field(uid_t, uid)
|
|
+ __field(unsigned long, pgtables)
|
|
+ __field(short, oom_score_adj)
|
|
),
|
|
|
|
TP_fast_assign(
|
|
- __entry->pid = pid;
|
|
+ __entry->pid = task->pid;
|
|
+ __assign_str(comm, task->comm);
|
|
+ __entry->total_vm = PG_COUNT_TO_KB(task->mm->total_vm);
|
|
+ __entry->anon_rss = PG_COUNT_TO_KB(get_mm_counter(task->mm, MM_ANONPAGES));
|
|
+ __entry->file_rss = PG_COUNT_TO_KB(get_mm_counter(task->mm, MM_FILEPAGES));
|
|
+ __entry->shmem_rss = PG_COUNT_TO_KB(get_mm_counter(task->mm, MM_SHMEMPAGES));
|
|
+ __entry->uid = uid;
|
|
+ __entry->pgtables = mm_pgtables_bytes(task->mm) >> 10;
|
|
+ __entry->oom_score_adj = task->signal->oom_score_adj;
|
|
),
|
|
|
|
- TP_printk("pid=%d", __entry->pid)
|
|
+ TP_printk("pid=%d comm=%s total-vm=%lukB anon-rss=%lukB file-rss:%lukB shmem-rss:%lukB uid=%u pgtables=%lukB oom_score_adj=%hd",
|
|
+ __entry->pid,
|
|
+ __get_str(comm),
|
|
+ __entry->total_vm,
|
|
+ __entry->anon_rss,
|
|
+ __entry->file_rss,
|
|
+ __entry->shmem_rss,
|
|
+ __entry->uid,
|
|
+ __entry->pgtables,
|
|
+ __entry->oom_score_adj
|
|
+ )
|
|
);
|
|
|
|
TRACE_EVENT(wake_reaper,
|
|
diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
|
|
index b61637dad442a7..5776440f584c76 100644
|
|
--- a/io_uring/io_uring.c
|
|
+++ b/io_uring/io_uring.c
|
|
@@ -2176,6 +2176,8 @@ static int io_init_req(struct io_ring_ctx *ctx, struct io_kiocb *req,
|
|
req->opcode = 0;
|
|
return io_init_fail_req(req, -EINVAL);
|
|
}
|
|
+ opcode = array_index_nospec(opcode, IORING_OP_LAST);
|
|
+
|
|
def = &io_issue_defs[opcode];
|
|
if (unlikely(sqe_flags & ~SQE_COMMON_FLAGS)) {
|
|
/* enforce forwards compatibility on users */
|
|
diff --git a/kernel/acct.c b/kernel/acct.c
|
|
index 1a9f929fe629e7..a58a284f1f38de 100644
|
|
--- a/kernel/acct.c
|
|
+++ b/kernel/acct.c
|
|
@@ -104,48 +104,50 @@ struct bsd_acct_struct {
|
|
atomic_long_t count;
|
|
struct rcu_head rcu;
|
|
struct mutex lock;
|
|
- int active;
|
|
+ bool active;
|
|
+ bool check_space;
|
|
unsigned long needcheck;
|
|
struct file *file;
|
|
struct pid_namespace *ns;
|
|
struct work_struct work;
|
|
struct completion done;
|
|
+ acct_t ac;
|
|
};
|
|
|
|
-static void do_acct_process(struct bsd_acct_struct *acct);
|
|
+static void fill_ac(struct bsd_acct_struct *acct);
|
|
+static void acct_write_process(struct bsd_acct_struct *acct);
|
|
|
|
/*
|
|
* Check the amount of free space and suspend/resume accordingly.
|
|
*/
|
|
-static int check_free_space(struct bsd_acct_struct *acct)
|
|
+static bool check_free_space(struct bsd_acct_struct *acct)
|
|
{
|
|
struct kstatfs sbuf;
|
|
|
|
- if (time_is_after_jiffies(acct->needcheck))
|
|
- goto out;
|
|
+ if (!acct->check_space)
|
|
+ return acct->active;
|
|
|
|
/* May block */
|
|
if (vfs_statfs(&acct->file->f_path, &sbuf))
|
|
- goto out;
|
|
+ return acct->active;
|
|
|
|
if (acct->active) {
|
|
u64 suspend = sbuf.f_blocks * SUSPEND;
|
|
do_div(suspend, 100);
|
|
if (sbuf.f_bavail <= suspend) {
|
|
- acct->active = 0;
|
|
+ acct->active = false;
|
|
pr_info("Process accounting paused\n");
|
|
}
|
|
} else {
|
|
u64 resume = sbuf.f_blocks * RESUME;
|
|
do_div(resume, 100);
|
|
if (sbuf.f_bavail >= resume) {
|
|
- acct->active = 1;
|
|
+ acct->active = true;
|
|
pr_info("Process accounting resumed\n");
|
|
}
|
|
}
|
|
|
|
acct->needcheck = jiffies + ACCT_TIMEOUT*HZ;
|
|
-out:
|
|
return acct->active;
|
|
}
|
|
|
|
@@ -190,7 +192,11 @@ static void acct_pin_kill(struct fs_pin *pin)
|
|
{
|
|
struct bsd_acct_struct *acct = to_acct(pin);
|
|
mutex_lock(&acct->lock);
|
|
- do_acct_process(acct);
|
|
+ /*
|
|
+ * Fill the accounting struct with the exiting task's info
|
|
+ * before punting to the workqueue.
|
|
+ */
|
|
+ fill_ac(acct);
|
|
schedule_work(&acct->work);
|
|
wait_for_completion(&acct->done);
|
|
cmpxchg(&acct->ns->bacct, pin, NULL);
|
|
@@ -203,6 +209,9 @@ static void close_work(struct work_struct *work)
|
|
{
|
|
struct bsd_acct_struct *acct = container_of(work, struct bsd_acct_struct, work);
|
|
struct file *file = acct->file;
|
|
+
|
|
+ /* We were fired by acct_pin_kill() which holds acct->lock. */
|
|
+ acct_write_process(acct);
|
|
if (file->f_op->flush)
|
|
file->f_op->flush(file, NULL);
|
|
__fput_sync(file);
|
|
@@ -235,6 +244,20 @@ static int acct_on(struct filename *pathname)
|
|
return -EACCES;
|
|
}
|
|
|
|
+ /* Exclude kernel kernel internal filesystems. */
|
|
+ if (file_inode(file)->i_sb->s_flags & (SB_NOUSER | SB_KERNMOUNT)) {
|
|
+ kfree(acct);
|
|
+ filp_close(file, NULL);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Exclude procfs and sysfs. */
|
|
+ if (file_inode(file)->i_sb->s_iflags & SB_I_USERNS_VISIBLE) {
|
|
+ kfree(acct);
|
|
+ filp_close(file, NULL);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
if (!(file->f_mode & FMODE_CAN_WRITE)) {
|
|
kfree(acct);
|
|
filp_close(file, NULL);
|
|
@@ -431,13 +454,27 @@ static u32 encode_float(u64 value)
|
|
* do_exit() or when switching to a different output file.
|
|
*/
|
|
|
|
-static void fill_ac(acct_t *ac)
|
|
+static void fill_ac(struct bsd_acct_struct *acct)
|
|
{
|
|
struct pacct_struct *pacct = ¤t->signal->pacct;
|
|
+ struct file *file = acct->file;
|
|
+ acct_t *ac = &acct->ac;
|
|
u64 elapsed, run_time;
|
|
time64_t btime;
|
|
struct tty_struct *tty;
|
|
|
|
+ lockdep_assert_held(&acct->lock);
|
|
+
|
|
+ if (time_is_after_jiffies(acct->needcheck)) {
|
|
+ acct->check_space = false;
|
|
+
|
|
+ /* Don't fill in @ac if nothing will be written. */
|
|
+ if (!acct->active)
|
|
+ return;
|
|
+ } else {
|
|
+ acct->check_space = true;
|
|
+ }
|
|
+
|
|
/*
|
|
* Fill the accounting struct with the needed info as recorded
|
|
* by the different kernel functions.
|
|
@@ -485,64 +522,61 @@ static void fill_ac(acct_t *ac)
|
|
ac->ac_majflt = encode_comp_t(pacct->ac_majflt);
|
|
ac->ac_exitcode = pacct->ac_exitcode;
|
|
spin_unlock_irq(¤t->sighand->siglock);
|
|
-}
|
|
-/*
|
|
- * do_acct_process does all actual work. Caller holds the reference to file.
|
|
- */
|
|
-static void do_acct_process(struct bsd_acct_struct *acct)
|
|
-{
|
|
- acct_t ac;
|
|
- unsigned long flim;
|
|
- const struct cred *orig_cred;
|
|
- struct file *file = acct->file;
|
|
|
|
- /*
|
|
- * Accounting records are not subject to resource limits.
|
|
- */
|
|
- flim = rlimit(RLIMIT_FSIZE);
|
|
- current->signal->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
|
|
- /* Perform file operations on behalf of whoever enabled accounting */
|
|
- orig_cred = override_creds(file->f_cred);
|
|
-
|
|
- /*
|
|
- * First check to see if there is enough free_space to continue
|
|
- * the process accounting system.
|
|
- */
|
|
- if (!check_free_space(acct))
|
|
- goto out;
|
|
-
|
|
- fill_ac(&ac);
|
|
/* we really need to bite the bullet and change layout */
|
|
- ac.ac_uid = from_kuid_munged(file->f_cred->user_ns, orig_cred->uid);
|
|
- ac.ac_gid = from_kgid_munged(file->f_cred->user_ns, orig_cred->gid);
|
|
+ ac->ac_uid = from_kuid_munged(file->f_cred->user_ns, current_uid());
|
|
+ ac->ac_gid = from_kgid_munged(file->f_cred->user_ns, current_gid());
|
|
#if ACCT_VERSION == 1 || ACCT_VERSION == 2
|
|
/* backward-compatible 16 bit fields */
|
|
- ac.ac_uid16 = ac.ac_uid;
|
|
- ac.ac_gid16 = ac.ac_gid;
|
|
+ ac->ac_uid16 = ac->ac_uid;
|
|
+ ac->ac_gid16 = ac->ac_gid;
|
|
#elif ACCT_VERSION == 3
|
|
{
|
|
struct pid_namespace *ns = acct->ns;
|
|
|
|
- ac.ac_pid = task_tgid_nr_ns(current, ns);
|
|
+ ac->ac_pid = task_tgid_nr_ns(current, ns);
|
|
rcu_read_lock();
|
|
- ac.ac_ppid = task_tgid_nr_ns(rcu_dereference(current->real_parent),
|
|
- ns);
|
|
+ ac->ac_ppid = task_tgid_nr_ns(rcu_dereference(current->real_parent), ns);
|
|
rcu_read_unlock();
|
|
}
|
|
#endif
|
|
+}
|
|
+
|
|
+static void acct_write_process(struct bsd_acct_struct *acct)
|
|
+{
|
|
+ struct file *file = acct->file;
|
|
+ const struct cred *cred;
|
|
+ acct_t *ac = &acct->ac;
|
|
+
|
|
+ /* Perform file operations on behalf of whoever enabled accounting */
|
|
+ cred = override_creds(file->f_cred);
|
|
+
|
|
/*
|
|
- * Get freeze protection. If the fs is frozen, just skip the write
|
|
- * as we could deadlock the system otherwise.
|
|
+ * First check to see if there is enough free_space to continue
|
|
+ * the process accounting system. Then get freeze protection. If
|
|
+ * the fs is frozen, just skip the write as we could deadlock
|
|
+ * the system otherwise.
|
|
*/
|
|
- if (file_start_write_trylock(file)) {
|
|
+ if (check_free_space(acct) && file_start_write_trylock(file)) {
|
|
/* it's been opened O_APPEND, so position is irrelevant */
|
|
loff_t pos = 0;
|
|
- __kernel_write(file, &ac, sizeof(acct_t), &pos);
|
|
+ __kernel_write(file, ac, sizeof(acct_t), &pos);
|
|
file_end_write(file);
|
|
}
|
|
-out:
|
|
+
|
|
+ revert_creds(cred);
|
|
+}
|
|
+
|
|
+static void do_acct_process(struct bsd_acct_struct *acct)
|
|
+{
|
|
+ unsigned long flim;
|
|
+
|
|
+ /* Accounting records are not subject to resource limits. */
|
|
+ flim = rlimit(RLIMIT_FSIZE);
|
|
+ current->signal->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY;
|
|
+ fill_ac(acct);
|
|
+ acct_write_process(acct);
|
|
current->signal->rlim[RLIMIT_FSIZE].rlim_cur = flim;
|
|
- revert_creds(orig_cred);
|
|
}
|
|
|
|
/**
|
|
diff --git a/kernel/bpf/bpf_cgrp_storage.c b/kernel/bpf/bpf_cgrp_storage.c
|
|
index d44fe8dd973295..ee1c7b77096e7b 100644
|
|
--- a/kernel/bpf/bpf_cgrp_storage.c
|
|
+++ b/kernel/bpf/bpf_cgrp_storage.c
|
|
@@ -154,7 +154,7 @@ static struct bpf_map *cgroup_storage_map_alloc(union bpf_attr *attr)
|
|
|
|
static void cgroup_storage_map_free(struct bpf_map *map)
|
|
{
|
|
- bpf_local_storage_map_free(map, &cgroup_cache, NULL);
|
|
+ bpf_local_storage_map_free(map, &cgroup_cache, &bpf_cgrp_storage_busy);
|
|
}
|
|
|
|
/* *gfp_flags* is a hidden argument provided by the verifier */
|
|
diff --git a/kernel/bpf/ringbuf.c b/kernel/bpf/ringbuf.c
|
|
index 246559c3e93d0d..528f4d6342262e 100644
|
|
--- a/kernel/bpf/ringbuf.c
|
|
+++ b/kernel/bpf/ringbuf.c
|
|
@@ -268,8 +268,6 @@ static int ringbuf_map_mmap_kern(struct bpf_map *map, struct vm_area_struct *vma
|
|
/* allow writable mapping for the consumer_pos only */
|
|
if (vma->vm_pgoff != 0 || vma->vm_end - vma->vm_start != PAGE_SIZE)
|
|
return -EPERM;
|
|
- } else {
|
|
- vm_flags_clear(vma, VM_MAYWRITE);
|
|
}
|
|
/* remap_vmalloc_range() checks size and offset constraints */
|
|
return remap_vmalloc_range(vma, rb_map->rb,
|
|
@@ -289,8 +287,6 @@ static int ringbuf_map_mmap_user(struct bpf_map *map, struct vm_area_struct *vma
|
|
* position, and the ring buffer data itself.
|
|
*/
|
|
return -EPERM;
|
|
- } else {
|
|
- vm_flags_clear(vma, VM_MAYWRITE);
|
|
}
|
|
/* remap_vmalloc_range() checks size and offset constraints */
|
|
return remap_vmalloc_range(vma, rb_map->rb, vma->vm_pgoff + RINGBUF_PGOFF);
|
|
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
|
|
index ba38c08a9a059a..f089a616301119 100644
|
|
--- a/kernel/bpf/syscall.c
|
|
+++ b/kernel/bpf/syscall.c
|
|
@@ -882,7 +882,7 @@ static const struct vm_operations_struct bpf_map_default_vmops = {
|
|
static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma)
|
|
{
|
|
struct bpf_map *map = filp->private_data;
|
|
- int err;
|
|
+ int err = 0;
|
|
|
|
if (!map->ops->map_mmap || !IS_ERR_OR_NULL(map->record))
|
|
return -ENOTSUPP;
|
|
@@ -906,24 +906,33 @@ static int bpf_map_mmap(struct file *filp, struct vm_area_struct *vma)
|
|
err = -EACCES;
|
|
goto out;
|
|
}
|
|
+ bpf_map_write_active_inc(map);
|
|
}
|
|
+out:
|
|
+ mutex_unlock(&map->freeze_mutex);
|
|
+ if (err)
|
|
+ return err;
|
|
|
|
/* set default open/close callbacks */
|
|
vma->vm_ops = &bpf_map_default_vmops;
|
|
vma->vm_private_data = map;
|
|
vm_flags_clear(vma, VM_MAYEXEC);
|
|
+ /* If mapping is read-only, then disallow potentially re-mapping with
|
|
+ * PROT_WRITE by dropping VM_MAYWRITE flag. This VM_MAYWRITE clearing
|
|
+ * means that as far as BPF map's memory-mapped VMAs are concerned,
|
|
+ * VM_WRITE and VM_MAYWRITE and equivalent, if one of them is set,
|
|
+ * both should be set, so we can forget about VM_MAYWRITE and always
|
|
+ * check just VM_WRITE
|
|
+ */
|
|
if (!(vma->vm_flags & VM_WRITE))
|
|
- /* disallow re-mapping with PROT_WRITE */
|
|
vm_flags_clear(vma, VM_MAYWRITE);
|
|
|
|
err = map->ops->map_mmap(map, vma);
|
|
- if (err)
|
|
- goto out;
|
|
+ if (err) {
|
|
+ if (vma->vm_flags & VM_WRITE)
|
|
+ bpf_map_write_active_dec(map);
|
|
+ }
|
|
|
|
- if (vma->vm_flags & VM_MAYWRITE)
|
|
- bpf_map_write_active_inc(map);
|
|
-out:
|
|
- mutex_unlock(&map->freeze_mutex);
|
|
return err;
|
|
}
|
|
|
|
@@ -1798,8 +1807,6 @@ int generic_map_update_batch(struct bpf_map *map, struct file *map_file,
|
|
return err;
|
|
}
|
|
|
|
-#define MAP_LOOKUP_RETRIES 3
|
|
-
|
|
int generic_map_lookup_batch(struct bpf_map *map,
|
|
const union bpf_attr *attr,
|
|
union bpf_attr __user *uattr)
|
|
@@ -1809,8 +1816,8 @@ int generic_map_lookup_batch(struct bpf_map *map,
|
|
void __user *values = u64_to_user_ptr(attr->batch.values);
|
|
void __user *keys = u64_to_user_ptr(attr->batch.keys);
|
|
void *buf, *buf_prevkey, *prev_key, *key, *value;
|
|
- int err, retry = MAP_LOOKUP_RETRIES;
|
|
u32 value_size, cp, max_count;
|
|
+ int err;
|
|
|
|
if (attr->batch.elem_flags & ~BPF_F_LOCK)
|
|
return -EINVAL;
|
|
@@ -1856,14 +1863,8 @@ int generic_map_lookup_batch(struct bpf_map *map,
|
|
err = bpf_map_copy_value(map, key, value,
|
|
attr->batch.elem_flags);
|
|
|
|
- if (err == -ENOENT) {
|
|
- if (retry) {
|
|
- retry--;
|
|
- continue;
|
|
- }
|
|
- err = -EINTR;
|
|
- break;
|
|
- }
|
|
+ if (err == -ENOENT)
|
|
+ goto next_key;
|
|
|
|
if (err)
|
|
goto free_buf;
|
|
@@ -1878,12 +1879,12 @@ int generic_map_lookup_batch(struct bpf_map *map,
|
|
goto free_buf;
|
|
}
|
|
|
|
+ cp++;
|
|
+next_key:
|
|
if (!prev_key)
|
|
prev_key = buf_prevkey;
|
|
|
|
swap(prev_key, key);
|
|
- retry = MAP_LOOKUP_RETRIES;
|
|
- cp++;
|
|
cond_resched();
|
|
}
|
|
|
|
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
|
|
index 1043936b352d12..6e6b2a5aa1402b 100644
|
|
--- a/kernel/trace/ftrace.c
|
|
+++ b/kernel/trace/ftrace.c
|
|
@@ -5233,6 +5233,9 @@ __ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)
|
|
return -ENOENT;
|
|
free_hash_entry(hash, entry);
|
|
return 0;
|
|
+ } else if (__ftrace_lookup_ip(hash, ip) != NULL) {
|
|
+ /* Already exists */
|
|
+ return 0;
|
|
}
|
|
|
|
entry = add_hash_entry(hash, ip);
|
|
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
|
|
index 9f1bfbe105e8d9..69e92c7359fb9a 100644
|
|
--- a/kernel/trace/trace_functions.c
|
|
+++ b/kernel/trace/trace_functions.c
|
|
@@ -185,7 +185,7 @@ function_trace_call(unsigned long ip, unsigned long parent_ip,
|
|
if (bit < 0)
|
|
return;
|
|
|
|
- trace_ctx = tracing_gen_ctx();
|
|
+ trace_ctx = tracing_gen_ctx_dec();
|
|
|
|
cpu = smp_processor_id();
|
|
data = per_cpu_ptr(tr->array_buffer.data, cpu);
|
|
@@ -285,7 +285,6 @@ function_no_repeats_trace_call(unsigned long ip, unsigned long parent_ip,
|
|
struct trace_array *tr = op->private;
|
|
struct trace_array_cpu *data;
|
|
unsigned int trace_ctx;
|
|
- unsigned long flags;
|
|
int bit;
|
|
int cpu;
|
|
|
|
@@ -312,8 +311,7 @@ function_no_repeats_trace_call(unsigned long ip, unsigned long parent_ip,
|
|
if (is_repeat_check(tr, last_info, ip, parent_ip))
|
|
goto out;
|
|
|
|
- local_save_flags(flags);
|
|
- trace_ctx = tracing_gen_ctx_flags(flags);
|
|
+ trace_ctx = tracing_gen_ctx_dec();
|
|
process_repeats(tr, ip, parent_ip, last_info, trace_ctx);
|
|
|
|
trace_function(tr, ip, parent_ip, trace_ctx);
|
|
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
|
|
index a4bb47efafe37d..d6620eaa951539 100644
|
|
--- a/lib/iov_iter.c
|
|
+++ b/lib/iov_iter.c
|
|
@@ -1441,6 +1441,8 @@ static ssize_t __import_iovec_ubuf(int type, const struct iovec __user *uvec,
|
|
struct iovec *iov = *iovp;
|
|
ssize_t ret;
|
|
|
|
+ *iovp = NULL;
|
|
+
|
|
if (compat)
|
|
ret = copy_compat_iovec_from_user(iov, uvec, 1);
|
|
else
|
|
@@ -1451,7 +1453,6 @@ static ssize_t __import_iovec_ubuf(int type, const struct iovec __user *uvec,
|
|
ret = import_ubuf(type, iov->iov_base, iov->iov_len, i);
|
|
if (unlikely(ret))
|
|
return ret;
|
|
- *iovp = NULL;
|
|
return i->count;
|
|
}
|
|
|
|
diff --git a/mm/madvise.c b/mm/madvise.c
|
|
index 98fdb9288a68a8..9d2a6cb655ff20 100644
|
|
--- a/mm/madvise.c
|
|
+++ b/mm/madvise.c
|
|
@@ -899,7 +899,16 @@ static long madvise_dontneed_free(struct vm_area_struct *vma,
|
|
*/
|
|
end = vma->vm_end;
|
|
}
|
|
- VM_WARN_ON(start >= end);
|
|
+ /*
|
|
+ * If the memory region between start and end was
|
|
+ * originally backed by 4kB pages and then remapped to
|
|
+ * be backed by hugepages while mmap_lock was dropped,
|
|
+ * the adjustment for hugetlb vma above may have rounded
|
|
+ * end down to the start address.
|
|
+ */
|
|
+ if (start == end)
|
|
+ return 0;
|
|
+ VM_WARN_ON(start > end);
|
|
}
|
|
|
|
if (behavior == MADV_DONTNEED || behavior == MADV_DONTNEED_LOCKED)
|
|
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
|
|
index d2ceadd11b1004..9bf5a69e20d87a 100644
|
|
--- a/mm/memcontrol.c
|
|
+++ b/mm/memcontrol.c
|
|
@@ -1266,6 +1266,7 @@ void mem_cgroup_scan_tasks(struct mem_cgroup *memcg,
|
|
{
|
|
struct mem_cgroup *iter;
|
|
int ret = 0;
|
|
+ int i = 0;
|
|
|
|
BUG_ON(mem_cgroup_is_root(memcg));
|
|
|
|
@@ -1274,8 +1275,12 @@ void mem_cgroup_scan_tasks(struct mem_cgroup *memcg,
|
|
struct task_struct *task;
|
|
|
|
css_task_iter_start(&iter->css, CSS_TASK_ITER_PROCS, &it);
|
|
- while (!ret && (task = css_task_iter_next(&it)))
|
|
+ while (!ret && (task = css_task_iter_next(&it))) {
|
|
+ /* Avoid potential softlockup warning */
|
|
+ if ((++i & 1023) == 0)
|
|
+ cond_resched();
|
|
ret = fn(task, arg);
|
|
+ }
|
|
css_task_iter_end(&it);
|
|
if (ret) {
|
|
mem_cgroup_iter_break(memcg, iter);
|
|
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
|
|
index 44bde56ecd025a..17a2ef9f93d3d3 100644
|
|
--- a/mm/oom_kill.c
|
|
+++ b/mm/oom_kill.c
|
|
@@ -44,6 +44,8 @@
|
|
#include <linux/kthread.h>
|
|
#include <linux/init.h>
|
|
#include <linux/mmu_notifier.h>
|
|
+#include <linux/cred.h>
|
|
+#include <linux/nmi.h>
|
|
|
|
#include <asm/tlb.h>
|
|
#include "internal.h"
|
|
@@ -429,10 +431,15 @@ static void dump_tasks(struct oom_control *oc)
|
|
mem_cgroup_scan_tasks(oc->memcg, dump_task, oc);
|
|
else {
|
|
struct task_struct *p;
|
|
+ int i = 0;
|
|
|
|
rcu_read_lock();
|
|
- for_each_process(p)
|
|
+ for_each_process(p) {
|
|
+ /* Avoid potential softlockup warning */
|
|
+ if ((++i & 1023) == 0)
|
|
+ touch_softlockup_watchdog();
|
|
dump_task(p, oc);
|
|
+ }
|
|
rcu_read_unlock();
|
|
}
|
|
}
|
|
@@ -755,6 +762,7 @@ static inline void queue_oom_reaper(struct task_struct *tsk)
|
|
*/
|
|
static void mark_oom_victim(struct task_struct *tsk)
|
|
{
|
|
+ const struct cred *cred;
|
|
struct mm_struct *mm = tsk->mm;
|
|
|
|
WARN_ON(oom_killer_disabled);
|
|
@@ -774,7 +782,9 @@ static void mark_oom_victim(struct task_struct *tsk)
|
|
*/
|
|
__thaw_task(tsk);
|
|
atomic_inc(&oom_victims);
|
|
- trace_mark_victim(tsk->pid);
|
|
+ cred = get_task_cred(tsk);
|
|
+ trace_mark_victim(tsk, cred->uid.val);
|
|
+ put_cred(cred);
|
|
}
|
|
|
|
/**
|
|
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
|
|
index 905de361f8623f..73fb9db55798c8 100644
|
|
--- a/net/bpf/test_run.c
|
|
+++ b/net/bpf/test_run.c
|
|
@@ -630,12 +630,9 @@ static void *bpf_test_init(const union bpf_attr *kattr, u32 user_size,
|
|
void __user *data_in = u64_to_user_ptr(kattr->test.data_in);
|
|
void *data;
|
|
|
|
- if (size < ETH_HLEN || size > PAGE_SIZE - headroom - tailroom)
|
|
+ if (user_size < ETH_HLEN || user_size > PAGE_SIZE - headroom - tailroom)
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
- if (user_size > size)
|
|
- return ERR_PTR(-EMSGSIZE);
|
|
-
|
|
size = SKB_DATA_ALIGN(size);
|
|
data = kzalloc(size + headroom + tailroom, GFP_USER);
|
|
if (!data)
|
|
diff --git a/net/core/dev.c b/net/core/dev.c
|
|
index 479a3892f98c3c..8c30cdcf05d4bd 100644
|
|
--- a/net/core/dev.c
|
|
+++ b/net/core/dev.c
|
|
@@ -954,6 +954,12 @@ int netdev_get_name(struct net *net, char *name, int ifindex)
|
|
return ret;
|
|
}
|
|
|
|
+static bool dev_addr_cmp(struct net_device *dev, unsigned short type,
|
|
+ const char *ha)
|
|
+{
|
|
+ return dev->type == type && !memcmp(dev->dev_addr, ha, dev->addr_len);
|
|
+}
|
|
+
|
|
/**
|
|
* dev_getbyhwaddr_rcu - find a device by its hardware address
|
|
* @net: the applicable net namespace
|
|
@@ -962,7 +968,7 @@ int netdev_get_name(struct net *net, char *name, int ifindex)
|
|
*
|
|
* Search for an interface by MAC address. Returns NULL if the device
|
|
* is not found or a pointer to the device.
|
|
- * The caller must hold RCU or RTNL.
|
|
+ * The caller must hold RCU.
|
|
* The returned device has not had its ref count increased
|
|
* and the caller must therefore be careful about locking
|
|
*
|
|
@@ -974,14 +980,39 @@ struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type,
|
|
struct net_device *dev;
|
|
|
|
for_each_netdev_rcu(net, dev)
|
|
- if (dev->type == type &&
|
|
- !memcmp(dev->dev_addr, ha, dev->addr_len))
|
|
+ if (dev_addr_cmp(dev, type, ha))
|
|
return dev;
|
|
|
|
return NULL;
|
|
}
|
|
EXPORT_SYMBOL(dev_getbyhwaddr_rcu);
|
|
|
|
+/**
|
|
+ * dev_getbyhwaddr() - find a device by its hardware address
|
|
+ * @net: the applicable net namespace
|
|
+ * @type: media type of device
|
|
+ * @ha: hardware address
|
|
+ *
|
|
+ * Similar to dev_getbyhwaddr_rcu(), but the owner needs to hold
|
|
+ * rtnl_lock.
|
|
+ *
|
|
+ * Context: rtnl_lock() must be held.
|
|
+ * Return: pointer to the net_device, or NULL if not found
|
|
+ */
|
|
+struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type,
|
|
+ const char *ha)
|
|
+{
|
|
+ struct net_device *dev;
|
|
+
|
|
+ ASSERT_RTNL();
|
|
+ for_each_netdev(net, dev)
|
|
+ if (dev_addr_cmp(dev, type, ha))
|
|
+ return dev;
|
|
+
|
|
+ return NULL;
|
|
+}
|
|
+EXPORT_SYMBOL(dev_getbyhwaddr);
|
|
+
|
|
struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type)
|
|
{
|
|
struct net_device *dev, *ret = NULL;
|
|
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
|
|
index 58843a52bad0e7..fccda85ce8fe1f 100644
|
|
--- a/net/core/drop_monitor.c
|
|
+++ b/net/core/drop_monitor.c
|
|
@@ -1731,30 +1731,30 @@ static int __init init_net_drop_monitor(void)
|
|
return -ENOSPC;
|
|
}
|
|
|
|
- rc = genl_register_family(&net_drop_monitor_family);
|
|
- if (rc) {
|
|
- pr_err("Could not create drop monitor netlink family\n");
|
|
- return rc;
|
|
+ for_each_possible_cpu(cpu) {
|
|
+ net_dm_cpu_data_init(cpu);
|
|
+ net_dm_hw_cpu_data_init(cpu);
|
|
}
|
|
- WARN_ON(net_drop_monitor_family.mcgrp_offset != NET_DM_GRP_ALERT);
|
|
|
|
rc = register_netdevice_notifier(&dropmon_net_notifier);
|
|
if (rc < 0) {
|
|
pr_crit("Failed to register netdevice notifier\n");
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ rc = genl_register_family(&net_drop_monitor_family);
|
|
+ if (rc) {
|
|
+ pr_err("Could not create drop monitor netlink family\n");
|
|
goto out_unreg;
|
|
}
|
|
+ WARN_ON(net_drop_monitor_family.mcgrp_offset != NET_DM_GRP_ALERT);
|
|
|
|
rc = 0;
|
|
|
|
- for_each_possible_cpu(cpu) {
|
|
- net_dm_cpu_data_init(cpu);
|
|
- net_dm_hw_cpu_data_init(cpu);
|
|
- }
|
|
-
|
|
goto out;
|
|
|
|
out_unreg:
|
|
- genl_unregister_family(&net_drop_monitor_family);
|
|
+ WARN_ON(unregister_netdevice_notifier(&dropmon_net_notifier));
|
|
out:
|
|
return rc;
|
|
}
|
|
@@ -1763,19 +1763,18 @@ static void exit_net_drop_monitor(void)
|
|
{
|
|
int cpu;
|
|
|
|
- BUG_ON(unregister_netdevice_notifier(&dropmon_net_notifier));
|
|
-
|
|
/*
|
|
* Because of the module_get/put we do in the trace state change path
|
|
* we are guaranteed not to have any current users when we get here
|
|
*/
|
|
+ BUG_ON(genl_unregister_family(&net_drop_monitor_family));
|
|
+
|
|
+ BUG_ON(unregister_netdevice_notifier(&dropmon_net_notifier));
|
|
|
|
for_each_possible_cpu(cpu) {
|
|
net_dm_hw_cpu_data_fini(cpu);
|
|
net_dm_cpu_data_fini(cpu);
|
|
}
|
|
-
|
|
- BUG_ON(genl_unregister_family(&net_drop_monitor_family));
|
|
}
|
|
|
|
module_init(init_net_drop_monitor);
|
|
diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c
|
|
index 00a5c41c1831df..aafa754b6cbab9 100644
|
|
--- a/net/core/flow_dissector.c
|
|
+++ b/net/core/flow_dissector.c
|
|
@@ -829,23 +829,30 @@ __skb_flow_dissect_ports(const struct sk_buff *skb,
|
|
void *target_container, const void *data,
|
|
int nhoff, u8 ip_proto, int hlen)
|
|
{
|
|
- enum flow_dissector_key_id dissector_ports = FLOW_DISSECTOR_KEY_MAX;
|
|
- struct flow_dissector_key_ports *key_ports;
|
|
+ struct flow_dissector_key_ports_range *key_ports_range = NULL;
|
|
+ struct flow_dissector_key_ports *key_ports = NULL;
|
|
+ __be32 ports;
|
|
|
|
if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS))
|
|
- dissector_ports = FLOW_DISSECTOR_KEY_PORTS;
|
|
- else if (dissector_uses_key(flow_dissector,
|
|
- FLOW_DISSECTOR_KEY_PORTS_RANGE))
|
|
- dissector_ports = FLOW_DISSECTOR_KEY_PORTS_RANGE;
|
|
+ key_ports = skb_flow_dissector_target(flow_dissector,
|
|
+ FLOW_DISSECTOR_KEY_PORTS,
|
|
+ target_container);
|
|
|
|
- if (dissector_ports == FLOW_DISSECTOR_KEY_MAX)
|
|
+ if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS_RANGE))
|
|
+ key_ports_range = skb_flow_dissector_target(flow_dissector,
|
|
+ FLOW_DISSECTOR_KEY_PORTS_RANGE,
|
|
+ target_container);
|
|
+
|
|
+ if (!key_ports && !key_ports_range)
|
|
return;
|
|
|
|
- key_ports = skb_flow_dissector_target(flow_dissector,
|
|
- dissector_ports,
|
|
- target_container);
|
|
- key_ports->ports = __skb_flow_get_ports(skb, nhoff, ip_proto,
|
|
- data, hlen);
|
|
+ ports = __skb_flow_get_ports(skb, nhoff, ip_proto, data, hlen);
|
|
+
|
|
+ if (key_ports)
|
|
+ key_ports->ports = ports;
|
|
+
|
|
+ if (key_ports_range)
|
|
+ key_ports_range->tp.ports = ports;
|
|
}
|
|
|
|
static void
|
|
@@ -900,6 +907,7 @@ static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys,
|
|
struct flow_dissector *flow_dissector,
|
|
void *target_container)
|
|
{
|
|
+ struct flow_dissector_key_ports_range *key_ports_range = NULL;
|
|
struct flow_dissector_key_ports *key_ports = NULL;
|
|
struct flow_dissector_key_control *key_control;
|
|
struct flow_dissector_key_basic *key_basic;
|
|
@@ -944,20 +952,21 @@ static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys,
|
|
key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
|
|
}
|
|
|
|
- if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS))
|
|
+ if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS)) {
|
|
key_ports = skb_flow_dissector_target(flow_dissector,
|
|
FLOW_DISSECTOR_KEY_PORTS,
|
|
target_container);
|
|
- else if (dissector_uses_key(flow_dissector,
|
|
- FLOW_DISSECTOR_KEY_PORTS_RANGE))
|
|
- key_ports = skb_flow_dissector_target(flow_dissector,
|
|
- FLOW_DISSECTOR_KEY_PORTS_RANGE,
|
|
- target_container);
|
|
-
|
|
- if (key_ports) {
|
|
key_ports->src = flow_keys->sport;
|
|
key_ports->dst = flow_keys->dport;
|
|
}
|
|
+ if (dissector_uses_key(flow_dissector,
|
|
+ FLOW_DISSECTOR_KEY_PORTS_RANGE)) {
|
|
+ key_ports_range = skb_flow_dissector_target(flow_dissector,
|
|
+ FLOW_DISSECTOR_KEY_PORTS_RANGE,
|
|
+ target_container);
|
|
+ key_ports_range->tp.src = flow_keys->sport;
|
|
+ key_ports_range->tp.dst = flow_keys->dport;
|
|
+ }
|
|
|
|
if (dissector_uses_key(flow_dissector,
|
|
FLOW_DISSECTOR_KEY_FLOW_LABEL)) {
|
|
diff --git a/net/core/skmsg.c b/net/core/skmsg.c
|
|
index 902098e221b396..b9b941c487c8a7 100644
|
|
--- a/net/core/skmsg.c
|
|
+++ b/net/core/skmsg.c
|
|
@@ -548,6 +548,9 @@ static int sk_psock_skb_ingress_enqueue(struct sk_buff *skb,
|
|
return num_sge;
|
|
}
|
|
|
|
+#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)
|
|
+ psock->ingress_bytes += len;
|
|
+#endif
|
|
copied = len;
|
|
msg->sg.start = 0;
|
|
msg->sg.size = copied;
|
|
@@ -1143,6 +1146,10 @@ int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock)
|
|
if (!ret)
|
|
sk_psock_set_state(psock, SK_PSOCK_RX_STRP_ENABLED);
|
|
|
|
+ if (sk_is_tcp(sk)) {
|
|
+ psock->strp.cb.read_sock = tcp_bpf_strp_read_sock;
|
|
+ psock->copied_seq = tcp_sk(sk)->copied_seq;
|
|
+ }
|
|
return ret;
|
|
}
|
|
|
|
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
|
|
index f37a26efdd8abe..3a53b6a0e76e2b 100644
|
|
--- a/net/core/sock_map.c
|
|
+++ b/net/core/sock_map.c
|
|
@@ -300,7 +300,10 @@ static int sock_map_link(struct bpf_map *map, struct sock *sk)
|
|
|
|
write_lock_bh(&sk->sk_callback_lock);
|
|
if (stream_parser && stream_verdict && !psock->saved_data_ready) {
|
|
- ret = sk_psock_init_strp(sk, psock);
|
|
+ if (sk_is_tcp(sk))
|
|
+ ret = sk_psock_init_strp(sk, psock);
|
|
+ else
|
|
+ ret = -EOPNOTSUPP;
|
|
if (ret) {
|
|
write_unlock_bh(&sk->sk_callback_lock);
|
|
sk_psock_put(sk, psock);
|
|
@@ -538,6 +541,9 @@ static bool sock_map_sk_state_allowed(const struct sock *sk)
|
|
return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN);
|
|
if (sk_is_stream_unix(sk))
|
|
return (1 << sk->sk_state) & TCPF_ESTABLISHED;
|
|
+ if (sk_is_vsock(sk) &&
|
|
+ (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET))
|
|
+ return (1 << sk->sk_state) & TCPF_ESTABLISHED;
|
|
return true;
|
|
}
|
|
|
|
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
|
|
index 02776453bf97a8..784dc8b37be5a2 100644
|
|
--- a/net/ipv4/arp.c
|
|
+++ b/net/ipv4/arp.c
|
|
@@ -1030,7 +1030,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
|
|
if (mask && mask != htonl(0xFFFFFFFF))
|
|
return -EINVAL;
|
|
if (!dev && (r->arp_flags & ATF_COM)) {
|
|
- dev = dev_getbyhwaddr_rcu(net, r->arp_ha.sa_family,
|
|
+ dev = dev_getbyhwaddr(net, r->arp_ha.sa_family,
|
|
r->arp_ha.sa_data);
|
|
if (!dev)
|
|
return -ENODEV;
|
|
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
|
|
index 5e6615f69f175d..7ad82be40f348d 100644
|
|
--- a/net/ipv4/tcp.c
|
|
+++ b/net/ipv4/tcp.c
|
|
@@ -1553,12 +1553,13 @@ EXPORT_SYMBOL(tcp_recv_skb);
|
|
* or for 'peeking' the socket using this routine
|
|
* (although both would be easy to implement).
|
|
*/
|
|
-int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|
- sk_read_actor_t recv_actor)
|
|
+static int __tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|
+ sk_read_actor_t recv_actor, bool noack,
|
|
+ u32 *copied_seq)
|
|
{
|
|
struct sk_buff *skb;
|
|
struct tcp_sock *tp = tcp_sk(sk);
|
|
- u32 seq = tp->copied_seq;
|
|
+ u32 seq = *copied_seq;
|
|
u32 offset;
|
|
int copied = 0;
|
|
|
|
@@ -1612,9 +1613,12 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|
tcp_eat_recv_skb(sk, skb);
|
|
if (!desc->count)
|
|
break;
|
|
- WRITE_ONCE(tp->copied_seq, seq);
|
|
+ WRITE_ONCE(*copied_seq, seq);
|
|
}
|
|
- WRITE_ONCE(tp->copied_seq, seq);
|
|
+ WRITE_ONCE(*copied_seq, seq);
|
|
+
|
|
+ if (noack)
|
|
+ goto out;
|
|
|
|
tcp_rcv_space_adjust(sk);
|
|
|
|
@@ -1623,10 +1627,25 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|
tcp_recv_skb(sk, seq, &offset);
|
|
tcp_cleanup_rbuf(sk, copied);
|
|
}
|
|
+out:
|
|
return copied;
|
|
}
|
|
+
|
|
+int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
|
|
+ sk_read_actor_t recv_actor)
|
|
+{
|
|
+ return __tcp_read_sock(sk, desc, recv_actor, false,
|
|
+ &tcp_sk(sk)->copied_seq);
|
|
+}
|
|
EXPORT_SYMBOL(tcp_read_sock);
|
|
|
|
+int tcp_read_sock_noack(struct sock *sk, read_descriptor_t *desc,
|
|
+ sk_read_actor_t recv_actor, bool noack,
|
|
+ u32 *copied_seq)
|
|
+{
|
|
+ return __tcp_read_sock(sk, desc, recv_actor, noack, copied_seq);
|
|
+}
|
|
+
|
|
int tcp_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
|
|
{
|
|
struct sk_buff *skb;
|
|
diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
|
|
index f882054fae5ee1..5312237e804093 100644
|
|
--- a/net/ipv4/tcp_bpf.c
|
|
+++ b/net/ipv4/tcp_bpf.c
|
|
@@ -646,6 +646,42 @@ static int tcp_bpf_assert_proto_ops(struct proto *ops)
|
|
ops->sendmsg == tcp_sendmsg ? 0 : -ENOTSUPP;
|
|
}
|
|
|
|
+#if IS_ENABLED(CONFIG_BPF_STREAM_PARSER)
|
|
+int tcp_bpf_strp_read_sock(struct strparser *strp, read_descriptor_t *desc,
|
|
+ sk_read_actor_t recv_actor)
|
|
+{
|
|
+ struct sock *sk = strp->sk;
|
|
+ struct sk_psock *psock;
|
|
+ struct tcp_sock *tp;
|
|
+ int copied = 0;
|
|
+
|
|
+ tp = tcp_sk(sk);
|
|
+ rcu_read_lock();
|
|
+ psock = sk_psock(sk);
|
|
+ if (WARN_ON_ONCE(!psock)) {
|
|
+ desc->error = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ psock->ingress_bytes = 0;
|
|
+ copied = tcp_read_sock_noack(sk, desc, recv_actor, true,
|
|
+ &psock->copied_seq);
|
|
+ if (copied < 0)
|
|
+ goto out;
|
|
+ /* recv_actor may redirect skb to another socket (SK_REDIRECT) or
|
|
+ * just put skb into ingress queue of current socket (SK_PASS).
|
|
+ * For SK_REDIRECT, we need to ack the frame immediately but for
|
|
+ * SK_PASS, we want to delay the ack until tcp_bpf_recvmsg_parser().
|
|
+ */
|
|
+ tp->copied_seq = psock->copied_seq - psock->ingress_bytes;
|
|
+ tcp_rcv_space_adjust(sk);
|
|
+ __tcp_cleanup_rbuf(sk, copied - psock->ingress_bytes);
|
|
+out:
|
|
+ rcu_read_unlock();
|
|
+ return copied;
|
|
+}
|
|
+#endif /* CONFIG_BPF_STREAM_PARSER */
|
|
+
|
|
int tcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
|
|
{
|
|
int family = sk->sk_family == AF_INET6 ? TCP_BPF_IPV6 : TCP_BPF_IPV4;
|
|
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c
|
|
index 0f523cbfe329ef..32b28fc21b63c0 100644
|
|
--- a/net/ipv4/tcp_fastopen.c
|
|
+++ b/net/ipv4/tcp_fastopen.c
|
|
@@ -178,7 +178,7 @@ void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb)
|
|
if (!skb)
|
|
return;
|
|
|
|
- skb_dst_drop(skb);
|
|
+ tcp_cleanup_skb(skb);
|
|
/* segs_in has been initialized to 1 in tcp_create_openreq_child().
|
|
* Hence, reset segs_in to 0 before calling tcp_segs_in()
|
|
* to avoid double counting. Also, tcp_segs_in() expects
|
|
@@ -195,7 +195,7 @@ void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb)
|
|
TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_SYN;
|
|
|
|
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
|
|
- __skb_queue_tail(&sk->sk_receive_queue, skb);
|
|
+ tcp_add_receive_queue(sk, skb);
|
|
tp->syn_data_acked = 1;
|
|
|
|
/* u64_stats_update_begin(&tp->syncp) not needed here,
|
|
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
|
|
index f6a213bae5cccb..10d38ec0ff5acd 100644
|
|
--- a/net/ipv4/tcp_input.c
|
|
+++ b/net/ipv4/tcp_input.c
|
|
@@ -248,9 +248,15 @@ static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb)
|
|
do_div(val, skb->truesize);
|
|
tcp_sk(sk)->scaling_ratio = val ? val : 1;
|
|
|
|
- if (old_ratio != tcp_sk(sk)->scaling_ratio)
|
|
- WRITE_ONCE(tcp_sk(sk)->window_clamp,
|
|
- tcp_win_from_space(sk, sk->sk_rcvbuf));
|
|
+ if (old_ratio != tcp_sk(sk)->scaling_ratio) {
|
|
+ struct tcp_sock *tp = tcp_sk(sk);
|
|
+
|
|
+ val = tcp_win_from_space(sk, sk->sk_rcvbuf);
|
|
+ tcp_set_window_clamp(sk, val);
|
|
+
|
|
+ if (tp->window_clamp < tp->rcvq_space.space)
|
|
+ tp->rcvq_space.space = tp->window_clamp;
|
|
+ }
|
|
}
|
|
icsk->icsk_ack.rcv_mss = min_t(unsigned int, len,
|
|
tcp_sk(sk)->advmss);
|
|
@@ -4868,7 +4874,7 @@ static void tcp_ofo_queue(struct sock *sk)
|
|
tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq);
|
|
fin = TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN;
|
|
if (!eaten)
|
|
- __skb_queue_tail(&sk->sk_receive_queue, skb);
|
|
+ tcp_add_receive_queue(sk, skb);
|
|
else
|
|
kfree_skb_partial(skb, fragstolen);
|
|
|
|
@@ -5059,7 +5065,7 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb,
|
|
skb, fragstolen)) ? 1 : 0;
|
|
tcp_rcv_nxt_update(tcp_sk(sk), TCP_SKB_CB(skb)->end_seq);
|
|
if (!eaten) {
|
|
- __skb_queue_tail(&sk->sk_receive_queue, skb);
|
|
+ tcp_add_receive_queue(sk, skb);
|
|
skb_set_owner_r(skb, sk);
|
|
}
|
|
return eaten;
|
|
@@ -5142,7 +5148,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
|
|
__kfree_skb(skb);
|
|
return;
|
|
}
|
|
- skb_dst_drop(skb);
|
|
+ tcp_cleanup_skb(skb);
|
|
__skb_pull(skb, tcp_hdr(skb)->doff * 4);
|
|
|
|
reason = SKB_DROP_REASON_NOT_SPECIFIED;
|
|
@@ -6092,7 +6098,7 @@ void tcp_rcv_established(struct sock *sk, struct sk_buff *skb)
|
|
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPHPHITS);
|
|
|
|
/* Bulk data transfer: receiver */
|
|
- skb_dst_drop(skb);
|
|
+ tcp_cleanup_skb(skb);
|
|
__skb_pull(skb, tcp_header_len);
|
|
eaten = tcp_queue_rcv(sk, skb, &fragstolen);
|
|
|
|
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
|
|
index 705320f160ac86..2f49a504c9d3e3 100644
|
|
--- a/net/ipv4/tcp_ipv4.c
|
|
+++ b/net/ipv4/tcp_ipv4.c
|
|
@@ -1842,7 +1842,7 @@ bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb,
|
|
*/
|
|
skb_condense(skb);
|
|
|
|
- skb_dst_drop(skb);
|
|
+ tcp_cleanup_skb(skb);
|
|
|
|
if (unlikely(tcp_checksum_complete(skb))) {
|
|
bh_unlock_sock(sk);
|
|
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
|
|
index 84e18b5f72a305..96c39e9a873c75 100644
|
|
--- a/net/sched/cls_api.c
|
|
+++ b/net/sched/cls_api.c
|
|
@@ -97,7 +97,7 @@ tcf_exts_miss_cookie_base_alloc(struct tcf_exts *exts, struct tcf_proto *tp,
|
|
|
|
err = xa_alloc_cyclic(&tcf_exts_miss_cookies_xa, &n->miss_cookie_base,
|
|
n, xa_limit_32b, &next, GFP_KERNEL);
|
|
- if (err)
|
|
+ if (err < 0)
|
|
goto err_xa_alloc;
|
|
|
|
exts->miss_cookie_node = n;
|
|
diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c
|
|
index 8299ceb3e3739d..95696f42647ec1 100644
|
|
--- a/net/strparser/strparser.c
|
|
+++ b/net/strparser/strparser.c
|
|
@@ -347,7 +347,10 @@ static int strp_read_sock(struct strparser *strp)
|
|
struct socket *sock = strp->sk->sk_socket;
|
|
read_descriptor_t desc;
|
|
|
|
- if (unlikely(!sock || !sock->ops || !sock->ops->read_sock))
|
|
+ if (unlikely(!sock || !sock->ops))
|
|
+ return -EBUSY;
|
|
+
|
|
+ if (unlikely(!strp->cb.read_sock && !sock->ops->read_sock))
|
|
return -EBUSY;
|
|
|
|
desc.arg.data = strp;
|
|
@@ -355,7 +358,10 @@ static int strp_read_sock(struct strparser *strp)
|
|
desc.count = 1; /* give more than one skb per call */
|
|
|
|
/* sk should be locked here, so okay to do read_sock */
|
|
- sock->ops->read_sock(strp->sk, &desc, strp_recv);
|
|
+ if (strp->cb.read_sock)
|
|
+ strp->cb.read_sock(strp, &desc, strp_recv);
|
|
+ else
|
|
+ sock->ops->read_sock(strp->sk, &desc, strp_recv);
|
|
|
|
desc.error = strp->cb.read_sock_done(strp, desc.error);
|
|
|
|
@@ -468,6 +474,7 @@ int strp_init(struct strparser *strp, struct sock *sk,
|
|
strp->cb.unlock = cb->unlock ? : strp_sock_unlock;
|
|
strp->cb.rcv_msg = cb->rcv_msg;
|
|
strp->cb.parse_msg = cb->parse_msg;
|
|
+ strp->cb.read_sock = cb->read_sock;
|
|
strp->cb.read_sock_done = cb->read_sock_done ? : default_read_sock_done;
|
|
strp->cb.abort_parser = cb->abort_parser ? : strp_abort_strp;
|
|
|
|
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c
|
|
index 618b18e80cea04..622875a6f787ca 100644
|
|
--- a/net/vmw_vsock/af_vsock.c
|
|
+++ b/net/vmw_vsock/af_vsock.c
|
|
@@ -1185,6 +1185,9 @@ static int vsock_read_skb(struct sock *sk, skb_read_actor_t read_actor)
|
|
{
|
|
struct vsock_sock *vsk = vsock_sk(sk);
|
|
|
|
+ if (WARN_ON_ONCE(!vsk->transport))
|
|
+ return -ENODEV;
|
|
+
|
|
return vsk->transport->read_skb(vsk, read_actor);
|
|
}
|
|
|
|
diff --git a/net/vmw_vsock/vsock_bpf.c b/net/vmw_vsock/vsock_bpf.c
|
|
index f201d9eca1df2f..07b96d56f3a577 100644
|
|
--- a/net/vmw_vsock/vsock_bpf.c
|
|
+++ b/net/vmw_vsock/vsock_bpf.c
|
|
@@ -87,7 +87,7 @@ static int vsock_bpf_recvmsg(struct sock *sk, struct msghdr *msg,
|
|
lock_sock(sk);
|
|
vsk = vsock_sk(sk);
|
|
|
|
- if (!vsk->transport) {
|
|
+ if (WARN_ON_ONCE(!vsk->transport)) {
|
|
copied = -ENODEV;
|
|
goto out;
|
|
}
|
|
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
|
|
index 8b7dfbc8e82075..54931ad0dc990f 100644
|
|
--- a/sound/core/seq/seq_clientmgr.c
|
|
+++ b/sound/core/seq/seq_clientmgr.c
|
|
@@ -682,12 +682,18 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client,
|
|
dest_port->time_real);
|
|
|
|
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
|
|
- if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) {
|
|
- if (snd_seq_ev_is_ump(event)) {
|
|
+ if (snd_seq_ev_is_ump(event)) {
|
|
+ if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) {
|
|
result = snd_seq_deliver_from_ump(client, dest, dest_port,
|
|
event, atomic, hop);
|
|
goto __skip;
|
|
- } else if (snd_seq_client_is_ump(dest)) {
|
|
+ } else if (dest->type == USER_CLIENT &&
|
|
+ !snd_seq_client_is_ump(dest)) {
|
|
+ result = 0; // drop the event
|
|
+ goto __skip;
|
|
+ }
|
|
+ } else if (snd_seq_client_is_ump(dest)) {
|
|
+ if (!(dest->filter & SNDRV_SEQ_FILTER_NO_CONVERT)) {
|
|
result = snd_seq_deliver_to_ump(client, dest, dest_port,
|
|
event, atomic, hop);
|
|
goto __skip;
|
|
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
|
|
index 33af707a65ab11..aa6dc00985b514 100644
|
|
--- a/sound/pci/hda/hda_codec.c
|
|
+++ b/sound/pci/hda/hda_codec.c
|
|
@@ -2463,7 +2463,9 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
|
|
break;
|
|
id = kctl->id;
|
|
id.index = spdif_index;
|
|
- snd_ctl_rename_id(codec->card, &kctl->id, &id);
|
|
+ err = snd_ctl_rename_id(codec->card, &kctl->id, &id);
|
|
+ if (err < 0)
|
|
+ return err;
|
|
}
|
|
bus->primary_dig_out_type = HDA_PCM_TYPE_HDMI;
|
|
}
|
|
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
|
|
index 989ce0fb62919f..157efd1530fbf3 100644
|
|
--- a/sound/pci/hda/patch_conexant.c
|
|
+++ b/sound/pci/hda/patch_conexant.c
|
|
@@ -1084,6 +1084,7 @@ static const struct hda_quirk cxt5066_fixups[] = {
|
|
SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
|
|
SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
|
|
SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
|
|
+ SND_PCI_QUIRK(0x103c, 0x8231, "HP ProBook 450 G4", CXT_FIXUP_MUTE_LED_GPIO),
|
|
SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
|
|
SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
|
|
SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
|
|
diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/pci/hda/patch_cs8409-tables.c
|
|
index 759f48038273df..621f947e38174d 100644
|
|
--- a/sound/pci/hda/patch_cs8409-tables.c
|
|
+++ b/sound/pci/hda/patch_cs8409-tables.c
|
|
@@ -121,7 +121,7 @@ static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
|
|
{ CS42L42_MIXER_CHA_VOL, 0x3F },
|
|
{ CS42L42_MIXER_CHB_VOL, 0x3F },
|
|
{ CS42L42_MIXER_ADC_VOL, 0x3f },
|
|
- { CS42L42_HP_CTL, 0x03 },
|
|
+ { CS42L42_HP_CTL, 0x0D },
|
|
{ CS42L42_MIC_DET_CTL1, 0xB6 },
|
|
{ CS42L42_TIPSENSE_CTL, 0xC2 },
|
|
{ CS42L42_HS_CLAMP_DISABLE, 0x01 },
|
|
@@ -315,7 +315,7 @@ static const struct cs8409_i2c_param dolphin_c0_init_reg_seq[] = {
|
|
{ CS42L42_ASP_TX_SZ_EN, 0x01 },
|
|
{ CS42L42_PWR_CTL1, 0x0A },
|
|
{ CS42L42_PWR_CTL2, 0x84 },
|
|
- { CS42L42_HP_CTL, 0x03 },
|
|
+ { CS42L42_HP_CTL, 0x0D },
|
|
{ CS42L42_MIXER_CHA_VOL, 0x3F },
|
|
{ CS42L42_MIXER_CHB_VOL, 0x3F },
|
|
{ CS42L42_MIXER_ADC_VOL, 0x3f },
|
|
@@ -371,7 +371,7 @@ static const struct cs8409_i2c_param dolphin_c1_init_reg_seq[] = {
|
|
{ CS42L42_ASP_TX_SZ_EN, 0x00 },
|
|
{ CS42L42_PWR_CTL1, 0x0E },
|
|
{ CS42L42_PWR_CTL2, 0x84 },
|
|
- { CS42L42_HP_CTL, 0x01 },
|
|
+ { CS42L42_HP_CTL, 0x0D },
|
|
{ CS42L42_MIXER_CHA_VOL, 0x3F },
|
|
{ CS42L42_MIXER_CHB_VOL, 0x3F },
|
|
{ CS42L42_MIXER_ADC_VOL, 0x3f },
|
|
diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c
|
|
index 892223d9e64aba..b003ac1990ba86 100644
|
|
--- a/sound/pci/hda/patch_cs8409.c
|
|
+++ b/sound/pci/hda/patch_cs8409.c
|
|
@@ -876,7 +876,7 @@ static void cs42l42_resume(struct sub_codec *cs42l42)
|
|
{ CS42L42_DET_INT_STATUS2, 0x00 },
|
|
{ CS42L42_TSRS_PLUG_STATUS, 0x00 },
|
|
};
|
|
- int fsv_old, fsv_new;
|
|
+ unsigned int fsv;
|
|
|
|
/* Bring CS42L42 out of Reset */
|
|
spec->gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0);
|
|
@@ -893,13 +893,15 @@ static void cs42l42_resume(struct sub_codec *cs42l42)
|
|
/* Clear interrupts, by reading interrupt status registers */
|
|
cs8409_i2c_bulk_read(cs42l42, irq_regs, ARRAY_SIZE(irq_regs));
|
|
|
|
- fsv_old = cs8409_i2c_read(cs42l42, CS42L42_HP_CTL);
|
|
- if (cs42l42->full_scale_vol == CS42L42_FULL_SCALE_VOL_0DB)
|
|
- fsv_new = fsv_old & ~CS42L42_FULL_SCALE_VOL_MASK;
|
|
- else
|
|
- fsv_new = fsv_old & CS42L42_FULL_SCALE_VOL_MASK;
|
|
- if (fsv_new != fsv_old)
|
|
- cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv_new);
|
|
+ fsv = cs8409_i2c_read(cs42l42, CS42L42_HP_CTL);
|
|
+ if (cs42l42->full_scale_vol) {
|
|
+ // Set the full scale volume bit
|
|
+ fsv |= CS42L42_FULL_SCALE_VOL_MASK;
|
|
+ cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv);
|
|
+ }
|
|
+ // Unmute analog channels A and B
|
|
+ fsv = (fsv & ~CS42L42_ANA_MUTE_AB);
|
|
+ cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv);
|
|
|
|
/* we have to explicitly allow unsol event handling even during the
|
|
* resume phase so that the jack event is processed properly
|
|
@@ -921,7 +923,7 @@ static void cs42l42_suspend(struct sub_codec *cs42l42)
|
|
{ CS42L42_MIXER_CHA_VOL, 0x3F },
|
|
{ CS42L42_MIXER_ADC_VOL, 0x3F },
|
|
{ CS42L42_MIXER_CHB_VOL, 0x3F },
|
|
- { CS42L42_HP_CTL, 0x0F },
|
|
+ { CS42L42_HP_CTL, 0x0D },
|
|
{ CS42L42_ASP_RX_DAI0_EN, 0x00 },
|
|
{ CS42L42_ASP_CLK_CFG, 0x00 },
|
|
{ CS42L42_PWR_CTL1, 0xFE },
|
|
diff --git a/sound/pci/hda/patch_cs8409.h b/sound/pci/hda/patch_cs8409.h
|
|
index 5e48115caf096b..14645d25e70fd2 100644
|
|
--- a/sound/pci/hda/patch_cs8409.h
|
|
+++ b/sound/pci/hda/patch_cs8409.h
|
|
@@ -230,9 +230,10 @@ enum cs8409_coefficient_index_registers {
|
|
#define CS42L42_PDN_TIMEOUT_US (250000)
|
|
#define CS42L42_PDN_SLEEP_US (2000)
|
|
#define CS42L42_INIT_TIMEOUT_MS (45)
|
|
+#define CS42L42_ANA_MUTE_AB (0x0C)
|
|
#define CS42L42_FULL_SCALE_VOL_MASK (2)
|
|
-#define CS42L42_FULL_SCALE_VOL_0DB (1)
|
|
-#define CS42L42_FULL_SCALE_VOL_MINUS6DB (0)
|
|
+#define CS42L42_FULL_SCALE_VOL_0DB (0)
|
|
+#define CS42L42_FULL_SCALE_VOL_MINUS6DB (1)
|
|
|
|
/* Dell BULLSEYE / WARLOCK / CYBORG Specific Definitions */
|
|
|
|
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
|
|
index abe3d5b9b84b3e..75162e5f712b40 100644
|
|
--- a/sound/pci/hda/patch_realtek.c
|
|
+++ b/sound/pci/hda/patch_realtek.c
|
|
@@ -3779,6 +3779,7 @@ static void alc225_init(struct hda_codec *codec)
|
|
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
|
|
|
|
msleep(75);
|
|
+ alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
|
|
alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
|
|
}
|
|
}
|
|
diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c
|
|
index f57f0ab8a1add1..80ff1d1359f64c 100644
|
|
--- a/sound/soc/fsl/fsl_micfil.c
|
|
+++ b/sound/soc/fsl/fsl_micfil.c
|
|
@@ -156,6 +156,8 @@ static int micfil_set_quality(struct fsl_micfil *micfil)
|
|
case QUALITY_VLOW2:
|
|
qsel = MICFIL_QSEL_VLOW2_QUALITY;
|
|
break;
|
|
+ default:
|
|
+ return -EINVAL;
|
|
}
|
|
|
|
return regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2,
|
|
diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c
|
|
index 14e5c53e697b0e..7ae93cbaea9a77 100644
|
|
--- a/sound/soc/rockchip/rockchip_i2s_tdm.c
|
|
+++ b/sound/soc/rockchip/rockchip_i2s_tdm.c
|
|
@@ -453,11 +453,11 @@ static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai,
|
|
break;
|
|
case SND_SOC_DAIFMT_DSP_A:
|
|
val = I2S_TXCR_TFS_TDM_PCM;
|
|
- tdm_val = TDM_SHIFT_CTRL(0);
|
|
+ tdm_val = TDM_SHIFT_CTRL(2);
|
|
break;
|
|
case SND_SOC_DAIFMT_DSP_B:
|
|
val = I2S_TXCR_TFS_TDM_PCM;
|
|
- tdm_val = TDM_SHIFT_CTRL(2);
|
|
+ tdm_val = TDM_SHIFT_CTRL(4);
|
|
break;
|
|
default:
|
|
ret = -EINVAL;
|
|
diff --git a/sound/soc/sh/rz-ssi.c b/sound/soc/sh/rz-ssi.c
|
|
index 353863f49b3131..54f096bdc7ee27 100644
|
|
--- a/sound/soc/sh/rz-ssi.c
|
|
+++ b/sound/soc/sh/rz-ssi.c
|
|
@@ -484,6 +484,8 @@ static int rz_ssi_pio_send(struct rz_ssi_priv *ssi, struct rz_ssi_stream *strm)
|
|
sample_space = strm->fifo_sample_size;
|
|
ssifsr = rz_ssi_reg_readl(ssi, SSIFSR);
|
|
sample_space -= (ssifsr >> SSIFSR_TDC_SHIFT) & SSIFSR_TDC_MASK;
|
|
+ if (sample_space < 0)
|
|
+ return -EINVAL;
|
|
|
|
/* Only add full frames at a time */
|
|
while (frames_left && (sample_space >= runtime->channels)) {
|
|
diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c
|
|
index 8e602e42afee23..7a8eebb078e83d 100644
|
|
--- a/sound/soc/sof/pcm.c
|
|
+++ b/sound/soc/sof/pcm.c
|
|
@@ -507,6 +507,8 @@ static int sof_pcm_close(struct snd_soc_component *component,
|
|
*/
|
|
}
|
|
|
|
+ spcm->stream[substream->stream].substream = NULL;
|
|
+
|
|
return 0;
|
|
}
|
|
|
|
diff --git a/sound/soc/sof/stream-ipc.c b/sound/soc/sof/stream-ipc.c
|
|
index 216b454f6b94e3..3edcb0ea38488c 100644
|
|
--- a/sound/soc/sof/stream-ipc.c
|
|
+++ b/sound/soc/sof/stream-ipc.c
|
|
@@ -43,7 +43,7 @@ int sof_ipc_msg_data(struct snd_sof_dev *sdev,
|
|
return -ESTRPIPE;
|
|
|
|
posn_offset = stream->posn_offset;
|
|
- } else {
|
|
+ } else if (sps->cstream) {
|
|
|
|
struct sof_compr_stream *sstream = sps->cstream->runtime->private_data;
|
|
|
|
@@ -51,6 +51,10 @@ int sof_ipc_msg_data(struct snd_sof_dev *sdev,
|
|
return -ESTRPIPE;
|
|
|
|
posn_offset = sstream->posn_offset;
|
|
+
|
|
+ } else {
|
|
+ dev_err(sdev->dev, "%s: No stream opened\n", __func__);
|
|
+ return -EINVAL;
|
|
}
|
|
|
|
snd_sof_dsp_mailbox_read(sdev, posn_offset, p, sz);
|