--- /dev/null
+From 838fb58f173edcce0d175049aac2bb54ac4c481f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 6 Sep 2019 11:33:43 +0200
+Subject: Add Acer Aspire Ethos 8951G model quirk
+
+From: Sergey Bostandzhyan <jin@mediatomb.cc>
+
+[ Upstream commit 00066e9733f629e536f6b7957de2ce11a85fe15a ]
+
+This notebook has 6 built in speakers for 5.1 surround support, however
+only two got autodetected and have also not been assigned correctly.
+
+This patch enables all speakers and also fixes muting when headphones are
+plugged in.
+
+The speaker layout is as follows:
+
+pin 0x15 Front Left / Front Right
+pin 0x18 Front Center / Subwoofer
+pin 0x1b Rear Left / Rear Right (Surround)
+
+The quirk will be enabled automatically on this hardware, but can also be
+activated manually via the model=aspire-ethos module parameter.
+
+Caveat: pin 0x1b is shared between headphones jack and surround speakers.
+When headphones are plugged in, the surround speakers get muted
+automatically by the hardware, however all other speakers remain
+unmuted. Currently it's not possible to make use of the generic automute
+function in the driver, because such shared pins are not supported.
+
+If we would change the pin settings to identify the pin as headphones,
+the surround channel and thus the ability to select 5.1 profiles would
+get lost.
+
+This quirk solves the above problem by monitoring jack state of 0x1b and
+by connecting/disconnecting all remaining speaker pins when something
+gets plugged in or unplugged from the headphones jack port.
+
+Signed-off-by: Sergey Bostandzhyan <jin@mediatomb.cc>
+Link: https://lore.kernel.org/r/20190906093343.GA7640@xn--80adja5bqm.su
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Stable-dep-of: 4bf5bf54476d ("ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 71 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 71 insertions(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 9670db6ad1e1..fe17fb8d7f67 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -8510,6 +8510,45 @@ static void alc662_fixup_usi_headset_mic(struct hda_codec *codec,
+ }
+ }
+
++static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec,
++ struct hda_jack_callback *cb)
++{
++ /* surround speakers at 0x1b already get muted automatically when
++ * headphones are plugged in, but we have to mute/unmute the remaining
++ * channels manually:
++ * 0x15 - front left/front right
++ * 0x18 - front center/ LFE
++ */
++ if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) {
++ snd_hda_set_pin_ctl_cache(codec, 0x15, 0);
++ snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
++ } else {
++ snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT);
++ snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT);
++ }
++}
++
++static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec,
++ const struct hda_fixup *fix, int action)
++{
++ /* Pin 0x1b: shared headphones jack and surround speakers */
++ if (!is_jack_detectable(codec, 0x1b))
++ return;
++
++ switch (action) {
++ case HDA_FIXUP_ACT_PRE_PROBE:
++ snd_hda_jack_detect_enable_callback(codec, 0x1b,
++ alc662_aspire_ethos_mute_speakers);
++ break;
++ case HDA_FIXUP_ACT_INIT:
++ /* Make sure to start in a correct state, i.e. if
++ * headphones have been plugged in before powering up the system
++ */
++ alc662_aspire_ethos_mute_speakers(codec, NULL);
++ break;
++ }
++}
++
+ static struct coef_fw alc668_coefs[] = {
+ WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0),
+ WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80),
+@@ -8581,6 +8620,9 @@ enum {
+ ALC662_FIXUP_USI_FUNC,
+ ALC662_FIXUP_USI_HEADSET_MODE,
+ ALC662_FIXUP_LENOVO_MULTI_CODECS,
++ ALC669_FIXUP_ACER_ASPIRE_ETHOS,
++ ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER,
++ ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
+ };
+
+ static const struct hda_fixup alc662_fixups[] = {
+@@ -8907,6 +8949,33 @@ static const struct hda_fixup alc662_fixups[] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc233_alc662_fixup_lenovo_dual_codecs,
+ },
++ [ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = {
++ .type = HDA_FIXUP_FUNC,
++ .v.func = alc662_fixup_aspire_ethos_hp,
++ },
++ [ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER] = {
++ .type = HDA_FIXUP_VERBS,
++ /* subwoofer needs an extra GPIO setting to become audible */
++ .v.verbs = (const struct hda_verb[]) {
++ {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
++ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
++ {0x01, AC_VERB_SET_GPIO_DATA, 0x00},
++ { }
++ },
++ .chained = true,
++ .chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET
++ },
++ [ALC669_FIXUP_ACER_ASPIRE_ETHOS] = {
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x15, 0x92130110 }, /* front speakers */
++ { 0x18, 0x99130111 }, /* center/subwoofer */
++ { 0x1b, 0x11130012 }, /* surround plus jack for HP */
++ { }
++ },
++ .chained = true,
++ .chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER
++ },
+ };
+
+ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+@@ -8952,6 +9021,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
+ SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
+ SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
++ SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS),
+
+ #if 0
+ /* Below is a quirk table taken from the old code.
+@@ -9044,6 +9114,7 @@ static const struct hda_model_fixup alc662_fixup_models[] = {
+ {.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},
+ {.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},
+ {.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
++ {.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"},
+ {}
+ };
+
+--
+2.35.1
+
--- /dev/null
+From 4a121175adb0c0db346f02cc9eb534800b95feee Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 3 Jul 2020 18:38:17 +0300
+Subject: ALSA: hda/hdmi: fix failures at PCM open on Intel ICL and later
+
+From: Kai Vehmanen <kai.vehmanen@linux.intel.com>
+
+[ Upstream commit 56275036d8185f92eceac7479d48b858ee3dab84 ]
+
+When HDMI PCM devices are opened in a specific order, with at least one
+HDMI/DP receiver connected, ALSA PCM open fails to -EBUSY on the
+connected monitor, on recent Intel platforms (ICL/JSL and newer). While
+this is not a typical sequence, at least Pulseaudio does this every time
+when it is started, to discover the available PCMs.
+
+The rootcause is an invalid assumption in hdmi_add_pin(), where the
+total number of converters is assumed to be known at the time the
+function is called. On older Intel platforms this held true, but after
+ICL/JSL, the order how pins and converters are in the subnode list as
+returned by snd_hda_get_sub_nodes(), was changed. As a result,
+information for some converters was not stored to per_pin->mux_nids.
+And this means some pins cannot be connected to all converters, and
+application instead gets -EBUSY instead at open.
+
+The assumption that converters are always before pins in the subnode
+list, is not really a valid one. Fix the problem in hdmi_parse_codec()
+by introducing separate loops for discovering converters and pins.
+
+BugLink: https://github.com/thesofproject/linux/issues/1978
+BugLink: https://github.com/thesofproject/linux/issues/2216
+BugLink: https://github.com/thesofproject/linux/issues/2217
+Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
+Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
+Link: https://lore.kernel.org/r/20200703153818.2808592-1-kai.vehmanen@linux.intel.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_hdmi.c | 36 +++++++++++++++++++++++-------------
+ 1 file changed, 23 insertions(+), 13 deletions(-)
+
+diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
+index cbd5118570fd..be9f1c4295cd 100644
+--- a/sound/pci/hda/patch_hdmi.c
++++ b/sound/pci/hda/patch_hdmi.c
+@@ -1804,33 +1804,43 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
+
+ static int hdmi_parse_codec(struct hda_codec *codec)
+ {
+- hda_nid_t nid;
++ hda_nid_t start_nid;
++ unsigned int caps;
+ int i, nodes;
+
+- nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &nid);
+- if (!nid || nodes < 0) {
++ nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &start_nid);
++ if (!start_nid || nodes < 0) {
+ codec_warn(codec, "HDMI: failed to get afg sub nodes\n");
+ return -EINVAL;
+ }
+
+- for (i = 0; i < nodes; i++, nid++) {
+- unsigned int caps;
+- unsigned int type;
++ /*
++ * hdmi_add_pin() assumes total amount of converters to
++ * be known, so first discover all converters
++ */
++ for (i = 0; i < nodes; i++) {
++ hda_nid_t nid = start_nid + i;
+
+ caps = get_wcaps(codec, nid);
+- type = get_wcaps_type(caps);
+
+ if (!(caps & AC_WCAP_DIGITAL))
+ continue;
+
+- switch (type) {
+- case AC_WID_AUD_OUT:
++ if (get_wcaps_type(caps) == AC_WID_AUD_OUT)
+ hdmi_add_cvt(codec, nid);
+- break;
+- case AC_WID_PIN:
++ }
++
++ /* discover audio pins */
++ for (i = 0; i < nodes; i++) {
++ hda_nid_t nid = start_nid + i;
++
++ caps = get_wcaps(codec, nid);
++
++ if (!(caps & AC_WCAP_DIGITAL))
++ continue;
++
++ if (get_wcaps_type(caps) == AC_WID_PIN)
+ hdmi_add_pin(codec, nid);
+- break;
+- }
+ }
+
+ return 0;
+--
+2.35.1
+
--- /dev/null
+From 0b4eb46f4710900534f2ed59e104c46e6d7d07d2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 23 Nov 2021 16:32:44 +0800
+Subject: ALSA: hda/realtek - Add headset Mic support for Lenovo ALC897
+ platform
+
+From: Kailang Yang <kailang@realtek.com>
+
+[ Upstream commit d7f32791a9fcf0dae8b073cdea9b79e29098c5f4 ]
+
+Lenovo ALC897 platform had headset Mic.
+This patch enable supported headset Mic.
+
+Signed-off-by: Kailang Yang <kailang@realtek.com>
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/baab2c2536cb4cc18677a862c6f6d840@realtek.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Stable-dep-of: 4bf5bf54476d ("ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 40 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 40 insertions(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 566d5ea74c62..f0cf3e23d355 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -8572,6 +8572,27 @@ static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
+ }
+ }
+
++static void alc897_hp_automute_hook(struct hda_codec *codec,
++ struct hda_jack_callback *jack)
++{
++ struct alc_spec *spec = codec->spec;
++ int vref;
++
++ snd_hda_gen_hp_automute(codec, jack);
++ vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
++ snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
++ vref);
++}
++
++static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
++ const struct hda_fixup *fix, int action)
++{
++ struct alc_spec *spec = codec->spec;
++ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
++ spec->gen.hp_automute_hook = alc897_hp_automute_hook;
++ }
++}
++
+ static const struct coef_fw alc668_coefs[] = {
+ WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0),
+ WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80),
+@@ -8652,6 +8673,8 @@ enum {
+ ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
+ ALC668_FIXUP_HEADSET_MIC,
+ ALC668_FIXUP_MIC_DET_COEF,
++ ALC897_FIXUP_LENOVO_HEADSET_MIC,
++ ALC897_FIXUP_HEADSET_MIC_PIN,
+ };
+
+ static const struct hda_fixup alc662_fixups[] = {
+@@ -9051,6 +9074,19 @@ static const struct hda_fixup alc662_fixups[] = {
+ {}
+ },
+ },
++ [ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
++ .type = HDA_FIXUP_FUNC,
++ .v.func = alc897_fixup_lenovo_headset_mic,
++ },
++ [ALC897_FIXUP_HEADSET_MIC_PIN] = {
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x1a, 0x03a11050 },
++ { }
++ },
++ .chained = true,
++ .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
++ },
+ };
+
+ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+@@ -9094,6 +9130,10 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
+ SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
++ SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
++ SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
++ SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
++ SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
+--
+2.35.1
+
--- /dev/null
+From 50f5ff94cf283068f9d643d3276c129b3d60faf5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 17 Jan 2020 14:04:01 +0800
+Subject: ALSA: hda/realtek - Add Headset Mic supported for HP cPC
+
+From: Kailang Yang <kailang@realtek.com>
+
+[ Upstream commit 5af29028fd6db9438b5584ab7179710a0a22569d ]
+
+HP ALC671 need to support Headset Mic.
+
+Signed-off-by: Kailang Yang <kailang@realtek.com>
+Link: https://lore.kernel.org/r/06a9d2b176e14706976d6584cbe2d92a@realtek.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Stable-dep-of: 4bf5bf54476d ("ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 44 +++++++++++++++++++++++++++++++++++
+ 1 file changed, 44 insertions(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 3abe30eec49a..375493d3807f 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -8549,6 +8549,29 @@ static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec,
+ }
+ }
+
++static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
++ const struct hda_fixup *fix, int action)
++{
++ struct alc_spec *spec = codec->spec;
++
++ static const struct hda_pintbl pincfgs[] = {
++ { 0x19, 0x02a11040 }, /* use as headset mic, with its own jack detect */
++ { 0x1b, 0x0181304f },
++ { }
++ };
++
++ switch (action) {
++ case HDA_FIXUP_ACT_PRE_PROBE:
++ spec->gen.mixer_nid = 0;
++ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
++ snd_hda_apply_pincfgs(codec, pincfgs);
++ break;
++ case HDA_FIXUP_ACT_INIT:
++ alc_write_coef_idx(codec, 0x19, 0xa054);
++ break;
++ }
++}
++
+ static const struct coef_fw alc668_coefs[] = {
+ WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0),
+ WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80),
+@@ -8623,6 +8646,7 @@ enum {
+ ALC669_FIXUP_ACER_ASPIRE_ETHOS,
+ ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER,
+ ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
++ ALC671_FIXUP_HP_HEADSET_MIC2,
+ };
+
+ static const struct hda_fixup alc662_fixups[] = {
+@@ -8976,6 +9000,10 @@ static const struct hda_fixup alc662_fixups[] = {
+ .chained = true,
+ .chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER
+ },
++ [ALC671_FIXUP_HP_HEADSET_MIC2] = {
++ .type = HDA_FIXUP_FUNC,
++ .v.func = alc671_fixup_hp_headset_mic2,
++ },
+ };
+
+ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+@@ -9157,6 +9185,22 @@ static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
+ {0x12, 0x90a60130},
+ {0x14, 0x90170110},
+ {0x15, 0x0321101f}),
++ SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
++ {0x14, 0x01014010},
++ {0x17, 0x90170150},
++ {0x1b, 0x01813030},
++ {0x21, 0x02211020}),
++ SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
++ {0x14, 0x01014010},
++ {0x18, 0x01a19040},
++ {0x1b, 0x01813030},
++ {0x21, 0x02211020}),
++ SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
++ {0x14, 0x01014020},
++ {0x17, 0x90170110},
++ {0x18, 0x01a19050},
++ {0x1b, 0x01813040},
++ {0x21, 0x02211030}),
+ {}
+ };
+
+--
+2.35.1
+
--- /dev/null
+From e71b599471f13a7c22ef65751c1c1257486ea353 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 7 Dec 2022 21:32:18 +0800
+Subject: ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB
+
+From: Edward Pacman <edward@edward-p.xyz>
+
+[ Upstream commit 4bf5bf54476dffe60e6b6d8d539f67309ff599e2 ]
+
+Lenovo TianYi510Pro-14IOB (17aa:3742)
+require quirk for enabling headset-mic
+
+Signed-off-by: Edward Pacman <edward@edward-p.xyz>
+Cc: <stable@vger.kernel.org>
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=216756
+Link: https://lore.kernel.org/r/20221207133218.18989-1-edward@edward-p.xyz
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 0a2cf8ca2812..ed14772a8e6e 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -8593,6 +8593,17 @@ static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
+ }
+ }
+
++static void alc897_fixup_lenovo_headset_mode(struct hda_codec *codec,
++ const struct hda_fixup *fix, int action)
++{
++ struct alc_spec *spec = codec->spec;
++
++ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
++ spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
++ spec->gen.hp_automute_hook = alc897_hp_automute_hook;
++ }
++}
++
+ static const struct coef_fw alc668_coefs[] = {
+ WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0),
+ WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80),
+@@ -8676,6 +8687,8 @@ enum {
+ ALC897_FIXUP_LENOVO_HEADSET_MIC,
+ ALC897_FIXUP_HEADSET_MIC_PIN,
+ ALC897_FIXUP_HP_HSMIC_VERB,
++ ALC897_FIXUP_LENOVO_HEADSET_MODE,
++ ALC897_FIXUP_HEADSET_MIC_PIN2,
+ };
+
+ static const struct hda_fixup alc662_fixups[] = {
+@@ -9095,6 +9108,19 @@ static const struct hda_fixup alc662_fixups[] = {
+ { }
+ },
+ },
++ [ALC897_FIXUP_LENOVO_HEADSET_MODE] = {
++ .type = HDA_FIXUP_FUNC,
++ .v.func = alc897_fixup_lenovo_headset_mode,
++ },
++ [ALC897_FIXUP_HEADSET_MIC_PIN2] = {
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
++ { }
++ },
++ .chained = true,
++ .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MODE
++ },
+ };
+
+ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+@@ -9143,6 +9169,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
++ SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2),
+ SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+ SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
+--
+2.35.1
+
--- /dev/null
+From 4d69f320a26a6c6e4fc4e91f5507c3eaa012d96e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 13 Jun 2022 14:57:19 +0800
+Subject: ALSA: hda/realtek - ALC897 headset MIC no sound
+
+From: Kailang Yang <kailang@realtek.com>
+
+[ Upstream commit fe6900bd8156467365bd5b976df64928fdebfeb0 ]
+
+There is not have Headset Mic verb table in BIOS default.
+So, it will have recording issue from headset MIC.
+Add the verb table value without jack detect. It will turn on Headset Mic.
+
+Signed-off-by: Kailang Yang <kailang@realtek.com>
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/719133a27d8844a890002cb817001dfa@realtek.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Stable-dep-of: 4bf5bf54476d ("ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index f0cf3e23d355..0a2cf8ca2812 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -8675,6 +8675,7 @@ enum {
+ ALC668_FIXUP_MIC_DET_COEF,
+ ALC897_FIXUP_LENOVO_HEADSET_MIC,
+ ALC897_FIXUP_HEADSET_MIC_PIN,
++ ALC897_FIXUP_HP_HSMIC_VERB,
+ };
+
+ static const struct hda_fixup alc662_fixups[] = {
+@@ -9087,6 +9088,13 @@ static const struct hda_fixup alc662_fixups[] = {
+ .chained = true,
+ .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
+ },
++ [ALC897_FIXUP_HP_HSMIC_VERB] = {
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
++ { }
++ },
++ },
+ };
+
+ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+@@ -9111,6 +9119,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
++ SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
+ SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
+ SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
+ SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
+--
+2.35.1
+
--- /dev/null
+From 2dc43622b34ae832e20e81b6dc53aedbaffb8e9c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Mar 2020 16:28:07 +0800
+Subject: ALSA: hda/realtek - Enable headset mic of Acer X2660G with ALC662
+
+From: Jian-Hong Pan <jian-hong@endlessm.com>
+
+[ Upstream commit d858c706bdca97698752bd26b60c21ec07ef04f2 ]
+
+The Acer desktop X2660G with ALC662 can't detect the headset microphone
+until ALC662_FIXUP_ACER_X2660G_HEADSET_MODE quirk applied.
+
+Signed-off-by: Jian-Hong Pan <jian-hong@endlessm.com>
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20200317082806.73194-2-jian-hong@endlessm.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Stable-dep-of: 4bf5bf54476d ("ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 375493d3807f..024a7e473e11 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -8647,6 +8647,7 @@ enum {
+ ALC669_FIXUP_ACER_ASPIRE_ETHOS_SUBWOOFER,
+ ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
+ ALC671_FIXUP_HP_HEADSET_MIC2,
++ ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
+ };
+
+ static const struct hda_fixup alc662_fixups[] = {
+@@ -9004,6 +9005,15 @@ static const struct hda_fixup alc662_fixups[] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc671_fixup_hp_headset_mic2,
+ },
++ [ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = {
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */
++ { }
++ },
++ .chained = true,
++ .chain_id = ALC662_FIXUP_USI_FUNC
++ },
+ };
+
+ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+@@ -9015,6 +9025,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
++ SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE),
+ SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13),
+--
+2.35.1
+
--- /dev/null
+From 2e7fe866347afee7c46766e1e47df33430caaf65 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Mar 2020 16:28:09 +0800
+Subject: ALSA: hda/realtek - Enable the headset of Acer N50-600 with ALC662
+
+From: Jian-Hong Pan <jian-hong@endlessm.com>
+
+[ Upstream commit a124458a127ccd7629e20cd7bae3e1f758ed32aa ]
+
+A headset on the desktop like Acer N50-600 does not work, until quirk
+ALC662_FIXUP_ACER_NITRO_HEADSET_MODE is applied.
+
+Signed-off-by: Jian-Hong Pan <jian-hong@endlessm.com>
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20200317082806.73194-3-jian-hong@endlessm.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Stable-dep-of: 4bf5bf54476d ("ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index 024a7e473e11..bb0917b9e68f 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -8648,6 +8648,7 @@ enum {
+ ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
+ ALC671_FIXUP_HP_HEADSET_MIC2,
+ ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
++ ALC662_FIXUP_ACER_NITRO_HEADSET_MODE,
+ };
+
+ static const struct hda_fixup alc662_fixups[] = {
+@@ -9014,6 +9015,16 @@ static const struct hda_fixup alc662_fixups[] = {
+ .chained = true,
+ .chain_id = ALC662_FIXUP_USI_FUNC
+ },
++ [ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = {
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
++ { 0x1b, 0x0221144f },
++ { }
++ },
++ .chained = true,
++ .chain_id = ALC662_FIXUP_USI_FUNC
++ },
+ };
+
+ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+@@ -9025,6 +9036,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
++ SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE),
+ SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE),
+ SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+--
+2.35.1
+
--- /dev/null
+From da632ed5ac77ffb74fa8511c3e07f25b133224da Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 12 Oct 2021 19:47:48 +0800
+Subject: ALSA: hda/realtek: Fix the mic type detection issue for ASUS G551JW
+
+From: Hui Wang <hui.wang@canonical.com>
+
+[ Upstream commit a3fd1a986e499a06ac5ef95c3a39aa4611e7444c ]
+
+We need to define the codec pin 0x1b to be the mic, but somehow
+the mic doesn't support hot plugging detection, and Windows also has
+this issue, so we set it to phantom headset-mic.
+
+Also the determine_headset_type() often returns the omtp type by a
+mistake when we plug a ctia headset, this makes the mic can't record
+sound at all. Because most of the headset are ctia type nowadays and
+some machines have the fixed ctia type audio jack, it is possible this
+machine has the fixed ctia jack too. Here we set this mic jack to
+fixed ctia type, this could avoid the mic type detection mistake and
+make the ctia headset work stable.
+
+BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=214537
+Reported-and-tested-by: msd <msd.mmq@gmail.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Hui Wang <hui.wang@canonical.com>
+Link: https://lore.kernel.org/r/20211012114748.5238-1-hui.wang@canonical.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Stable-dep-of: 4bf5bf54476d ("ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index a3cc5cc0d668..566d5ea74c62 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -8649,6 +8649,9 @@ enum {
+ ALC671_FIXUP_HP_HEADSET_MIC2,
+ ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
+ ALC662_FIXUP_ACER_NITRO_HEADSET_MODE,
++ ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
++ ALC668_FIXUP_HEADSET_MIC,
++ ALC668_FIXUP_MIC_DET_COEF,
+ };
+
+ static const struct hda_fixup alc662_fixups[] = {
+@@ -9025,6 +9028,29 @@ static const struct hda_fixup alc662_fixups[] = {
+ .chained = true,
+ .chain_id = ALC662_FIXUP_USI_FUNC
+ },
++ [ALC668_FIXUP_ASUS_NO_HEADSET_MIC] = {
++ .type = HDA_FIXUP_PINS,
++ .v.pins = (const struct hda_pintbl[]) {
++ { 0x1b, 0x04a1112c },
++ { }
++ },
++ .chained = true,
++ .chain_id = ALC668_FIXUP_HEADSET_MIC
++ },
++ [ALC668_FIXUP_HEADSET_MIC] = {
++ .type = HDA_FIXUP_FUNC,
++ .v.func = alc269_fixup_headset_mic,
++ .chained = true,
++ .chain_id = ALC668_FIXUP_MIC_DET_COEF
++ },
++ [ALC668_FIXUP_MIC_DET_COEF] = {
++ .type = HDA_FIXUP_VERBS,
++ .v.verbs = (const struct hda_verb[]) {
++ { 0x20, AC_VERB_SET_COEF_INDEX, 0x15 },
++ { 0x20, AC_VERB_SET_PROC_COEF, 0x0d60 },
++ {}
++ },
++ },
+ };
+
+ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+@@ -9059,6 +9085,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
+ SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
+ SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51),
++ SND_PCI_QUIRK(0x1043, 0x185d, "ASUS G551JW", ALC668_FIXUP_ASUS_NO_HEADSET_MIC),
+ SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8),
+ SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
+ SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
+--
+2.35.1
+
--- /dev/null
+From 6e631f1d938fd402205892d0be1a0319a7593335 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 5 Jan 2020 15:47:18 +0100
+Subject: ALSA: hda/realtek - More constifications
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit 6b0f95c49d890440c01a759c767dfe40e2acdbf2 ]
+
+Apply const prefix to each coef table array.
+
+Just for minor optimization and no functional changes.
+
+Link: https://lore.kernel.org/r/20200105144823.29547-4-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Stable-dep-of: 4bf5bf54476d ("ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 118 +++++++++++++++++-----------------
+ 1 file changed, 59 insertions(+), 59 deletions(-)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index fe17fb8d7f67..3abe30eec49a 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -956,7 +956,7 @@ struct alc_codec_rename_pci_table {
+ const char *name;
+ };
+
+-static struct alc_codec_rename_table rename_tbl[] = {
++static const struct alc_codec_rename_table rename_tbl[] = {
+ { 0x10ec0221, 0xf00f, 0x1003, "ALC231" },
+ { 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
+ { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
+@@ -977,7 +977,7 @@ static struct alc_codec_rename_table rename_tbl[] = {
+ { } /* terminator */
+ };
+
+-static struct alc_codec_rename_pci_table rename_pci_tbl[] = {
++static const struct alc_codec_rename_pci_table rename_pci_tbl[] = {
+ { 0x10ec0280, 0x1028, 0, "ALC3220" },
+ { 0x10ec0282, 0x1028, 0, "ALC3221" },
+ { 0x10ec0283, 0x1028, 0, "ALC3223" },
+@@ -3115,7 +3115,7 @@ static void alc269_shutup(struct hda_codec *codec)
+ alc_shutup_pins(codec);
+ }
+
+-static struct coef_fw alc282_coefs[] = {
++static const struct coef_fw alc282_coefs[] = {
+ WRITE_COEF(0x03, 0x0002), /* Power Down Control */
+ UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */
+ WRITE_COEF(0x07, 0x0200), /* DMIC control */
+@@ -3227,7 +3227,7 @@ static void alc282_shutup(struct hda_codec *codec)
+ alc_write_coef_idx(codec, 0x78, coef78);
+ }
+
+-static struct coef_fw alc283_coefs[] = {
++static const struct coef_fw alc283_coefs[] = {
+ WRITE_COEF(0x03, 0x0002), /* Power Down Control */
+ UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */
+ WRITE_COEF(0x07, 0x0200), /* DMIC control */
+@@ -4234,7 +4234,7 @@ static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
+ }
+ }
+
+-static struct coef_fw alc225_pre_hsmode[] = {
++static const struct coef_fw alc225_pre_hsmode[] = {
+ UPDATE_COEF(0x4a, 1<<8, 0),
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
+ UPDATE_COEF(0x63, 3<<14, 3<<14),
+@@ -4247,7 +4247,7 @@ static struct coef_fw alc225_pre_hsmode[] = {
+
+ static void alc_headset_mode_unplugged(struct hda_codec *codec)
+ {
+- static struct coef_fw coef0255[] = {
++ static const struct coef_fw coef0255[] = {
+ WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
+ WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+@@ -4255,7 +4255,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
+ WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
+ {}
+ };
+- static struct coef_fw coef0256[] = {
++ static const struct coef_fw coef0256[] = {
+ WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */
+ WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
+ WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
+@@ -4263,7 +4263,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+ {}
+ };
+- static struct coef_fw coef0233[] = {
++ static const struct coef_fw coef0233[] = {
+ WRITE_COEF(0x1b, 0x0c0b),
+ WRITE_COEF(0x45, 0xc429),
+ UPDATE_COEF(0x35, 0x4000, 0),
+@@ -4273,7 +4273,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
+ WRITE_COEF(0x32, 0x42a3),
+ {}
+ };
+- static struct coef_fw coef0288[] = {
++ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
+ UPDATE_COEF(0x50, 0x2000, 0x2000),
+ UPDATE_COEF(0x56, 0x0006, 0x0006),
+@@ -4281,18 +4281,18 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
+ UPDATE_COEF(0x67, 0x2000, 0),
+ {}
+ };
+- static struct coef_fw coef0298[] = {
++ static const struct coef_fw coef0298[] = {
+ UPDATE_COEF(0x19, 0x1300, 0x0300),
+ {}
+ };
+- static struct coef_fw coef0292[] = {
++ static const struct coef_fw coef0292[] = {
+ WRITE_COEF(0x76, 0x000e),
+ WRITE_COEF(0x6c, 0x2400),
+ WRITE_COEF(0x18, 0x7308),
+ WRITE_COEF(0x6b, 0xc429),
+ {}
+ };
+- static struct coef_fw coef0293[] = {
++ static const struct coef_fw coef0293[] = {
+ UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */
+ UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */
+ UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */
+@@ -4301,16 +4301,16 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
+ UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+ {}
+ };
+- static struct coef_fw coef0668[] = {
++ static const struct coef_fw coef0668[] = {
+ WRITE_COEF(0x15, 0x0d40),
+ WRITE_COEF(0xb7, 0x802b),
+ {}
+ };
+- static struct coef_fw coef0225[] = {
++ static const struct coef_fw coef0225[] = {
+ UPDATE_COEF(0x63, 3<<14, 0),
+ {}
+ };
+- static struct coef_fw coef0274[] = {
++ static const struct coef_fw coef0274[] = {
+ UPDATE_COEF(0x4a, 0x0100, 0),
+ UPDATE_COEFEX(0x57, 0x05, 0x4000, 0),
+ UPDATE_COEF(0x6b, 0xf000, 0x5000),
+@@ -4375,25 +4375,25 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec)
+ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
+ hda_nid_t mic_pin)
+ {
+- static struct coef_fw coef0255[] = {
++ static const struct coef_fw coef0255[] = {
+ WRITE_COEFEX(0x57, 0x03, 0x8aa6),
+ WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
+ {}
+ };
+- static struct coef_fw coef0256[] = {
++ static const struct coef_fw coef0256[] = {
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/
+ WRITE_COEFEX(0x57, 0x03, 0x09a3),
+ WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
+ {}
+ };
+- static struct coef_fw coef0233[] = {
++ static const struct coef_fw coef0233[] = {
+ UPDATE_COEF(0x35, 0, 1<<14),
+ WRITE_COEF(0x06, 0x2100),
+ WRITE_COEF(0x1a, 0x0021),
+ WRITE_COEF(0x26, 0x008c),
+ {}
+ };
+- static struct coef_fw coef0288[] = {
++ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x4f, 0x00c0, 0),
+ UPDATE_COEF(0x50, 0x2000, 0),
+ UPDATE_COEF(0x56, 0x0006, 0),
+@@ -4402,30 +4402,30 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
+ UPDATE_COEF(0x67, 0x2000, 0x2000),
+ {}
+ };
+- static struct coef_fw coef0292[] = {
++ static const struct coef_fw coef0292[] = {
+ WRITE_COEF(0x19, 0xa208),
+ WRITE_COEF(0x2e, 0xacf0),
+ {}
+ };
+- static struct coef_fw coef0293[] = {
++ static const struct coef_fw coef0293[] = {
+ UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */
+ UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */
+ UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+ {}
+ };
+- static struct coef_fw coef0688[] = {
++ static const struct coef_fw coef0688[] = {
+ WRITE_COEF(0xb7, 0x802b),
+ WRITE_COEF(0xb5, 0x1040),
+ UPDATE_COEF(0xc3, 0, 1<<12),
+ {}
+ };
+- static struct coef_fw coef0225[] = {
++ static const struct coef_fw coef0225[] = {
+ UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14),
+ UPDATE_COEF(0x4a, 3<<4, 2<<4),
+ UPDATE_COEF(0x63, 3<<14, 0),
+ {}
+ };
+- static struct coef_fw coef0274[] = {
++ static const struct coef_fw coef0274[] = {
+ UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000),
+ UPDATE_COEF(0x4a, 0x0010, 0),
+ UPDATE_COEF(0x6b, 0xf000, 0),
+@@ -4511,7 +4511,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
+
+ static void alc_headset_mode_default(struct hda_codec *codec)
+ {
+- static struct coef_fw coef0225[] = {
++ static const struct coef_fw coef0225[] = {
+ UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
+ UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
+ UPDATE_COEF(0x49, 3<<8, 0<<8),
+@@ -4520,14 +4520,14 @@ static void alc_headset_mode_default(struct hda_codec *codec)
+ UPDATE_COEF(0x67, 0xf000, 0x3000),
+ {}
+ };
+- static struct coef_fw coef0255[] = {
++ static const struct coef_fw coef0255[] = {
+ WRITE_COEF(0x45, 0xc089),
+ WRITE_COEF(0x45, 0xc489),
+ WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+ WRITE_COEF(0x49, 0x0049),
+ {}
+ };
+- static struct coef_fw coef0256[] = {
++ static const struct coef_fw coef0256[] = {
+ WRITE_COEF(0x45, 0xc489),
+ WRITE_COEFEX(0x57, 0x03, 0x0da3),
+ WRITE_COEF(0x49, 0x0049),
+@@ -4535,12 +4535,12 @@ static void alc_headset_mode_default(struct hda_codec *codec)
+ WRITE_COEF(0x06, 0x6100),
+ {}
+ };
+- static struct coef_fw coef0233[] = {
++ static const struct coef_fw coef0233[] = {
+ WRITE_COEF(0x06, 0x2100),
+ WRITE_COEF(0x32, 0x4ea3),
+ {}
+ };
+- static struct coef_fw coef0288[] = {
++ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */
+ UPDATE_COEF(0x50, 0x2000, 0x2000),
+ UPDATE_COEF(0x56, 0x0006, 0x0006),
+@@ -4548,26 +4548,26 @@ static void alc_headset_mode_default(struct hda_codec *codec)
+ UPDATE_COEF(0x67, 0x2000, 0),
+ {}
+ };
+- static struct coef_fw coef0292[] = {
++ static const struct coef_fw coef0292[] = {
+ WRITE_COEF(0x76, 0x000e),
+ WRITE_COEF(0x6c, 0x2400),
+ WRITE_COEF(0x6b, 0xc429),
+ WRITE_COEF(0x18, 0x7308),
+ {}
+ };
+- static struct coef_fw coef0293[] = {
++ static const struct coef_fw coef0293[] = {
+ UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+ WRITE_COEF(0x45, 0xC429), /* Set to TRS type */
+ UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+ {}
+ };
+- static struct coef_fw coef0688[] = {
++ static const struct coef_fw coef0688[] = {
+ WRITE_COEF(0x11, 0x0041),
+ WRITE_COEF(0x15, 0x0d40),
+ WRITE_COEF(0xb7, 0x802b),
+ {}
+ };
+- static struct coef_fw coef0274[] = {
++ static const struct coef_fw coef0274[] = {
+ WRITE_COEF(0x45, 0x4289),
+ UPDATE_COEF(0x4a, 0x0010, 0x0010),
+ UPDATE_COEF(0x6b, 0x0f00, 0),
+@@ -4630,53 +4630,53 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
+ {
+ int val;
+
+- static struct coef_fw coef0255[] = {
++ static const struct coef_fw coef0255[] = {
+ WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
+ WRITE_COEF(0x1b, 0x0c2b),
+ WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+ {}
+ };
+- static struct coef_fw coef0256[] = {
++ static const struct coef_fw coef0256[] = {
+ WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
+ WRITE_COEF(0x1b, 0x0e6b),
+ {}
+ };
+- static struct coef_fw coef0233[] = {
++ static const struct coef_fw coef0233[] = {
+ WRITE_COEF(0x45, 0xd429),
+ WRITE_COEF(0x1b, 0x0c2b),
+ WRITE_COEF(0x32, 0x4ea3),
+ {}
+ };
+- static struct coef_fw coef0288[] = {
++ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x50, 0x2000, 0x2000),
+ UPDATE_COEF(0x56, 0x0006, 0x0006),
+ UPDATE_COEF(0x66, 0x0008, 0),
+ UPDATE_COEF(0x67, 0x2000, 0),
+ {}
+ };
+- static struct coef_fw coef0292[] = {
++ static const struct coef_fw coef0292[] = {
+ WRITE_COEF(0x6b, 0xd429),
+ WRITE_COEF(0x76, 0x0008),
+ WRITE_COEF(0x18, 0x7388),
+ {}
+ };
+- static struct coef_fw coef0293[] = {
++ static const struct coef_fw coef0293[] = {
+ WRITE_COEF(0x45, 0xd429), /* Set to ctia type */
+ UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+ {}
+ };
+- static struct coef_fw coef0688[] = {
++ static const struct coef_fw coef0688[] = {
+ WRITE_COEF(0x11, 0x0001),
+ WRITE_COEF(0x15, 0x0d60),
+ WRITE_COEF(0xc3, 0x0000),
+ {}
+ };
+- static struct coef_fw coef0225_1[] = {
++ static const struct coef_fw coef0225_1[] = {
+ UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+ UPDATE_COEF(0x63, 3<<14, 2<<14),
+ {}
+ };
+- static struct coef_fw coef0225_2[] = {
++ static const struct coef_fw coef0225_2[] = {
+ UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+ UPDATE_COEF(0x63, 3<<14, 1<<14),
+ {}
+@@ -4748,48 +4748,48 @@ static void alc_headset_mode_ctia(struct hda_codec *codec)
+ /* Nokia type */
+ static void alc_headset_mode_omtp(struct hda_codec *codec)
+ {
+- static struct coef_fw coef0255[] = {
++ static const struct coef_fw coef0255[] = {
+ WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
+ WRITE_COEF(0x1b, 0x0c2b),
+ WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+ {}
+ };
+- static struct coef_fw coef0256[] = {
++ static const struct coef_fw coef0256[] = {
+ WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
+ WRITE_COEF(0x1b, 0x0e6b),
+ {}
+ };
+- static struct coef_fw coef0233[] = {
++ static const struct coef_fw coef0233[] = {
+ WRITE_COEF(0x45, 0xe429),
+ WRITE_COEF(0x1b, 0x0c2b),
+ WRITE_COEF(0x32, 0x4ea3),
+ {}
+ };
+- static struct coef_fw coef0288[] = {
++ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x50, 0x2000, 0x2000),
+ UPDATE_COEF(0x56, 0x0006, 0x0006),
+ UPDATE_COEF(0x66, 0x0008, 0),
+ UPDATE_COEF(0x67, 0x2000, 0),
+ {}
+ };
+- static struct coef_fw coef0292[] = {
++ static const struct coef_fw coef0292[] = {
+ WRITE_COEF(0x6b, 0xe429),
+ WRITE_COEF(0x76, 0x0008),
+ WRITE_COEF(0x18, 0x7388),
+ {}
+ };
+- static struct coef_fw coef0293[] = {
++ static const struct coef_fw coef0293[] = {
+ WRITE_COEF(0x45, 0xe429), /* Set to omtp type */
+ UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+ {}
+ };
+- static struct coef_fw coef0688[] = {
++ static const struct coef_fw coef0688[] = {
+ WRITE_COEF(0x11, 0x0001),
+ WRITE_COEF(0x15, 0x0d50),
+ WRITE_COEF(0xc3, 0x0000),
+ {}
+ };
+- static struct coef_fw coef0225[] = {
++ static const struct coef_fw coef0225[] = {
+ UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
+ UPDATE_COEF(0x63, 3<<14, 2<<14),
+ {}
+@@ -4849,17 +4849,17 @@ static void alc_determine_headset_type(struct hda_codec *codec)
+ int val;
+ bool is_ctia = false;
+ struct alc_spec *spec = codec->spec;
+- static struct coef_fw coef0255[] = {
++ static const struct coef_fw coef0255[] = {
+ WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/
+ WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref
+ conteol) */
+ {}
+ };
+- static struct coef_fw coef0288[] = {
++ static const struct coef_fw coef0288[] = {
+ UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
+ {}
+ };
+- static struct coef_fw coef0298[] = {
++ static const struct coef_fw coef0298[] = {
+ UPDATE_COEF(0x50, 0x2000, 0x2000),
+ UPDATE_COEF(0x56, 0x0006, 0x0006),
+ UPDATE_COEF(0x66, 0x0008, 0),
+@@ -4867,19 +4867,19 @@ static void alc_determine_headset_type(struct hda_codec *codec)
+ UPDATE_COEF(0x19, 0x1300, 0x1300),
+ {}
+ };
+- static struct coef_fw coef0293[] = {
++ static const struct coef_fw coef0293[] = {
+ UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
+ WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
+ {}
+ };
+- static struct coef_fw coef0688[] = {
++ static const struct coef_fw coef0688[] = {
+ WRITE_COEF(0x11, 0x0001),
+ WRITE_COEF(0xb7, 0x802b),
+ WRITE_COEF(0x15, 0x0d60),
+ WRITE_COEF(0xc3, 0x0c00),
+ {}
+ };
+- static struct coef_fw coef0274[] = {
++ static const struct coef_fw coef0274[] = {
+ UPDATE_COEF(0x4a, 0x0010, 0),
+ UPDATE_COEF(0x4a, 0x8000, 0),
+ WRITE_COEF(0x45, 0xd289),
+@@ -5164,7 +5164,7 @@ static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
+ static void alc255_set_default_jack_type(struct hda_codec *codec)
+ {
+ /* Set to iphone type */
+- static struct coef_fw alc255fw[] = {
++ static const struct coef_fw alc255fw[] = {
+ WRITE_COEF(0x1b, 0x880b),
+ WRITE_COEF(0x45, 0xd089),
+ WRITE_COEF(0x1b, 0x080b),
+@@ -5172,7 +5172,7 @@ static void alc255_set_default_jack_type(struct hda_codec *codec)
+ WRITE_COEF(0x1b, 0x0c0b),
+ {}
+ };
+- static struct coef_fw alc256fw[] = {
++ static const struct coef_fw alc256fw[] = {
+ WRITE_COEF(0x1b, 0x884b),
+ WRITE_COEF(0x45, 0xd089),
+ WRITE_COEF(0x1b, 0x084b),
+@@ -8549,7 +8549,7 @@ static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec,
+ }
+ }
+
+-static struct coef_fw alc668_coefs[] = {
++static const struct coef_fw alc668_coefs[] = {
+ WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0),
+ WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80),
+ WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b, 0x0),
+--
+2.35.1
+
--- /dev/null
+From 3f997afe6915a117e99439677f69fdf9c66d1780 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 8 Oct 2020 18:56:44 +0800
+Subject: ALSA: hda/realtek - The front Mic on a HP machine doesn't work
+
+From: Jeremy Szu <jeremy.szu@canonical.com>
+
+[ Upstream commit 148ebf548a1af366fc797fcc7d03f0bb92b12a79 ]
+
+On a HP ZCentral, the front Mic could not be detected.
+
+The codec of the HP ZCentrol is alc671 and it needs to override the pin
+configuration to enable the headset mic.
+
+Signed-off-by: Jeremy Szu <jeremy.szu@canonical.com>
+Cc: <stable@vger.kernel.org>
+Link: https://lore.kernel.org/r/20201008105645.65505-1-jeremy.szu@canonical.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Stable-dep-of: 4bf5bf54476d ("ALSA: hda/realtek: Add quirk for Lenovo TianYi510Pro-14IOB")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/pci/hda/patch_realtek.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index bb0917b9e68f..a3cc5cc0d668 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -9049,6 +9049,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
++ SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
+ SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
+ SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
+ SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
+--
+2.35.1
+
--- /dev/null
+From 1e4d3f9286661240c542984257d065efdcc3afed Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 1 Oct 2018 14:17:41 -0400
+Subject: ext4: add new pending reservation mechanism
+
+From: Eric Whitney <enwlinux@gmail.com>
+
+[ Upstream commit 1dc0aa46e74a3366e12f426b7caaca477853e9c3 ]
+
+Add new pending reservation mechanism to help manage reserved cluster
+accounting. Its primary function is to avoid the need to read extents
+from the disk when invalidating pages as a result of a truncate, punch
+hole, or collapse range operation.
+
+Signed-off-by: Eric Whitney <enwlinux@gmail.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 131294c35ed6 ("ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/ext4.h | 3 +
+ fs/ext4/extents_status.c | 187 +++++++++++++++++++++++++++++++++++++++
+ fs/ext4/extents_status.h | 51 +++++++++++
+ fs/ext4/super.c | 8 ++
+ 4 files changed, 249 insertions(+)
+
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index 24bbfbf9a5aa..e914a0df209f 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -1041,6 +1041,9 @@ struct ext4_inode_info {
+ ext4_lblk_t i_da_metadata_calc_last_lblock;
+ int i_da_metadata_calc_len;
+
++ /* pending cluster reservations for bigalloc file systems */
++ struct ext4_pending_tree i_pending_tree;
++
+ /* on-disk additional length */
+ __u16 i_extra_isize;
+
+diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
+index e7503a3a3299..90e473084fd4 100644
+--- a/fs/ext4/extents_status.c
++++ b/fs/ext4/extents_status.c
+@@ -142,6 +142,7 @@
+ */
+
+ static struct kmem_cache *ext4_es_cachep;
++static struct kmem_cache *ext4_pending_cachep;
+
+ static int __es_insert_extent(struct inode *inode, struct extent_status *newes);
+ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
+@@ -1363,3 +1364,189 @@ static int es_reclaim_extents(struct ext4_inode_info *ei, int *nr_to_scan)
+ ei->i_es_tree.cache_es = NULL;
+ return nr_shrunk;
+ }
++
++#ifdef ES_DEBUG__
++static void ext4_print_pending_tree(struct inode *inode)
++{
++ struct ext4_pending_tree *tree;
++ struct rb_node *node;
++ struct pending_reservation *pr;
++
++ printk(KERN_DEBUG "pending reservations for inode %lu:", inode->i_ino);
++ tree = &EXT4_I(inode)->i_pending_tree;
++ node = rb_first(&tree->root);
++ while (node) {
++ pr = rb_entry(node, struct pending_reservation, rb_node);
++ printk(KERN_DEBUG " %u", pr->lclu);
++ node = rb_next(node);
++ }
++ printk(KERN_DEBUG "\n");
++}
++#else
++#define ext4_print_pending_tree(inode)
++#endif
++
++int __init ext4_init_pending(void)
++{
++ ext4_pending_cachep = kmem_cache_create("ext4_pending_reservation",
++ sizeof(struct pending_reservation),
++ 0, (SLAB_RECLAIM_ACCOUNT), NULL);
++ if (ext4_pending_cachep == NULL)
++ return -ENOMEM;
++ return 0;
++}
++
++void ext4_exit_pending(void)
++{
++ kmem_cache_destroy(ext4_pending_cachep);
++}
++
++void ext4_init_pending_tree(struct ext4_pending_tree *tree)
++{
++ tree->root = RB_ROOT;
++}
++
++/*
++ * __get_pending - retrieve a pointer to a pending reservation
++ *
++ * @inode - file containing the pending cluster reservation
++ * @lclu - logical cluster of interest
++ *
++ * Returns a pointer to a pending reservation if it's a member of
++ * the set, and NULL if not. Must be called holding i_es_lock.
++ */
++static struct pending_reservation *__get_pending(struct inode *inode,
++ ext4_lblk_t lclu)
++{
++ struct ext4_pending_tree *tree;
++ struct rb_node *node;
++ struct pending_reservation *pr = NULL;
++
++ tree = &EXT4_I(inode)->i_pending_tree;
++ node = (&tree->root)->rb_node;
++
++ while (node) {
++ pr = rb_entry(node, struct pending_reservation, rb_node);
++ if (lclu < pr->lclu)
++ node = node->rb_left;
++ else if (lclu > pr->lclu)
++ node = node->rb_right;
++ else if (lclu == pr->lclu)
++ return pr;
++ }
++ return NULL;
++}
++
++/*
++ * __insert_pending - adds a pending cluster reservation to the set of
++ * pending reservations
++ *
++ * @inode - file containing the cluster
++ * @lblk - logical block in the cluster to be added
++ *
++ * Returns 0 on successful insertion and -ENOMEM on failure. If the
++ * pending reservation is already in the set, returns successfully.
++ */
++static int __insert_pending(struct inode *inode, ext4_lblk_t lblk)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
++ struct ext4_pending_tree *tree = &EXT4_I(inode)->i_pending_tree;
++ struct rb_node **p = &tree->root.rb_node;
++ struct rb_node *parent = NULL;
++ struct pending_reservation *pr;
++ ext4_lblk_t lclu;
++ int ret = 0;
++
++ lclu = EXT4_B2C(sbi, lblk);
++ /* search to find parent for insertion */
++ while (*p) {
++ parent = *p;
++ pr = rb_entry(parent, struct pending_reservation, rb_node);
++
++ if (lclu < pr->lclu) {
++ p = &(*p)->rb_left;
++ } else if (lclu > pr->lclu) {
++ p = &(*p)->rb_right;
++ } else {
++ /* pending reservation already inserted */
++ goto out;
++ }
++ }
++
++ pr = kmem_cache_alloc(ext4_pending_cachep, GFP_ATOMIC);
++ if (pr == NULL) {
++ ret = -ENOMEM;
++ goto out;
++ }
++ pr->lclu = lclu;
++
++ rb_link_node(&pr->rb_node, parent, p);
++ rb_insert_color(&pr->rb_node, &tree->root);
++
++out:
++ return ret;
++}
++
++/*
++ * __remove_pending - removes a pending cluster reservation from the set
++ * of pending reservations
++ *
++ * @inode - file containing the cluster
++ * @lblk - logical block in the pending cluster reservation to be removed
++ *
++ * Returns successfully if pending reservation is not a member of the set.
++ */
++static void __remove_pending(struct inode *inode, ext4_lblk_t lblk)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
++ struct pending_reservation *pr;
++ struct ext4_pending_tree *tree;
++
++ pr = __get_pending(inode, EXT4_B2C(sbi, lblk));
++ if (pr != NULL) {
++ tree = &EXT4_I(inode)->i_pending_tree;
++ rb_erase(&pr->rb_node, &tree->root);
++ kmem_cache_free(ext4_pending_cachep, pr);
++ }
++}
++
++/*
++ * ext4_remove_pending - removes a pending cluster reservation from the set
++ * of pending reservations
++ *
++ * @inode - file containing the cluster
++ * @lblk - logical block in the pending cluster reservation to be removed
++ *
++ * Locking for external use of __remove_pending.
++ */
++void ext4_remove_pending(struct inode *inode, ext4_lblk_t lblk)
++{
++ struct ext4_inode_info *ei = EXT4_I(inode);
++
++ write_lock(&ei->i_es_lock);
++ __remove_pending(inode, lblk);
++ write_unlock(&ei->i_es_lock);
++}
++
++/*
++ * ext4_is_pending - determine whether a cluster has a pending reservation
++ * on it
++ *
++ * @inode - file containing the cluster
++ * @lblk - logical block in the cluster
++ *
++ * Returns true if there's a pending reservation for the cluster in the
++ * set of pending reservations, and false if not.
++ */
++bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
++ struct ext4_inode_info *ei = EXT4_I(inode);
++ bool ret;
++
++ read_lock(&ei->i_es_lock);
++ ret = (bool)(__get_pending(inode, EXT4_B2C(sbi, lblk)) != NULL);
++ read_unlock(&ei->i_es_lock);
++
++ return ret;
++}
+diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h
+index df9628c3ec3b..379b7171c67c 100644
+--- a/fs/ext4/extents_status.h
++++ b/fs/ext4/extents_status.h
+@@ -78,6 +78,51 @@ struct ext4_es_stats {
+ struct percpu_counter es_stats_shk_cnt;
+ };
+
++/*
++ * Pending cluster reservations for bigalloc file systems
++ *
++ * A cluster with a pending reservation is a logical cluster shared by at
++ * least one extent in the extents status tree with delayed and unwritten
++ * status and at least one other written or unwritten extent. The
++ * reservation is said to be pending because a cluster reservation would
++ * have to be taken in the event all blocks in the cluster shared with
++ * written or unwritten extents were deleted while the delayed and
++ * unwritten blocks remained.
++ *
++ * The set of pending cluster reservations is an auxiliary data structure
++ * used with the extents status tree to implement reserved cluster/block
++ * accounting for bigalloc file systems. The set is kept in memory and
++ * records all pending cluster reservations.
++ *
++ * Its primary function is to avoid the need to read extents from the
++ * disk when invalidating pages as a result of a truncate, punch hole, or
++ * collapse range operation. Page invalidation requires a decrease in the
++ * reserved cluster count if it results in the removal of all delayed
++ * and unwritten extents (blocks) from a cluster that is not shared with a
++ * written or unwritten extent, and no decrease otherwise. Determining
++ * whether the cluster is shared can be done by searching for a pending
++ * reservation on it.
++ *
++ * Secondarily, it provides a potentially faster method for determining
++ * whether the reserved cluster count should be increased when a physical
++ * cluster is deallocated as a result of a truncate, punch hole, or
++ * collapse range operation. The necessary information is also present
++ * in the extents status tree, but might be more rapidly accessed in
++ * the pending reservation set in many cases due to smaller size.
++ *
++ * The pending cluster reservation set is implemented as a red-black tree
++ * with the goal of minimizing per page search time overhead.
++ */
++
++struct pending_reservation {
++ struct rb_node rb_node;
++ ext4_lblk_t lclu;
++};
++
++struct ext4_pending_tree {
++ struct rb_root root;
++};
++
+ extern int __init ext4_init_es(void);
+ extern void ext4_exit_es(void);
+ extern void ext4_es_init_tree(struct ext4_es_tree *tree);
+@@ -182,4 +227,10 @@ extern void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi);
+
+ extern int ext4_seq_es_shrinker_info_show(struct seq_file *seq, void *v);
+
++extern int __init ext4_init_pending(void);
++extern void ext4_exit_pending(void);
++extern void ext4_init_pending_tree(struct ext4_pending_tree *tree);
++extern void ext4_remove_pending(struct inode *inode, ext4_lblk_t lblk);
++extern bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk);
++
+ #endif /* _EXT4_EXTENTS_STATUS_H */
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index e54a5be15636..73a431b6e720 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -1095,6 +1095,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
+ ei->i_da_metadata_calc_len = 0;
+ ei->i_da_metadata_calc_last_lblock = 0;
+ spin_lock_init(&(ei->i_block_reservation_lock));
++ ext4_init_pending_tree(&ei->i_pending_tree);
+ #ifdef CONFIG_QUOTA
+ ei->i_reserved_quota = 0;
+ memset(&ei->i_dquot, 0, sizeof(ei->i_dquot));
+@@ -6189,6 +6190,10 @@ static int __init ext4_init_fs(void)
+ if (err)
+ return err;
+
++ err = ext4_init_pending();
++ if (err)
++ goto out6;
++
+ err = ext4_init_pageio();
+ if (err)
+ goto out5;
+@@ -6227,6 +6232,8 @@ static int __init ext4_init_fs(void)
+ out4:
+ ext4_exit_pageio();
+ out5:
++ ext4_exit_pending();
++out6:
+ ext4_exit_es();
+
+ return err;
+@@ -6244,6 +6251,7 @@ static void __exit ext4_exit_fs(void)
+ ext4_exit_system_zone();
+ ext4_exit_pageio();
+ ext4_exit_es();
++ ext4_exit_pending();
+ }
+
+ MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
+--
+2.35.1
+
--- /dev/null
+From ca803d95c0c2b5366c817f7a9a5f8f3b01913c35 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 26 Oct 2022 12:23:07 +0800
+Subject: ext4: fix bug_on in __es_tree_search caused by bad quota inode
+
+From: Baokun Li <libaokun1@huawei.com>
+
+[ Upstream commit d323877484765aaacbb2769b06e355c2041ed115 ]
+
+We got a issue as fllows:
+==================================================================
+ kernel BUG at fs/ext4/extents_status.c:202!
+ invalid opcode: 0000 [#1] PREEMPT SMP
+ CPU: 1 PID: 810 Comm: mount Not tainted 6.1.0-rc1-next-g9631525255e3 #352
+ RIP: 0010:__es_tree_search.isra.0+0xb8/0xe0
+ RSP: 0018:ffffc90001227900 EFLAGS: 00010202
+ RAX: 0000000000000000 RBX: 0000000077512a0f RCX: 0000000000000000
+ RDX: 0000000000000002 RSI: 0000000000002a10 RDI: ffff8881004cd0c8
+ RBP: ffff888177512ac8 R08: 47ffffffffffffff R09: 0000000000000001
+ R10: 0000000000000001 R11: 00000000000679af R12: 0000000000002a10
+ R13: ffff888177512d88 R14: 0000000077512a10 R15: 0000000000000000
+ FS: 00007f4bd76dbc40(0000)GS:ffff88842fd00000(0000)knlGS:0000000000000000
+ CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+ CR2: 00005653bf993cf8 CR3: 000000017bfdf000 CR4: 00000000000006e0
+ DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+ DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+ Call Trace:
+ <TASK>
+ ext4_es_cache_extent+0xe2/0x210
+ ext4_cache_extents+0xd2/0x110
+ ext4_find_extent+0x5d5/0x8c0
+ ext4_ext_map_blocks+0x9c/0x1d30
+ ext4_map_blocks+0x431/0xa50
+ ext4_getblk+0x82/0x340
+ ext4_bread+0x14/0x110
+ ext4_quota_read+0xf0/0x180
+ v2_read_header+0x24/0x90
+ v2_check_quota_file+0x2f/0xa0
+ dquot_load_quota_sb+0x26c/0x760
+ dquot_load_quota_inode+0xa5/0x190
+ ext4_enable_quotas+0x14c/0x300
+ __ext4_fill_super+0x31cc/0x32c0
+ ext4_fill_super+0x115/0x2d0
+ get_tree_bdev+0x1d2/0x360
+ ext4_get_tree+0x19/0x30
+ vfs_get_tree+0x26/0xe0
+ path_mount+0x81d/0xfc0
+ do_mount+0x8d/0xc0
+ __x64_sys_mount+0xc0/0x160
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x63/0xcd
+ </TASK>
+==================================================================
+
+Above issue may happen as follows:
+-------------------------------------
+ext4_fill_super
+ ext4_orphan_cleanup
+ ext4_enable_quotas
+ ext4_quota_enable
+ ext4_iget --> get error inode <5>
+ ext4_ext_check_inode --> Wrong imode makes it escape inspection
+ make_bad_inode(inode) --> EXT4_BOOT_LOADER_INO set imode
+ dquot_load_quota_inode
+ vfs_setup_quota_inode --> check pass
+ dquot_load_quota_sb
+ v2_check_quota_file
+ v2_read_header
+ ext4_quota_read
+ ext4_bread
+ ext4_getblk
+ ext4_map_blocks
+ ext4_ext_map_blocks
+ ext4_find_extent
+ ext4_cache_extents
+ ext4_es_cache_extent
+ __es_tree_search.isra.0
+ ext4_es_end --> Wrong extents trigger BUG_ON
+
+In the above issue, s_usr_quota_inum is set to 5, but inode<5> contains
+incorrect imode and disordered extents. Because 5 is EXT4_BOOT_LOADER_INO,
+the ext4_ext_check_inode check in the ext4_iget function can be bypassed,
+finally, the extents that are not checked trigger the BUG_ON in the
+__es_tree_search function. To solve this issue, check whether the inode is
+bad_inode in vfs_setup_quota_inode().
+
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
+Reviewed-by: Jason Yan <yanaijie@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20221026042310.3839669-2-libaokun1@huawei.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/quota/dquot.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
+index a1d2aed0d833..770a2b143485 100644
+--- a/fs/quota/dquot.c
++++ b/fs/quota/dquot.c
+@@ -2303,6 +2303,8 @@ static int vfs_setup_quota_inode(struct inode *inode, int type)
+ struct super_block *sb = inode->i_sb;
+ struct quota_info *dqopt = sb_dqopt(sb);
+
++ if (is_bad_inode(inode))
++ return -EUCLEAN;
+ if (!S_ISREG(inode->i_mode))
+ return -EACCES;
+ if (IS_RDONLY(inode))
+--
+2.35.1
+
--- /dev/null
+From 70a393283f87ce85b538285dfd5b6449d01eae6f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Nov 2022 10:22:07 -0500
+Subject: ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc +
+ inline
+
+From: Eric Whitney <enwlinux@gmail.com>
+
+[ Upstream commit 131294c35ed6f777bd4e79d42af13b5c41bf2775 ]
+
+When converting files with inline data to extents, delayed allocations
+made on a file system created with both the bigalloc and inline options
+can result in invalid extent status cache content, incorrect reserved
+cluster counts, kernel memory leaks, and potential kernel panics.
+
+With bigalloc, the code that determines whether a block must be
+delayed allocated searches the extent tree to see if that block maps
+to a previously allocated cluster. If not, the block is delayed
+allocated, and otherwise, it isn't. However, if the inline option is
+also used, and if the file containing the block is marked as able to
+store data inline, there isn't a valid extent tree associated with
+the file. The current code in ext4_clu_mapped() calls
+ext4_find_extent() to search the non-existent tree for a previously
+allocated cluster anyway, which typically finds nothing, as desired.
+However, a side effect of the search can be to cache invalid content
+from the non-existent tree (garbage) in the extent status tree,
+including bogus entries in the pending reservation tree.
+
+To fix this, avoid searching the extent tree when allocating blocks
+for bigalloc + inline files that are being converted from inline to
+extent mapped.
+
+Signed-off-by: Eric Whitney <enwlinux@gmail.com>
+Link: https://lore.kernel.org/r/20221117152207.2424-1-enwlinux@gmail.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/extents.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index 0bb772cd7f88..1ad4c8eb82c1 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -5984,6 +5984,14 @@ int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu)
+ struct ext4_extent *extent;
+ ext4_lblk_t first_lblk, first_lclu, last_lclu;
+
++ /*
++ * if data can be stored inline, the logical cluster isn't
++ * mapped - no physical clusters have been allocated, and the
++ * file has no extents
++ */
++ if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA))
++ return 0;
++
+ /* search for the extent closest to the first block in the cluster */
+ path = ext4_find_extent(inode, EXT4_C2B(sbi, lclu), NULL, 0);
+ if (IS_ERR(path)) {
+--
+2.35.1
+
--- /dev/null
+From fa738f0cc8380c18b39d69f0af4eecae95cf174a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 1 Oct 2018 14:19:37 -0400
+Subject: ext4: fix reserved cluster accounting at delayed write time
+
+From: Eric Whitney <enwlinux@gmail.com>
+
+[ Upstream commit 0b02f4c0d6d9e2c611dfbdd4317193e9dca740e6 ]
+
+The code in ext4_da_map_blocks sometimes reserves space for more
+delayed allocated clusters than it should, resulting in premature
+ENOSPC, exceeded quota, and inaccurate free space reporting.
+
+Fix this by checking for written and unwritten blocks shared in the
+same cluster with the newly delayed allocated block. A cluster
+reservation should not be made for a cluster for which physical space
+has already been allocated.
+
+Signed-off-by: Eric Whitney <enwlinux@gmail.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 131294c35ed6 ("ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/ext4.h | 1 +
+ fs/ext4/extents.c | 79 +++++++++++++++++++++++++++++++++++++
+ fs/ext4/extents_status.c | 53 +++++++++++++++++++++++++
+ fs/ext4/extents_status.h | 12 ++++++
+ fs/ext4/inode.c | 79 ++++++++++++++++++++++++++++---------
+ include/trace/events/ext4.h | 35 ++++++++++++++++
+ 6 files changed, 241 insertions(+), 18 deletions(-)
+
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index e914a0df209f..d8068c0e547d 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -3241,6 +3241,7 @@ extern int ext4_swap_extents(handle_t *handle, struct inode *inode1,
+ struct inode *inode2, ext4_lblk_t lblk1,
+ ext4_lblk_t lblk2, ext4_lblk_t count,
+ int mark_unwritten,int *err);
++extern int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu);
+
+ /* move_extent.c */
+ extern void ext4_double_down_write_data_sem(struct inode *first,
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index c5c8326f5c25..0bb772cd7f88 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -5963,3 +5963,82 @@ ext4_swap_extents(handle_t *handle, struct inode *inode1,
+ }
+ return replaced_count;
+ }
++
++/*
++ * ext4_clu_mapped - determine whether any block in a logical cluster has
++ * been mapped to a physical cluster
++ *
++ * @inode - file containing the logical cluster
++ * @lclu - logical cluster of interest
++ *
++ * Returns 1 if any block in the logical cluster is mapped, signifying
++ * that a physical cluster has been allocated for it. Otherwise,
++ * returns 0. Can also return negative error codes. Derived from
++ * ext4_ext_map_blocks().
++ */
++int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
++ struct ext4_ext_path *path;
++ int depth, mapped = 0, err = 0;
++ struct ext4_extent *extent;
++ ext4_lblk_t first_lblk, first_lclu, last_lclu;
++
++ /* search for the extent closest to the first block in the cluster */
++ path = ext4_find_extent(inode, EXT4_C2B(sbi, lclu), NULL, 0);
++ if (IS_ERR(path)) {
++ err = PTR_ERR(path);
++ path = NULL;
++ goto out;
++ }
++
++ depth = ext_depth(inode);
++
++ /*
++ * A consistent leaf must not be empty. This situation is possible,
++ * though, _during_ tree modification, and it's why an assert can't
++ * be put in ext4_find_extent().
++ */
++ if (unlikely(path[depth].p_ext == NULL && depth != 0)) {
++ EXT4_ERROR_INODE(inode,
++ "bad extent address - lblock: %lu, depth: %d, pblock: %lld",
++ (unsigned long) EXT4_C2B(sbi, lclu),
++ depth, path[depth].p_block);
++ err = -EFSCORRUPTED;
++ goto out;
++ }
++
++ extent = path[depth].p_ext;
++
++ /* can't be mapped if the extent tree is empty */
++ if (extent == NULL)
++ goto out;
++
++ first_lblk = le32_to_cpu(extent->ee_block);
++ first_lclu = EXT4_B2C(sbi, first_lblk);
++
++ /*
++ * Three possible outcomes at this point - found extent spanning
++ * the target cluster, to the left of the target cluster, or to the
++ * right of the target cluster. The first two cases are handled here.
++ * The last case indicates the target cluster is not mapped.
++ */
++ if (lclu >= first_lclu) {
++ last_lclu = EXT4_B2C(sbi, first_lblk +
++ ext4_ext_get_actual_len(extent) - 1);
++ if (lclu <= last_lclu) {
++ mapped = 1;
++ } else {
++ first_lblk = ext4_ext_next_allocated_block(path);
++ first_lclu = EXT4_B2C(sbi, first_lblk);
++ if (lclu == first_lclu)
++ mapped = 1;
++ }
++ }
++
++out:
++ ext4_ext_drop_refs(path);
++ kfree(path);
++
++ return err ? err : mapped;
++}
+diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
+index 90e473084fd4..441ee2e747d3 100644
+--- a/fs/ext4/extents_status.c
++++ b/fs/ext4/extents_status.c
+@@ -1550,3 +1550,56 @@ bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk)
+
+ return ret;
+ }
++
++/*
++ * ext4_es_insert_delayed_block - adds a delayed block to the extents status
++ * tree, adding a pending reservation where
++ * needed
++ *
++ * @inode - file containing the newly added block
++ * @lblk - logical block to be added
++ * @allocated - indicates whether a physical cluster has been allocated for
++ * the logical cluster that contains the block
++ *
++ * Returns 0 on success, negative error code on failure.
++ */
++int ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk,
++ bool allocated)
++{
++ struct extent_status newes;
++ int err = 0;
++
++ es_debug("add [%u/1) delayed to extent status tree of inode %lu\n",
++ lblk, inode->i_ino);
++
++ newes.es_lblk = lblk;
++ newes.es_len = 1;
++ ext4_es_store_pblock_status(&newes, ~0, EXTENT_STATUS_DELAYED);
++ trace_ext4_es_insert_delayed_block(inode, &newes, allocated);
++
++ ext4_es_insert_extent_check(inode, &newes);
++
++ write_lock(&EXT4_I(inode)->i_es_lock);
++
++ err = __es_remove_extent(inode, lblk, lblk);
++ if (err != 0)
++ goto error;
++retry:
++ err = __es_insert_extent(inode, &newes);
++ if (err == -ENOMEM && __es_shrink(EXT4_SB(inode->i_sb),
++ 128, EXT4_I(inode)))
++ goto retry;
++ if (err != 0)
++ goto error;
++
++ if (allocated)
++ __insert_pending(inode, lblk);
++
++error:
++ write_unlock(&EXT4_I(inode)->i_es_lock);
++
++ ext4_es_print_tree(inode);
++ ext4_print_pending_tree(inode);
++
++ return err;
++}
+diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h
+index 379b7171c67c..9d3c676ec623 100644
+--- a/fs/ext4/extents_status.h
++++ b/fs/ext4/extents_status.h
+@@ -178,6 +178,16 @@ static inline int ext4_es_is_hole(struct extent_status *es)
+ return (ext4_es_type(es) & EXTENT_STATUS_HOLE) != 0;
+ }
+
++static inline int ext4_es_is_mapped(struct extent_status *es)
++{
++ return (ext4_es_is_written(es) || ext4_es_is_unwritten(es));
++}
++
++static inline int ext4_es_is_delonly(struct extent_status *es)
++{
++ return (ext4_es_is_delayed(es) && !ext4_es_is_unwritten(es));
++}
++
+ static inline void ext4_es_set_referenced(struct extent_status *es)
+ {
+ es->es_pblk |= ((ext4_fsblk_t)EXTENT_STATUS_REFERENCED) << ES_SHIFT;
+@@ -232,5 +242,7 @@ extern void ext4_exit_pending(void);
+ extern void ext4_init_pending_tree(struct ext4_pending_tree *tree);
+ extern void ext4_remove_pending(struct inode *inode, ext4_lblk_t lblk);
+ extern bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk);
++extern int ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk,
++ bool allocated);
+
+ #endif /* _EXT4_EXTENTS_STATUS_H */
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index cba27ba41834..17d120ac2010 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -1823,6 +1823,65 @@ static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh)
+ return (buffer_delay(bh) || buffer_unwritten(bh)) && buffer_dirty(bh);
+ }
+
++/*
++ * ext4_insert_delayed_block - adds a delayed block to the extents status
++ * tree, incrementing the reserved cluster/block
++ * count or making a pending reservation
++ * where needed
++ *
++ * @inode - file containing the newly added block
++ * @lblk - logical block to be added
++ *
++ * Returns 0 on success, negative error code on failure.
++ */
++static int ext4_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
++ int ret;
++ bool allocated = false;
++
++ /*
++ * If the cluster containing lblk is shared with a delayed,
++ * written, or unwritten extent in a bigalloc file system, it's
++ * already been accounted for and does not need to be reserved.
++ * A pending reservation must be made for the cluster if it's
++ * shared with a written or unwritten extent and doesn't already
++ * have one. Written and unwritten extents can be purged from the
++ * extents status tree if the system is under memory pressure, so
++ * it's necessary to examine the extent tree if a search of the
++ * extents status tree doesn't get a match.
++ */
++ if (sbi->s_cluster_ratio == 1) {
++ ret = ext4_da_reserve_space(inode);
++ if (ret != 0) /* ENOSPC */
++ goto errout;
++ } else { /* bigalloc */
++ if (!ext4_es_scan_clu(inode, &ext4_es_is_delonly, lblk)) {
++ if (!ext4_es_scan_clu(inode,
++ &ext4_es_is_mapped, lblk)) {
++ ret = ext4_clu_mapped(inode,
++ EXT4_B2C(sbi, lblk));
++ if (ret < 0)
++ goto errout;
++ if (ret == 0) {
++ ret = ext4_da_reserve_space(inode);
++ if (ret != 0) /* ENOSPC */
++ goto errout;
++ } else {
++ allocated = true;
++ }
++ } else {
++ allocated = true;
++ }
++ }
++ }
++
++ ret = ext4_es_insert_delayed_block(inode, lblk, allocated);
++
++errout:
++ return ret;
++}
++
+ /*
+ * This function is grabs code from the very beginning of
+ * ext4_map_blocks, but assumes that the caller is from delayed write
+@@ -1907,25 +1966,9 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
+ * XXX: __block_prepare_write() unmaps passed block,
+ * is it OK?
+ */
+- /*
+- * If the block was allocated from previously allocated cluster,
+- * then we don't need to reserve it again. However we still need
+- * to reserve metadata for every block we're going to write.
+- */
+- if (EXT4_SB(inode->i_sb)->s_cluster_ratio == 1 ||
+- !ext4_es_scan_clu(inode,
+- &ext4_es_is_delayed, map->m_lblk)) {
+- ret = ext4_da_reserve_space(inode);
+- if (ret) {
+- /* not enough space to reserve */
+- retval = ret;
+- goto out_unlock;
+- }
+- }
+
+- ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len,
+- ~0, EXTENT_STATUS_DELAYED);
+- if (ret) {
++ ret = ext4_insert_delayed_block(inode, map->m_lblk);
++ if (ret != 0) {
+ retval = ret;
+ goto out_unlock;
+ }
+diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
+index 388dc3666cc7..20c9b8e77a57 100644
+--- a/include/trace/events/ext4.h
++++ b/include/trace/events/ext4.h
+@@ -2532,6 +2532,41 @@ TRACE_EVENT(ext4_es_shrink,
+ __entry->scan_time, __entry->nr_skipped, __entry->retried)
+ );
+
++TRACE_EVENT(ext4_es_insert_delayed_block,
++ TP_PROTO(struct inode *inode, struct extent_status *es,
++ bool allocated),
++
++ TP_ARGS(inode, es, allocated),
++
++ TP_STRUCT__entry(
++ __field( dev_t, dev )
++ __field( ino_t, ino )
++ __field( ext4_lblk_t, lblk )
++ __field( ext4_lblk_t, len )
++ __field( ext4_fsblk_t, pblk )
++ __field( char, status )
++ __field( bool, allocated )
++ ),
++
++ TP_fast_assign(
++ __entry->dev = inode->i_sb->s_dev;
++ __entry->ino = inode->i_ino;
++ __entry->lblk = es->es_lblk;
++ __entry->len = es->es_len;
++ __entry->pblk = ext4_es_pblock(es);
++ __entry->status = ext4_es_status(es);
++ __entry->allocated = allocated;
++ ),
++
++ TP_printk("dev %d,%d ino %lu es [%u/%u) mapped %llu status %s "
++ "allocated %d",
++ MAJOR(__entry->dev), MINOR(__entry->dev),
++ (unsigned long) __entry->ino,
++ __entry->lblk, __entry->len,
++ __entry->pblk, show_extent_status(__entry->status),
++ __entry->allocated)
++);
++
+ /* fsmap traces */
+ DECLARE_EVENT_CLASS(ext4_fsmap_class,
+ TP_PROTO(struct super_block *sb, u32 keydev, u32 agno, u64 bno, u64 len,
+--
+2.35.1
+
--- /dev/null
+From d18baeee2b2eb18b38f13f083db0772fb783788f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 17 Nov 2022 15:36:03 +0800
+Subject: ext4: fix uninititialized value in 'ext4_evict_inode'
+
+From: Ye Bin <yebin10@huawei.com>
+
+[ Upstream commit 7ea71af94eaaaf6d9aed24bc94a05b977a741cb9 ]
+
+Syzbot found the following issue:
+=====================================================
+BUG: KMSAN: uninit-value in ext4_evict_inode+0xdd/0x26b0 fs/ext4/inode.c:180
+ ext4_evict_inode+0xdd/0x26b0 fs/ext4/inode.c:180
+ evict+0x365/0x9a0 fs/inode.c:664
+ iput_final fs/inode.c:1747 [inline]
+ iput+0x985/0xdd0 fs/inode.c:1773
+ __ext4_new_inode+0xe54/0x7ec0 fs/ext4/ialloc.c:1361
+ ext4_mknod+0x376/0x840 fs/ext4/namei.c:2844
+ vfs_mknod+0x79d/0x830 fs/namei.c:3914
+ do_mknodat+0x47d/0xaa0
+ __do_sys_mknodat fs/namei.c:3992 [inline]
+ __se_sys_mknodat fs/namei.c:3989 [inline]
+ __ia32_sys_mknodat+0xeb/0x150 fs/namei.c:3989
+ do_syscall_32_irqs_on arch/x86/entry/common.c:112 [inline]
+ __do_fast_syscall_32+0xa2/0x100 arch/x86/entry/common.c:178
+ do_fast_syscall_32+0x33/0x70 arch/x86/entry/common.c:203
+ do_SYSENTER_32+0x1b/0x20 arch/x86/entry/common.c:246
+ entry_SYSENTER_compat_after_hwframe+0x70/0x82
+
+Uninit was created at:
+ __alloc_pages+0x9f1/0xe80 mm/page_alloc.c:5578
+ alloc_pages+0xaae/0xd80 mm/mempolicy.c:2285
+ alloc_slab_page mm/slub.c:1794 [inline]
+ allocate_slab+0x1b5/0x1010 mm/slub.c:1939
+ new_slab mm/slub.c:1992 [inline]
+ ___slab_alloc+0x10c3/0x2d60 mm/slub.c:3180
+ __slab_alloc mm/slub.c:3279 [inline]
+ slab_alloc_node mm/slub.c:3364 [inline]
+ slab_alloc mm/slub.c:3406 [inline]
+ __kmem_cache_alloc_lru mm/slub.c:3413 [inline]
+ kmem_cache_alloc_lru+0x6f3/0xb30 mm/slub.c:3429
+ alloc_inode_sb include/linux/fs.h:3117 [inline]
+ ext4_alloc_inode+0x5f/0x860 fs/ext4/super.c:1321
+ alloc_inode+0x83/0x440 fs/inode.c:259
+ new_inode_pseudo fs/inode.c:1018 [inline]
+ new_inode+0x3b/0x430 fs/inode.c:1046
+ __ext4_new_inode+0x2a7/0x7ec0 fs/ext4/ialloc.c:959
+ ext4_mkdir+0x4d5/0x1560 fs/ext4/namei.c:2992
+ vfs_mkdir+0x62a/0x870 fs/namei.c:4035
+ do_mkdirat+0x466/0x7b0 fs/namei.c:4060
+ __do_sys_mkdirat fs/namei.c:4075 [inline]
+ __se_sys_mkdirat fs/namei.c:4073 [inline]
+ __ia32_sys_mkdirat+0xc4/0x120 fs/namei.c:4073
+ do_syscall_32_irqs_on arch/x86/entry/common.c:112 [inline]
+ __do_fast_syscall_32+0xa2/0x100 arch/x86/entry/common.c:178
+ do_fast_syscall_32+0x33/0x70 arch/x86/entry/common.c:203
+ do_SYSENTER_32+0x1b/0x20 arch/x86/entry/common.c:246
+ entry_SYSENTER_compat_after_hwframe+0x70/0x82
+
+CPU: 1 PID: 4625 Comm: syz-executor.2 Not tainted 6.1.0-rc4-syzkaller-62821-gcb231e2f67ec #0
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/26/2022
+=====================================================
+
+Now, 'ext4_alloc_inode()' didn't init 'ei->i_flags'. If new inode failed
+before set 'ei->i_flags' in '__ext4_new_inode()', then do 'iput()'. As after
+6bc0d63dad7f commit will access 'ei->i_flags' in 'ext4_evict_inode()' which
+will lead to access uninit-value.
+To solve above issue just init 'ei->i_flags' in 'ext4_alloc_inode()'.
+
+Reported-by: syzbot+57b25da729eb0b88177d@syzkaller.appspotmail.com
+Signed-off-by: Ye Bin <yebin10@huawei.com>
+Fixes: 6bc0d63dad7f ("ext4: remove EA inode entry from mbcache on inode eviction")
+Reviewed-by: Jan Kara <jack@suse.cz>
+Reviewed-by: Eric Biggers <ebiggers@google.com>
+Link: https://lore.kernel.org/r/20221117073603.2598882-1-yebin@huaweicloud.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/super.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/fs/ext4/super.c b/fs/ext4/super.c
+index 85703a3e69e5..e54a5be15636 100644
+--- a/fs/ext4/super.c
++++ b/fs/ext4/super.c
+@@ -1081,6 +1081,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
+ return NULL;
+
+ inode_set_iversion(&ei->vfs_inode, 1);
++ ei->i_flags = 0;
+ spin_lock_init(&ei->i_raw_lock);
+ INIT_LIST_HEAD(&ei->i_prealloc_list);
+ spin_lock_init(&ei->i_prealloc_lock);
+--
+2.35.1
+
--- /dev/null
+From c38979a0ed86a39afa58548afc86881d6960ab57 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 2 Nov 2022 16:06:33 +0800
+Subject: ext4: fix use-after-free in ext4_orphan_cleanup
+
+From: Baokun Li <libaokun1@huawei.com>
+
+[ Upstream commit a71248b1accb2b42e4980afef4fa4a27fa0e36f5 ]
+
+I caught a issue as follows:
+==================================================================
+ BUG: KASAN: use-after-free in __list_add_valid+0x28/0x1a0
+ Read of size 8 at addr ffff88814b13f378 by task mount/710
+
+ CPU: 1 PID: 710 Comm: mount Not tainted 6.1.0-rc3-next #370
+ Call Trace:
+ <TASK>
+ dump_stack_lvl+0x73/0x9f
+ print_report+0x25d/0x759
+ kasan_report+0xc0/0x120
+ __asan_load8+0x99/0x140
+ __list_add_valid+0x28/0x1a0
+ ext4_orphan_cleanup+0x564/0x9d0 [ext4]
+ __ext4_fill_super+0x48e2/0x5300 [ext4]
+ ext4_fill_super+0x19f/0x3a0 [ext4]
+ get_tree_bdev+0x27b/0x450
+ ext4_get_tree+0x19/0x30 [ext4]
+ vfs_get_tree+0x49/0x150
+ path_mount+0xaae/0x1350
+ do_mount+0xe2/0x110
+ __x64_sys_mount+0xf0/0x190
+ do_syscall_64+0x35/0x80
+ entry_SYSCALL_64_after_hwframe+0x63/0xcd
+ </TASK>
+ [...]
+==================================================================
+
+Above issue may happen as follows:
+-------------------------------------
+ext4_fill_super
+ ext4_orphan_cleanup
+ --- loop1: assume last_orphan is 12 ---
+ list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan)
+ ext4_truncate --> return 0
+ ext4_inode_attach_jinode --> return -ENOMEM
+ iput(inode) --> free inode<12>
+ --- loop2: last_orphan is still 12 ---
+ list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan);
+ // use inode<12> and trigger UAF
+
+To solve this issue, we need to propagate the return value of
+ext4_inode_attach_jinode() appropriately.
+
+Signed-off-by: Baokun Li <libaokun1@huawei.com>
+Reviewed-by: Jan Kara <jack@suse.cz>
+Link: https://lore.kernel.org/r/20221102080633.1630225-1-libaokun1@huawei.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Cc: stable@kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/inode.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 16d2b88bc66d..3c7bbdaa425a 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -4568,7 +4568,8 @@ int ext4_truncate(struct inode *inode)
+
+ /* If we zero-out tail of the page, we have to create jinode for jbd2 */
+ if (inode->i_size & (inode->i_sb->s_blocksize - 1)) {
+- if (ext4_inode_attach_jinode(inode) < 0)
++ err = ext4_inode_attach_jinode(inode);
++ if (err)
+ goto out_trace;
+ }
+
+--
+2.35.1
+
--- /dev/null
+From 24d8fd52d6535265069404abafc1d2223c93db9c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 1 Oct 2018 14:10:39 -0400
+Subject: ext4: generalize extents status tree search functions
+
+From: Eric Whitney <enwlinux@gmail.com>
+
+[ Upstream commit ad431025aecda85d3ebef5e4a3aca5c1c681d0c7 ]
+
+Ext4 contains a few functions that are used to search for delayed
+extents or blocks in the extents status tree. Rather than duplicate
+code to add new functions to search for extents with different status
+values, such as written or a combination of delayed and unwritten,
+generalize the existing code to search for caller-specified extents
+status values. Also, move this code into extents_status.c where it
+is better associated with the data structures it operates upon, and
+where it can be more readily used to implement new extents status tree
+functions that might want a broader scope for i_es_lock.
+
+Three missing static specifiers in RFC version of patch reported and
+fixed by Fengguang Wu <fengguang.wu@intel.com>.
+
+Signed-off-by: Eric Whitney <enwlinux@gmail.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: 131294c35ed6 ("ext4: fix delayed allocation bug in ext4_clu_mapped for bigalloc + inline")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/ext4.h | 4 -
+ fs/ext4/extents.c | 52 +++----------
+ fs/ext4/extents_status.c | 149 +++++++++++++++++++++++++++++++-----
+ fs/ext4/extents_status.h | 13 +++-
+ fs/ext4/inode.c | 17 ++--
+ include/trace/events/ext4.h | 4 +-
+ 6 files changed, 165 insertions(+), 74 deletions(-)
+
+diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
+index e58b162ad5d6..24bbfbf9a5aa 100644
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -3228,10 +3228,6 @@ extern struct ext4_ext_path *ext4_find_extent(struct inode *, ext4_lblk_t,
+ int flags);
+ extern void ext4_ext_drop_refs(struct ext4_ext_path *);
+ extern int ext4_ext_check_inode(struct inode *inode);
+-extern int ext4_find_delalloc_range(struct inode *inode,
+- ext4_lblk_t lblk_start,
+- ext4_lblk_t lblk_end);
+-extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk);
+ extern ext4_lblk_t ext4_ext_next_allocated_block(struct ext4_ext_path *path);
+ extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+ __u64 start, __u64 len);
+diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
+index 6c492fca60c4..c5c8326f5c25 100644
+--- a/fs/ext4/extents.c
++++ b/fs/ext4/extents.c
+@@ -2381,8 +2381,8 @@ ext4_ext_put_gap_in_cache(struct inode *inode, ext4_lblk_t hole_start,
+ {
+ struct extent_status es;
+
+- ext4_es_find_delayed_extent_range(inode, hole_start,
+- hole_start + hole_len - 1, &es);
++ ext4_es_find_extent_range(inode, &ext4_es_is_delayed, hole_start,
++ hole_start + hole_len - 1, &es);
+ if (es.es_len) {
+ /* There's delayed extent containing lblock? */
+ if (es.es_lblk <= hole_start)
+@@ -3852,39 +3852,6 @@ static int check_eofblocks_fl(handle_t *handle, struct inode *inode,
+ return ext4_mark_inode_dirty(handle, inode);
+ }
+
+-/**
+- * ext4_find_delalloc_range: find delayed allocated block in the given range.
+- *
+- * Return 1 if there is a delalloc block in the range, otherwise 0.
+- */
+-int ext4_find_delalloc_range(struct inode *inode,
+- ext4_lblk_t lblk_start,
+- ext4_lblk_t lblk_end)
+-{
+- struct extent_status es;
+-
+- ext4_es_find_delayed_extent_range(inode, lblk_start, lblk_end, &es);
+- if (es.es_len == 0)
+- return 0; /* there is no delay extent in this tree */
+- else if (es.es_lblk <= lblk_start &&
+- lblk_start < es.es_lblk + es.es_len)
+- return 1;
+- else if (lblk_start <= es.es_lblk && es.es_lblk <= lblk_end)
+- return 1;
+- else
+- return 0;
+-}
+-
+-int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk)
+-{
+- struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+- ext4_lblk_t lblk_start, lblk_end;
+- lblk_start = EXT4_LBLK_CMASK(sbi, lblk);
+- lblk_end = lblk_start + sbi->s_cluster_ratio - 1;
+-
+- return ext4_find_delalloc_range(inode, lblk_start, lblk_end);
+-}
+-
+ /**
+ * Determines how many complete clusters (out of those specified by the 'map')
+ * are under delalloc and were reserved quota for.
+@@ -3943,7 +3910,8 @@ get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start,
+ lblk_from = EXT4_LBLK_CMASK(sbi, lblk_start);
+ lblk_to = lblk_from + c_offset - 1;
+
+- if (ext4_find_delalloc_range(inode, lblk_from, lblk_to))
++ if (ext4_es_scan_range(inode, &ext4_es_is_delayed, lblk_from,
++ lblk_to))
+ allocated_clusters--;
+ }
+
+@@ -3953,7 +3921,8 @@ get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start,
+ lblk_from = lblk_start + num_blks;
+ lblk_to = lblk_from + (sbi->s_cluster_ratio - c_offset) - 1;
+
+- if (ext4_find_delalloc_range(inode, lblk_from, lblk_to))
++ if (ext4_es_scan_range(inode, &ext4_es_is_delayed, lblk_from,
++ lblk_to))
+ allocated_clusters--;
+ }
+
+@@ -5108,8 +5077,10 @@ static int ext4_find_delayed_extent(struct inode *inode,
+ ext4_lblk_t block, next_del;
+
+ if (newes->es_pblk == 0) {
+- ext4_es_find_delayed_extent_range(inode, newes->es_lblk,
+- newes->es_lblk + newes->es_len - 1, &es);
++ ext4_es_find_extent_range(inode, &ext4_es_is_delayed,
++ newes->es_lblk,
++ newes->es_lblk + newes->es_len - 1,
++ &es);
+
+ /*
+ * No extent in extent-tree contains block @newes->es_pblk,
+@@ -5130,7 +5101,8 @@ static int ext4_find_delayed_extent(struct inode *inode,
+ }
+
+ block = newes->es_lblk + newes->es_len;
+- ext4_es_find_delayed_extent_range(inode, block, EXT_MAX_BLOCKS, &es);
++ ext4_es_find_extent_range(inode, &ext4_es_is_delayed, block,
++ EXT_MAX_BLOCKS, &es);
+ if (es.es_len == 0)
+ next_del = EXT_MAX_BLOCKS;
+ else
+diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
+index 027c3e1b9f61..e7503a3a3299 100644
+--- a/fs/ext4/extents_status.c
++++ b/fs/ext4/extents_status.c
+@@ -233,30 +233,38 @@ static struct extent_status *__es_tree_search(struct rb_root *root,
+ }
+
+ /*
+- * ext4_es_find_delayed_extent_range: find the 1st delayed extent covering
+- * @es->lblk if it exists, otherwise, the next extent after @es->lblk.
++ * ext4_es_find_extent_range - find extent with specified status within block
++ * range or next extent following block range in
++ * extents status tree
+ *
+- * @inode: the inode which owns delayed extents
+- * @lblk: the offset where we start to search
+- * @end: the offset where we stop to search
+- * @es: delayed extent that we found
++ * @inode - file containing the range
++ * @matching_fn - pointer to function that matches extents with desired status
++ * @lblk - logical block defining start of range
++ * @end - logical block defining end of range
++ * @es - extent found, if any
++ *
++ * Find the first extent within the block range specified by @lblk and @end
++ * in the extents status tree that satisfies @matching_fn. If a match
++ * is found, it's returned in @es. If not, and a matching extent is found
++ * beyond the block range, it's returned in @es. If no match is found, an
++ * extent is returned in @es whose es_lblk, es_len, and es_pblk components
++ * are 0.
+ */
+-void ext4_es_find_delayed_extent_range(struct inode *inode,
+- ext4_lblk_t lblk, ext4_lblk_t end,
+- struct extent_status *es)
++static void __es_find_extent_range(struct inode *inode,
++ int (*matching_fn)(struct extent_status *es),
++ ext4_lblk_t lblk, ext4_lblk_t end,
++ struct extent_status *es)
+ {
+ struct ext4_es_tree *tree = NULL;
+ struct extent_status *es1 = NULL;
+ struct rb_node *node;
+
+- BUG_ON(es == NULL);
+- BUG_ON(end < lblk);
+- trace_ext4_es_find_delayed_extent_range_enter(inode, lblk);
++ WARN_ON(es == NULL);
++ WARN_ON(end < lblk);
+
+- read_lock(&EXT4_I(inode)->i_es_lock);
+ tree = &EXT4_I(inode)->i_es_tree;
+
+- /* find extent in cache firstly */
++ /* see if the extent has been cached */
+ es->es_lblk = es->es_len = es->es_pblk = 0;
+ if (tree->cache_es) {
+ es1 = tree->cache_es;
+@@ -271,28 +279,133 @@ void ext4_es_find_delayed_extent_range(struct inode *inode,
+ es1 = __es_tree_search(&tree->root, lblk);
+
+ out:
+- if (es1 && !ext4_es_is_delayed(es1)) {
++ if (es1 && !matching_fn(es1)) {
+ while ((node = rb_next(&es1->rb_node)) != NULL) {
+ es1 = rb_entry(node, struct extent_status, rb_node);
+ if (es1->es_lblk > end) {
+ es1 = NULL;
+ break;
+ }
+- if (ext4_es_is_delayed(es1))
++ if (matching_fn(es1))
+ break;
+ }
+ }
+
+- if (es1 && ext4_es_is_delayed(es1)) {
++ if (es1 && matching_fn(es1)) {
+ tree->cache_es = es1;
+ es->es_lblk = es1->es_lblk;
+ es->es_len = es1->es_len;
+ es->es_pblk = es1->es_pblk;
+ }
+
++}
++
++/*
++ * Locking for __es_find_extent_range() for external use
++ */
++void ext4_es_find_extent_range(struct inode *inode,
++ int (*matching_fn)(struct extent_status *es),
++ ext4_lblk_t lblk, ext4_lblk_t end,
++ struct extent_status *es)
++{
++ trace_ext4_es_find_extent_range_enter(inode, lblk);
++
++ read_lock(&EXT4_I(inode)->i_es_lock);
++ __es_find_extent_range(inode, matching_fn, lblk, end, es);
++ read_unlock(&EXT4_I(inode)->i_es_lock);
++
++ trace_ext4_es_find_extent_range_exit(inode, es);
++}
++
++/*
++ * __es_scan_range - search block range for block with specified status
++ * in extents status tree
++ *
++ * @inode - file containing the range
++ * @matching_fn - pointer to function that matches extents with desired status
++ * @lblk - logical block defining start of range
++ * @end - logical block defining end of range
++ *
++ * Returns true if at least one block in the specified block range satisfies
++ * the criterion specified by @matching_fn, and false if not. If at least
++ * one extent has the specified status, then there is at least one block
++ * in the cluster with that status. Should only be called by code that has
++ * taken i_es_lock.
++ */
++static bool __es_scan_range(struct inode *inode,
++ int (*matching_fn)(struct extent_status *es),
++ ext4_lblk_t start, ext4_lblk_t end)
++{
++ struct extent_status es;
++
++ __es_find_extent_range(inode, matching_fn, start, end, &es);
++ if (es.es_len == 0)
++ return false; /* no matching extent in the tree */
++ else if (es.es_lblk <= start &&
++ start < es.es_lblk + es.es_len)
++ return true;
++ else if (start <= es.es_lblk && es.es_lblk <= end)
++ return true;
++ else
++ return false;
++}
++/*
++ * Locking for __es_scan_range() for external use
++ */
++bool ext4_es_scan_range(struct inode *inode,
++ int (*matching_fn)(struct extent_status *es),
++ ext4_lblk_t lblk, ext4_lblk_t end)
++{
++ bool ret;
++
++ read_lock(&EXT4_I(inode)->i_es_lock);
++ ret = __es_scan_range(inode, matching_fn, lblk, end);
++ read_unlock(&EXT4_I(inode)->i_es_lock);
++
++ return ret;
++}
++
++/*
++ * __es_scan_clu - search cluster for block with specified status in
++ * extents status tree
++ *
++ * @inode - file containing the cluster
++ * @matching_fn - pointer to function that matches extents with desired status
++ * @lblk - logical block in cluster to be searched
++ *
++ * Returns true if at least one extent in the cluster containing @lblk
++ * satisfies the criterion specified by @matching_fn, and false if not. If at
++ * least one extent has the specified status, then there is at least one block
++ * in the cluster with that status. Should only be called by code that has
++ * taken i_es_lock.
++ */
++static bool __es_scan_clu(struct inode *inode,
++ int (*matching_fn)(struct extent_status *es),
++ ext4_lblk_t lblk)
++{
++ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
++ ext4_lblk_t lblk_start, lblk_end;
++
++ lblk_start = EXT4_LBLK_CMASK(sbi, lblk);
++ lblk_end = lblk_start + sbi->s_cluster_ratio - 1;
++
++ return __es_scan_range(inode, matching_fn, lblk_start, lblk_end);
++}
++
++/*
++ * Locking for __es_scan_clu() for external use
++ */
++bool ext4_es_scan_clu(struct inode *inode,
++ int (*matching_fn)(struct extent_status *es),
++ ext4_lblk_t lblk)
++{
++ bool ret;
++
++ read_lock(&EXT4_I(inode)->i_es_lock);
++ ret = __es_scan_clu(inode, matching_fn, lblk);
+ read_unlock(&EXT4_I(inode)->i_es_lock);
+
+- trace_ext4_es_find_delayed_extent_range_exit(inode, es);
++ return ret;
+ }
+
+ static void ext4_es_list_add(struct inode *inode)
+diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h
+index 8efdeb903d6b..df9628c3ec3b 100644
+--- a/fs/ext4/extents_status.h
++++ b/fs/ext4/extents_status.h
+@@ -90,11 +90,18 @@ extern void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk,
+ unsigned int status);
+ extern int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
+ ext4_lblk_t len);
+-extern void ext4_es_find_delayed_extent_range(struct inode *inode,
+- ext4_lblk_t lblk, ext4_lblk_t end,
+- struct extent_status *es);
++extern void ext4_es_find_extent_range(struct inode *inode,
++ int (*match_fn)(struct extent_status *es),
++ ext4_lblk_t lblk, ext4_lblk_t end,
++ struct extent_status *es);
+ extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
+ struct extent_status *es);
++extern bool ext4_es_scan_range(struct inode *inode,
++ int (*matching_fn)(struct extent_status *es),
++ ext4_lblk_t lblk, ext4_lblk_t end);
++extern bool ext4_es_scan_clu(struct inode *inode,
++ int (*matching_fn)(struct extent_status *es),
++ ext4_lblk_t lblk);
+
+ static inline unsigned int ext4_es_status(struct extent_status *es)
+ {
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index 3c7bbdaa425a..cba27ba41834 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -600,8 +600,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
+ EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
+ if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
+ !(status & EXTENT_STATUS_WRITTEN) &&
+- ext4_find_delalloc_range(inode, map->m_lblk,
+- map->m_lblk + map->m_len - 1))
++ ext4_es_scan_range(inode, &ext4_es_is_delayed, map->m_lblk,
++ map->m_lblk + map->m_len - 1))
+ status |= EXTENT_STATUS_DELAYED;
+ ret = ext4_es_insert_extent(inode, map->m_lblk,
+ map->m_len, map->m_pblk, status);
+@@ -724,8 +724,8 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
+ EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN;
+ if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) &&
+ !(status & EXTENT_STATUS_WRITTEN) &&
+- ext4_find_delalloc_range(inode, map->m_lblk,
+- map->m_lblk + map->m_len - 1))
++ ext4_es_scan_range(inode, &ext4_es_is_delayed, map->m_lblk,
++ map->m_lblk + map->m_len - 1))
+ status |= EXTENT_STATUS_DELAYED;
+ ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len,
+ map->m_pblk, status);
+@@ -1717,7 +1717,7 @@ static void ext4_da_page_release_reservation(struct page *page,
+ lblk = (page->index << (PAGE_SHIFT - inode->i_blkbits)) +
+ ((num_clusters - 1) << sbi->s_cluster_bits);
+ if (sbi->s_cluster_ratio == 1 ||
+- !ext4_find_delalloc_cluster(inode, lblk))
++ !ext4_es_scan_clu(inode, &ext4_es_is_delayed, lblk))
+ ext4_da_release_space(inode, 1);
+
+ num_clusters--;
+@@ -1902,6 +1902,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
+ add_delayed:
+ if (retval == 0) {
+ int ret;
++
+ /*
+ * XXX: __block_prepare_write() unmaps passed block,
+ * is it OK?
+@@ -1912,7 +1913,8 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
+ * to reserve metadata for every block we're going to write.
+ */
+ if (EXT4_SB(inode->i_sb)->s_cluster_ratio == 1 ||
+- !ext4_find_delalloc_cluster(inode, map->m_lblk)) {
++ !ext4_es_scan_clu(inode,
++ &ext4_es_is_delayed, map->m_lblk)) {
+ ret = ext4_da_reserve_space(inode);
+ if (ret) {
+ /* not enough space to reserve */
+@@ -3519,7 +3521,8 @@ static int ext4_iomap_begin(struct inode *inode, loff_t offset, loff_t length,
+ ext4_lblk_t end = map.m_lblk + map.m_len - 1;
+ struct extent_status es;
+
+- ext4_es_find_delayed_extent_range(inode, map.m_lblk, end, &es);
++ ext4_es_find_extent_range(inode, &ext4_es_is_delayed,
++ map.m_lblk, end, &es);
+
+ if (!es.es_len || es.es_lblk > end) {
+ /* entire range is a hole */
+diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
+index 0dfb174f707e..388dc3666cc7 100644
+--- a/include/trace/events/ext4.h
++++ b/include/trace/events/ext4.h
+@@ -2290,7 +2290,7 @@ TRACE_EVENT(ext4_es_remove_extent,
+ __entry->lblk, __entry->len)
+ );
+
+-TRACE_EVENT(ext4_es_find_delayed_extent_range_enter,
++TRACE_EVENT(ext4_es_find_extent_range_enter,
+ TP_PROTO(struct inode *inode, ext4_lblk_t lblk),
+
+ TP_ARGS(inode, lblk),
+@@ -2312,7 +2312,7 @@ TRACE_EVENT(ext4_es_find_delayed_extent_range_enter,
+ (unsigned long) __entry->ino, __entry->lblk)
+ );
+
+-TRACE_EVENT(ext4_es_find_delayed_extent_range_exit,
++TRACE_EVENT(ext4_es_find_extent_range_exit,
+ TP_PROTO(struct inode *inode, struct extent_status *es),
+
+ TP_ARGS(inode, es),
+--
+2.35.1
+
--- /dev/null
+From 2c7d9deb7582867fbf82542db6612c226b15af2f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 1 Jul 2020 16:30:27 +0800
+Subject: ext4: lost matching-pair of trace in ext4_truncate
+
+From: zhengliang <zhengliang6@huawei.com>
+
+[ Upstream commit 9a5d265fed014115f35e598022c956e5d2fb863e ]
+
+It should call trace exit in all return path for ext4_truncate.
+
+Signed-off-by: zhengliang <zhengliang6@huawei.com>
+Reviewed-by: Andreas Dilger <adilger@dilger.ca>
+Reviewed-by: Ritesh Harjani <riteshh@linux.ibm.com>
+Link: https://lore.kernel.org/r/20200701083027.45996-1-zhengliang6@huawei.com
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Stable-dep-of: a71248b1accb ("ext4: fix use-after-free in ext4_orphan_cleanup")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/ext4/inode.c | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
+index b322658ceff1..16d2b88bc66d 100644
+--- a/fs/ext4/inode.c
++++ b/fs/ext4/inode.c
+@@ -4551,7 +4551,7 @@ int ext4_truncate(struct inode *inode)
+ trace_ext4_truncate_enter(inode);
+
+ if (!ext4_can_truncate(inode))
+- return 0;
++ goto out_trace;
+
+ ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS);
+
+@@ -4562,16 +4562,14 @@ int ext4_truncate(struct inode *inode)
+ int has_inline = 1;
+
+ err = ext4_inline_data_truncate(inode, &has_inline);
+- if (err)
+- return err;
+- if (has_inline)
+- return 0;
++ if (err || has_inline)
++ goto out_trace;
+ }
+
+ /* If we zero-out tail of the page, we have to create jinode for jbd2 */
+ if (inode->i_size & (inode->i_sb->s_blocksize - 1)) {
+ if (ext4_inode_attach_jinode(inode) < 0)
+- return 0;
++ goto out_trace;
+ }
+
+ if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
+@@ -4580,8 +4578,10 @@ int ext4_truncate(struct inode *inode)
+ credits = ext4_blocks_for_truncate(inode);
+
+ handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits);
+- if (IS_ERR(handle))
+- return PTR_ERR(handle);
++ if (IS_ERR(handle)) {
++ err = PTR_ERR(handle);
++ goto out_trace;
++ }
+
+ if (inode->i_size & (inode->i_sb->s_blocksize - 1))
+ ext4_block_truncate_page(handle, mapping, inode->i_size);
+@@ -4630,6 +4630,7 @@ int ext4_truncate(struct inode *inode)
+ ext4_mark_inode_dirty(handle, inode);
+ ext4_journal_stop(handle);
+
++out_trace:
+ trace_ext4_truncate_exit(inode);
+ return err;
+ }
+--
+2.35.1
+
--- /dev/null
+From 2ef6249539ff0a94c778486d5043123e550d7c07 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Nov 2022 17:54:34 -0500
+Subject: kest.pl: Fix grub2 menu handling for rebooting
+
+From: Steven Rostedt <rostedt@goodmis.org>
+
+[ Upstream commit 26df05a8c1420ad3de314fdd407e7fc2058cc7aa ]
+
+grub2 has submenus where to use grub-reboot, it requires:
+
+ grub-reboot X>Y
+
+where X is the main index and Y is the submenu. Thus if you have:
+
+menuentry 'Debian GNU/Linux' --class debian --class gnu-linux ...
+ [...]
+}
+submenu 'Advanced options for Debian GNU/Linux' $menuentry_id_option ...
+ menuentry 'Debian GNU/Linux, with Linux 6.0.0-4-amd64' --class debian --class gnu-linux ...
+ [...]
+ }
+ menuentry 'Debian GNU/Linux, with Linux 6.0.0-4-amd64 (recovery mode)' --class debian --class gnu-linux ...
+ [...]
+ }
+ menuentry 'Debian GNU/Linux, with Linux test' --class debian --class gnu-linux ...
+ [...]
+ }
+
+And wanted to boot to the "Linux test" kernel, you need to run:
+
+ # grub-reboot 1>2
+
+As 1 is the second top menu (the submenu) and 2 is the third of the sub
+menu entries.
+
+Have the grub.cfg parsing for grub2 handle such cases.
+
+Cc: stable@vger.kernel.org
+Fixes: a15ba91361d46 ("ktest: Add support for grub2")
+Reviewed-by: John 'Warthog9' Hawley (VMware) <warthog9@eaglescrag.net>
+Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/ktest/ktest.pl | 20 +++++++++++++++-----
+ 1 file changed, 15 insertions(+), 5 deletions(-)
+
+diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
+index 689fa4fd3d76..a0b53309c5d8 100755
+--- a/tools/testing/ktest/ktest.pl
++++ b/tools/testing/ktest/ktest.pl
+@@ -1860,7 +1860,7 @@ sub run_scp_mod {
+
+ sub _get_grub_index {
+
+- my ($command, $target, $skip) = @_;
++ my ($command, $target, $skip, $submenu) = @_;
+
+ return if (defined($grub_number) && defined($last_grub_menu) &&
+ $last_grub_menu eq $grub_menu && defined($last_machine) &&
+@@ -1877,11 +1877,16 @@ sub _get_grub_index {
+
+ my $found = 0;
+
++ my $submenu_number = 0;
++
+ while (<IN>) {
+ if (/$target/) {
+ $grub_number++;
+ $found = 1;
+ last;
++ } elsif (defined($submenu) && /$submenu/) {
++ $submenu_number++;
++ $grub_number = -1;
+ } elsif (/$skip/) {
+ $grub_number++;
+ }
+@@ -1890,6 +1895,9 @@ sub _get_grub_index {
+
+ dodie "Could not find '$grub_menu' through $command on $machine"
+ if (!$found);
++ if ($submenu_number > 0) {
++ $grub_number = "$submenu_number>$grub_number";
++ }
+ doprint "$grub_number\n";
+ $last_grub_menu = $grub_menu;
+ $last_machine = $machine;
+@@ -1936,6 +1944,7 @@ sub get_grub_index {
+ my $command;
+ my $target;
+ my $skip;
++ my $submenu;
+ my $grub_menu_qt;
+
+ if ($reboot_type !~ /^grub/) {
+@@ -1950,8 +1959,9 @@ sub get_grub_index {
+ $skip = '^\s*title\s';
+ } elsif ($reboot_type eq "grub2") {
+ $command = "cat $grub_file";
+- $target = '^menuentry.*' . $grub_menu_qt;
+- $skip = '^menuentry\s|^submenu\s';
++ $target = '^\s*menuentry.*' . $grub_menu_qt;
++ $skip = '^\s*menuentry';
++ $submenu = '^\s*submenu\s';
+ } elsif ($reboot_type eq "grub2bls") {
+ $command = $grub_bls_get;
+ $target = '^title=.*' . $grub_menu_qt;
+@@ -1960,7 +1970,7 @@ sub get_grub_index {
+ return;
+ }
+
+- _get_grub_index($command, $target, $skip);
++ _get_grub_index($command, $target, $skip, $submenu);
+ }
+
+ sub wait_for_input
+@@ -2024,7 +2034,7 @@ sub reboot_to {
+ if ($reboot_type eq "grub") {
+ run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'";
+ } elsif (($reboot_type eq "grub2") or ($reboot_type eq "grub2bls")) {
+- run_ssh "$grub_reboot $grub_number";
++ run_ssh "$grub_reboot \"'$grub_number'\"";
+ } elsif ($reboot_type eq "syslinux") {
+ run_ssh "$syslinux --once \\\"$syslinux_label\\\" $syslinux_path";
+ } elsif (defined $reboot_script) {
+--
+2.35.1
+
--- /dev/null
+From 00893dd3710e13e7ecf9a3110d31d6deb4d51674 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 17 Apr 2019 19:58:23 -0400
+Subject: ktest: Add support for meta characters in GRUB_MENU
+
+From: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+
+[ Upstream commit 68911069f509ba3bf0f513d9af00309e07932906 ]
+
+ktest fails if meta characters are in GRUB_MENU, for example
+GRUB_MENU = 'Fedora (test)'
+
+The failure happens because the meta characters are not escaped,
+so the menu doesn't match in any entries in GRUB_FILE.
+
+Use quotemeta() to escape the meta characters.
+
+Link: http://lkml.kernel.org/r/20190417235823.18176-1-msys.mizuma@gmail.com
+
+Signed-off-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
+Stable-dep-of: 26df05a8c142 ("kest.pl: Fix grub2 menu handling for rebooting")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/ktest/ktest.pl | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
+index 92663d123be1..635121ecf543 100755
+--- a/tools/testing/ktest/ktest.pl
++++ b/tools/testing/ktest/ktest.pl
+@@ -1866,9 +1866,10 @@ sub get_grub2_index {
+ or dodie "unable to get $grub_file";
+
+ my $found = 0;
++ my $grub_menu_qt = quotemeta($grub_menu);
+
+ while (<IN>) {
+- if (/^menuentry.*$grub_menu/) {
++ if (/^menuentry.*$grub_menu_qt/) {
+ $grub_number++;
+ $found = 1;
+ last;
+@@ -1909,9 +1910,10 @@ sub get_grub_index {
+ or dodie "unable to get menu.lst";
+
+ my $found = 0;
++ my $grub_menu_qt = quotemeta($grub_menu);
+
+ while (<IN>) {
+- if (/^\s*title\s+$grub_menu\s*$/) {
++ if (/^\s*title\s+$grub_menu_qt\s*$/) {
+ $grub_number++;
+ $found = 1;
+ last;
+--
+2.35.1
+
--- /dev/null
+From f056a77a93c17e5c10f6b6bb3401470ef2a4b78b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 May 2019 17:36:43 -0400
+Subject: ktest: cleanup get_grub_index
+
+From: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+
+[ Upstream commit 38891392916c42d4ba46f474d553c76d1ed329ca ]
+
+Cleanup get_grub_index().
+
+Link: http://lkml.kernel.org/r/20190509213647.6276-3-msys.mizuma@gmail.com
+
+Signed-off-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
+Stable-dep-of: 26df05a8c142 ("kest.pl: Fix grub2 menu handling for rebooting")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/ktest/ktest.pl | 50 ++++++++++++------------------------
+ 1 file changed, 17 insertions(+), 33 deletions(-)
+
+diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
+index 5fa60b3c564f..a1067469ba0e 100755
+--- a/tools/testing/ktest/ktest.pl
++++ b/tools/testing/ktest/ktest.pl
+@@ -1925,46 +1925,30 @@ sub get_grub2_index {
+
+ sub get_grub_index {
+
+- if ($reboot_type eq "grub2") {
+- get_grub2_index;
+- return;
+- }
++ my $command;
++ my $target;
++ my $skip;
++ my $grub_menu_qt;
+
+- if ($reboot_type ne "grub") {
++ if ($reboot_type !~ /^grub/) {
+ return;
+ }
+- return if (defined($grub_number) && defined($last_grub_menu) &&
+- $last_grub_menu eq $grub_menu && defined($last_machine) &&
+- $last_machine eq $machine);
+-
+- doprint "Find grub menu ... ";
+- $grub_number = -1;
+
+- my $ssh_grub = $ssh_exec;
+- $ssh_grub =~ s,\$SSH_COMMAND,cat /boot/grub/menu.lst,g;
+-
+- open(IN, "$ssh_grub |")
+- or dodie "unable to get menu.lst";
++ $grub_menu_qt = quotemeta($grub_menu);
+
+- my $found = 0;
+- my $grub_menu_qt = quotemeta($grub_menu);
+-
+- while (<IN>) {
+- if (/^\s*title\s+$grub_menu_qt\s*$/) {
+- $grub_number++;
+- $found = 1;
+- last;
+- } elsif (/^\s*title\s/) {
+- $grub_number++;
+- }
++ if ($reboot_type eq "grub") {
++ $command = "cat /boot/grub/menu.lst";
++ $target = '^\s*title\s+' . $grub_menu_qt . '\s*$';
++ $skip = '^\s*title\s';
++ } elsif ($reboot_type eq "grub2") {
++ $command = "cat $grub_file";
++ $target = '^menuentry.*' . $grub_menu_qt;
++ $skip = '^menuentry\s|^submenu\s';
++ } else {
++ return;
+ }
+- close(IN);
+
+- dodie "Could not find '$grub_menu' in /boot/grub/menu on $machine"
+- if (!$found);
+- doprint "$grub_number\n";
+- $last_grub_menu = $grub_menu;
+- $last_machine = $machine;
++ _get_grub_index($command, $target, $skip);
+ }
+
+ sub wait_for_input
+--
+2.35.1
+
--- /dev/null
+From 0ccee5cb4ab817d238b06632a8af2443c69f02b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 May 2019 17:36:42 -0400
+Subject: ktest: introduce _get_grub_index
+
+From: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+
+[ Upstream commit f824b6866835bc5051c44ffd289134974f214e98 ]
+
+Introduce _get_grub_index() to deal with Boot Loader
+Specification (BLS) and cleanup.
+
+Link: http://lkml.kernel.org/r/20190509213647.6276-2-msys.mizuma@gmail.com
+
+Signed-off-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
+Stable-dep-of: 26df05a8c142 ("kest.pl: Fix grub2 menu handling for rebooting")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/ktest/ktest.pl | 37 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 37 insertions(+)
+
+diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
+index 635121ecf543..5fa60b3c564f 100755
+--- a/tools/testing/ktest/ktest.pl
++++ b/tools/testing/ktest/ktest.pl
+@@ -1850,6 +1850,43 @@ sub run_scp_mod {
+ return run_scp($src, $dst, $cp_scp);
+ }
+
++sub _get_grub_index {
++
++ my ($command, $target, $skip) = @_;
++
++ return if (defined($grub_number) && defined($last_grub_menu) &&
++ $last_grub_menu eq $grub_menu && defined($last_machine) &&
++ $last_machine eq $machine);
++
++ doprint "Find $reboot_type menu ... ";
++ $grub_number = -1;
++
++ my $ssh_grub = $ssh_exec;
++ $ssh_grub =~ s,\$SSH_COMMAND,$command,g;
++
++ open(IN, "$ssh_grub |")
++ or dodie "unable to execute $command";
++
++ my $found = 0;
++
++ while (<IN>) {
++ if (/$target/) {
++ $grub_number++;
++ $found = 1;
++ last;
++ } elsif (/$skip/) {
++ $grub_number++;
++ }
++ }
++ close(IN);
++
++ dodie "Could not find '$grub_menu' through $command on $machine"
++ if (!$found);
++ doprint "$grub_number\n";
++ $last_grub_menu = $grub_menu;
++ $last_machine = $machine;
++}
++
+ sub get_grub2_index {
+
+ return if (defined($grub_number) && defined($last_grub_menu) &&
+--
+2.35.1
+
--- /dev/null
+From 895503847551777f218c09eee0fe4c35c07bb2cd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 May 2019 17:36:44 -0400
+Subject: ktest: introduce grub2bls REBOOT_TYPE option
+
+From: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+
+[ Upstream commit ac2466456eaa0ff9b8cf647c4c52832024bc929f ]
+
+Fedora 30 introduces Boot Loader Specification (BLS),
+it changes around grub entry configuration.
+
+kernel entries aren't in grub.cfg. We can get the entries
+by "grubby --info=ALL" command.
+
+Introduce grub2bls as REBOOT_TYPE option for BLS.
+
+Link: http://lkml.kernel.org/r/20190509213647.6276-4-msys.mizuma@gmail.com
+
+Signed-off-by: Masayoshi Mizuma <m.mizuma@jp.fujitsu.com>
+Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
+Stable-dep-of: 26df05a8c142 ("kest.pl: Fix grub2 menu handling for rebooting")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/ktest/ktest.pl | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
+index a1067469ba0e..76468e2d619f 100755
+--- a/tools/testing/ktest/ktest.pl
++++ b/tools/testing/ktest/ktest.pl
+@@ -63,6 +63,7 @@ my %default = (
+ "STOP_TEST_AFTER" => 600,
+ "MAX_MONITOR_WAIT" => 1800,
+ "GRUB_REBOOT" => "grub2-reboot",
++ "GRUB_BLS_GET" => "grubby --info=ALL",
+ "SYSLINUX" => "extlinux",
+ "SYSLINUX_PATH" => "/boot/extlinux",
+ "CONNECT_TIMEOUT" => 25,
+@@ -123,6 +124,7 @@ my $last_grub_menu;
+ my $grub_file;
+ my $grub_number;
+ my $grub_reboot;
++my $grub_bls_get;
+ my $syslinux;
+ my $syslinux_path;
+ my $syslinux_label;
+@@ -292,6 +294,7 @@ my %option_map = (
+ "GRUB_MENU" => \$grub_menu,
+ "GRUB_FILE" => \$grub_file,
+ "GRUB_REBOOT" => \$grub_reboot,
++ "GRUB_BLS_GET" => \$grub_bls_get,
+ "SYSLINUX" => \$syslinux,
+ "SYSLINUX_PATH" => \$syslinux_path,
+ "SYSLINUX_LABEL" => \$syslinux_label,
+@@ -437,7 +440,7 @@ EOF
+ ;
+ $config_help{"REBOOT_TYPE"} = << "EOF"
+ Way to reboot the box to the test kernel.
+- Only valid options so far are "grub", "grub2", "syslinux", and "script".
++ Only valid options so far are "grub", "grub2", "grub2bls", "syslinux", and "script".
+
+ If you specify grub, it will assume grub version 1
+ and will search in /boot/grub/menu.lst for the title \$GRUB_MENU
+@@ -451,6 +454,8 @@ $config_help{"REBOOT_TYPE"} = << "EOF"
+ If you specify grub2, then you also need to specify both \$GRUB_MENU
+ and \$GRUB_FILE.
+
++ If you specify grub2bls, then you also need to specify \$GRUB_MENU.
++
+ If you specify syslinux, then you may use SYSLINUX to define the syslinux
+ command (defaults to extlinux), and SYSLINUX_PATH to specify the path to
+ the syslinux install (defaults to /boot/extlinux). But you have to specify
+@@ -476,6 +481,9 @@ $config_help{"GRUB_MENU"} = << "EOF"
+ menu must be a non-nested menu. Add the quotes used in the menu
+ to guarantee your selection, as the first menuentry with the content
+ of \$GRUB_MENU that is found will be used.
++
++ For grub2bls, \$GRUB_MENU is searched on the result of \$GRUB_BLS_GET
++ command for the lines that begin with "title".
+ EOF
+ ;
+ $config_help{"GRUB_FILE"} = << "EOF"
+@@ -692,7 +700,7 @@ sub get_mandatory_configs {
+ }
+ }
+
+- if ($rtype eq "grub") {
++ if (($rtype eq "grub") or ($rtype eq "grub2bls")) {
+ get_mandatory_config("GRUB_MENU");
+ }
+
+@@ -1944,6 +1952,10 @@ sub get_grub_index {
+ $command = "cat $grub_file";
+ $target = '^menuentry.*' . $grub_menu_qt;
+ $skip = '^menuentry\s|^submenu\s';
++ } elsif ($reboot_type eq "grub2bls") {
++ $command = $grub_bls_get;
++ $target = '^title=.*' . $grub_menu_qt;
++ $skip = '^title=';
+ } else {
+ return;
+ }
+@@ -4307,7 +4319,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
+
+ if (!$buildonly) {
+ $target = "$ssh_user\@$machine";
+- if ($reboot_type eq "grub") {
++ if (($reboot_type eq "grub") or ($reboot_type eq "grub2bls")) {
+ dodie "GRUB_MENU not defined" if (!defined($grub_menu));
+ } elsif ($reboot_type eq "grub2") {
+ dodie "GRUB_MENU not defined" if (!defined($grub_menu));
+--
+2.35.1
+
--- /dev/null
+From 37af8e738417415b592907ed48bebb0b975af426 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 20 Nov 2020 18:12:43 -0800
+Subject: ktest.pl: Fix incorrect reboot for grub2bls
+
+From: Libo Chen <libo.chen@oracle.com>
+
+[ Upstream commit 271e0c9dce1b02a825b3cc1a7aa1fab7c381d44b ]
+
+This issue was first noticed when I was testing different kernels on
+Oracle Linux 8 which as Fedora 30+ adopts BLS as default. Even though a
+kernel entry was added successfully and the index of that kernel entry was
+retrieved correctly, ktest still wouldn't reboot the system into
+user-specified kernel.
+
+The bug was spotted in subroutine reboot_to where the if-statement never
+checks for REBOOT_TYPE "grub2bls", therefore the desired entry will not be
+set for the next boot.
+
+Add a check for "grub2bls" so that $grub_reboot $grub_number can
+be run before a reboot if REBOOT_TYPE is "grub2bls" then we can boot to
+the correct kernel.
+
+Link: https://lkml.kernel.org/r/20201121021243.1532477-1-libo.chen@oracle.com
+
+Cc: stable@vger.kernel.org
+Fixes: ac2466456eaa ("ktest: introduce grub2bls REBOOT_TYPE option")
+Signed-off-by: Libo Chen <libo.chen@oracle.com>
+Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
+Stable-dep-of: 26df05a8c142 ("kest.pl: Fix grub2 menu handling for rebooting")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/testing/ktest/ktest.pl | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
+index 76468e2d619f..689fa4fd3d76 100755
+--- a/tools/testing/ktest/ktest.pl
++++ b/tools/testing/ktest/ktest.pl
+@@ -2023,7 +2023,7 @@ sub reboot_to {
+
+ if ($reboot_type eq "grub") {
+ run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch)'";
+- } elsif ($reboot_type eq "grub2") {
++ } elsif (($reboot_type eq "grub2") or ($reboot_type eq "grub2bls")) {
+ run_ssh "$grub_reboot $grub_number";
+ } elsif ($reboot_type eq "syslinux") {
+ run_ssh "$syslinux --once \\\"$syslinux_label\\\" $syslinux_path";
+--
+2.35.1
+
--- /dev/null
+From a99d6a0b738922dd1fcb3cf8a5d6378ec49b7a02 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 1 Nov 2019 17:45:31 +0100
+Subject: quota: Factor out setup of quota inode
+
+From: Jan Kara <jack@suse.cz>
+
+[ Upstream commit c7d3d28360fdb3ed3a5aa0bab19315e0fdc994a1 ]
+
+Factor out setting up of quota inode and eventual error cleanup from
+vfs_load_quota_inode(). This will simplify situation for filesystems
+that don't have any quota inodes.
+
+Signed-off-by: Jan Kara <jack@suse.cz>
+Stable-dep-of: d32387748476 ("ext4: fix bug_on in __es_tree_search caused by bad quota inode")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/quota/dquot.c | 108 ++++++++++++++++++++++++---------------
+ include/linux/quotaops.h | 2 +
+ 2 files changed, 69 insertions(+), 41 deletions(-)
+
+diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
+index ddb379abd919..a1d2aed0d833 100644
+--- a/fs/quota/dquot.c
++++ b/fs/quota/dquot.c
+@@ -2298,28 +2298,60 @@ EXPORT_SYMBOL(dquot_quota_off);
+ * Turn quotas on on a device
+ */
+
+-/*
+- * Helper function to turn quotas on when we already have the inode of
+- * quota file and no quota information is loaded.
+- */
+-static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
++static int vfs_setup_quota_inode(struct inode *inode, int type)
++{
++ struct super_block *sb = inode->i_sb;
++ struct quota_info *dqopt = sb_dqopt(sb);
++
++ if (!S_ISREG(inode->i_mode))
++ return -EACCES;
++ if (IS_RDONLY(inode))
++ return -EROFS;
++ if (sb_has_quota_loaded(sb, type))
++ return -EBUSY;
++
++ dqopt->files[type] = igrab(inode);
++ if (!dqopt->files[type])
++ return -EIO;
++ if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
++ /* We don't want quota and atime on quota files (deadlocks
++ * possible) Also nobody should write to the file - we use
++ * special IO operations which ignore the immutable bit. */
++ inode_lock(inode);
++ inode->i_flags |= S_NOQUOTA;
++ inode_unlock(inode);
++ /*
++ * When S_NOQUOTA is set, remove dquot references as no more
++ * references can be added
++ */
++ __dquot_drop(inode);
++ }
++ return 0;
++}
++
++static void vfs_cleanup_quota_inode(struct super_block *sb, int type)
++{
++ struct quota_info *dqopt = sb_dqopt(sb);
++ struct inode *inode = dqopt->files[type];
++
++ if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
++ inode_lock(inode);
++ inode->i_flags &= ~S_NOQUOTA;
++ inode_unlock(inode);
++ }
++ dqopt->files[type] = NULL;
++ iput(inode);
++}
++
++int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
+ unsigned int flags)
+ {
+ struct quota_format_type *fmt = find_quota_format(format_id);
+- struct super_block *sb = inode->i_sb;
+ struct quota_info *dqopt = sb_dqopt(sb);
+ int error;
+
+ if (!fmt)
+ return -ESRCH;
+- if (!S_ISREG(inode->i_mode)) {
+- error = -EACCES;
+- goto out_fmt;
+- }
+- if (IS_RDONLY(inode)) {
+- error = -EROFS;
+- goto out_fmt;
+- }
+ if (!sb->s_op->quota_write || !sb->s_op->quota_read ||
+ (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) {
+ error = -EINVAL;
+@@ -2351,27 +2383,9 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+ invalidate_bdev(sb->s_bdev);
+ }
+
+- if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
+- /* We don't want quota and atime on quota files (deadlocks
+- * possible) Also nobody should write to the file - we use
+- * special IO operations which ignore the immutable bit. */
+- inode_lock(inode);
+- inode->i_flags |= S_NOQUOTA;
+- inode_unlock(inode);
+- /*
+- * When S_NOQUOTA is set, remove dquot references as no more
+- * references can be added
+- */
+- __dquot_drop(inode);
+- }
+-
+- error = -EIO;
+- dqopt->files[type] = igrab(inode);
+- if (!dqopt->files[type])
+- goto out_file_flags;
+ error = -EINVAL;
+ if (!fmt->qf_ops->check_quota_file(sb, type))
+- goto out_file_init;
++ goto out_fmt;
+
+ dqopt->ops[type] = fmt->qf_ops;
+ dqopt->info[type].dqi_format = fmt;
+@@ -2379,7 +2393,7 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+ INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list);
+ error = dqopt->ops[type]->read_file_info(sb, type);
+ if (error < 0)
+- goto out_file_init;
++ goto out_fmt;
+ if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) {
+ spin_lock(&dq_data_lock);
+ dqopt->info[type].dqi_flags |= DQF_SYS_FILE;
+@@ -2394,18 +2408,30 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+ dquot_disable(sb, type, flags);
+
+ return error;
+-out_file_init:
+- dqopt->files[type] = NULL;
+- iput(inode);
+-out_file_flags:
+- inode_lock(inode);
+- inode->i_flags &= ~S_NOQUOTA;
+- inode_unlock(inode);
+ out_fmt:
+ put_quota_format(fmt);
+
+ return error;
+ }
++EXPORT_SYMBOL(dquot_load_quota_sb);
++
++/*
++ * Helper function to turn quotas on when we already have the inode of
++ * quota file and no quota information is loaded.
++ */
++static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
++ unsigned int flags)
++{
++ int err;
++
++ err = vfs_setup_quota_inode(inode, type);
++ if (err < 0)
++ return err;
++ err = dquot_load_quota_sb(inode->i_sb, type, format_id, flags);
++ if (err < 0)
++ vfs_cleanup_quota_inode(inode->i_sb, type);
++ return err;
++}
+
+ /* Reenable quotas on remount RW */
+ int dquot_resume(struct super_block *sb, int type)
+diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
+index 91e0b7624053..ec10897f7f60 100644
+--- a/include/linux/quotaops.h
++++ b/include/linux/quotaops.h
+@@ -99,6 +99,8 @@ int dquot_file_open(struct inode *inode, struct file *file);
+
+ int dquot_enable(struct inode *inode, int type, int format_id,
+ unsigned int flags);
++int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
++ unsigned int flags);
+ int dquot_quota_on(struct super_block *sb, int type, int format_id,
+ const struct path *path);
+ int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
+--
+2.35.1
+
s390-percpu-add-read_once-to-arch_this_cpu_to_op_simple.patch
net-ulp-prevent-ulp-without-clone-op-from-entering-the-listen-status.patch
alsa-pcm-move-rwsem-lock-inside-snd_ctl_elem_read-to-prevent-uaf.patch
+wifi-wilc1000-sdio-fix-module-autoloading.patch
+alsa-hda-hdmi-fix-failures-at-pcm-open-on-intel-icl-.patch
+add-acer-aspire-ethos-8951g-model-quirk.patch
+alsa-hda-realtek-more-constifications.patch
+alsa-hda-realtek-add-headset-mic-supported-for-hp-cp.patch
+alsa-hda-realtek-enable-headset-mic-of-acer-x2660g-w.patch
+alsa-hda-realtek-enable-the-headset-of-acer-n50-600-.patch
+alsa-hda-realtek-the-front-mic-on-a-hp-machine-doesn.patch
+alsa-hda-realtek-fix-the-mic-type-detection-issue-fo.patch
+alsa-hda-realtek-add-headset-mic-support-for-lenovo-.patch
+alsa-hda-realtek-alc897-headset-mic-no-sound.patch
+alsa-hda-realtek-add-quirk-for-lenovo-tianyi510pro-1.patch
+ktest-add-support-for-meta-characters-in-grub_menu.patch
+ktest-introduce-_get_grub_index.patch
+ktest-cleanup-get_grub_index.patch
+ktest-introduce-grub2bls-reboot_type-option.patch
+ktest.pl-fix-incorrect-reboot-for-grub2bls.patch
+kest.pl-fix-grub2-menu-handling-for-rebooting.patch
+usb-ulpi-defer-ulpi_register-on-ulpi_read_id-timeout.patch
+quota-factor-out-setup-of-quota-inode.patch
+ext4-fix-bug_on-in-__es_tree_search-caused-by-bad-qu.patch
+ext4-lost-matching-pair-of-trace-in-ext4_truncate.patch
+ext4-fix-use-after-free-in-ext4_orphan_cleanup.patch
+ext4-fix-uninititialized-value-in-ext4_evict_inode.patch
+ext4-generalize-extents-status-tree-search-functions.patch
+ext4-add-new-pending-reservation-mechanism.patch
+ext4-fix-reserved-cluster-accounting-at-delayed-writ.patch
+ext4-fix-delayed-allocation-bug-in-ext4_clu_mapped-f.patch
--- /dev/null
+From 85a42569f5edafb3142250de260797938db4f826 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 5 Dec 2022 21:15:26 +0100
+Subject: usb: ulpi: defer ulpi_register on ulpi_read_id timeout
+
+From: Ferry Toth <ftoth@exalondelft.nl>
+
+[ Upstream commit 8a7b31d545d3a15f0e6f5984ae16f0ca4fd76aac ]
+
+Since commit 0f0101719138 ("usb: dwc3: Don't switch OTG -> peripheral
+if extcon is present") Dual Role support on Intel Merrifield platform
+broke due to rearranging the call to dwc3_get_extcon().
+
+It appears to be caused by ulpi_read_id() on the first test write failing
+with -ETIMEDOUT. Currently ulpi_read_id() expects to discover the phy via
+DT when the test write fails and returns 0 in that case, even if DT does not
+provide the phy. As a result usb probe completes without phy.
+
+Make ulpi_read_id() return -ETIMEDOUT to its user if the first test write
+fails. The user should then handle it appropriately. A follow up patch
+will make dwc3_core_init() set -EPROBE_DEFER in this case and bail out.
+
+Fixes: ef6a7bcfb01c ("usb: ulpi: Support device discovery via DT")
+Cc: stable@vger.kernel.org
+Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Signed-off-by: Ferry Toth <ftoth@exalondelft.nl>
+Link: https://lore.kernel.org/r/20221205201527.13525-2-ftoth@exalondelft.nl
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/usb/common/ulpi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
+index c42c152bbc33..94700c1d2f6e 100644
+--- a/drivers/usb/common/ulpi.c
++++ b/drivers/usb/common/ulpi.c
+@@ -207,7 +207,7 @@ static int ulpi_read_id(struct ulpi *ulpi)
+ /* Test the interface */
+ ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa);
+ if (ret < 0)
+- goto err;
++ return ret;
+
+ ret = ulpi_read(ulpi, ULPI_SCRATCH);
+ if (ret < 0)
+--
+2.35.1
+
--- /dev/null
+From 3f6ef7bc16eca5d3b22f708134e5dfe0a440a6b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 27 Oct 2022 19:12:21 +0200
+Subject: wifi: wilc1000: sdio: fix module autoloading
+
+From: Michael Walle <michael@walle.cc>
+
+[ Upstream commit 57d545b5a3d6ce3a8fb6b093f02bfcbb908973f3 ]
+
+There are no SDIO module aliases included in the driver, therefore,
+module autoloading isn't working. Add the proper MODULE_DEVICE_TABLE().
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Michael Walle <michael@walle.cc>
+Signed-off-by: Kalle Valo <kvalo@kernel.org>
+Link: https://lore.kernel.org/r/20221027171221.491937-1-michael@walle.cc
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/staging/wilc1000/wilc_sdio.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/wilc_sdio.c
+index e52c3bdeaf04..b4d456f3fb1b 100644
+--- a/drivers/staging/wilc1000/wilc_sdio.c
++++ b/drivers/staging/wilc1000/wilc_sdio.c
+@@ -18,6 +18,7 @@ static const struct sdio_device_id wilc_sdio_ids[] = {
+ { SDIO_DEVICE(SDIO_VENDOR_ID_WILC, SDIO_DEVICE_ID_WILC) },
+ { },
+ };
++MODULE_DEVICE_TABLE(sdio, wilc_sdio_ids);
+
+ #define WILC_SDIO_BLOCK_SIZE 512
+
+--
+2.35.1
+