summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pagano <mpagano@gentoo.org>2023-06-28 06:28:31 -0400
committerMike Pagano <mpagano@gentoo.org>2023-06-28 06:28:31 -0400
commit03dfae5a53a7cbff9a35c3d87405556b864ea494 (patch)
treeaffdae4a2c757cd91ddec695312c57e3a7539c66
parentLinux patch 5.4.248 (diff)
downloadlinux-patches-03dfae5a53a7cbff9a35c3d87405556b864ea494.tar.gz
linux-patches-03dfae5a53a7cbff9a35c3d87405556b864ea494.tar.bz2
linux-patches-03dfae5a53a7cbff9a35c3d87405556b864ea494.zip
Linux patch 5.4.2495.4-256
Signed-off-by: Mike Pagano <mpagano@gentoo.org>
-rw-r--r--0000_README4
-rw-r--r--1248_linux-5.4.249.patch3204
2 files changed, 3208 insertions, 0 deletions
diff --git a/0000_README b/0000_README
index 1368c885..35a73c75 100644
--- a/0000_README
+++ b/0000_README
@@ -1035,6 +1035,10 @@ Patch: 1247_linux-5.4.248.patch
From: https://www.kernel.org
Desc: Linux 5.4.248
+Patch: 1248_linux-5.4.249.patch
+From: https://www.kernel.org
+Desc: Linux 5.4.249
+
Patch: 1500_XATTR_USER_PREFIX.patch
From: https://bugs.gentoo.org/show_bug.cgi?id=470644
Desc: Support for namespace user.pax.* on tmpfs.
diff --git a/1248_linux-5.4.249.patch b/1248_linux-5.4.249.patch
new file mode 100644
index 00000000..0d2ac6fb
--- /dev/null
+++ b/1248_linux-5.4.249.patch
@@ -0,0 +1,3204 @@
+diff --git a/Makefile b/Makefile
+index 100787c4e6bda..26a05e73de78f 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ # SPDX-License-Identifier: GPL-2.0
+ VERSION = 5
+ PATCHLEVEL = 4
+-SUBLEVEL = 248
++SUBLEVEL = 249
+ EXTRAVERSION =
+ NAME = Kleptomaniac Octopus
+
+diff --git a/arch/arm/boot/dts/am57xx-cl-som-am57x.dts b/arch/arm/boot/dts/am57xx-cl-som-am57x.dts
+index e86d4795e0244..e542a9f59e936 100644
+--- a/arch/arm/boot/dts/am57xx-cl-som-am57x.dts
++++ b/arch/arm/boot/dts/am57xx-cl-som-am57x.dts
+@@ -527,7 +527,7 @@
+
+ interrupt-parent = <&gpio1>;
+ interrupts = <31 0>;
+- pendown-gpio = <&gpio1 31 0>;
++ pendown-gpio = <&gpio1 31 GPIO_ACTIVE_LOW>;
+
+
+ ti,x-min = /bits/ 16 <0x0>;
+diff --git a/arch/arm/boot/dts/at91sam9261ek.dts b/arch/arm/boot/dts/at91sam9261ek.dts
+index c4ef74fea97c2..ee90ea09e781f 100644
+--- a/arch/arm/boot/dts/at91sam9261ek.dts
++++ b/arch/arm/boot/dts/at91sam9261ek.dts
+@@ -156,7 +156,7 @@
+ compatible = "ti,ads7843";
+ interrupts-extended = <&pioC 2 IRQ_TYPE_EDGE_BOTH>;
+ spi-max-frequency = <3000000>;
+- pendown-gpio = <&pioC 2 GPIO_ACTIVE_HIGH>;
++ pendown-gpio = <&pioC 2 GPIO_ACTIVE_LOW>;
+
+ ti,x-min = /bits/ 16 <150>;
+ ti,x-max = /bits/ 16 <3830>;
+diff --git a/arch/arm/boot/dts/imx7d-pico-hobbit.dts b/arch/arm/boot/dts/imx7d-pico-hobbit.dts
+index d917dc4f2f227..6ad39dca70096 100644
+--- a/arch/arm/boot/dts/imx7d-pico-hobbit.dts
++++ b/arch/arm/boot/dts/imx7d-pico-hobbit.dts
+@@ -64,7 +64,7 @@
+ interrupt-parent = <&gpio2>;
+ interrupts = <7 0>;
+ spi-max-frequency = <1000000>;
+- pendown-gpio = <&gpio2 7 0>;
++ pendown-gpio = <&gpio2 7 GPIO_ACTIVE_LOW>;
+ vcc-supply = <&reg_3p3v>;
+ ti,x-min = /bits/ 16 <0>;
+ ti,x-max = /bits/ 16 <4095>;
+diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts
+index 363d1f57a608b..88e62801b82e1 100644
+--- a/arch/arm/boot/dts/imx7d-sdb.dts
++++ b/arch/arm/boot/dts/imx7d-sdb.dts
+@@ -176,7 +176,7 @@
+ pinctrl-0 = <&pinctrl_tsc2046_pendown>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <29 0>;
+- pendown-gpio = <&gpio2 29 GPIO_ACTIVE_HIGH>;
++ pendown-gpio = <&gpio2 29 GPIO_ACTIVE_LOW>;
+ touchscreen-max-pressure = <255>;
+ wakeup-source;
+ };
+diff --git a/arch/arm/boot/dts/omap3-cm-t3x.dtsi b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
+index cdb632df152a1..11ae189441954 100644
+--- a/arch/arm/boot/dts/omap3-cm-t3x.dtsi
++++ b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
+@@ -227,7 +227,7 @@
+
+ interrupt-parent = <&gpio2>;
+ interrupts = <25 0>; /* gpio_57 */
+- pendown-gpio = <&gpio2 25 GPIO_ACTIVE_HIGH>;
++ pendown-gpio = <&gpio2 25 GPIO_ACTIVE_LOW>;
+
+ ti,x-min = /bits/ 16 <0x0>;
+ ti,x-max = /bits/ 16 <0x0fff>;
+diff --git a/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi b/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
+index 3decc2d78a6ca..a7f99ae0c1fe9 100644
+--- a/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
++++ b/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
+@@ -54,7 +54,7 @@
+
+ interrupt-parent = <&gpio1>;
+ interrupts = <27 0>; /* gpio_27 */
+- pendown-gpio = <&gpio1 27 GPIO_ACTIVE_HIGH>;
++ pendown-gpio = <&gpio1 27 GPIO_ACTIVE_LOW>;
+
+ ti,x-min = /bits/ 16 <0x0>;
+ ti,x-max = /bits/ 16 <0x0fff>;
+diff --git a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
+index c22833d4e5685..fba69b3f79c2b 100644
+--- a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
++++ b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
+@@ -311,7 +311,7 @@
+ interrupt-parent = <&gpio1>;
+ interrupts = <8 0>; /* boot6 / gpio_8 */
+ spi-max-frequency = <1000000>;
+- pendown-gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
++ pendown-gpio = <&gpio1 8 GPIO_ACTIVE_LOW>;
+ vcc-supply = <&reg_vcc3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&tsc2048_pins>;
+diff --git a/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi b/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
+index 185ce53de0ece..0523a369a4d75 100644
+--- a/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
++++ b/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
+@@ -149,7 +149,7 @@
+
+ interrupt-parent = <&gpio4>;
+ interrupts = <18 0>; /* gpio_114 */
+- pendown-gpio = <&gpio4 18 GPIO_ACTIVE_HIGH>;
++ pendown-gpio = <&gpio4 18 GPIO_ACTIVE_LOW>;
+
+ ti,x-min = /bits/ 16 <0x0>;
+ ti,x-max = /bits/ 16 <0x0fff>;
+diff --git a/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi b/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
+index 7fe0f9148232b..d340eb722f129 100644
+--- a/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
++++ b/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
+@@ -160,7 +160,7 @@
+
+ interrupt-parent = <&gpio4>;
+ interrupts = <18 0>; /* gpio_114 */
+- pendown-gpio = <&gpio4 18 GPIO_ACTIVE_HIGH>;
++ pendown-gpio = <&gpio4 18 GPIO_ACTIVE_LOW>;
+
+ ti,x-min = /bits/ 16 <0x0>;
+ ti,x-max = /bits/ 16 <0x0fff>;
+diff --git a/arch/arm/boot/dts/omap3-pandora-common.dtsi b/arch/arm/boot/dts/omap3-pandora-common.dtsi
+index 150d5be42d278..4ea5656825de7 100644
+--- a/arch/arm/boot/dts/omap3-pandora-common.dtsi
++++ b/arch/arm/boot/dts/omap3-pandora-common.dtsi
+@@ -651,7 +651,7 @@
+ pinctrl-0 = <&penirq_pins>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <30 IRQ_TYPE_NONE>; /* GPIO_94 */
+- pendown-gpio = <&gpio3 30 GPIO_ACTIVE_HIGH>;
++ pendown-gpio = <&gpio3 30 GPIO_ACTIVE_LOW>;
+ vcc-supply = <&vaux4>;
+
+ ti,x-min = /bits/ 16 <0>;
+diff --git a/arch/arm/boot/dts/omap5-cm-t54.dts b/arch/arm/boot/dts/omap5-cm-t54.dts
+index e78d3718f145d..d38781025eef8 100644
+--- a/arch/arm/boot/dts/omap5-cm-t54.dts
++++ b/arch/arm/boot/dts/omap5-cm-t54.dts
+@@ -354,7 +354,7 @@
+
+ interrupt-parent = <&gpio1>;
+ interrupts = <15 0>; /* gpio1_wk15 */
+- pendown-gpio = <&gpio1 15 GPIO_ACTIVE_HIGH>;
++ pendown-gpio = <&gpio1 15 GPIO_ACTIVE_LOW>;
+
+
+ ti,x-min = /bits/ 16 <0x0>;
+diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
+index 5b3bdad66b27e..1ff93878c8132 100644
+--- a/arch/arm64/include/asm/sysreg.h
++++ b/arch/arm64/include/asm/sysreg.h
+@@ -102,8 +102,14 @@
+ #define SB_BARRIER_INSN __SYS_BARRIER_INSN(0, 7, 31)
+
+ #define SYS_DC_ISW sys_insn(1, 0, 7, 6, 2)
++#define SYS_DC_IGSW sys_insn(1, 0, 7, 6, 4)
++#define SYS_DC_IGDSW sys_insn(1, 0, 7, 6, 6)
+ #define SYS_DC_CSW sys_insn(1, 0, 7, 10, 2)
++#define SYS_DC_CGSW sys_insn(1, 0, 7, 10, 4)
++#define SYS_DC_CGDSW sys_insn(1, 0, 7, 10, 6)
+ #define SYS_DC_CISW sys_insn(1, 0, 7, 14, 2)
++#define SYS_DC_CIGSW sys_insn(1, 0, 7, 14, 4)
++#define SYS_DC_CIGDSW sys_insn(1, 0, 7, 14, 6)
+
+ #define SYS_OSDTRRX_EL1 sys_reg(2, 0, 0, 0, 2)
+ #define SYS_MDCCINT_EL1 sys_reg(2, 0, 0, 2, 0)
+diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
+index 032a00e5d9fa6..76c80e191a1b1 100644
+--- a/arch/x86/kernel/apic/x2apic_phys.c
++++ b/arch/x86/kernel/apic/x2apic_phys.c
+@@ -97,7 +97,10 @@ static void init_x2apic_ldr(void)
+
+ static int x2apic_phys_probe(void)
+ {
+- if (x2apic_mode && (x2apic_phys || x2apic_fadt_phys()))
++ if (!x2apic_mode)
++ return 0;
++
++ if (x2apic_phys || x2apic_fadt_phys())
+ return 1;
+
+ return apic == &apic_x2apic_phys;
+diff --git a/arch/x86/mm/kaslr.c b/arch/x86/mm/kaslr.c
+index dc6182eecefad..a37c2873fdb55 100644
+--- a/arch/x86/mm/kaslr.c
++++ b/arch/x86/mm/kaslr.c
+@@ -182,11 +182,11 @@ static void __meminit init_trampoline_pud(void)
+ set_p4d(p4d_tramp,
+ __p4d(_KERNPG_TABLE | __pa(pud_page_tramp)));
+
+- set_pgd(&trampoline_pgd_entry,
+- __pgd(_KERNPG_TABLE | __pa(p4d_page_tramp)));
++ trampoline_pgd_entry =
++ __pgd(_KERNPG_TABLE | __pa(p4d_page_tramp));
+ } else {
+- set_pgd(&trampoline_pgd_entry,
+- __pgd(_KERNPG_TABLE | __pa(pud_page_tramp)));
++ trampoline_pgd_entry =
++ __pgd(_KERNPG_TABLE | __pa(pud_page_tramp));
+ }
+ }
+
+diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile
+index 969d2b2eb7d71..8309e230aeed1 100644
+--- a/arch/x86/purgatory/Makefile
++++ b/arch/x86/purgatory/Makefile
+@@ -14,6 +14,11 @@ $(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE
+
+ CFLAGS_sha256.o := -D__DISABLE_EXPORTS
+
++# When profile-guided optimization is enabled, llvm emits two different
++# overlapping text sections, which is not supported by kexec. Remove profile
++# optimization flags.
++KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%,$(KBUILD_CFLAGS))
++
+ LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined -nostdlib -z nodefaultlib
+ targets += purgatory.ro
+
+diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+index fcee33a43aca3..2df04de7f4354 100644
+--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
++++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+@@ -1332,7 +1332,7 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
+ /* Let the runqueue know that there is work to do. */
+ queue_work(g2d->g2d_workq, &g2d->runqueue_work);
+
+- if (runqueue_node->async)
++ if (req->async)
+ goto out;
+
+ wait_for_completion(&runqueue_node->complete);
+diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+index 65b891cb9c50b..d882a22dfd6e6 100644
+--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
++++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+@@ -483,8 +483,6 @@ static int vidi_remove(struct platform_device *pdev)
+ if (ctx->raw_edid != (struct edid *)fake_edid_info) {
+ kfree(ctx->raw_edid);
+ ctx->raw_edid = NULL;
+-
+- return -EINVAL;
+ }
+
+ component_del(&pdev->dev, &vidi_component_ops);
+diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
+index b2b076606f54b..e164b3c7a234f 100644
+--- a/drivers/gpu/drm/radeon/radeon_gem.c
++++ b/drivers/gpu/drm/radeon/radeon_gem.c
+@@ -384,7 +384,6 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
+ struct radeon_device *rdev = dev->dev_private;
+ struct drm_radeon_gem_set_domain *args = data;
+ struct drm_gem_object *gobj;
+- struct radeon_bo *robj;
+ int r;
+
+ /* for now if someone requests domain CPU -
+@@ -397,13 +396,12 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
+ up_read(&rdev->exclusive_lock);
+ return -ENOENT;
+ }
+- robj = gem_to_radeon_bo(gobj);
+
+ r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain);
+
+ drm_gem_object_put_unlocked(gobj);
+ up_read(&rdev->exclusive_lock);
+- r = radeon_gem_handle_lockup(robj->rdev, r);
++ r = radeon_gem_handle_lockup(rdev, r);
+ return r;
+ }
+
+diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
+index a93070f5b214c..36cb456709ed7 100644
+--- a/drivers/hid/wacom_sys.c
++++ b/drivers/hid/wacom_sys.c
+@@ -2419,8 +2419,13 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
+ goto fail_quirks;
+ }
+
+- if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
++ if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) {
+ error = hid_hw_open(hdev);
++ if (error) {
++ hid_err(hdev, "hw open failed\n");
++ goto fail_quirks;
++ }
++ }
+
+ wacom_set_shared_values(wacom_wac);
+ devres_close_group(&hdev->dev, wacom);
+diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
+index 3adf4fae452a7..3eb27f33e1fba 100644
+--- a/drivers/hv/channel_mgmt.c
++++ b/drivers/hv/channel_mgmt.c
+@@ -802,11 +802,22 @@ static void vmbus_wait_for_unload(void)
+ if (completion_done(&vmbus_connection.unload_event))
+ goto completed;
+
+- for_each_online_cpu(cpu) {
++ for_each_present_cpu(cpu) {
+ struct hv_per_cpu_context *hv_cpu
+ = per_cpu_ptr(hv_context.cpu_context, cpu);
+
++ /*
++ * In a CoCo VM the synic_message_page is not allocated
++ * in hv_synic_alloc(). Instead it is set/cleared in
++ * hv_synic_enable_regs() and hv_synic_disable_regs()
++ * such that it is set only when the CPU is online. If
++ * not all present CPUs are online, the message page
++ * might be NULL, so skip such CPUs.
++ */
+ page_addr = hv_cpu->synic_message_page;
++ if (!page_addr)
++ continue;
++
+ msg = (struct hv_message *)page_addr
+ + VMBUS_MESSAGE_SINT;
+
+@@ -840,11 +851,14 @@ completed:
+ * maybe-pending messages on all CPUs to be able to receive new
+ * messages after we reconnect.
+ */
+- for_each_online_cpu(cpu) {
++ for_each_present_cpu(cpu) {
+ struct hv_per_cpu_context *hv_cpu
+ = per_cpu_ptr(hv_context.cpu_context, cpu);
+
+ page_addr = hv_cpu->synic_message_page;
++ if (!page_addr)
++ continue;
++
+ msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
+ msg->header.message_type = HVMSG_NONE;
+ }
+diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c
+index 4fac2591b6618..89faef6f013b4 100644
+--- a/drivers/i2c/busses/i2c-imx-lpi2c.c
++++ b/drivers/i2c/busses/i2c-imx-lpi2c.c
+@@ -206,8 +206,8 @@ static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx)
+ /* CLKLO = I2C_CLK_RATIO * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */
+ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx)
+ {
+- u8 prescale, filt, sethold, clkhi, clklo, datavd;
+- unsigned int clk_rate, clk_cycle;
++ u8 prescale, filt, sethold, datavd;
++ unsigned int clk_rate, clk_cycle, clkhi, clklo;
+ enum lpi2c_imx_pincfg pincfg;
+ unsigned int temp;
+
+diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c
+index c665f7d20c448..4c1770b8128cb 100644
+--- a/drivers/media/cec/cec-adap.c
++++ b/drivers/media/cec/cec-adap.c
+@@ -1077,7 +1077,8 @@ void cec_received_msg_ts(struct cec_adapter *adap,
+ mutex_lock(&adap->lock);
+ dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg);
+
+- adap->last_initiator = 0xff;
++ if (!adap->transmit_in_progress)
++ adap->last_initiator = 0xff;
+
+ /* Check if this message was for us (directed or broadcast). */
+ if (!cec_msg_is_broadcast(msg))
+diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
+index 454301149a8f5..31b299ced3c12 100644
+--- a/drivers/media/dvb-core/dvbdev.c
++++ b/drivers/media/dvb-core/dvbdev.c
+@@ -37,6 +37,7 @@
+ #include <media/tuner.h>
+
+ static DEFINE_MUTEX(dvbdev_mutex);
++static LIST_HEAD(dvbdevfops_list);
+ static int dvbdev_debug;
+
+ module_param(dvbdev_debug, int, 0644);
+@@ -462,14 +463,15 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
+ enum dvb_device_type type, int demux_sink_pads)
+ {
+ struct dvb_device *dvbdev;
+- struct file_operations *dvbdevfops;
++ struct file_operations *dvbdevfops = NULL;
++ struct dvbdevfops_node *node = NULL, *new_node = NULL;
+ struct device *clsdev;
+ int minor;
+ int id, ret;
+
+ mutex_lock(&dvbdev_register_lock);
+
+- if ((id = dvbdev_get_free_id (adap, type)) < 0){
++ if ((id = dvbdev_get_free_id (adap, type)) < 0) {
+ mutex_unlock(&dvbdev_register_lock);
+ *pdvbdev = NULL;
+ pr_err("%s: couldn't find free device id\n", __func__);
+@@ -477,18 +479,45 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
+ }
+
+ *pdvbdev = dvbdev = kzalloc(sizeof(*dvbdev), GFP_KERNEL);
+-
+ if (!dvbdev){
+ mutex_unlock(&dvbdev_register_lock);
+ return -ENOMEM;
+ }
+
+- dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
++ /*
++ * When a device of the same type is probe()d more than once,
++ * the first allocated fops are used. This prevents memory leaks
++ * that can occur when the same device is probe()d repeatedly.
++ */
++ list_for_each_entry(node, &dvbdevfops_list, list_head) {
++ if (node->fops->owner == adap->module &&
++ node->type == type &&
++ node->template == template) {
++ dvbdevfops = node->fops;
++ break;
++ }
++ }
+
+- if (!dvbdevfops){
+- kfree (dvbdev);
+- mutex_unlock(&dvbdev_register_lock);
+- return -ENOMEM;
++ if (dvbdevfops == NULL) {
++ dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
++ if (!dvbdevfops) {
++ kfree(dvbdev);
++ mutex_unlock(&dvbdev_register_lock);
++ return -ENOMEM;
++ }
++
++ new_node = kzalloc(sizeof(struct dvbdevfops_node), GFP_KERNEL);
++ if (!new_node) {
++ kfree(dvbdevfops);
++ kfree(dvbdev);
++ mutex_unlock(&dvbdev_register_lock);
++ return -ENOMEM;
++ }
++
++ new_node->fops = dvbdevfops;
++ new_node->type = type;
++ new_node->template = template;
++ list_add_tail (&new_node->list_head, &dvbdevfops_list);
+ }
+
+ memcpy(dvbdev, template, sizeof(struct dvb_device));
+@@ -499,19 +528,20 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
+ dvbdev->priv = priv;
+ dvbdev->fops = dvbdevfops;
+ init_waitqueue_head (&dvbdev->wait_queue);
+-
+ dvbdevfops->owner = adap->module;
+-
+ list_add_tail (&dvbdev->list_head, &adap->device_list);
+-
+ down_write(&minor_rwsem);
+ #ifdef CONFIG_DVB_DYNAMIC_MINORS
+ for (minor = 0; minor < MAX_DVB_MINORS; minor++)
+ if (dvb_minors[minor] == NULL)
+ break;
+-
+ if (minor == MAX_DVB_MINORS) {
+- kfree(dvbdevfops);
++ if (new_node) {
++ list_del (&new_node->list_head);
++ kfree(dvbdevfops);
++ kfree(new_node);
++ }
++ list_del (&dvbdev->list_head);
+ kfree(dvbdev);
+ up_write(&minor_rwsem);
+ mutex_unlock(&dvbdev_register_lock);
+@@ -520,36 +550,47 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
+ #else
+ minor = nums2minor(adap->num, type, id);
+ #endif
+-
+ dvbdev->minor = minor;
+ dvb_minors[minor] = dvb_device_get(dvbdev);
+ up_write(&minor_rwsem);
+-
+ ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads);
+ if (ret) {
+ pr_err("%s: dvb_register_media_device failed to create the mediagraph\n",
+ __func__);
+-
++ if (new_node) {
++ list_del (&new_node->list_head);
++ kfree(dvbdevfops);
++ kfree(new_node);
++ }
+ dvb_media_device_free(dvbdev);
+- kfree(dvbdevfops);
++ list_del (&dvbdev->list_head);
+ kfree(dvbdev);
+ mutex_unlock(&dvbdev_register_lock);
+ return ret;
+ }
+
+- mutex_unlock(&dvbdev_register_lock);
+-
+ clsdev = device_create(dvb_class, adap->device,
+ MKDEV(DVB_MAJOR, minor),
+ dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
+ if (IS_ERR(clsdev)) {
+ pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n",
+ __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
++ if (new_node) {
++ list_del (&new_node->list_head);
++ kfree(dvbdevfops);
++ kfree(new_node);
++ }
++ dvb_media_device_free(dvbdev);
++ list_del (&dvbdev->list_head);
++ kfree(dvbdev);
++ mutex_unlock(&dvbdev_register_lock);
+ return PTR_ERR(clsdev);
+ }
++
+ dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+ adap->num, dnames[type], id, minor, minor);
+
++ mutex_unlock(&dvbdev_register_lock);
+ return 0;
+ }
+ EXPORT_SYMBOL(dvb_register_device);
+@@ -578,7 +619,6 @@ static void dvb_free_device(struct kref *ref)
+ {
+ struct dvb_device *dvbdev = container_of(ref, struct dvb_device, ref);
+
+- kfree (dvbdev->fops);
+ kfree (dvbdev);
+ }
+
+@@ -1084,9 +1124,17 @@ error:
+
+ static void __exit exit_dvbdev(void)
+ {
++ struct dvbdevfops_node *node, *next;
++
+ class_destroy(dvb_class);
+ cdev_del(&dvb_device_cdev);
+ unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
++
++ list_for_each_entry_safe(node, next, &dvbdevfops_list, list_head) {
++ list_del (&node->list_head);
++ kfree(node->fops);
++ kfree(node);
++ }
+ }
+
+ subsys_initcall(init_dvbdev);
+diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
+index 95a8ba4cf3da9..35bdca9384d55 100644
+--- a/drivers/mmc/host/meson-gx-mmc.c
++++ b/drivers/mmc/host/meson-gx-mmc.c
+@@ -973,11 +973,8 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
+ if (status & (IRQ_END_OF_CHAIN | IRQ_RESP_STATUS)) {
+ if (data && !cmd->error)
+ data->bytes_xfered = data->blksz * data->blocks;
+- if (meson_mmc_bounce_buf_read(data) ||
+- meson_mmc_get_next_command(cmd))
+- ret = IRQ_WAKE_THREAD;
+- else
+- ret = IRQ_HANDLED;
++
++ return IRQ_WAKE_THREAD;
+ }
+
+ out:
+@@ -989,9 +986,6 @@ out:
+ writel(start, host->regs + SD_EMMC_START);
+ }
+
+- if (ret == IRQ_HANDLED)
+- meson_mmc_request_done(host->mmc, cmd->mrq);
+-
+ return ret;
+ }
+
+diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
+index 1254a5650cfff..2673890c76900 100644
+--- a/drivers/mmc/host/mtk-sd.c
++++ b/drivers/mmc/host/mtk-sd.c
+@@ -2249,7 +2249,7 @@ static int msdc_drv_probe(struct platform_device *pdev)
+
+ host->irq = platform_get_irq(pdev, 0);
+ if (host->irq < 0) {
+- ret = -EINVAL;
++ ret = host->irq;
+ goto host_free;
+ }
+
+diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
+index 74a0a7fbbf7fd..0dfcf7bea9ffa 100644
+--- a/drivers/mmc/host/mvsdio.c
++++ b/drivers/mmc/host/mvsdio.c
+@@ -696,17 +696,15 @@ static int mvsd_probe(struct platform_device *pdev)
+ struct mmc_host *mmc = NULL;
+ struct mvsd_host *host = NULL;
+ const struct mbus_dram_target_info *dram;
+- struct resource *r;
+ int ret, irq;
+
+ if (!np) {
+ dev_err(&pdev->dev, "no DT node\n");
+ return -ENODEV;
+ }
+- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+- if (!r || irq < 0)
+- return -ENXIO;
++ if (irq < 0)
++ return irq;
+
+ mmc = mmc_alloc_host(sizeof(struct mvsd_host), &pdev->dev);
+ if (!mmc) {
+@@ -758,7 +756,7 @@ static int mvsd_probe(struct platform_device *pdev)
+
+ spin_lock_init(&host->lock);
+
+- host->base = devm_ioremap_resource(&pdev->dev, r);
++ host->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(host->base)) {
+ ret = PTR_ERR(host->base);
+ goto out;
+diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
+index d74e73c95fdff..80574040d8fb3 100644
+--- a/drivers/mmc/host/omap.c
++++ b/drivers/mmc/host/omap.c
+@@ -1344,7 +1344,7 @@ static int mmc_omap_probe(struct platform_device *pdev)
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+- return -ENXIO;
++ return irq;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ host->virt_base = devm_ioremap_resource(&pdev->dev, res);
+diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
+index ee9edf817a326..aef2253ed5c81 100644
+--- a/drivers/mmc/host/omap_hsmmc.c
++++ b/drivers/mmc/host/omap_hsmmc.c
+@@ -1843,9 +1843,11 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- irq = platform_get_irq(pdev, 0);
+- if (res == NULL || irq < 0)
++ if (!res)
+ return -ENXIO;
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0)
++ return irq;
+
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
+index 0dc8eafdc81d0..a02f3538d5611 100644
+--- a/drivers/mmc/host/sdhci-acpi.c
++++ b/drivers/mmc/host/sdhci-acpi.c
+@@ -835,7 +835,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
+ host->ops = &sdhci_acpi_ops_dflt;
+ host->irq = platform_get_irq(pdev, 0);
+ if (host->irq < 0) {
+- err = -EINVAL;
++ err = host->irq;
+ goto err_free;
+ }
+
+diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
+index 98c575de43c75..ed18c233c7864 100644
+--- a/drivers/mmc/host/sh_mmcif.c
++++ b/drivers/mmc/host/sh_mmcif.c
+@@ -1395,7 +1395,7 @@ static int sh_mmcif_probe(struct platform_device *pdev)
+ irq[0] = platform_get_irq(pdev, 0);
+ irq[1] = platform_get_irq_optional(pdev, 1);
+ if (irq[0] < 0)
+- return -ENXIO;
++ return irq[0];
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(dev, res);
+diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c
+index 96b0f81a20322..56d131183c1e4 100644
+--- a/drivers/mmc/host/usdhi6rol0.c
++++ b/drivers/mmc/host/usdhi6rol0.c
+@@ -1743,8 +1743,10 @@ static int usdhi6_probe(struct platform_device *pdev)
+ irq_cd = platform_get_irq_byname(pdev, "card detect");
+ irq_sd = platform_get_irq_byname(pdev, "data");
+ irq_sdio = platform_get_irq_byname(pdev, "SDIO");
+- if (irq_sd < 0 || irq_sdio < 0)
+- return -ENODEV;
++ if (irq_sd < 0)
++ return irq_sd;
++ if (irq_sdio < 0)
++ return irq_sdio;
+
+ mmc = mmc_alloc_host(sizeof(struct usdhi6_host), dev);
+ if (!mmc)
+diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
+index baa994b7f78b5..935004f5f5fe7 100644
+--- a/drivers/net/dsa/mt7530.c
++++ b/drivers/net/dsa/mt7530.c
+@@ -644,7 +644,7 @@ mt7530_cpu_port_enable(struct mt7530_priv *priv,
+ mt7530_rmw(priv, MT7530_MFC, UNM_FFP_MASK, UNM_FFP(BIT(port)));
+
+ /* Set CPU port number */
+- if (priv->id == ID_MT7621)
++ if (priv->id == ID_MT7530 || priv->id == ID_MT7621)
+ mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port));
+
+ /* CPU port gets connected to all user ports of
+diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
+index 552877590a8ab..f1cce7636722e 100644
+--- a/drivers/net/ethernet/emulex/benet/be_main.c
++++ b/drivers/net/ethernet/emulex/benet/be_main.c
+@@ -1137,8 +1137,8 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
+ eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ?
+ VLAN_ETH_HLEN : ETH_HLEN;
+ if (skb->len <= 60 &&
+- (lancer_chip(adapter) || skb_vlan_tag_present(skb)) &&
+- is_ipv4_pkt(skb)) {
++ (lancer_chip(adapter) || BE3_chip(adapter) ||
++ skb_vlan_tag_present(skb)) && is_ipv4_pkt(skb)) {
+ ip = (struct iphdr *)ip_hdr(skb);
+ pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len));
+ }
+diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
+index 15591ad5fe4ea..db6817de24a14 100644
+--- a/drivers/net/ethernet/qualcomm/qca_spi.c
++++ b/drivers/net/ethernet/qualcomm/qca_spi.c
+@@ -574,8 +574,7 @@ qcaspi_spi_thread(void *data)
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if ((qca->intr_req == qca->intr_svc) &&
+- (qca->txr.skb[qca->txr.head] == NULL) &&
+- (qca->sync == QCASPI_SYNC_READY))
++ !qca->txr.skb[qca->txr.head])
+ schedule();
+
+ set_current_state(TASK_RUNNING);
+diff --git a/drivers/net/ieee802154/mac802154_hwsim.c b/drivers/net/ieee802154/mac802154_hwsim.c
+index 1d181eff0c299..4028cbe275d67 100644
+--- a/drivers/net/ieee802154/mac802154_hwsim.c
++++ b/drivers/net/ieee802154/mac802154_hwsim.c
+@@ -522,7 +522,7 @@ static int hwsim_del_edge_nl(struct sk_buff *msg, struct genl_info *info)
+ static int hwsim_set_edge_lqi(struct sk_buff *msg, struct genl_info *info)
+ {
+ struct nlattr *edge_attrs[MAC802154_HWSIM_EDGE_ATTR_MAX + 1];
+- struct hwsim_edge_info *einfo;
++ struct hwsim_edge_info *einfo, *einfo_old;
+ struct hwsim_phy *phy_v0;
+ struct hwsim_edge *e;
+ u32 v0, v1;
+@@ -560,8 +560,10 @@ static int hwsim_set_edge_lqi(struct sk_buff *msg, struct genl_info *info)
+ list_for_each_entry_rcu(e, &phy_v0->edges, list) {
+ if (e->endpoint->idx == v1) {
+ einfo->lqi = lqi;
+- rcu_assign_pointer(e->info, einfo);
++ einfo_old = rcu_replace_pointer(e->info, einfo,
++ lockdep_is_held(&hwsim_phys_lock));
+ rcu_read_unlock();
++ kfree_rcu(einfo_old, rcu);
+ mutex_unlock(&hwsim_phys_lock);
+ return 0;
+ }
+diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
+index c7d91415a4369..1375beb3cf83c 100644
+--- a/drivers/net/phy/dp83867.c
++++ b/drivers/net/phy/dp83867.c
+@@ -476,7 +476,7 @@ static int dp83867_phy_reset(struct phy_device *phydev)
+ {
+ int err;
+
+- err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESTART);
++ err = phy_write(phydev, DP83867_CTRL, DP83867_SW_RESET);
+ if (err < 0)
+ return err;
+
+diff --git a/drivers/nfc/nfcsim.c b/drivers/nfc/nfcsim.c
+index dd27c85190d34..b42d386350b72 100644
+--- a/drivers/nfc/nfcsim.c
++++ b/drivers/nfc/nfcsim.c
+@@ -336,10 +336,6 @@ static struct dentry *nfcsim_debugfs_root;
+ static void nfcsim_debugfs_init(void)
+ {
+ nfcsim_debugfs_root = debugfs_create_dir("nfcsim", NULL);
+-
+- if (!nfcsim_debugfs_root)
+- pr_err("Could not create debugfs entry\n");
+-
+ }
+
+ static void nfcsim_debugfs_remove(void)
+diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
+index 3d48fa685aaae..f66f07b8eebdf 100644
+--- a/drivers/pci/controller/pci-hyperv.c
++++ b/drivers/pci/controller/pci-hyperv.c
+@@ -2739,6 +2739,24 @@ static int hv_pci_query_relations(struct hv_device *hdev)
+ if (!ret)
+ ret = wait_for_response(hdev, &comp);
+
++ /*
++ * In the case of fast device addition/removal, it's possible that
++ * vmbus_sendpacket() or wait_for_response() returns -ENODEV but we
++ * already got a PCI_BUS_RELATIONS* message from the host and the
++ * channel callback already scheduled a work to hbus->wq, which can be
++ * running pci_devices_present_work() -> survey_child_resources() ->
++ * complete(&hbus->survey_event), even after hv_pci_query_relations()
++ * exits and the stack variable 'comp' is no longer valid; as a result,
++ * a hang or a page fault may happen when the complete() calls
++ * raw_spin_lock_irqsave(). Flush hbus->wq before we exit from
++ * hv_pci_query_relations() to avoid the issues. Note: if 'ret' is
++ * -ENODEV, there can't be any more work item scheduled to hbus->wq
++ * after the flush_workqueue(): see vmbus_onoffer_rescind() ->
++ * vmbus_reset_channel_cb(), vmbus_rescind_cleanup() ->
++ * channel->rescind = true.
++ */
++ flush_workqueue(hbus->wq);
++
+ return ret;
+ }
+
+diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
+index 23e9227e60fd7..d7ca75efb49fb 100644
+--- a/drivers/s390/cio/device.c
++++ b/drivers/s390/cio/device.c
+@@ -1385,6 +1385,7 @@ void ccw_device_set_notoper(struct ccw_device *cdev)
+ enum io_sch_action {
+ IO_SCH_UNREG,
+ IO_SCH_ORPH_UNREG,
++ IO_SCH_UNREG_CDEV,
+ IO_SCH_ATTACH,
+ IO_SCH_UNREG_ATTACH,
+ IO_SCH_ORPH_ATTACH,
+@@ -1417,7 +1418,7 @@ static enum io_sch_action sch_get_action(struct subchannel *sch)
+ }
+ if ((sch->schib.pmcw.pam & sch->opm) == 0) {
+ if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK)
+- return IO_SCH_UNREG;
++ return IO_SCH_UNREG_CDEV;
+ return IO_SCH_DISC;
+ }
+ if (device_is_disconnected(cdev))
+@@ -1479,6 +1480,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
+ case IO_SCH_ORPH_ATTACH:
+ ccw_device_set_disconnected(cdev);
+ break;
++ case IO_SCH_UNREG_CDEV:
+ case IO_SCH_UNREG_ATTACH:
+ case IO_SCH_UNREG:
+ if (!cdev)
+@@ -1512,6 +1514,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
+ if (rc)
+ goto out;
+ break;
++ case IO_SCH_UNREG_CDEV:
+ case IO_SCH_UNREG_ATTACH:
+ spin_lock_irqsave(sch->lock, flags);
+ if (cdev->private->flags.resuming) {
+diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
+index e32d93b927428..4017464a5909b 100644
+--- a/drivers/target/iscsi/iscsi_target_nego.c
++++ b/drivers/target/iscsi/iscsi_target_nego.c
+@@ -1053,6 +1053,7 @@ int iscsi_target_locate_portal(
+ iscsi_target_set_sock_callbacks(conn);
+
+ login->np = np;
++ conn->tpg = NULL;
+
+ login_req = (struct iscsi_login_req *) login->req;
+ payload_length = ntoh24(login_req->dlength);
+@@ -1122,7 +1123,6 @@ int iscsi_target_locate_portal(
+ */
+ sessiontype = strncmp(s_buf, DISCOVERY, 9);
+ if (!sessiontype) {
+- conn->tpg = iscsit_global->discovery_tpg;
+ if (!login->leading_connection)
+ goto get_target;
+
+@@ -1139,9 +1139,11 @@ int iscsi_target_locate_portal(
+ * Serialize access across the discovery struct iscsi_portal_group to
+ * process login attempt.
+ */
++ conn->tpg = iscsit_global->discovery_tpg;
+ if (iscsit_access_np(np, conn->tpg) < 0) {
+ iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+ ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
++ conn->tpg = NULL;
+ ret = -1;
+ goto out;
+ }
+diff --git a/drivers/usb/gadget/udc/amd5536udc_pci.c b/drivers/usb/gadget/udc/amd5536udc_pci.c
+index 362284057d307..a3d15c3fb82a9 100644
+--- a/drivers/usb/gadget/udc/amd5536udc_pci.c
++++ b/drivers/usb/gadget/udc/amd5536udc_pci.c
+@@ -171,6 +171,9 @@ static int udc_pci_probe(
+ retval = -ENODEV;
+ goto err_probe;
+ }
++
++ udc = dev;
++
+ return 0;
+
+ err_probe:
+diff --git a/fs/cifs/dfs_cache.c b/fs/cifs/dfs_cache.c
+index cf6cec59696c2..cf9267cf42e79 100644
+--- a/fs/cifs/dfs_cache.c
++++ b/fs/cifs/dfs_cache.c
+@@ -22,67 +22,69 @@
+
+ #include "dfs_cache.h"
+
+-#define DFS_CACHE_HTABLE_SIZE 32
+-#define DFS_CACHE_MAX_ENTRIES 64
++#define CACHE_HTABLE_SIZE 32
++#define CACHE_MAX_ENTRIES 64
+
+ #define IS_INTERLINK_SET(v) ((v) & (DFSREF_REFERRAL_SERVER | \
+ DFSREF_STORAGE_SERVER))
+
+-struct dfs_cache_tgt {
+- char *t_name;
+- struct list_head t_list;
++struct cache_dfs_tgt {
++ char *name;
++ struct list_head list;
+ };
+
+-struct dfs_cache_entry {
+- struct hlist_node ce_hlist;
+- const char *ce_path;
+- int ce_ttl;
+- int ce_srvtype;
+- int ce_flags;
+- struct timespec64 ce_etime;
+- int ce_path_consumed;
+- int ce_numtgts;
+- struct list_head ce_tlist;
+- struct dfs_cache_tgt *ce_tgthint;
+- struct rcu_head ce_rcu;
++struct cache_entry {
++ struct hlist_node hlist;
++ const char *path;
++ int ttl;
++ int srvtype;
++ int flags;
++ struct timespec64 etime;
++ int path_consumed;
++ int numtgts;
++ struct list_head tlist;
++ struct cache_dfs_tgt *tgthint;
++ struct rcu_head rcu;
+ };
+
+-static struct kmem_cache *dfs_cache_slab __read_mostly;
+-
+-struct dfs_cache_vol_info {
+- char *vi_fullpath;
+- struct smb_vol vi_vol;
+- char *vi_mntdata;
+- struct list_head vi_list;
++struct vol_info {
++ char *fullpath;
++ spinlock_t smb_vol_lock;
++ struct smb_vol smb_vol;
++ char *mntdata;
++ struct list_head list;
++ struct list_head rlist;
++ struct kref refcnt;
+ };
+
+-struct dfs_cache {
+- struct mutex dc_lock;
+- struct nls_table *dc_nlsc;
+- struct list_head dc_vol_list;
+- int dc_ttl;
+- struct delayed_work dc_refresh;
+-};
++static struct kmem_cache *cache_slab __read_mostly;
++static struct workqueue_struct *dfscache_wq __read_mostly;
++
++static int cache_ttl;
++static DEFINE_SPINLOCK(cache_ttl_lock);
+
+-static struct dfs_cache dfs_cache;
++static struct nls_table *cache_nlsc;
+
+ /*
+ * Number of entries in the cache
+ */
+-static size_t dfs_cache_count;
++static size_t cache_count;
+
+-static DEFINE_MUTEX(dfs_cache_list_lock);
+-static struct hlist_head dfs_cache_htable[DFS_CACHE_HTABLE_SIZE];
++static struct hlist_head cache_htable[CACHE_HTABLE_SIZE];
++static DEFINE_MUTEX(list_lock);
++
++static LIST_HEAD(vol_list);
++static DEFINE_SPINLOCK(vol_list_lock);
+
+ static void refresh_cache_worker(struct work_struct *work);
+
+-static inline bool is_path_valid(const char *path)
+-{
+- return path && (strchr(path + 1, '\\') || strchr(path + 1, '/'));
+-}
++static DECLARE_DELAYED_WORK(refresh_task, refresh_cache_worker);
+
+-static inline int get_normalized_path(const char *path, char **npath)
++static int get_normalized_path(const char *path, char **npath)
+ {
++ if (!path || strlen(path) < 3 || (*path != '\\' && *path != '/'))
++ return -EINVAL;
++
+ if (*path == '\\') {
+ *npath = (char *)path;
+ } else {
+@@ -100,42 +102,42 @@ static inline void free_normalized_path(const char *path, char *npath)
+ kfree(npath);
+ }
+
+-static inline bool cache_entry_expired(const struct dfs_cache_entry *ce)
++static inline bool cache_entry_expired(const struct cache_entry *ce)
+ {
+ struct timespec64 ts;
+
+ ktime_get_coarse_real_ts64(&ts);
+- return timespec64_compare(&ts, &ce->ce_etime) >= 0;
++ return timespec64_compare(&ts, &ce->etime) >= 0;
+ }
+
+-static inline void free_tgts(struct dfs_cache_entry *ce)
++static inline void free_tgts(struct cache_entry *ce)
+ {
+- struct dfs_cache_tgt *t, *n;
++ struct cache_dfs_tgt *t, *n;
+
+- list_for_each_entry_safe(t, n, &ce->ce_tlist, t_list) {
+- list_del(&t->t_list);
+- kfree(t->t_name);
++ list_for_each_entry_safe(t, n, &ce->tlist, list) {
++ list_del(&t->list);
++ kfree(t->name);
+ kfree(t);
+ }
+ }
+
+ static void free_cache_entry(struct rcu_head *rcu)
+ {
+- struct dfs_cache_entry *ce = container_of(rcu, struct dfs_cache_entry,
+- ce_rcu);
+- kmem_cache_free(dfs_cache_slab, ce);
++ struct cache_entry *ce = container_of(rcu, struct cache_entry, rcu);
++
++ kmem_cache_free(cache_slab, ce);
+ }
+
+-static inline void flush_cache_ent(struct dfs_cache_entry *ce)
++static inline void flush_cache_ent(struct cache_entry *ce)
+ {
+- if (hlist_unhashed(&ce->ce_hlist))
++ if (hlist_unhashed(&ce->hlist))
+ return;
+
+- hlist_del_init_rcu(&ce->ce_hlist);
+- kfree_const(ce->ce_path);
++ hlist_del_init_rcu(&ce->hlist);
++ kfree(ce->path);
+ free_tgts(ce);
+- dfs_cache_count--;
+- call_rcu(&ce->ce_rcu, free_cache_entry);
++ cache_count--;
++ call_rcu(&ce->rcu, free_cache_entry);
+ }
+
+ static void flush_cache_ents(void)
+@@ -143,11 +145,11 @@ static void flush_cache_ents(void)
+ int i;
+
+ rcu_read_lock();
+- for (i = 0; i < DFS_CACHE_HTABLE_SIZE; i++) {
+- struct hlist_head *l = &dfs_cache_htable[i];
+- struct dfs_cache_entry *ce;
++ for (i = 0; i < CACHE_HTABLE_SIZE; i++) {
++ struct hlist_head *l = &cache_htable[i];
++ struct cache_entry *ce;
+
+- hlist_for_each_entry_rcu(ce, l, ce_hlist)
++ hlist_for_each_entry_rcu(ce, l, hlist)
+ flush_cache_ent(ce);
+ }
+ rcu_read_unlock();
+@@ -159,35 +161,35 @@ static void flush_cache_ents(void)
+ static int dfscache_proc_show(struct seq_file *m, void *v)
+ {
+ int bucket;
+- struct dfs_cache_entry *ce;
+- struct dfs_cache_tgt *t;
++ struct cache_entry *ce;
++ struct cache_dfs_tgt *t;
+
+ seq_puts(m, "DFS cache\n---------\n");
+
+- mutex_lock(&dfs_cache_list_lock);
++ mutex_lock(&list_lock);
+
+ rcu_read_lock();
+- hash_for_each_rcu(dfs_cache_htable, bucket, ce, ce_hlist) {
++ hash_for_each_rcu(cache_htable, bucket, ce, hlist) {
+ seq_printf(m,
+ "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,"
+ "interlink=%s,path_consumed=%d,expired=%s\n",
+- ce->ce_path,
+- ce->ce_srvtype == DFS_TYPE_ROOT ? "root" : "link",
+- ce->ce_ttl, ce->ce_etime.tv_nsec,
+- IS_INTERLINK_SET(ce->ce_flags) ? "yes" : "no",
+- ce->ce_path_consumed,
++ ce->path,
++ ce->srvtype == DFS_TYPE_ROOT ? "root" : "link",
++ ce->ttl, ce->etime.tv_nsec,
++ IS_INTERLINK_SET(ce->flags) ? "yes" : "no",
++ ce->path_consumed,
+ cache_entry_expired(ce) ? "yes" : "no");
+
+- list_for_each_entry(t, &ce->ce_tlist, t_list) {
++ list_for_each_entry(t, &ce->tlist, list) {
+ seq_printf(m, " %s%s\n",
+- t->t_name,
+- ce->ce_tgthint == t ? " (target hint)" : "");
++ t->name,
++ ce->tgthint == t ? " (target hint)" : "");
+ }
+
+ }
+ rcu_read_unlock();
+
+- mutex_unlock(&dfs_cache_list_lock);
++ mutex_unlock(&list_lock);
+ return 0;
+ }
+
+@@ -205,9 +207,9 @@ static ssize_t dfscache_proc_write(struct file *file, const char __user *buffer,
+ return -EINVAL;
+
+ cifs_dbg(FYI, "clearing dfs cache");
+- mutex_lock(&dfs_cache_list_lock);
++ mutex_lock(&list_lock);
+ flush_cache_ents();
+- mutex_unlock(&dfs_cache_list_lock);
++ mutex_unlock(&list_lock);
+
+ return count;
+ }
+@@ -226,25 +228,25 @@ const struct file_operations dfscache_proc_fops = {
+ };
+
+ #ifdef CONFIG_CIFS_DEBUG2
+-static inline void dump_tgts(const struct dfs_cache_entry *ce)
++static inline void dump_tgts(const struct cache_entry *ce)
+ {
+- struct dfs_cache_tgt *t;
++ struct cache_dfs_tgt *t;
+
+ cifs_dbg(FYI, "target list:\n");
+- list_for_each_entry(t, &ce->ce_tlist, t_list) {
+- cifs_dbg(FYI, " %s%s\n", t->t_name,
+- ce->ce_tgthint == t ? " (target hint)" : "");
++ list_for_each_entry(t, &ce->tlist, list) {
++ cifs_dbg(FYI, " %s%s\n", t->name,
++ ce->tgthint == t ? " (target hint)" : "");
+ }
+ }
+
+-static inline void dump_ce(const struct dfs_cache_entry *ce)
++static inline void dump_ce(const struct cache_entry *ce)
+ {
+ cifs_dbg(FYI, "cache entry: path=%s,type=%s,ttl=%d,etime=%ld,"
+- "interlink=%s,path_consumed=%d,expired=%s\n", ce->ce_path,
+- ce->ce_srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ce_ttl,
+- ce->ce_etime.tv_nsec,
+- IS_INTERLINK_SET(ce->ce_flags) ? "yes" : "no",
+- ce->ce_path_consumed,
++ "interlink=%s,path_consumed=%d,expired=%s\n", ce->path,
++ ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl,
++ ce->etime.tv_nsec,
++ IS_INTERLINK_SET(ce->flags) ? "yes" : "no",
++ ce->path_consumed,
+ cache_entry_expired(ce) ? "yes" : "no");
+ dump_tgts(ce);
+ }
+@@ -284,25 +286,33 @@ static inline void dump_refs(const struct dfs_info3_param *refs, int numrefs)
+ */
+ int dfs_cache_init(void)
+ {
++ int rc;
+ int i;
+
+- dfs_cache_slab = kmem_cache_create("cifs_dfs_cache",
+- sizeof(struct dfs_cache_entry), 0,
+- SLAB_HWCACHE_ALIGN, NULL);
+- if (!dfs_cache_slab)
++ dfscache_wq = alloc_workqueue("cifs-dfscache",
++ WQ_FREEZABLE | WQ_MEM_RECLAIM, 1);
++ if (!dfscache_wq)
+ return -ENOMEM;
+
+- for (i = 0; i < DFS_CACHE_HTABLE_SIZE; i++)
+- INIT_HLIST_HEAD(&dfs_cache_htable[i]);
++ cache_slab = kmem_cache_create("cifs_dfs_cache",
++ sizeof(struct cache_entry), 0,
++ SLAB_HWCACHE_ALIGN, NULL);
++ if (!cache_slab) {
++ rc = -ENOMEM;
++ goto out_destroy_wq;
++ }
+
+- INIT_LIST_HEAD(&dfs_cache.dc_vol_list);
+- mutex_init(&dfs_cache.dc_lock);
+- INIT_DELAYED_WORK(&dfs_cache.dc_refresh, refresh_cache_worker);
+- dfs_cache.dc_ttl = -1;
+- dfs_cache.dc_nlsc = load_nls_default();
++ for (i = 0; i < CACHE_HTABLE_SIZE; i++)
++ INIT_HLIST_HEAD(&cache_htable[i]);
++
++ cache_nlsc = load_nls_default();
+
+ cifs_dbg(FYI, "%s: initialized DFS referral cache\n", __func__);
+ return 0;
++
++out_destroy_wq:
++ destroy_workqueue(dfscache_wq);
++ return rc;
+ }
+
+ static inline unsigned int cache_entry_hash(const void *data, int size)
+@@ -310,7 +320,7 @@ static inline unsigned int cache_entry_hash(const void *data, int size)
+ unsigned int h;
+
+ h = jhash(data, size, 0);
+- return h & (DFS_CACHE_HTABLE_SIZE - 1);
++ return h & (CACHE_HTABLE_SIZE - 1);
+ }
+
+ /* Check whether second path component of @path is SYSVOL or NETLOGON */
+@@ -325,11 +335,11 @@ static inline bool is_sysvol_or_netlogon(const char *path)
+ }
+
+ /* Return target hint of a DFS cache entry */
+-static inline char *get_tgt_name(const struct dfs_cache_entry *ce)
++static inline char *get_tgt_name(const struct cache_entry *ce)
+ {
+- struct dfs_cache_tgt *t = ce->ce_tgthint;
++ struct cache_dfs_tgt *t = ce->tgthint;
+
+- return t ? t->t_name : ERR_PTR(-ENOENT);
++ return t ? t->name : ERR_PTR(-ENOENT);
+ }
+
+ /* Return expire time out of a new entry's TTL */
+@@ -346,19 +356,19 @@ static inline struct timespec64 get_expire_time(int ttl)
+ }
+
+ /* Allocate a new DFS target */
+-static inline struct dfs_cache_tgt *alloc_tgt(const char *name)
++static inline struct cache_dfs_tgt *alloc_tgt(const char *name)
+ {
+- struct dfs_cache_tgt *t;
++ struct cache_dfs_tgt *t;
+
+ t = kmalloc(sizeof(*t), GFP_KERNEL);
+ if (!t)
+ return ERR_PTR(-ENOMEM);
+- t->t_name = kstrndup(name, strlen(name), GFP_KERNEL);
+- if (!t->t_name) {
++ t->name = kstrndup(name, strlen(name), GFP_KERNEL);
++ if (!t->name) {
+ kfree(t);
+ return ERR_PTR(-ENOMEM);
+ }
+- INIT_LIST_HEAD(&t->t_list);
++ INIT_LIST_HEAD(&t->list);
+ return t;
+ }
+
+@@ -367,63 +377,63 @@ static inline struct dfs_cache_tgt *alloc_tgt(const char *name)
+ * target hint.
+ */
+ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
+- struct dfs_cache_entry *ce, const char *tgthint)
++ struct cache_entry *ce, const char *tgthint)
+ {
+ int i;
+
+- ce->ce_ttl = refs[0].ttl;
+- ce->ce_etime = get_expire_time(ce->ce_ttl);
+- ce->ce_srvtype = refs[0].server_type;
+- ce->ce_flags = refs[0].ref_flag;
+- ce->ce_path_consumed = refs[0].path_consumed;
++ ce->ttl = refs[0].ttl;
++ ce->etime = get_expire_time(ce->ttl);
++ ce->srvtype = refs[0].server_type;
++ ce->flags = refs[0].ref_flag;
++ ce->path_consumed = refs[0].path_consumed;
+
+ for (i = 0; i < numrefs; i++) {
+- struct dfs_cache_tgt *t;
++ struct cache_dfs_tgt *t;
+
+ t = alloc_tgt(refs[i].node_name);
+ if (IS_ERR(t)) {
+ free_tgts(ce);
+ return PTR_ERR(t);
+ }
+- if (tgthint && !strcasecmp(t->t_name, tgthint)) {
+- list_add(&t->t_list, &ce->ce_tlist);
++ if (tgthint && !strcasecmp(t->name, tgthint)) {
++ list_add(&t->list, &ce->tlist);
+ tgthint = NULL;
+ } else {
+- list_add_tail(&t->t_list, &ce->ce_tlist);
++ list_add_tail(&t->list, &ce->tlist);
+ }
+- ce->ce_numtgts++;
++ ce->numtgts++;
+ }
+
+- ce->ce_tgthint = list_first_entry_or_null(&ce->ce_tlist,
+- struct dfs_cache_tgt, t_list);
++ ce->tgthint = list_first_entry_or_null(&ce->tlist,
++ struct cache_dfs_tgt, list);
+
+ return 0;
+ }
+
+ /* Allocate a new cache entry */
+-static struct dfs_cache_entry *
+-alloc_cache_entry(const char *path, const struct dfs_info3_param *refs,
+- int numrefs)
++static struct cache_entry *alloc_cache_entry(const char *path,
++ const struct dfs_info3_param *refs,
++ int numrefs)
+ {
+- struct dfs_cache_entry *ce;
++ struct cache_entry *ce;
+ int rc;
+
+- ce = kmem_cache_zalloc(dfs_cache_slab, GFP_KERNEL);
++ ce = kmem_cache_zalloc(cache_slab, GFP_KERNEL);
+ if (!ce)
+ return ERR_PTR(-ENOMEM);
+
+- ce->ce_path = kstrdup_const(path, GFP_KERNEL);
+- if (!ce->ce_path) {
+- kmem_cache_free(dfs_cache_slab, ce);
++ ce->path = kstrndup(path, strlen(path), GFP_KERNEL);
++ if (!ce->path) {
++ kmem_cache_free(cache_slab, ce);
+ return ERR_PTR(-ENOMEM);
+ }
+- INIT_HLIST_NODE(&ce->ce_hlist);
+- INIT_LIST_HEAD(&ce->ce_tlist);
++ INIT_HLIST_NODE(&ce->hlist);
++ INIT_LIST_HEAD(&ce->tlist);
+
+ rc = copy_ref_data(refs, numrefs, ce, NULL);
+ if (rc) {
+- kfree_const(ce->ce_path);
+- kmem_cache_free(dfs_cache_slab, ce);
++ kfree(ce->path);
++ kmem_cache_free(cache_slab, ce);
+ ce = ERR_PTR(rc);
+ }
+ return ce;
+@@ -432,13 +442,13 @@ alloc_cache_entry(const char *path, const struct dfs_info3_param *refs,
+ static void remove_oldest_entry(void)
+ {
+ int bucket;
+- struct dfs_cache_entry *ce;
+- struct dfs_cache_entry *to_del = NULL;
++ struct cache_entry *ce;
++ struct cache_entry *to_del = NULL;
+
+ rcu_read_lock();
+- hash_for_each_rcu(dfs_cache_htable, bucket, ce, ce_hlist) {
+- if (!to_del || timespec64_compare(&ce->ce_etime,
+- &to_del->ce_etime) < 0)
++ hash_for_each_rcu(cache_htable, bucket, ce, hlist) {
++ if (!to_del || timespec64_compare(&ce->etime,
++ &to_del->etime) < 0)
+ to_del = ce;
+ }
+ if (!to_del) {
+@@ -453,94 +463,96 @@ out:
+ }
+
+ /* Add a new DFS cache entry */
+-static inline struct dfs_cache_entry *
++static inline struct cache_entry *
+ add_cache_entry(unsigned int hash, const char *path,
+ const struct dfs_info3_param *refs, int numrefs)
+ {
+- struct dfs_cache_entry *ce;
++ struct cache_entry *ce;
+
+ ce = alloc_cache_entry(path, refs, numrefs);
+ if (IS_ERR(ce))
+ return ce;
+
+- hlist_add_head_rcu(&ce->ce_hlist, &dfs_cache_htable[hash]);
++ hlist_add_head_rcu(&ce->hlist, &cache_htable[hash]);
+
+- mutex_lock(&dfs_cache.dc_lock);
+- if (dfs_cache.dc_ttl < 0) {
+- dfs_cache.dc_ttl = ce->ce_ttl;
+- queue_delayed_work(cifsiod_wq, &dfs_cache.dc_refresh,
+- dfs_cache.dc_ttl * HZ);
++ spin_lock(&cache_ttl_lock);
++ if (!cache_ttl) {
++ cache_ttl = ce->ttl;
++ queue_delayed_work(dfscache_wq, &refresh_task, cache_ttl * HZ);
+ } else {
+- dfs_cache.dc_ttl = min_t(int, dfs_cache.dc_ttl, ce->ce_ttl);
+- mod_delayed_work(cifsiod_wq, &dfs_cache.dc_refresh,
+- dfs_cache.dc_ttl * HZ);
++ cache_ttl = min_t(int, cache_ttl, ce->ttl);
++ mod_delayed_work(dfscache_wq, &refresh_task, cache_ttl * HZ);
+ }
+- mutex_unlock(&dfs_cache.dc_lock);
++ spin_unlock(&cache_ttl_lock);
+
+ return ce;
+ }
+
+-static struct dfs_cache_entry *__find_cache_entry(unsigned int hash,
+- const char *path)
++/*
++ * Find a DFS cache entry in hash table and optionally check prefix path against
++ * @path.
++ * Use whole path components in the match.
++ * Return ERR_PTR(-ENOENT) if the entry is not found.
++ */
++static struct cache_entry *lookup_cache_entry(const char *path,
++ unsigned int *hash)
+ {
+- struct dfs_cache_entry *ce;
++ struct cache_entry *ce;
++ unsigned int h;
+ bool found = false;
+
+- rcu_read_lock();
+- hlist_for_each_entry_rcu(ce, &dfs_cache_htable[hash], ce_hlist) {
+- if (!strcasecmp(path, ce->ce_path)) {
+-#ifdef CONFIG_CIFS_DEBUG2
+- char *name = get_tgt_name(ce);
++ h = cache_entry_hash(path, strlen(path));
+
+- if (IS_ERR(name)) {
+- rcu_read_unlock();
+- return ERR_CAST(name);
+- }
+- cifs_dbg(FYI, "%s: cache hit\n", __func__);
+- cifs_dbg(FYI, "%s: target hint: %s\n", __func__, name);
+-#endif
++ rcu_read_lock();
++ hlist_for_each_entry_rcu(ce, &cache_htable[h], hlist) {
++ if (!strcasecmp(path, ce->path)) {
+ found = true;
++ dump_ce(ce);
+ break;
+ }
+ }
+ rcu_read_unlock();
+- return found ? ce : ERR_PTR(-ENOENT);
+-}
+
+-/*
+- * Find a DFS cache entry in hash table and optionally check prefix path against
+- * @path.
+- * Use whole path components in the match.
+- * Return ERR_PTR(-ENOENT) if the entry is not found.
+- */
+-static inline struct dfs_cache_entry *find_cache_entry(const char *path,
+- unsigned int *hash)
+-{
+- *hash = cache_entry_hash(path, strlen(path));
+- return __find_cache_entry(*hash, path);
++ if (!found)
++ ce = ERR_PTR(-ENOENT);
++ if (hash)
++ *hash = h;
++
++ return ce;
+ }
+
+ static inline void destroy_slab_cache(void)
+ {
+ rcu_barrier();
+- kmem_cache_destroy(dfs_cache_slab);
++ kmem_cache_destroy(cache_slab);
+ }
+
+-static inline void free_vol(struct dfs_cache_vol_info *vi)
++static void __vol_release(struct vol_info *vi)
+ {
+- list_del(&vi->vi_list);
+- kfree(vi->vi_fullpath);
+- kfree(vi->vi_mntdata);
+- cifs_cleanup_volume_info_contents(&vi->vi_vol);
++ kfree(vi->fullpath);
++ kfree(vi->mntdata);
++ cifs_cleanup_volume_info_contents(&vi->smb_vol);
+ kfree(vi);
+ }
+
++static void vol_release(struct kref *kref)
++{
++ struct vol_info *vi = container_of(kref, struct vol_info, refcnt);
++
++ spin_lock(&vol_list_lock);
++ list_del(&vi->list);
++ spin_unlock(&vol_list_lock);
++ __vol_release(vi);
++}
++
+ static inline void free_vol_list(void)
+ {
+- struct dfs_cache_vol_info *vi, *nvi;
++ struct vol_info *vi, *nvi;
+
+- list_for_each_entry_safe(vi, nvi, &dfs_cache.dc_vol_list, vi_list)
+- free_vol(vi);
++ list_for_each_entry_safe(vi, nvi, &vol_list, list) {
++ list_del_init(&vi->list);
++ __vol_release(vi);
++ }
+ }
+
+ /**
+@@ -548,40 +560,38 @@ static inline void free_vol_list(void)
+ */
+ void dfs_cache_destroy(void)
+ {
+- cancel_delayed_work_sync(&dfs_cache.dc_refresh);
+- unload_nls(dfs_cache.dc_nlsc);
++ cancel_delayed_work_sync(&refresh_task);
++ unload_nls(cache_nlsc);
+ free_vol_list();
+- mutex_destroy(&dfs_cache.dc_lock);
+-
+ flush_cache_ents();
+ destroy_slab_cache();
+- mutex_destroy(&dfs_cache_list_lock);
++ destroy_workqueue(dfscache_wq);
+
+ cifs_dbg(FYI, "%s: destroyed DFS referral cache\n", __func__);
+ }
+
+-static inline struct dfs_cache_entry *
++static inline struct cache_entry *
+ __update_cache_entry(const char *path, const struct dfs_info3_param *refs,
+ int numrefs)
+ {
+ int rc;
+ unsigned int h;
+- struct dfs_cache_entry *ce;
++ struct cache_entry *ce;
+ char *s, *th = NULL;
+
+- ce = find_cache_entry(path, &h);
++ ce = lookup_cache_entry(path, &h);
+ if (IS_ERR(ce))
+ return ce;
+
+- if (ce->ce_tgthint) {
+- s = ce->ce_tgthint->t_name;
++ if (ce->tgthint) {
++ s = ce->tgthint->name;
+ th = kstrndup(s, strlen(s), GFP_KERNEL);
+ if (!th)
+ return ERR_PTR(-ENOMEM);
+ }
+
+ free_tgts(ce);
+- ce->ce_numtgts = 0;
++ ce->numtgts = 0;
+
+ rc = copy_ref_data(refs, numrefs, ce, th);
+ kfree(th);
+@@ -593,10 +603,10 @@ __update_cache_entry(const char *path, const struct dfs_info3_param *refs,
+ }
+
+ /* Update an expired cache entry by getting a new DFS referral from server */
+-static struct dfs_cache_entry *
++static struct cache_entry *
+ update_cache_entry(const unsigned int xid, struct cifs_ses *ses,
+ const struct nls_table *nls_codepage, int remap,
+- const char *path, struct dfs_cache_entry *ce)
++ const char *path, struct cache_entry *ce)
+ {
+ int rc;
+ struct dfs_info3_param *refs = NULL;
+@@ -636,20 +646,20 @@ update_cache_entry(const unsigned int xid, struct cifs_ses *ses,
+ * For interlinks, __cifs_dfs_mount() and expand_dfs_referral() are supposed to
+ * handle them properly.
+ */
+-static struct dfs_cache_entry *
++static struct cache_entry *
+ do_dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
+ const struct nls_table *nls_codepage, int remap,
+ const char *path, bool noreq)
+ {
+ int rc;
+ unsigned int h;
+- struct dfs_cache_entry *ce;
++ struct cache_entry *ce;
+ struct dfs_info3_param *nrefs;
+ int numnrefs;
+
+ cifs_dbg(FYI, "%s: search path: %s\n", __func__, path);
+
+- ce = find_cache_entry(path, &h);
++ ce = lookup_cache_entry(path, &h);
+ if (IS_ERR(ce)) {
+ cifs_dbg(FYI, "%s: cache miss\n", __func__);
+ /*
+@@ -690,9 +700,9 @@ do_dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
+
+ cifs_dbg(FYI, "%s: new cache entry\n", __func__);
+
+- if (dfs_cache_count >= DFS_CACHE_MAX_ENTRIES) {
++ if (cache_count >= CACHE_MAX_ENTRIES) {
+ cifs_dbg(FYI, "%s: reached max cache size (%d)",
+- __func__, DFS_CACHE_MAX_ENTRIES);
++ __func__, CACHE_MAX_ENTRIES);
+ remove_oldest_entry();
+ }
+ ce = add_cache_entry(h, path, nrefs, numnrefs);
+@@ -701,7 +711,7 @@ do_dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
+ if (IS_ERR(ce))
+ return ce;
+
+- dfs_cache_count++;
++ cache_count++;
+ }
+
+ dump_ce(ce);
+@@ -723,7 +733,7 @@ do_dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
+ }
+
+ /* Set up a new DFS referral from a given cache entry */
+-static int setup_ref(const char *path, const struct dfs_cache_entry *ce,
++static int setup_ref(const char *path, const struct cache_entry *ce,
+ struct dfs_info3_param *ref, const char *tgt)
+ {
+ int rc;
+@@ -736,7 +746,7 @@ static int setup_ref(const char *path, const struct dfs_cache_entry *ce,
+ if (!ref->path_name)
+ return -ENOMEM;
+
+- ref->path_consumed = ce->ce_path_consumed;
++ ref->path_consumed = ce->path_consumed;
+
+ ref->node_name = kstrndup(tgt, strlen(tgt), GFP_KERNEL);
+ if (!ref->node_name) {
+@@ -744,9 +754,9 @@ static int setup_ref(const char *path, const struct dfs_cache_entry *ce,
+ goto err_free_path;
+ }
+
+- ref->ttl = ce->ce_ttl;
+- ref->server_type = ce->ce_srvtype;
+- ref->ref_flag = ce->ce_flags;
++ ref->ttl = ce->ttl;
++ ref->server_type = ce->srvtype;
++ ref->ref_flag = ce->flags;
+
+ return 0;
+
+@@ -757,25 +767,25 @@ err_free_path:
+ }
+
+ /* Return target list of a DFS cache entry */
+-static int get_tgt_list(const struct dfs_cache_entry *ce,
++static int get_tgt_list(const struct cache_entry *ce,
+ struct dfs_cache_tgt_list *tl)
+ {
+ int rc;
+ struct list_head *head = &tl->tl_list;
+- struct dfs_cache_tgt *t;
++ struct cache_dfs_tgt *t;
+ struct dfs_cache_tgt_iterator *it, *nit;
+
+ memset(tl, 0, sizeof(*tl));
+ INIT_LIST_HEAD(head);
+
+- list_for_each_entry(t, &ce->ce_tlist, t_list) {
++ list_for_each_entry(t, &ce->tlist, list) {
+ it = kzalloc(sizeof(*it), GFP_KERNEL);
+ if (!it) {
+ rc = -ENOMEM;
+ goto err_free_it;
+ }
+
+- it->it_name = kstrndup(t->t_name, strlen(t->t_name),
++ it->it_name = kstrndup(t->name, strlen(t->name),
+ GFP_KERNEL);
+ if (!it->it_name) {
+ kfree(it);
+@@ -783,12 +793,12 @@ static int get_tgt_list(const struct dfs_cache_entry *ce,
+ goto err_free_it;
+ }
+
+- if (ce->ce_tgthint == t)
++ if (ce->tgthint == t)
+ list_add(&it->it_list, head);
+ else
+ list_add_tail(&it->it_list, head);
+ }
+- tl->tl_numtgts = ce->ce_numtgts;
++ tl->tl_numtgts = ce->numtgts;
+
+ return 0;
+
+@@ -829,16 +839,13 @@ int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
+ {
+ int rc;
+ char *npath;
+- struct dfs_cache_entry *ce;
+-
+- if (unlikely(!is_path_valid(path)))
+- return -EINVAL;
++ struct cache_entry *ce;
+
+ rc = get_normalized_path(path, &npath);
+ if (rc)
+ return rc;
+
+- mutex_lock(&dfs_cache_list_lock);
++ mutex_lock(&list_lock);
+ ce = do_dfs_cache_find(xid, ses, nls_codepage, remap, npath, false);
+ if (!IS_ERR(ce)) {
+ if (ref)
+@@ -850,7 +857,7 @@ int dfs_cache_find(const unsigned int xid, struct cifs_ses *ses,
+ } else {
+ rc = PTR_ERR(ce);
+ }
+- mutex_unlock(&dfs_cache_list_lock);
++ mutex_unlock(&list_lock);
+ free_normalized_path(path, npath);
+ return rc;
+ }
+@@ -876,16 +883,13 @@ int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
+ {
+ int rc;
+ char *npath;
+- struct dfs_cache_entry *ce;
+-
+- if (unlikely(!is_path_valid(path)))
+- return -EINVAL;
++ struct cache_entry *ce;
+
+ rc = get_normalized_path(path, &npath);
+ if (rc)
+ return rc;
+
+- mutex_lock(&dfs_cache_list_lock);
++ mutex_lock(&list_lock);
+ ce = do_dfs_cache_find(0, NULL, NULL, 0, npath, true);
+ if (IS_ERR(ce)) {
+ rc = PTR_ERR(ce);
+@@ -899,7 +903,7 @@ int dfs_cache_noreq_find(const char *path, struct dfs_info3_param *ref,
+ if (!rc && tgt_list)
+ rc = get_tgt_list(ce, tgt_list);
+ out:
+- mutex_unlock(&dfs_cache_list_lock);
++ mutex_unlock(&list_lock);
+ free_normalized_path(path, npath);
+ return rc;
+ }
+@@ -929,11 +933,8 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
+ {
+ int rc;
+ char *npath;
+- struct dfs_cache_entry *ce;
+- struct dfs_cache_tgt *t;
+-
+- if (unlikely(!is_path_valid(path)))
+- return -EINVAL;
++ struct cache_entry *ce;
++ struct cache_dfs_tgt *t;
+
+ rc = get_normalized_path(path, &npath);
+ if (rc)
+@@ -941,7 +942,7 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
+
+ cifs_dbg(FYI, "%s: path: %s\n", __func__, npath);
+
+- mutex_lock(&dfs_cache_list_lock);
++ mutex_lock(&list_lock);
+ ce = do_dfs_cache_find(xid, ses, nls_codepage, remap, npath, false);
+ if (IS_ERR(ce)) {
+ rc = PTR_ERR(ce);
+@@ -950,14 +951,14 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
+
+ rc = 0;
+
+- t = ce->ce_tgthint;
++ t = ce->tgthint;
+
+- if (likely(!strcasecmp(it->it_name, t->t_name)))
++ if (likely(!strcasecmp(it->it_name, t->name)))
+ goto out;
+
+- list_for_each_entry(t, &ce->ce_tlist, t_list) {
+- if (!strcasecmp(t->t_name, it->it_name)) {
+- ce->ce_tgthint = t;
++ list_for_each_entry(t, &ce->tlist, list) {
++ if (!strcasecmp(t->name, it->it_name)) {
++ ce->tgthint = t;
+ cifs_dbg(FYI, "%s: new target hint: %s\n", __func__,
+ it->it_name);
+ break;
+@@ -965,7 +966,7 @@ int dfs_cache_update_tgthint(const unsigned int xid, struct cifs_ses *ses,
+ }
+
+ out:
+- mutex_unlock(&dfs_cache_list_lock);
++ mutex_unlock(&list_lock);
+ free_normalized_path(path, npath);
+ return rc;
+ }
+@@ -989,10 +990,10 @@ int dfs_cache_noreq_update_tgthint(const char *path,
+ {
+ int rc;
+ char *npath;
+- struct dfs_cache_entry *ce;
+- struct dfs_cache_tgt *t;
++ struct cache_entry *ce;
++ struct cache_dfs_tgt *t;
+
+- if (unlikely(!is_path_valid(path)) || !it)
++ if (!it)
+ return -EINVAL;
+
+ rc = get_normalized_path(path, &npath);
+@@ -1001,7 +1002,7 @@ int dfs_cache_noreq_update_tgthint(const char *path,
+
+ cifs_dbg(FYI, "%s: path: %s\n", __func__, npath);
+
+- mutex_lock(&dfs_cache_list_lock);
++ mutex_lock(&list_lock);
+
+ ce = do_dfs_cache_find(0, NULL, NULL, 0, npath, true);
+ if (IS_ERR(ce)) {
+@@ -1011,14 +1012,14 @@ int dfs_cache_noreq_update_tgthint(const char *path,
+
+ rc = 0;
+
+- t = ce->ce_tgthint;
++ t = ce->tgthint;
+
+- if (unlikely(!strcasecmp(it->it_name, t->t_name)))
++ if (unlikely(!strcasecmp(it->it_name, t->name)))
+ goto out;
+
+- list_for_each_entry(t, &ce->ce_tlist, t_list) {
+- if (!strcasecmp(t->t_name, it->it_name)) {
+- ce->ce_tgthint = t;
++ list_for_each_entry(t, &ce->tlist, list) {
++ if (!strcasecmp(t->name, it->it_name)) {
++ ce->tgthint = t;
+ cifs_dbg(FYI, "%s: new target hint: %s\n", __func__,
+ it->it_name);
+ break;
+@@ -1026,7 +1027,7 @@ int dfs_cache_noreq_update_tgthint(const char *path,
+ }
+
+ out:
+- mutex_unlock(&dfs_cache_list_lock);
++ mutex_unlock(&list_lock);
+ free_normalized_path(path, npath);
+ return rc;
+ }
+@@ -1047,13 +1048,11 @@ int dfs_cache_get_tgt_referral(const char *path,
+ {
+ int rc;
+ char *npath;
+- struct dfs_cache_entry *ce;
++ struct cache_entry *ce;
+ unsigned int h;
+
+ if (!it || !ref)
+ return -EINVAL;
+- if (unlikely(!is_path_valid(path)))
+- return -EINVAL;
+
+ rc = get_normalized_path(path, &npath);
+ if (rc)
+@@ -1061,9 +1060,9 @@ int dfs_cache_get_tgt_referral(const char *path,
+
+ cifs_dbg(FYI, "%s: path: %s\n", __func__, npath);
+
+- mutex_lock(&dfs_cache_list_lock);
++ mutex_lock(&list_lock);
+
+- ce = find_cache_entry(npath, &h);
++ ce = lookup_cache_entry(npath, &h);
+ if (IS_ERR(ce)) {
+ rc = PTR_ERR(ce);
+ goto out;
+@@ -1074,7 +1073,7 @@ int dfs_cache_get_tgt_referral(const char *path,
+ rc = setup_ref(path, ce, ref, it->it_name);
+
+ out:
+- mutex_unlock(&dfs_cache_list_lock);
++ mutex_unlock(&list_lock);
+ free_normalized_path(path, npath);
+ return rc;
+ }
+@@ -1085,7 +1084,7 @@ static int dup_vol(struct smb_vol *vol, struct smb_vol *new)
+
+ if (vol->username) {
+ new->username = kstrndup(vol->username, strlen(vol->username),
+- GFP_KERNEL);
++ GFP_KERNEL);
+ if (!new->username)
+ return -ENOMEM;
+ }
+@@ -1103,7 +1102,7 @@ static int dup_vol(struct smb_vol *vol, struct smb_vol *new)
+ }
+ if (vol->domainname) {
+ new->domainname = kstrndup(vol->domainname,
+- strlen(vol->domainname), GFP_KERNEL);
++ strlen(vol->domainname), GFP_KERNEL);
+ if (!new->domainname)
+ goto err_free_unc;
+ }
+@@ -1150,7 +1149,7 @@ err_free_username:
+ int dfs_cache_add_vol(char *mntdata, struct smb_vol *vol, const char *fullpath)
+ {
+ int rc;
+- struct dfs_cache_vol_info *vi;
++ struct vol_info *vi;
+
+ if (!vol || !fullpath || !mntdata)
+ return -EINVAL;
+@@ -1161,38 +1160,41 @@ int dfs_cache_add_vol(char *mntdata, struct smb_vol *vol, const char *fullpath)
+ if (!vi)
+ return -ENOMEM;
+
+- vi->vi_fullpath = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL);
+- if (!vi->vi_fullpath) {
++ vi->fullpath = kstrndup(fullpath, strlen(fullpath), GFP_KERNEL);
++ if (!vi->fullpath) {
+ rc = -ENOMEM;
+ goto err_free_vi;
+ }
+
+- rc = dup_vol(vol, &vi->vi_vol);
++ rc = dup_vol(vol, &vi->smb_vol);
+ if (rc)
+ goto err_free_fullpath;
+
+- vi->vi_mntdata = mntdata;
++ vi->mntdata = mntdata;
++ spin_lock_init(&vi->smb_vol_lock);
++ kref_init(&vi->refcnt);
++
++ spin_lock(&vol_list_lock);
++ list_add_tail(&vi->list, &vol_list);
++ spin_unlock(&vol_list_lock);
+
+- mutex_lock(&dfs_cache.dc_lock);
+- list_add_tail(&vi->vi_list, &dfs_cache.dc_vol_list);
+- mutex_unlock(&dfs_cache.dc_lock);
+ return 0;
+
+ err_free_fullpath:
+- kfree(vi->vi_fullpath);
++ kfree(vi->fullpath);
+ err_free_vi:
+ kfree(vi);
+ return rc;
+ }
+
+-static inline struct dfs_cache_vol_info *find_vol(const char *fullpath)
++/* Must be called with vol_list_lock held */
++static struct vol_info *find_vol(const char *fullpath)
+ {
+- struct dfs_cache_vol_info *vi;
++ struct vol_info *vi;
+
+- list_for_each_entry(vi, &dfs_cache.dc_vol_list, vi_list) {
+- cifs_dbg(FYI, "%s: vi->vi_fullpath: %s\n", __func__,
+- vi->vi_fullpath);
+- if (!strcasecmp(vi->vi_fullpath, fullpath))
++ list_for_each_entry(vi, &vol_list, list) {
++ cifs_dbg(FYI, "%s: vi->fullpath: %s\n", __func__, vi->fullpath);
++ if (!strcasecmp(vi->fullpath, fullpath))
+ return vi;
+ }
+ return ERR_PTR(-ENOENT);
+@@ -1208,30 +1210,31 @@ static inline struct dfs_cache_vol_info *find_vol(const char *fullpath)
+ */
+ int dfs_cache_update_vol(const char *fullpath, struct TCP_Server_Info *server)
+ {
+- int rc;
+- struct dfs_cache_vol_info *vi;
++ struct vol_info *vi;
+
+ if (!fullpath || !server)
+ return -EINVAL;
+
+ cifs_dbg(FYI, "%s: fullpath: %s\n", __func__, fullpath);
+
+- mutex_lock(&dfs_cache.dc_lock);
+-
++ spin_lock(&vol_list_lock);
+ vi = find_vol(fullpath);
+ if (IS_ERR(vi)) {
+- rc = PTR_ERR(vi);
+- goto out;
++ spin_unlock(&vol_list_lock);
++ return PTR_ERR(vi);
+ }
++ kref_get(&vi->refcnt);
++ spin_unlock(&vol_list_lock);
+
+ cifs_dbg(FYI, "%s: updating volume info\n", __func__);
+- memcpy(&vi->vi_vol.dstaddr, &server->dstaddr,
+- sizeof(vi->vi_vol.dstaddr));
+- rc = 0;
++ spin_lock(&vi->smb_vol_lock);
++ memcpy(&vi->smb_vol.dstaddr, &server->dstaddr,
++ sizeof(vi->smb_vol.dstaddr));
++ spin_unlock(&vi->smb_vol_lock);
+
+-out:
+- mutex_unlock(&dfs_cache.dc_lock);
+- return rc;
++ kref_put(&vi->refcnt, vol_release);
++
++ return 0;
+ }
+
+ /**
+@@ -1241,18 +1244,18 @@ out:
+ */
+ void dfs_cache_del_vol(const char *fullpath)
+ {
+- struct dfs_cache_vol_info *vi;
++ struct vol_info *vi;
+
+ if (!fullpath || !*fullpath)
+ return;
+
+ cifs_dbg(FYI, "%s: fullpath: %s\n", __func__, fullpath);
+
+- mutex_lock(&dfs_cache.dc_lock);
++ spin_lock(&vol_list_lock);
+ vi = find_vol(fullpath);
+- if (!IS_ERR(vi))
+- free_vol(vi);
+- mutex_unlock(&dfs_cache.dc_lock);
++ spin_unlock(&vol_list_lock);
++
++ kref_put(&vi->refcnt, vol_release);
+ }
+
+ /* Get all tcons that are within a DFS namespace and can be refreshed */
+@@ -1280,7 +1283,7 @@ static void get_tcons(struct TCP_Server_Info *server, struct list_head *head)
+ spin_unlock(&cifs_tcp_ses_lock);
+ }
+
+-static inline bool is_dfs_link(const char *path)
++static bool is_dfs_link(const char *path)
+ {
+ char *s;
+
+@@ -1290,7 +1293,7 @@ static inline bool is_dfs_link(const char *path)
+ return !!strchr(s + 1, '\\');
+ }
+
+-static inline char *get_dfs_root(const char *path)
++static char *get_dfs_root(const char *path)
+ {
+ char *s, *npath;
+
+@@ -1309,9 +1312,34 @@ static inline char *get_dfs_root(const char *path)
+ return npath;
+ }
+
++static inline void put_tcp_server(struct TCP_Server_Info *server)
++{
++ cifs_put_tcp_session(server, 0);
++}
++
++static struct TCP_Server_Info *get_tcp_server(struct smb_vol *vol)
++{
++ struct TCP_Server_Info *server;
++
++ server = cifs_find_tcp_session(vol);
++ if (IS_ERR_OR_NULL(server))
++ return NULL;
++
++ spin_lock(&GlobalMid_Lock);
++ if (server->tcpStatus != CifsGood) {
++ spin_unlock(&GlobalMid_Lock);
++ put_tcp_server(server);
++ return NULL;
++ }
++ spin_unlock(&GlobalMid_Lock);
++
++ return server;
++}
++
+ /* Find root SMB session out of a DFS link path */
+-static struct cifs_ses *find_root_ses(struct dfs_cache_vol_info *vi,
+- struct cifs_tcon *tcon, const char *path)
++static struct cifs_ses *find_root_ses(struct vol_info *vi,
++ struct cifs_tcon *tcon,
++ const char *path)
+ {
+ char *rpath;
+ int rc;
+@@ -1333,8 +1361,7 @@ static struct cifs_ses *find_root_ses(struct dfs_cache_vol_info *vi,
+ goto out;
+ }
+
+- mdata = cifs_compose_mount_options(vi->vi_mntdata, rpath, &ref,
+- &devname);
++ mdata = cifs_compose_mount_options(vi->mntdata, rpath, &ref, &devname);
+ free_dfs_info_param(&ref);
+
+ if (IS_ERR(mdata)) {
+@@ -1351,13 +1378,8 @@ static struct cifs_ses *find_root_ses(struct dfs_cache_vol_info *vi,
+ goto out;
+ }
+
+- server = cifs_find_tcp_session(&vol);
+- if (IS_ERR_OR_NULL(server)) {
+- ses = ERR_PTR(-EHOSTDOWN);
+- goto out;
+- }
+- if (server->tcpStatus != CifsGood) {
+- cifs_put_tcp_session(server, 0);
++ server = get_tcp_server(&vol);
++ if (!server) {
+ ses = ERR_PTR(-EHOSTDOWN);
+ goto out;
+ }
+@@ -1373,14 +1395,13 @@ out:
+ }
+
+ /* Refresh DFS cache entry from a given tcon */
+-static void do_refresh_tcon(struct dfs_cache *dc, struct dfs_cache_vol_info *vi,
+- struct cifs_tcon *tcon)
++static void refresh_tcon(struct vol_info *vi, struct cifs_tcon *tcon)
+ {
+ int rc = 0;
+ unsigned int xid;
+ char *path, *npath;
+ unsigned int h;
+- struct dfs_cache_entry *ce;
++ struct cache_entry *ce;
+ struct dfs_info3_param *refs = NULL;
+ int numrefs = 0;
+ struct cifs_ses *root_ses = NULL, *ses;
+@@ -1393,9 +1414,9 @@ static void do_refresh_tcon(struct dfs_cache *dc, struct dfs_cache_vol_info *vi,
+ if (rc)
+ goto out;
+
+- mutex_lock(&dfs_cache_list_lock);
+- ce = find_cache_entry(npath, &h);
+- mutex_unlock(&dfs_cache_list_lock);
++ mutex_lock(&list_lock);
++ ce = lookup_cache_entry(npath, &h);
++ mutex_unlock(&list_lock);
+
+ if (IS_ERR(ce)) {
+ rc = PTR_ERR(ce);
+@@ -1421,12 +1442,12 @@ static void do_refresh_tcon(struct dfs_cache *dc, struct dfs_cache_vol_info *vi,
+ rc = -EOPNOTSUPP;
+ } else {
+ rc = ses->server->ops->get_dfs_refer(xid, ses, path, &refs,
+- &numrefs, dc->dc_nlsc,
++ &numrefs, cache_nlsc,
+ tcon->remap);
+ if (!rc) {
+- mutex_lock(&dfs_cache_list_lock);
++ mutex_lock(&list_lock);
+ ce = __update_cache_entry(npath, refs, numrefs);
+- mutex_unlock(&dfs_cache_list_lock);
++ mutex_unlock(&list_lock);
+ dump_refs(refs, numrefs);
+ free_dfs_info_array(refs, numrefs);
+ if (IS_ERR(ce))
+@@ -1448,30 +1469,52 @@ out:
+ */
+ static void refresh_cache_worker(struct work_struct *work)
+ {
+- struct dfs_cache *dc = container_of(work, struct dfs_cache,
+- dc_refresh.work);
+- struct dfs_cache_vol_info *vi;
++ struct vol_info *vi, *nvi;
+ struct TCP_Server_Info *server;
+- LIST_HEAD(list);
++ LIST_HEAD(vols);
++ LIST_HEAD(tcons);
+ struct cifs_tcon *tcon, *ntcon;
+
+- mutex_lock(&dc->dc_lock);
+-
+- list_for_each_entry(vi, &dc->dc_vol_list, vi_list) {
+- server = cifs_find_tcp_session(&vi->vi_vol);
+- if (IS_ERR_OR_NULL(server))
++ /*
++ * Find SMB volumes that are eligible (server->tcpStatus == CifsGood)
++ * for refreshing.
++ */
++ spin_lock(&vol_list_lock);
++ list_for_each_entry(vi, &vol_list, list) {
++ server = get_tcp_server(&vi->smb_vol);
++ if (!server)
+ continue;
+- if (server->tcpStatus != CifsGood)
+- goto next;
+- get_tcons(server, &list);
+- list_for_each_entry_safe(tcon, ntcon, &list, ulist) {
+- do_refresh_tcon(dc, vi, tcon);
++
++ kref_get(&vi->refcnt);
++ list_add_tail(&vi->rlist, &vols);
++ put_tcp_server(server);
++ }
++ spin_unlock(&vol_list_lock);
++
++ /* Walk through all TCONs and refresh any expired cache entry */
++ list_for_each_entry_safe(vi, nvi, &vols, rlist) {
++ spin_lock(&vi->smb_vol_lock);
++ server = get_tcp_server(&vi->smb_vol);
++ spin_unlock(&vi->smb_vol_lock);
++
++ if (!server)
++ goto next_vol;
++
++ get_tcons(server, &tcons);
++ list_for_each_entry_safe(tcon, ntcon, &tcons, ulist) {
++ refresh_tcon(vi, tcon);
+ list_del_init(&tcon->ulist);
+ cifs_put_tcon(tcon);
+ }
+-next:
+- cifs_put_tcp_session(server, 0);
++
++ put_tcp_server(server);
++
++next_vol:
++ list_del_init(&vi->rlist);
++ kref_put(&vi->refcnt, vol_release);
+ }
+- queue_delayed_work(cifsiod_wq, &dc->dc_refresh, dc->dc_ttl * HZ);
+- mutex_unlock(&dc->dc_lock);
++
++ spin_lock(&cache_ttl_lock);
++ queue_delayed_work(dfscache_wq, &refresh_task, cache_ttl * HZ);
++ spin_unlock(&cache_ttl_lock);
+ }
+diff --git a/fs/eventpoll.c b/fs/eventpoll.c
+index 877f9f61a4e8d..8c0e94183186f 100644
+--- a/fs/eventpoll.c
++++ b/fs/eventpoll.c
+@@ -1814,7 +1814,11 @@ static int ep_autoremove_wake_function(struct wait_queue_entry *wq_entry,
+ {
+ int ret = default_wake_function(wq_entry, mode, sync, key);
+
+- list_del_init(&wq_entry->entry);
++ /*
++ * Pairs with list_empty_careful in ep_poll, and ensures future loop
++ * iterations see the cause of this wakeup.
++ */
++ list_del_init_careful(&wq_entry->entry);
+ return ret;
+ }
+
+diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c
+index 98d21ad9a073f..108e4528fccd0 100644
+--- a/fs/nilfs2/page.c
++++ b/fs/nilfs2/page.c
+@@ -370,7 +370,15 @@ void nilfs_clear_dirty_pages(struct address_space *mapping, bool silent)
+ struct page *page = pvec.pages[i];
+
+ lock_page(page);
+- nilfs_clear_dirty_page(page, silent);
++
++ /*
++ * This page may have been removed from the address
++ * space by truncation or invalidation when the lock
++ * was acquired. Skip processing in that case.
++ */
++ if (likely(page->mapping == mapping))
++ nilfs_clear_dirty_page(page, silent);
++
+ unlock_page(page);
+ }
+ pagevec_release(&pvec);
+diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c
+index 20c479b5e41b8..e72466fc8ca93 100644
+--- a/fs/nilfs2/segbuf.c
++++ b/fs/nilfs2/segbuf.c
+@@ -101,6 +101,12 @@ int nilfs_segbuf_extend_segsum(struct nilfs_segment_buffer *segbuf)
+ if (unlikely(!bh))
+ return -ENOMEM;
+
++ lock_buffer(bh);
++ if (!buffer_uptodate(bh)) {
++ memset(bh->b_data, 0, bh->b_size);
++ set_buffer_uptodate(bh);
++ }
++ unlock_buffer(bh);
+ nilfs_segbuf_add_segsum_buffer(segbuf, bh);
+ return 0;
+ }
+diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
+index 3091d1a3eddea..d9e0b2b2b5552 100644
+--- a/fs/nilfs2/segment.c
++++ b/fs/nilfs2/segment.c
+@@ -984,10 +984,13 @@ static void nilfs_segctor_fill_in_super_root(struct nilfs_sc_info *sci,
+ unsigned int isz, srsz;
+
+ bh_sr = NILFS_LAST_SEGBUF(&sci->sc_segbufs)->sb_super_root;
++
++ lock_buffer(bh_sr);
+ raw_sr = (struct nilfs_super_root *)bh_sr->b_data;
+ isz = nilfs->ns_inode_size;
+ srsz = NILFS_SR_BYTES(isz);
+
++ raw_sr->sr_sum = 0; /* Ensure initialization within this update */
+ raw_sr->sr_bytes = cpu_to_le16(srsz);
+ raw_sr->sr_nongc_ctime
+ = cpu_to_le64(nilfs_doing_gc() ?
+@@ -1001,6 +1004,8 @@ static void nilfs_segctor_fill_in_super_root(struct nilfs_sc_info *sci,
+ nilfs_write_inode_common(nilfs->ns_sufile, (void *)raw_sr +
+ NILFS_SR_SUFILE_OFFSET(isz), 1);
+ memset((void *)raw_sr + srsz, 0, nilfs->ns_blocksize - srsz);
++ set_buffer_uptodate(bh_sr);
++ unlock_buffer(bh_sr);
+ }
+
+ static void nilfs_redirty_inodes(struct list_head *head)
+@@ -1778,6 +1783,7 @@ static void nilfs_abort_logs(struct list_head *logs, int err)
+ list_for_each_entry(segbuf, logs, sb_list) {
+ list_for_each_entry(bh, &segbuf->sb_segsum_buffers,
+ b_assoc_buffers) {
++ clear_buffer_uptodate(bh);
+ if (bh->b_page != bd_page) {
+ if (bd_page)
+ end_page_writeback(bd_page);
+@@ -1789,6 +1795,7 @@ static void nilfs_abort_logs(struct list_head *logs, int err)
+ b_assoc_buffers) {
+ clear_buffer_async_write(bh);
+ if (bh == segbuf->sb_super_root) {
++ clear_buffer_uptodate(bh);
+ if (bh->b_page != bd_page) {
+ end_page_writeback(bd_page);
+ bd_page = bh->b_page;
+diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
+index 94cf515ec602a..2263ebedf9d58 100644
+--- a/fs/nilfs2/super.c
++++ b/fs/nilfs2/super.c
+@@ -367,10 +367,31 @@ static int nilfs_move_2nd_super(struct super_block *sb, loff_t sb2off)
+ goto out;
+ }
+ nsbp = (void *)nsbh->b_data + offset;
+- memset(nsbp, 0, nilfs->ns_blocksize);
+
++ lock_buffer(nsbh);
+ if (sb2i >= 0) {
++ /*
++ * The position of the second superblock only changes by 4KiB,
++ * which is larger than the maximum superblock data size
++ * (= 1KiB), so there is no need to use memmove() to allow
++ * overlap between source and destination.
++ */
+ memcpy(nsbp, nilfs->ns_sbp[sb2i], nilfs->ns_sbsize);
++
++ /*
++ * Zero fill after copy to avoid overwriting in case of move
++ * within the same block.
++ */
++ memset(nsbh->b_data, 0, offset);
++ memset((void *)nsbp + nilfs->ns_sbsize, 0,
++ nsbh->b_size - offset - nilfs->ns_sbsize);
++ } else {
++ memset(nsbh->b_data, 0, nsbh->b_size);
++ }
++ set_buffer_uptodate(nsbh);
++ unlock_buffer(nsbh);
++
++ if (sb2i >= 0) {
+ brelse(nilfs->ns_sbh[sb2i]);
+ nilfs->ns_sbh[sb2i] = nsbh;
+ nilfs->ns_sbp[sb2i] = nsbp;
+diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
+index 24f626e7d012a..d550a564645e2 100644
+--- a/fs/nilfs2/the_nilfs.c
++++ b/fs/nilfs2/the_nilfs.c
+@@ -375,6 +375,18 @@ unsigned long nilfs_nrsvsegs(struct the_nilfs *nilfs, unsigned long nsegs)
+ 100));
+ }
+
++/**
++ * nilfs_max_segment_count - calculate the maximum number of segments
++ * @nilfs: nilfs object
++ */
++static u64 nilfs_max_segment_count(struct the_nilfs *nilfs)
++{
++ u64 max_count = U64_MAX;
++
++ do_div(max_count, nilfs->ns_blocks_per_segment);
++ return min_t(u64, max_count, ULONG_MAX);
++}
++
+ void nilfs_set_nsegments(struct the_nilfs *nilfs, unsigned long nsegs)
+ {
+ nilfs->ns_nsegments = nsegs;
+@@ -384,6 +396,8 @@ void nilfs_set_nsegments(struct the_nilfs *nilfs, unsigned long nsegs)
+ static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
+ struct nilfs_super_block *sbp)
+ {
++ u64 nsegments, nblocks;
++
+ if (le32_to_cpu(sbp->s_rev_level) < NILFS_MIN_SUPP_REV) {
+ nilfs_msg(nilfs->ns_sb, KERN_ERR,
+ "unsupported revision (superblock rev.=%d.%d, current rev.=%d.%d). Please check the version of mkfs.nilfs(2).",
+@@ -430,7 +444,35 @@ static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
+ return -EINVAL;
+ }
+
+- nilfs_set_nsegments(nilfs, le64_to_cpu(sbp->s_nsegments));
++ nsegments = le64_to_cpu(sbp->s_nsegments);
++ if (nsegments > nilfs_max_segment_count(nilfs)) {
++ nilfs_msg(nilfs->ns_sb, KERN_ERR,
++ "segment count %llu exceeds upper limit (%llu segments)",
++ (unsigned long long)nsegments,
++ (unsigned long long)nilfs_max_segment_count(nilfs));
++ return -EINVAL;
++ }
++
++ nblocks = (u64)i_size_read(nilfs->ns_sb->s_bdev->bd_inode) >>
++ nilfs->ns_sb->s_blocksize_bits;
++ if (nblocks) {
++ u64 min_block_count = nsegments * nilfs->ns_blocks_per_segment;
++ /*
++ * To avoid failing to mount early device images without a
++ * second superblock, exclude that block count from the
++ * "min_block_count" calculation.
++ */
++
++ if (nblocks < min_block_count) {
++ nilfs_msg(nilfs->ns_sb, KERN_ERR,
++ "total number of segment blocks %llu exceeds device size (%llu blocks)",
++ (unsigned long long)min_block_count,
++ (unsigned long long)nblocks);
++ return -EINVAL;
++ }
++ }
++
++ nilfs_set_nsegments(nilfs, nsegments);
+ nilfs->ns_crc_seed = le32_to_cpu(sbp->s_crc_seed);
+ return 0;
+ }
+diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
+index 84f6c8628db5d..d9b906d75dfad 100644
+--- a/fs/xfs/xfs_log_recover.c
++++ b/fs/xfs/xfs_log_recover.c
+@@ -2783,6 +2783,16 @@ xlog_recover_buffer_pass2(
+ if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
+ trace_xfs_log_recover_buf_skip(log, buf_f);
+ xlog_recover_validate_buf_type(mp, bp, buf_f, NULLCOMMITLSN);
++
++ /*
++ * We're skipping replay of this buffer log item due to the log
++ * item LSN being behind the ondisk buffer. Verify the buffer
++ * contents since we aren't going to run the write verifier.
++ */
++ if (bp->b_ops) {
++ bp->b_ops->verify_read(bp);
++ error = bp->b_error;
++ }
+ goto out_release;
+ }
+
+diff --git a/include/linux/list.h b/include/linux/list.h
+index ce19c6b632a59..231ff089f7d1c 100644
+--- a/include/linux/list.h
++++ b/include/linux/list.h
+@@ -268,6 +268,24 @@ static inline int list_empty(const struct list_head *head)
+ return READ_ONCE(head->next) == head;
+ }
+
++/**
++ * list_del_init_careful - deletes entry from list and reinitialize it.
++ * @entry: the element to delete from the list.
++ *
++ * This is the same as list_del_init(), except designed to be used
++ * together with list_empty_careful() in a way to guarantee ordering
++ * of other memory operations.
++ *
++ * Any memory operations done before a list_del_init_careful() are
++ * guaranteed to be visible after a list_empty_careful() test.
++ */
++static inline void list_del_init_careful(struct list_head *entry)
++{
++ __list_del_entry(entry);
++ entry->prev = entry;
++ smp_store_release(&entry->next, entry);
++}
++
+ /**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+@@ -283,7 +301,7 @@ static inline int list_empty(const struct list_head *head)
+ */
+ static inline int list_empty_careful(const struct list_head *head)
+ {
+- struct list_head *next = head->next;
++ struct list_head *next = smp_load_acquire(&head->next);
+ return (next == head) && (next == head->prev);
+ }
+
+diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
+index 09e6ac4b669b2..c75b38ba4a728 100644
+--- a/include/linux/rcupdate.h
++++ b/include/linux/rcupdate.h
+@@ -384,6 +384,24 @@ do { \
+ smp_store_release(&p, RCU_INITIALIZER((typeof(p))_r_a_p__v)); \
+ } while (0)
+
++/**
++ * rcu_replace_pointer() - replace an RCU pointer, returning its old value
++ * @rcu_ptr: RCU pointer, whose old value is returned
++ * @ptr: regular pointer
++ * @c: the lockdep conditions under which the dereference will take place
++ *
++ * Perform a replacement, where @rcu_ptr is an RCU-annotated
++ * pointer and @c is the lockdep argument that is passed to the
++ * rcu_dereference_protected() call used to read that pointer. The old
++ * value of @rcu_ptr is returned, and @rcu_ptr is set to @ptr.
++ */
++#define rcu_replace_pointer(rcu_ptr, ptr, c) \
++({ \
++ typeof(ptr) __tmp = rcu_dereference_protected((rcu_ptr), (c)); \
++ rcu_assign_pointer((rcu_ptr), (ptr)); \
++ __tmp; \
++})
++
+ /**
+ * rcu_swap_protected() - swap an RCU and a regular pointer
+ * @rcu_ptr: RCU pointer
+diff --git a/include/media/dvbdev.h b/include/media/dvbdev.h
+index 73c1df584a146..3745a13f6e08f 100644
+--- a/include/media/dvbdev.h
++++ b/include/media/dvbdev.h
+@@ -189,6 +189,21 @@ struct dvb_device {
+ void *priv;
+ };
+
++/**
++ * struct dvbdevfops_node - fops nodes registered in dvbdevfops_list
++ *
++ * @fops: Dynamically allocated fops for ->owner registration
++ * @type: type of dvb_device
++ * @template: dvb_device used for registration
++ * @list_head: list_head for dvbdevfops_list
++ */
++struct dvbdevfops_node {
++ struct file_operations *fops;
++ enum dvb_device_type type;
++ const struct dvb_device *template;
++ struct list_head list_head;
++};
++
+ /**
+ * dvb_device_get - Increase dvb_device reference
+ *
+diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
+index 6f75a84b47de5..8d063e23aa408 100644
+--- a/include/net/ip_tunnels.h
++++ b/include/net/ip_tunnels.h
+@@ -374,9 +374,11 @@ static inline int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t,
+ static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph,
+ const struct sk_buff *skb)
+ {
+- if (skb->protocol == htons(ETH_P_IP))
++ __be16 payload_protocol = skb_protocol(skb, true);
++
++ if (payload_protocol == htons(ETH_P_IP))
+ return iph->tos;
+- else if (skb->protocol == htons(ETH_P_IPV6))
++ else if (payload_protocol == htons(ETH_P_IPV6))
+ return ipv6_get_dsfield((const struct ipv6hdr *)iph);
+ else
+ return 0;
+@@ -385,9 +387,11 @@ static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph,
+ static inline u8 ip_tunnel_get_ttl(const struct iphdr *iph,
+ const struct sk_buff *skb)
+ {
+- if (skb->protocol == htons(ETH_P_IP))
++ __be16 payload_protocol = skb_protocol(skb, true);
++
++ if (payload_protocol == htons(ETH_P_IP))
+ return iph->ttl;
+- else if (skb->protocol == htons(ETH_P_IPV6))
++ else if (payload_protocol == htons(ETH_P_IPV6))
+ return ((const struct ipv6hdr *)iph)->hop_limit;
+ else
+ return 0;
+diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h
+index 011e8faa608b9..b70c32e4a4918 100644
+--- a/include/trace/events/writeback.h
++++ b/include/trace/events/writeback.h
+@@ -68,7 +68,7 @@ DECLARE_EVENT_CLASS(writeback_page_template,
+ strscpy_pad(__entry->name,
+ bdi_dev_name(mapping ? inode_to_bdi(mapping->host) :
+ NULL), 32);
+- __entry->ino = mapping ? mapping->host->i_ino : 0;
++ __entry->ino = (mapping && mapping->host) ? mapping->host->i_ino : 0;
+ __entry->index = page->index;
+ ),
+
+diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
+index d14575c0e4640..62a7a50750149 100644
+--- a/kernel/cgroup/cgroup.c
++++ b/kernel/cgroup/cgroup.c
+@@ -1723,7 +1723,7 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
+ {
+ struct cgroup *dcgrp = &dst_root->cgrp;
+ struct cgroup_subsys *ss;
+- int ssid, i, ret;
++ int ssid, ret;
+ u16 dfl_disable_ss_mask = 0;
+
+ lockdep_assert_held(&cgroup_mutex);
+@@ -1767,7 +1767,8 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
+ struct cgroup_root *src_root = ss->root;
+ struct cgroup *scgrp = &src_root->cgrp;
+ struct cgroup_subsys_state *css = cgroup_css(scgrp, ss);
+- struct css_set *cset;
++ struct css_set *cset, *cset_pos;
++ struct css_task_iter *it;
+
+ WARN_ON(!css || cgroup_css(dcgrp, ss));
+
+@@ -1785,9 +1786,22 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
+ css->cgroup = dcgrp;
+
+ spin_lock_irq(&css_set_lock);
+- hash_for_each(css_set_table, i, cset, hlist)
++ WARN_ON(!list_empty(&dcgrp->e_csets[ss->id]));
++ list_for_each_entry_safe(cset, cset_pos, &scgrp->e_csets[ss->id],
++ e_cset_node[ss->id]) {
+ list_move_tail(&cset->e_cset_node[ss->id],
+ &dcgrp->e_csets[ss->id]);
++ /*
++ * all css_sets of scgrp together in same order to dcgrp,
++ * patch in-flight iterators to preserve correct iteration.
++ * since the iterator is always advanced right away and
++ * finished when it->cset_pos meets it->cset_head, so only
++ * update it->cset_head is enough here.
++ */
++ list_for_each_entry(it, &cset->task_iters, iters_node)
++ if (it->cset_head == &scgrp->e_csets[ss->id])
++ it->cset_head = &dcgrp->e_csets[ss->id];
++ }
+ spin_unlock_irq(&css_set_lock);
+
+ /* default hierarchy doesn't enable controllers by default */
+diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c
+index 7d668b31dbc6d..c76fe1d4d91e2 100644
+--- a/kernel/sched/wait.c
++++ b/kernel/sched/wait.c
+@@ -384,7 +384,7 @@ int autoremove_wake_function(struct wait_queue_entry *wq_entry, unsigned mode, i
+ int ret = default_wake_function(wq_entry, mode, sync, key);
+
+ if (ret)
+- list_del_init(&wq_entry->entry);
++ list_del_init_careful(&wq_entry->entry);
+
+ return ret;
+ }
+diff --git a/kernel/time/tick-common.c b/kernel/time/tick-common.c
+index 2b7448ae5b478..e883d12dcb0d4 100644
+--- a/kernel/time/tick-common.c
++++ b/kernel/time/tick-common.c
+@@ -216,19 +216,8 @@ static void tick_setup_device(struct tick_device *td,
+ * this cpu:
+ */
+ if (tick_do_timer_cpu == TICK_DO_TIMER_BOOT) {
+- ktime_t next_p;
+- u32 rem;
+-
+ tick_do_timer_cpu = cpu;
+-
+- next_p = ktime_get();
+- div_u64_rem(next_p, TICK_NSEC, &rem);
+- if (rem) {
+- next_p -= rem;
+- next_p += TICK_NSEC;
+- }
+-
+- tick_next_period = next_p;
++ tick_next_period = ktime_get();
+ #ifdef CONFIG_NO_HZ_FULL
+ /*
+ * The boot CPU may be nohz_full, in which case set
+diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
+index a70c611df137c..5093cff932736 100644
+--- a/kernel/time/tick-sched.c
++++ b/kernel/time/tick-sched.c
+@@ -129,8 +129,19 @@ static ktime_t tick_init_jiffy_update(void)
+ raw_spin_lock(&jiffies_lock);
+ write_seqcount_begin(&jiffies_seq);
+ /* Did we start the jiffies update yet ? */
+- if (last_jiffies_update == 0)
++ if (last_jiffies_update == 0) {
++ u32 rem;
++
++ /*
++ * Ensure that the tick is aligned to a multiple of
++ * TICK_NSEC.
++ */
++ div_u64_rem(tick_next_period, TICK_NSEC, &rem);
++ if (rem)
++ tick_next_period += TICK_NSEC - rem;
++
+ last_jiffies_update = tick_next_period;
++ }
+ period = last_jiffies_update;
+ write_seqcount_end(&jiffies_seq);
+ raw_spin_unlock(&jiffies_lock);
+diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
+index d068124815bc3..219cd2c819369 100644
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -1931,10 +1931,12 @@ void tracing_reset_online_cpus(struct trace_buffer *buf)
+ }
+
+ /* Must have trace_types_lock held */
+-void tracing_reset_all_online_cpus(void)
++void tracing_reset_all_online_cpus_unlocked(void)
+ {
+ struct trace_array *tr;
+
++ lockdep_assert_held(&trace_types_lock);
++
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ if (!tr->clear_trace)
+ continue;
+@@ -1946,6 +1948,13 @@ void tracing_reset_all_online_cpus(void)
+ }
+ }
+
++void tracing_reset_all_online_cpus(void)
++{
++ mutex_lock(&trace_types_lock);
++ tracing_reset_all_online_cpus_unlocked();
++ mutex_unlock(&trace_types_lock);
++}
++
+ /*
+ * The tgid_map array maps from pid to tgid; i.e. the value stored at index i
+ * is the tgid last observed corresponding to pid=i.
+diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
+index f2ff39353e037..edc17a640ab34 100644
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -677,6 +677,7 @@ int tracing_is_enabled(void);
+ void tracing_reset_online_cpus(struct trace_buffer *buf);
+ void tracing_reset_current(int cpu);
+ void tracing_reset_all_online_cpus(void);
++void tracing_reset_all_online_cpus_unlocked(void);
+ int tracing_open_generic(struct inode *inode, struct file *filp);
+ int tracing_open_generic_tr(struct inode *inode, struct file *filp);
+ bool tracing_is_disabled(void);
+diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
+index 8f2cbc9ebb6e3..a0675ecc8142e 100644
+--- a/kernel/trace/trace_events.c
++++ b/kernel/trace/trace_events.c
+@@ -2440,7 +2440,7 @@ static void trace_module_remove_events(struct module *mod)
+ * over from this module may be passed to the new module events and
+ * unexpected results may occur.
+ */
+- tracing_reset_all_online_cpus();
++ tracing_reset_all_online_cpus_unlocked();
+ }
+
+ static int trace_module_notify(struct notifier_block *self,
+diff --git a/mm/filemap.c b/mm/filemap.c
+index c094103191a6e..adc27af737c64 100644
+--- a/mm/filemap.c
++++ b/mm/filemap.c
+@@ -1046,6 +1046,7 @@ struct wait_page_queue {
+
+ static int wake_page_function(wait_queue_entry_t *wait, unsigned mode, int sync, void *arg)
+ {
++ int ret;
+ struct wait_page_key *key = arg;
+ struct wait_page_queue *wait_page
+ = container_of(wait, struct wait_page_queue, wait);
+@@ -1058,17 +1059,35 @@ static int wake_page_function(wait_queue_entry_t *wait, unsigned mode, int sync,
+ return 0;
+
+ /*
+- * Stop walking if it's locked.
+- * Is this safe if put_and_wait_on_page_locked() is in use?
+- * Yes: the waker must hold a reference to this page, and if PG_locked
+- * has now already been set by another task, that task must also hold
+- * a reference to the *same usage* of this page; so there is no need
+- * to walk on to wake even the put_and_wait_on_page_locked() callers.
++ * If it's an exclusive wait, we get the bit for it, and
++ * stop walking if we can't.
++ *
++ * If it's a non-exclusive wait, then the fact that this
++ * wake function was called means that the bit already
++ * was cleared, and we don't care if somebody then
++ * re-took it.
+ */
+- if (test_bit(key->bit_nr, &key->page->flags))
+- return -1;
++ ret = 0;
++ if (wait->flags & WQ_FLAG_EXCLUSIVE) {
++ if (test_and_set_bit(key->bit_nr, &key->page->flags))
++ return -1;
++ ret = 1;
++ }
++ wait->flags |= WQ_FLAG_WOKEN;
+
+- return autoremove_wake_function(wait, mode, sync, key);
++ wake_up_state(wait->private, mode);
++
++ /*
++ * Ok, we have successfully done what we're waiting for,
++ * and we can unconditionally remove the wait entry.
++ *
++ * Note that this has to be the absolute last thing we do,
++ * since after list_del_init(&wait->entry) the wait entry
++ * might be de-allocated and the process might even have
++ * exited.
++ */
++ list_del_init_careful(&wait->entry);
++ return ret;
+ }
+
+ static void wake_up_page_bit(struct page *page, int bit_nr)
+@@ -1147,16 +1166,31 @@ enum behavior {
+ */
+ };
+
++/*
++ * Attempt to check (or get) the page bit, and mark the
++ * waiter woken if successful.
++ */
++static inline bool trylock_page_bit_common(struct page *page, int bit_nr,
++ struct wait_queue_entry *wait)
++{
++ if (wait->flags & WQ_FLAG_EXCLUSIVE) {
++ if (test_and_set_bit(bit_nr, &page->flags))
++ return false;
++ } else if (test_bit(bit_nr, &page->flags))
++ return false;
++
++ wait->flags |= WQ_FLAG_WOKEN;
++ return true;
++}
++
+ static inline int wait_on_page_bit_common(wait_queue_head_t *q,
+ struct page *page, int bit_nr, int state, enum behavior behavior)
+ {
+ struct wait_page_queue wait_page;
+ wait_queue_entry_t *wait = &wait_page.wait;
+- bool bit_is_set;
+ bool thrashing = false;
+ bool delayacct = false;
+ unsigned long pflags;
+- int ret = 0;
+
+ if (bit_nr == PG_locked &&
+ !PageUptodate(page) && PageWorkingset(page)) {
+@@ -1174,48 +1208,47 @@ static inline int wait_on_page_bit_common(wait_queue_head_t *q,
+ wait_page.page = page;
+ wait_page.bit_nr = bit_nr;
+
+- for (;;) {
+- spin_lock_irq(&q->lock);
++ /*
++ * Do one last check whether we can get the
++ * page bit synchronously.
++ *
++ * Do the SetPageWaiters() marking before that
++ * to let any waker we _just_ missed know they
++ * need to wake us up (otherwise they'll never
++ * even go to the slow case that looks at the
++ * page queue), and add ourselves to the wait
++ * queue if we need to sleep.
++ *
++ * This part needs to be done under the queue
++ * lock to avoid races.
++ */
++ spin_lock_irq(&q->lock);
++ SetPageWaiters(page);
++ if (!trylock_page_bit_common(page, bit_nr, wait))
++ __add_wait_queue_entry_tail(q, wait);
++ spin_unlock_irq(&q->lock);
+
+- if (likely(list_empty(&wait->entry))) {
+- __add_wait_queue_entry_tail(q, wait);
+- SetPageWaiters(page);
+- }
++ /*
++ * From now on, all the logic will be based on
++ * the WQ_FLAG_WOKEN flag, and the and the page
++ * bit testing (and setting) will be - or has
++ * already been - done by the wake function.
++ *
++ * We can drop our reference to the page.
++ */
++ if (behavior == DROP)
++ put_page(page);
+
++ for (;;) {
+ set_current_state(state);
+
+- spin_unlock_irq(&q->lock);
+-
+- bit_is_set = test_bit(bit_nr, &page->flags);
+- if (behavior == DROP)
+- put_page(page);
+-
+- if (likely(bit_is_set))
+- io_schedule();
+-
+- if (behavior == EXCLUSIVE) {
+- if (!test_and_set_bit_lock(bit_nr, &page->flags))
+- break;
+- } else if (behavior == SHARED) {
+- if (!test_bit(bit_nr, &page->flags))
+- break;
+- }
+-
+- if (signal_pending_state(state, current)) {
+- ret = -EINTR;
++ if (signal_pending_state(state, current))
+ break;
+- }
+
+- if (behavior == DROP) {
+- /*
+- * We can no longer safely access page->flags:
+- * even if CONFIG_MEMORY_HOTREMOVE is not enabled,
+- * there is a risk of waiting forever on a page reused
+- * for something that keeps it locked indefinitely.
+- * But best check for -EINTR above before breaking.
+- */
++ if (wait->flags & WQ_FLAG_WOKEN)
+ break;
+- }
++
++ io_schedule();
+ }
+
+ finish_wait(q, wait);
+@@ -1234,7 +1267,7 @@ static inline int wait_on_page_bit_common(wait_queue_head_t *q,
+ * bother with signals either.
+ */
+
+- return ret;
++ return wait->flags & WQ_FLAG_WOKEN ? 0 : -EINTR;
+ }
+
+ void wait_on_page_bit(struct page *page, int bit_nr)
+@@ -1355,11 +1388,19 @@ void end_page_writeback(struct page *page)
+ rotate_reclaimable_page(page);
+ }
+
++ /*
++ * Writeback does not hold a page reference of its own, relying
++ * on truncation to wait for the clearing of PG_writeback.
++ * But here we must make sure that the page is not freed and
++ * reused before the wake_up_page().
++ */
++ get_page(page);
+ if (!test_clear_page_writeback(page))
+ BUG();
+
+ smp_mb__after_atomic();
+ wake_up_page(page, PG_writeback);
++ put_page(page);
+ }
+ EXPORT_SYMBOL(end_page_writeback);
+
+diff --git a/mm/page-writeback.c b/mm/page-writeback.c
+index 2d658b2083194..5cc892b26339a 100644
+--- a/mm/page-writeback.c
++++ b/mm/page-writeback.c
+@@ -2746,12 +2746,6 @@ int test_clear_page_writeback(struct page *page)
+ } else {
+ ret = TestClearPageWriteback(page);
+ }
+- /*
+- * NOTE: Page might be free now! Writeback doesn't hold a page
+- * reference on its own, it relies on truncation to wait for
+- * the clearing of PG_writeback. The below can only access
+- * page state that is static across allocation cycles.
+- */
+ if (ret) {
+ dec_lruvec_state(lruvec, NR_WRITEBACK);
+ dec_zone_page_state(page, NR_ZONE_WRITE_PENDING);
+@@ -2817,7 +2811,7 @@ EXPORT_SYMBOL(__test_set_page_writeback);
+ */
+ void wait_on_page_writeback(struct page *page)
+ {
+- if (PageWriteback(page)) {
++ while (PageWriteback(page)) {
+ trace_wait_on_page_writeback(page, page_mapping(page));
+ wait_on_page_bit(page, PG_writeback);
+ }
+diff --git a/net/ipv4/esp4_offload.c b/net/ipv4/esp4_offload.c
+index 8c0af30fb0679..5cd219d7e7466 100644
+--- a/net/ipv4/esp4_offload.c
++++ b/net/ipv4/esp4_offload.c
+@@ -283,6 +283,9 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_
+
+ secpath_reset(skb);
+
++ if (skb_needs_linearize(skb, skb->dev->features) &&
++ __skb_linearize(skb))
++ return -ENOMEM;
+ return 0;
+ }
+
+diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c
+index 1c532638b2adf..e19c1844276f8 100644
+--- a/net/ipv6/esp6_offload.c
++++ b/net/ipv6/esp6_offload.c
+@@ -314,6 +314,9 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features
+
+ secpath_reset(skb);
+
++ if (skb_needs_linearize(skb, skb->dev->features) &&
++ __skb_linearize(skb))
++ return -ENOMEM;
+ return 0;
+ }
+
+diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
+index cefc39878b1a4..43ef3e25ea7d9 100644
+--- a/net/netfilter/ipvs/ip_vs_xmit.c
++++ b/net/netfilter/ipvs/ip_vs_xmit.c
+@@ -1231,6 +1231,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
+ skb->transport_header = skb->network_header;
+
+ skb_set_inner_ipproto(skb, next_protocol);
++ skb_set_inner_mac_header(skb, skb_inner_network_offset(skb));
+
+ if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE) {
+ bool check = false;
+@@ -1379,6 +1380,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+ skb->transport_header = skb->network_header;
+
+ skb_set_inner_ipproto(skb, next_protocol);
++ skb_set_inner_mac_header(skb, skb_inner_network_offset(skb));
+
+ if (tun_type == IP_VS_CONN_F_TUNNEL_TYPE_GUE) {
+ bool check = false;
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index 909076ef157e8..914fbd9ecef96 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -4804,7 +4804,8 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
+ if (IS_ERR(set))
+ return PTR_ERR(set);
+
+- if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
++ if (!list_empty(&set->bindings) &&
++ (set->flags & (NFT_SET_CONSTANT | NFT_SET_ANONYMOUS)))
+ return -EBUSY;
+
+ nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
+@@ -4987,7 +4988,9 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
+ set = nft_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET], genmask);
+ if (IS_ERR(set))
+ return PTR_ERR(set);
+- if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
++
++ if (!list_empty(&set->bindings) &&
++ (set->flags & (NFT_SET_CONSTANT | NFT_SET_ANONYMOUS)))
+ return -EBUSY;
+
+ if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) {
+diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c
+index 51e3953b414c0..9dbaa5ce24e51 100644
+--- a/net/netfilter/nfnetlink_osf.c
++++ b/net/netfilter/nfnetlink_osf.c
+@@ -440,3 +440,4 @@ module_init(nfnl_osf_init);
+ module_exit(nfnl_osf_fini);
+
+ MODULE_LICENSE("GPL");
++MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);
+diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c
+index e1990baf3a3b7..dc9485854002a 100644
+--- a/net/netfilter/xt_osf.c
++++ b/net/netfilter/xt_osf.c
+@@ -71,4 +71,3 @@ MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
+ MODULE_DESCRIPTION("Passive OS fingerprint matching.");
+ MODULE_ALIAS("ipt_osf");
+ MODULE_ALIAS("ip6t_osf");
+-MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);
+diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
+index 1802f134aa407..69034c8cc3b86 100644
+--- a/net/sched/sch_netem.c
++++ b/net/sched/sch_netem.c
+@@ -969,6 +969,7 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
+ if (ret < 0)
+ return ret;
+
++ sch_tree_lock(sch);
+ /* backup q->clg and q->loss_model */
+ old_clg = q->clg;
+ old_loss_model = q->loss_model;
+@@ -977,7 +978,7 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
+ ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]);
+ if (ret) {
+ q->loss_model = old_loss_model;
+- return ret;
++ goto unlock;
+ }
+ } else {
+ q->loss_model = CLG_RANDOM;
+@@ -1044,6 +1045,8 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
+ /* capping jitter to the range acceptable by tabledist() */
+ q->jitter = min_t(s64, abs(q->jitter), INT_MAX);
+
++unlock:
++ sch_tree_unlock(sch);
+ return ret;
+
+ get_table_failure:
+@@ -1053,7 +1056,8 @@ get_table_failure:
+ */
+ q->clg = old_clg;
+ q->loss_model = old_loss_model;
+- return ret;
++
++ goto unlock;
+ }
+
+ static int netem_init(struct Qdisc *sch, struct nlattr *opt,
+diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c
+index a95fe3fff1db8..9b22219a76937 100644
+--- a/sound/soc/codecs/nau8824.c
++++ b/sound/soc/codecs/nau8824.c
+@@ -1896,6 +1896,30 @@ static const struct dmi_system_id nau8824_quirk_table[] = {
+ },
+ .driver_data = (void *)(NAU8824_JD_ACTIVE_HIGH),
+ },
++ {
++ /* Positivo CW14Q01P */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"),
++ DMI_MATCH(DMI_BOARD_NAME, "CW14Q01P"),
++ },
++ .driver_data = (void *)(NAU8824_JD_ACTIVE_HIGH),
++ },
++ {
++ /* Positivo K1424G */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"),
++ DMI_MATCH(DMI_BOARD_NAME, "K1424G"),
++ },
++ .driver_data = (void *)(NAU8824_JD_ACTIVE_HIGH),
++ },
++ {
++ /* Positivo N14ZP74G */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"),
++ DMI_MATCH(DMI_BOARD_NAME, "N14ZP74G"),
++ },
++ .driver_data = (void *)(NAU8824_JD_ACTIVE_HIGH),
++ },
+ {}
+ };
+