From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id F19E8138334 for ; Tue, 11 Jun 2019 12:40:37 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id EE4C8E086F; Tue, 11 Jun 2019 12:40:36 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id C1DBAE086F for ; Tue, 11 Jun 2019 12:40:36 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 41452345E5A for ; Tue, 11 Jun 2019 12:40:34 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id ABFA5603 for ; Tue, 11 Jun 2019 12:40:32 +0000 (UTC) From: "Mike Pagano" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Mike Pagano" Message-ID: <1560256812.982b50a3514d5ab2fdcd2e3b711c9ffcf6b14c1c.mpagano@gentoo> Subject: [gentoo-commits] proj/linux-patches:4.14 commit in: / X-VCS-Repository: proj/linux-patches X-VCS-Files: 0000_README 1124_linux-4.14.125.patch X-VCS-Directories: / X-VCS-Committer: mpagano X-VCS-Committer-Name: Mike Pagano X-VCS-Revision: 982b50a3514d5ab2fdcd2e3b711c9ffcf6b14c1c X-VCS-Branch: 4.14 Date: Tue, 11 Jun 2019 12:40:32 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 656b88a5-6aa3-4d15-ae10-67b994b78fdb X-Archives-Hash: df72c7472cd4ccb7e8dd7501b0edf37a commit: 982b50a3514d5ab2fdcd2e3b711c9ffcf6b14c1c Author: Mike Pagano gentoo org> AuthorDate: Tue Jun 11 12:40:12 2019 +0000 Commit: Mike Pagano gentoo org> CommitDate: Tue Jun 11 12:40:12 2019 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=982b50a3 Linux patch 4.14.125 Signed-off-by: Mike Pagano gentoo.org> 0000_README | 4 + 1124_linux-4.14.125.patch | 1878 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1882 insertions(+) diff --git a/0000_README b/0000_README index ccbc586..7f5a97c 100644 --- a/0000_README +++ b/0000_README @@ -539,6 +539,10 @@ Patch: 1123_4.14.124.patch From: http://www.kernel.org Desc: Linux 4.14.124 +Patch: 1124_4.14.125.patch +From: http://www.kernel.org +Desc: Linux 4.14.125 + 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/1124_linux-4.14.125.patch b/1124_linux-4.14.125.patch new file mode 100644 index 0000000..1498ac1 --- /dev/null +++ b/1124_linux-4.14.125.patch @@ -0,0 +1,1878 @@ +diff --git a/Makefile b/Makefile +index 8416103c15a1..9182c0b13988 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 4 + PATCHLEVEL = 14 +-SUBLEVEL = 124 ++SUBLEVEL = 125 + EXTRAVERSION = + NAME = Petit Gorille + +diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c +index c7c31e214813..26a058d58d37 100644 +--- a/arch/mips/ath79/setup.c ++++ b/arch/mips/ath79/setup.c +@@ -183,6 +183,12 @@ const char *get_system_type(void) + return ath79_sys_type; + } + ++int get_c0_perfcount_int(void) ++{ ++ return ATH79_MISC_IRQ(5); ++} ++EXPORT_SYMBOL_GPL(get_c0_perfcount_int); ++ + unsigned int get_c0_compare_int(void) + { + return CP0_LEGACY_COMPARE_IRQ; +diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c +index 33d3251ecd37..91ad023ead8c 100644 +--- a/arch/mips/mm/mmap.c ++++ b/arch/mips/mm/mmap.c +@@ -203,6 +203,11 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) + + int __virt_addr_valid(const volatile void *kaddr) + { ++ unsigned long vaddr = (unsigned long)vaddr; ++ ++ if ((vaddr < PAGE_OFFSET) || (vaddr >= MAP_BASE)) ++ return 0; ++ + return pfn_valid(PFN_DOWN(virt_to_phys(kaddr))); + } + EXPORT_SYMBOL_GPL(__virt_addr_valid); +diff --git a/arch/mips/pistachio/Platform b/arch/mips/pistachio/Platform +index d80cd612df1f..c3592b374ad2 100644 +--- a/arch/mips/pistachio/Platform ++++ b/arch/mips/pistachio/Platform +@@ -6,3 +6,4 @@ cflags-$(CONFIG_MACH_PISTACHIO) += \ + -I$(srctree)/arch/mips/include/asm/mach-pistachio + load-$(CONFIG_MACH_PISTACHIO) += 0xffffffff80400000 + zload-$(CONFIG_MACH_PISTACHIO) += 0xffffffff81000000 ++all-$(CONFIG_MACH_PISTACHIO) := uImage.gz +diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c +index 496d6393bd41..f860ced07f8e 100644 +--- a/arch/powerpc/kernel/nvram_64.c ++++ b/arch/powerpc/kernel/nvram_64.c +@@ -566,8 +566,6 @@ static int nvram_pstore_init(void) + nvram_pstore_info.buf = oops_data; + nvram_pstore_info.bufsize = oops_data_sz; + +- spin_lock_init(&nvram_pstore_info.buf_lock); +- + rc = pstore_register(&nvram_pstore_info); + if (rc && (rc != -EPERM)) + /* Print error only when pstore.backend == nvram */ +diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c +index a7d966964c6f..513ce09e9950 100644 +--- a/arch/x86/power/cpu.c ++++ b/arch/x86/power/cpu.c +@@ -299,7 +299,17 @@ int hibernate_resume_nonboot_cpu_disable(void) + * address in its instruction pointer may not be possible to resolve + * any more at that point (the page tables used by it previously may + * have been overwritten by hibernate image data). ++ * ++ * First, make sure that we wake up all the potentially disabled SMT ++ * threads which have been initially brought up and then put into ++ * mwait/cpuidle sleep. ++ * Those will be put to proper (not interfering with hibernation ++ * resume) sleep afterwards, and the resumed kernel will decide itself ++ * what to do with them. + */ ++ ret = cpuhp_smt_enable(); ++ if (ret) ++ return ret; + smp_ops.play_dead = resume_play_dead; + ret = disable_nonboot_cpus(); + smp_ops.play_dead = play_dead; +diff --git a/arch/x86/power/hibernate_64.c b/arch/x86/power/hibernate_64.c +index 0ef5e5204968..9c80966c80ba 100644 +--- a/arch/x86/power/hibernate_64.c ++++ b/arch/x86/power/hibernate_64.c +@@ -13,6 +13,7 @@ + #include + #include + #include ++#include + + #include + +@@ -347,3 +348,35 @@ int arch_hibernation_header_restore(void *addr) + + return 0; + } ++ ++int arch_resume_nosmt(void) ++{ ++ int ret = 0; ++ /* ++ * We reached this while coming out of hibernation. This means ++ * that SMT siblings are sleeping in hlt, as mwait is not safe ++ * against control transition during resume (see comment in ++ * hibernate_resume_nonboot_cpu_disable()). ++ * ++ * If the resumed kernel has SMT disabled, we have to take all the ++ * SMT siblings out of hlt, and offline them again so that they ++ * end up in mwait proper. ++ * ++ * Called with hotplug disabled. ++ */ ++ cpu_hotplug_enable(); ++ if (cpu_smt_control == CPU_SMT_DISABLED || ++ cpu_smt_control == CPU_SMT_FORCE_DISABLED) { ++ enum cpuhp_smt_control old = cpu_smt_control; ++ ++ ret = cpuhp_smt_enable(); ++ if (ret) ++ goto out; ++ ret = cpuhp_smt_disable(old); ++ if (ret) ++ goto out; ++ } ++out: ++ cpu_hotplug_disable(); ++ return ret; ++} +diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c +index a943cf17faa7..5b149d2d52f4 100644 +--- a/drivers/acpi/apei/erst.c ++++ b/drivers/acpi/apei/erst.c +@@ -1175,7 +1175,6 @@ static int __init erst_init(void) + "Error Record Serialization Table (ERST) support is initialized.\n"); + + buf = kmalloc(erst_erange.size, GFP_KERNEL); +- spin_lock_init(&erst_info.buf_lock); + if (buf) { + erst_info.buf = buf + sizeof(struct cper_pstore_record); + erst_info.bufsize = erst_erange.size - +diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c +index 5a0fa939d70f..4277147f7140 100644 +--- a/drivers/firmware/efi/efi-pstore.c ++++ b/drivers/firmware/efi/efi-pstore.c +@@ -258,8 +258,7 @@ static int efi_pstore_write(struct pstore_record *record) + efi_name[i] = name[i]; + + ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES, +- !pstore_cannot_block_path(record->reason), +- record->size, record->psi->buf); ++ preemptible(), record->size, record->psi->buf); + + if (record->reason == KMSG_DUMP_OOPS) + efivar_run_worker(); +@@ -368,7 +367,6 @@ static __init int efivars_pstore_init(void) + return -ENOMEM; + + efi_pstore_info.bufsize = 1024; +- spin_lock_init(&efi_pstore_info.buf_lock); + + if (pstore_register(&efi_pstore_info)) { + kfree(efi_pstore_info.buf); +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +index 7ad8fa891ce6..3d01582cf6ff 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c +@@ -37,18 +37,10 @@ static void psp_set_funcs(struct amdgpu_device *adev); + static int psp_early_init(void *handle) + { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct psp_context *psp = &adev->psp; + + psp_set_funcs(adev); + +- return 0; +-} +- +-static int psp_sw_init(void *handle) +-{ +- struct amdgpu_device *adev = (struct amdgpu_device *)handle; +- struct psp_context *psp = &adev->psp; +- int ret; +- + switch (adev->asic_type) { + case CHIP_VEGA10: + psp->init_microcode = psp_v3_1_init_microcode; +@@ -79,6 +71,15 @@ static int psp_sw_init(void *handle) + + psp->adev = adev; + ++ return 0; ++} ++ ++static int psp_sw_init(void *handle) ++{ ++ struct amdgpu_device *adev = (struct amdgpu_device *)handle; ++ struct psp_context *psp = &adev->psp; ++ int ret; ++ + ret = psp_init_microcode(psp); + if (ret) { + DRM_ERROR("Failed to load psp firmware!\n"); +diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c +index e64960db3224..e022951894e3 100644 +--- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c ++++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c +@@ -594,6 +594,9 @@ void cdv_intel_lvds_init(struct drm_device *dev, + int pipe; + u8 pin; + ++ if (!dev_priv->lvds_enabled_in_vbt) ++ return; ++ + pin = GMBUS_PORT_PANEL; + if (!lvds_is_present_in_vbt(dev, &pin)) { + DRM_DEBUG_KMS("LVDS is not present in VBT\n"); +diff --git a/drivers/gpu/drm/gma500/intel_bios.c b/drivers/gpu/drm/gma500/intel_bios.c +index 63bde4e86c6a..e019ea271ffc 100644 +--- a/drivers/gpu/drm/gma500/intel_bios.c ++++ b/drivers/gpu/drm/gma500/intel_bios.c +@@ -436,6 +436,9 @@ parse_driver_features(struct drm_psb_private *dev_priv, + if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP) + dev_priv->edp.support = 1; + ++ dev_priv->lvds_enabled_in_vbt = driver->lvds_config != 0; ++ DRM_DEBUG_KMS("LVDS VBT config bits: 0x%x\n", driver->lvds_config); ++ + /* This bit means to use 96Mhz for DPLL_A or not */ + if (driver->primary_lfp_id) + dev_priv->dplla_96mhz = true; +diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h +index 821497dbd3fc..f9814c4ed51b 100644 +--- a/drivers/gpu/drm/gma500/psb_drv.h ++++ b/drivers/gpu/drm/gma500/psb_drv.h +@@ -538,6 +538,7 @@ struct drm_psb_private { + int lvds_ssc_freq; + bool is_lvds_on; + bool is_mipi_on; ++ bool lvds_enabled_in_vbt; + u32 mipi_ctrl_display; + + unsigned int core_freq; +diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c +index 8c8ead2276e0..c9c15e96f5e6 100644 +--- a/drivers/gpu/drm/i915/intel_fbc.c ++++ b/drivers/gpu/drm/i915/intel_fbc.c +@@ -1299,6 +1299,10 @@ static int intel_sanitize_fbc_option(struct drm_i915_private *dev_priv) + if (!HAS_FBC(dev_priv)) + return 0; + ++ /* https://bugs.freedesktop.org/show_bug.cgi?id=108085 */ ++ if (IS_GEMINILAKE(dev_priv)) ++ return 0; ++ + if (IS_BROADWELL(dev_priv) || INTEL_GEN(dev_priv) >= 9) + return 1; + +diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig +index c02a13406a81..a0c0630a0857 100644 +--- a/drivers/gpu/drm/nouveau/Kconfig ++++ b/drivers/gpu/drm/nouveau/Kconfig +@@ -16,10 +16,21 @@ config DRM_NOUVEAU + select INPUT if ACPI && X86 + select THERMAL if ACPI && X86 + select ACPI_VIDEO if ACPI && X86 +- select DRM_VM + help + Choose this option for open-source NVIDIA support. + ++config NOUVEAU_LEGACY_CTX_SUPPORT ++ bool "Nouveau legacy context support" ++ depends on DRM_NOUVEAU ++ select DRM_VM ++ default y ++ help ++ There was a version of the nouveau DDX that relied on legacy ++ ctx ioctls not erroring out. But that was back in time a long ++ ways, so offer a way to disable it now. For uapi compat with ++ old nouveau ddx this should be on by default, but modern distros ++ should consider turning it off. ++ + config NOUVEAU_PLATFORM_DRIVER + bool "Nouveau (NVIDIA) SoC GPUs" + depends on DRM_NOUVEAU && ARCH_TEGRA +diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c +index 7d3c7bb0ebfa..70a8d0b0c4f1 100644 +--- a/drivers/gpu/drm/nouveau/nouveau_drm.c ++++ b/drivers/gpu/drm/nouveau/nouveau_drm.c +@@ -967,8 +967,11 @@ nouveau_driver_fops = { + static struct drm_driver + driver_stub = { + .driver_features = +- DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER | +- DRIVER_KMS_LEGACY_CONTEXT, ++ DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER ++#if defined(CONFIG_NOUVEAU_LEGACY_CTX_SUPPORT) ++ | DRIVER_KMS_LEGACY_CONTEXT ++#endif ++ , + + .load = nouveau_drm_load, + .unload = nouveau_drm_unload, +diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c +index ddfe91efa61e..4f94b78cb464 100644 +--- a/drivers/gpu/drm/radeon/radeon_display.c ++++ b/drivers/gpu/drm/radeon/radeon_display.c +@@ -923,12 +923,12 @@ static void avivo_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div, + ref_div_max = max(min(100 / post_div, ref_div_max), 1u); + + /* get matching reference and feedback divider */ +- *ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max); ++ *ref_div = min(max(den/post_div, 1u), ref_div_max); + *fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den); + + /* limit fb divider to its maximum */ + if (*fb_div > fb_div_max) { +- *ref_div = DIV_ROUND_CLOSEST(*ref_div * fb_div_max, *fb_div); ++ *ref_div = (*ref_div * fb_div_max)/(*fb_div); + *fb_div = fb_div_max; + } + } +diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c +index 732d6c456a6f..5a94f732049e 100644 +--- a/drivers/i2c/busses/i2c-xiic.c ++++ b/drivers/i2c/busses/i2c-xiic.c +@@ -725,11 +725,16 @@ static const struct i2c_algorithm xiic_algorithm = { + .functionality = xiic_func, + }; + ++static const struct i2c_adapter_quirks xiic_quirks = { ++ .max_read_len = 255, ++}; ++ + static const struct i2c_adapter xiic_adapter = { + .owner = THIS_MODULE, + .name = DRIVER_NAME, + .class = I2C_CLASS_DEPRECATED, + .algo = &xiic_algorithm, ++ .quirks = &xiic_quirks, + }; + + +diff --git a/drivers/irqchip/irq-ath79-misc.c b/drivers/irqchip/irq-ath79-misc.c +index 0390603170b4..aa7290784636 100644 +--- a/drivers/irqchip/irq-ath79-misc.c ++++ b/drivers/irqchip/irq-ath79-misc.c +@@ -22,15 +22,6 @@ + #define AR71XX_RESET_REG_MISC_INT_ENABLE 4 + + #define ATH79_MISC_IRQ_COUNT 32 +-#define ATH79_MISC_PERF_IRQ 5 +- +-static int ath79_perfcount_irq; +- +-int get_c0_perfcount_int(void) +-{ +- return ath79_perfcount_irq; +-} +-EXPORT_SYMBOL_GPL(get_c0_perfcount_int); + + static void ath79_misc_irq_handler(struct irq_desc *desc) + { +@@ -122,8 +113,6 @@ static void __init ath79_misc_intc_domain_init( + { + void __iomem *base = domain->host_data; + +- ath79_perfcount_irq = irq_create_mapping(domain, ATH79_MISC_PERF_IRQ); +- + /* Disable and clear all interrupts */ + __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE); + __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS); +diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c +index dbd5eaa69311..92a2998f74db 100644 +--- a/drivers/misc/genwqe/card_dev.c ++++ b/drivers/misc/genwqe/card_dev.c +@@ -782,6 +782,8 @@ static int genwqe_pin_mem(struct genwqe_file *cfile, struct genwqe_mem *m) + + if ((m->addr == 0x0) || (m->size == 0)) + return -EINVAL; ++ if (m->size > ULONG_MAX - PAGE_SIZE - (m->addr & ~PAGE_MASK)) ++ return -EINVAL; + + map_addr = (m->addr & PAGE_MASK); + map_size = round_up(m->size + (m->addr & ~PAGE_MASK), PAGE_SIZE); +diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c +index 2769eb0dfcf5..cb1240985157 100644 +--- a/drivers/misc/genwqe/card_utils.c ++++ b/drivers/misc/genwqe/card_utils.c +@@ -582,6 +582,10 @@ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, void *uaddr, + /* determine space needed for page_list. */ + data = (unsigned long)uaddr; + offs = offset_in_page(data); ++ if (size > ULONG_MAX - PAGE_SIZE - offs) { ++ m->size = 0; /* mark unused and not added */ ++ return -EINVAL; ++ } + m->nr_pages = DIV_ROUND_UP(offs + size, PAGE_SIZE); + + m->page_list = kcalloc(m->nr_pages, +diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +index 5363cee88a0a..d631cd94ee63 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c ++++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +@@ -1982,6 +1982,8 @@ static int mlx4_en_set_tunable(struct net_device *dev, + return ret; + } + ++#define MLX4_EEPROM_PAGE_LEN 256 ++ + static int mlx4_en_get_module_info(struct net_device *dev, + struct ethtool_modinfo *modinfo) + { +@@ -2016,7 +2018,7 @@ static int mlx4_en_get_module_info(struct net_device *dev, + break; + case MLX4_MODULE_ID_SFP: + modinfo->type = ETH_MODULE_SFF_8472; +- modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; ++ modinfo->eeprom_len = MLX4_EEPROM_PAGE_LEN; + break; + default: + return -EINVAL; +diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c +index 3ef3406ff4cb..5922fb318d30 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/port.c ++++ b/drivers/net/ethernet/mellanox/mlx4/port.c +@@ -2077,11 +2077,6 @@ int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, + size -= offset + size - I2C_PAGE_SIZE; + + i2c_addr = I2C_ADDR_LOW; +- if (offset >= I2C_PAGE_SIZE) { +- /* Reset offset to high page */ +- i2c_addr = I2C_ADDR_HIGH; +- offset -= I2C_PAGE_SIZE; +- } + + cable_info = (struct mlx4_cable_info *)inmad->data; + cable_info->dev_mem_address = cpu_to_be16(offset); +diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c +index 5ab725a571a8..2dcb25aa0452 100644 +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -168,6 +168,7 @@ static int sfp__i2c_read(struct i2c_adapter *i2c, u8 bus_addr, u8 dev_addr, + void *buf, size_t len) + { + struct i2c_msg msgs[2]; ++ size_t this_len; + int ret; + + msgs[0].addr = bus_addr; +@@ -179,11 +180,26 @@ static int sfp__i2c_read(struct i2c_adapter *i2c, u8 bus_addr, u8 dev_addr, + msgs[1].len = len; + msgs[1].buf = buf; + +- ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs)); +- if (ret < 0) +- return ret; ++ while (len) { ++ this_len = len; ++ if (this_len > 16) ++ this_len = 16; ++ ++ msgs[1].len = this_len; ++ ++ ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs)); ++ if (ret < 0) ++ return ret; ++ ++ if (ret != ARRAY_SIZE(msgs)) ++ break; ++ ++ msgs[1].buf += this_len; ++ dev_addr += this_len; ++ len -= this_len; ++ } + +- return ret == ARRAY_SIZE(msgs) ? len : 0; ++ return msgs[1].buf - (u8 *)buf; + } + + static int sfp_i2c_read(struct sfp *sfp, bool a2, u8 addr, void *buf, +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 6d39dab497f7..c2d6c501dd85 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -63,6 +63,7 @@ enum qmi_wwan_flags { + + enum qmi_wwan_quirks { + QMI_WWAN_QUIRK_DTR = 1 << 0, /* needs "set DTR" request */ ++ QMI_WWAN_QUIRK_QUECTEL_DYNCFG = 1 << 1, /* check num. endpoints */ + }; + + struct qmimux_hdr { +@@ -845,6 +846,16 @@ static const struct driver_info qmi_wwan_info_quirk_dtr = { + .data = QMI_WWAN_QUIRK_DTR, + }; + ++static const struct driver_info qmi_wwan_info_quirk_quectel_dyncfg = { ++ .description = "WWAN/QMI device", ++ .flags = FLAG_WWAN | FLAG_SEND_ZLP, ++ .bind = qmi_wwan_bind, ++ .unbind = qmi_wwan_unbind, ++ .manage_power = qmi_wwan_manage_power, ++ .rx_fixup = qmi_wwan_rx_fixup, ++ .data = QMI_WWAN_QUIRK_DTR | QMI_WWAN_QUIRK_QUECTEL_DYNCFG, ++}; ++ + #define HUAWEI_VENDOR_ID 0x12D1 + + /* map QMI/wwan function by a fixed interface number */ +@@ -865,6 +876,15 @@ static const struct driver_info qmi_wwan_info_quirk_dtr = { + #define QMI_GOBI_DEVICE(vend, prod) \ + QMI_FIXED_INTF(vend, prod, 0) + ++/* Quectel does not use fixed interface numbers on at least some of their ++ * devices. We need to check the number of endpoints to ensure that we bind to ++ * the correct interface. ++ */ ++#define QMI_QUIRK_QUECTEL_DYNCFG(vend, prod) \ ++ USB_DEVICE_AND_INTERFACE_INFO(vend, prod, USB_CLASS_VENDOR_SPEC, \ ++ USB_SUBCLASS_VENDOR_SPEC, 0xff), \ ++ .driver_info = (unsigned long)&qmi_wwan_info_quirk_quectel_dyncfg ++ + static const struct usb_device_id products[] = { + /* 1. CDC ECM like devices match on the control interface */ + { /* Huawei E392, E398 and possibly others sharing both device id and more... */ +@@ -969,6 +989,9 @@ static const struct usb_device_id products[] = { + USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7), + .driver_info = (unsigned long)&qmi_wwan_info, + }, ++ {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0125)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ ++ {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0306)}, /* Quectel EP06/EG06/EM06 */ ++ {QMI_QUIRK_QUECTEL_DYNCFG(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */ + + /* 3. Combined interface devices matching on interface number */ + {QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */ +@@ -1258,11 +1281,9 @@ static const struct usb_device_id products[] = { + {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)}, /* HP lt4120 Snapdragon X5 LTE */ + {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */ + {QMI_QUIRK_SET_DTR(0x1e0e, 0x9001, 5)}, /* SIMCom 7100E, 7230E, 7600E ++ */ +- {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0 Mini PCIe */ + {QMI_QUIRK_SET_DTR(0x2c7c, 0x0121, 4)}, /* Quectel EC21 Mini PCIe */ + {QMI_QUIRK_SET_DTR(0x2c7c, 0x0191, 4)}, /* Quectel EG91 */ + {QMI_FIXED_INTF(0x2c7c, 0x0296, 4)}, /* Quectel BG96 */ +- {QMI_QUIRK_SET_DTR(0x2c7c, 0x0306, 4)}, /* Quectel EP06 Mini PCIe */ + {QMI_QUIRK_SET_DTR(0x2cb7, 0x0104, 4)}, /* Fibocom NL678 series */ + + /* 4. Gobi 1000 devices */ +@@ -1344,6 +1365,7 @@ static int qmi_wwan_probe(struct usb_interface *intf, + { + struct usb_device_id *id = (struct usb_device_id *)prod; + struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc; ++ const struct driver_info *info; + + /* Workaround to enable dynamic IDs. This disables usbnet + * blacklisting functionality. Which, if required, can be +@@ -1373,6 +1395,19 @@ static int qmi_wwan_probe(struct usb_interface *intf, + return -ENODEV; + } + ++ info = (void *)&id->driver_info; ++ ++ /* Several Quectel modems supports dynamic interface configuration, so ++ * we need to match on class/subclass/protocol. These values are ++ * identical for the diagnostic- and QMI-interface, but bNumEndpoints is ++ * different. Ignore the current interface if the number of endpoints ++ * equals the number for the diag interface (two). ++ */ ++ if (info->data & QMI_WWAN_QUIRK_QUECTEL_DYNCFG) { ++ if (desc->bNumEndpoints == 2) ++ return -ENODEV; ++ } ++ + return usbnet_probe(intf, id); + } + +diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c +index acba1f56af3e..d7649a70a0c4 100644 +--- a/drivers/parisc/ccio-dma.c ++++ b/drivers/parisc/ccio-dma.c +@@ -565,8 +565,6 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, + /* We currently only support kernel addresses */ + BUG_ON(sid != KERNEL_SPACE); + +- mtsp(sid,1); +- + /* + ** WORD 1 - low order word + ** "hints" parm includes the VALID bit! +@@ -597,7 +595,7 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, + ** Grab virtual index [0:11] + ** Deposit virt_idx bits into I/O PDIR word + */ +- asm volatile ("lci %%r0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); ++ asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (vba)); + asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci)); + asm volatile ("depw %1,15,12,%0" : "+r" (pa) : "r" (ci)); + +diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c +index 0a9c762a70fa..5468490d2298 100644 +--- a/drivers/parisc/sba_iommu.c ++++ b/drivers/parisc/sba_iommu.c +@@ -575,8 +575,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, + pa = virt_to_phys(vba); + pa &= IOVP_MASK; + +- mtsp(sid,1); +- asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); ++ asm("lci 0(%1), %0" : "=r" (ci) : "r" (vba)); + pa |= (ci >> PAGE_SHIFT) & 0xff; /* move CI (8 bits) into lowest byte */ + + pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */ +diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c +index 51a58c367953..c39246b916af 100644 +--- a/drivers/tty/serial/serial_core.c ++++ b/drivers/tty/serial/serial_core.c +@@ -143,9 +143,6 @@ static void uart_start(struct tty_struct *tty) + struct uart_port *port; + unsigned long flags; + +- if (!state) +- return; +- + port = uart_port_lock(state, flags); + __uart_start(tty); + uart_port_unlock(port, flags); +@@ -1731,11 +1728,8 @@ static void uart_dtr_rts(struct tty_port *port, int raise) + */ + static int uart_open(struct tty_struct *tty, struct file *filp) + { +- struct uart_driver *drv = tty->driver->driver_state; +- int retval, line = tty->index; +- struct uart_state *state = drv->state + line; +- +- tty->driver_data = state; ++ struct uart_state *state = tty->driver_data; ++ int retval; + + retval = tty_port_open(&state->port, tty, filp); + if (retval > 0) +@@ -2418,9 +2412,6 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) + struct uart_state *state = drv->state + line; + struct uart_port *port; + +- if (!state) +- return; +- + port = uart_port_ref(state); + if (!port) + return; +@@ -2432,7 +2423,18 @@ static void uart_poll_put_char(struct tty_driver *driver, int line, char ch) + } + #endif + ++static int uart_install(struct tty_driver *driver, struct tty_struct *tty) ++{ ++ struct uart_driver *drv = driver->driver_state; ++ struct uart_state *state = drv->state + tty->index; ++ ++ tty->driver_data = state; ++ ++ return tty_standard_install(driver, tty); ++} ++ + static const struct tty_operations uart_ops = { ++ .install = uart_install, + .open = uart_open, + .close = uart_close, + .write = uart_write, +diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c +index 83243af22d51..53877e078a7b 100644 +--- a/drivers/xen/xenbus/xenbus_dev_frontend.c ++++ b/drivers/xen/xenbus/xenbus_dev_frontend.c +@@ -614,9 +614,7 @@ static int xenbus_file_open(struct inode *inode, struct file *filp) + if (xen_store_evtchn == 0) + return -ENOENT; + +- nonseekable_open(inode, filp); +- +- filp->f_mode &= ~FMODE_ATOMIC_POS; /* cdev-style semantics */ ++ stream_open(inode, filp); + + u = kzalloc(sizeof(*u), GFP_KERNEL); + if (u == NULL) +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 7882fc34113c..e340449ca862 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -178,7 +178,9 @@ void fuse_finish_open(struct inode *inode, struct file *file) + file->f_op = &fuse_direct_io_file_operations; + if (!(ff->open_flags & FOPEN_KEEP_CACHE)) + invalidate_inode_pages2(inode->i_mapping); +- if (ff->open_flags & FOPEN_NONSEEKABLE) ++ if (ff->open_flags & FOPEN_STREAM) ++ stream_open(inode, file); ++ else if (ff->open_flags & FOPEN_NONSEEKABLE) + nonseekable_open(inode, file); + if (fc->atomic_o_trunc && (file->f_flags & O_TRUNC)) { + struct fuse_inode *fi = get_fuse_inode(inode); +@@ -2978,7 +2980,7 @@ static long fuse_file_fallocate(struct file *file, int mode, loff_t offset, + offset + length > i_size_read(inode)) { + err = inode_newsize_ok(inode, offset + length); + if (err) +- return err; ++ goto out; + } + + if (!(mode & FALLOC_FL_KEEP_SIZE)) +diff --git a/fs/open.c b/fs/open.c +index 28a3956c4479..f4ea0dc88823 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -1212,3 +1212,21 @@ int nonseekable_open(struct inode *inode, struct file *filp) + } + + EXPORT_SYMBOL(nonseekable_open); ++ ++/* ++ * stream_open is used by subsystems that want stream-like file descriptors. ++ * Such file descriptors are not seekable and don't have notion of position ++ * (file.f_pos is always 0). Contrary to file descriptors of other regular ++ * files, .read() and .write() can run simultaneously. ++ * ++ * stream_open never fails and is marked to return int so that it could be ++ * directly used as file_operations.open . ++ */ ++int stream_open(struct inode *inode, struct file *filp) ++{ ++ filp->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE | FMODE_ATOMIC_POS); ++ filp->f_mode |= FMODE_STREAM; ++ return 0; ++} ++ ++EXPORT_SYMBOL(stream_open); +diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c +index 2b21d180157c..8af9efa0ca0a 100644 +--- a/fs/pstore/platform.c ++++ b/fs/pstore/platform.c +@@ -129,26 +129,27 @@ static const char *get_reason_str(enum kmsg_dump_reason reason) + } + } + +-bool pstore_cannot_block_path(enum kmsg_dump_reason reason) ++/* ++ * Should pstore_dump() wait for a concurrent pstore_dump()? If ++ * not, the current pstore_dump() will report a failure to dump ++ * and return. ++ */ ++static bool pstore_cannot_wait(enum kmsg_dump_reason reason) + { +- /* +- * In case of NMI path, pstore shouldn't be blocked +- * regardless of reason. +- */ ++ /* In NMI path, pstore shouldn't block regardless of reason. */ + if (in_nmi()) + return true; + + switch (reason) { + /* In panic case, other cpus are stopped by smp_send_stop(). */ + case KMSG_DUMP_PANIC: +- /* Emergency restart shouldn't be blocked by spin lock. */ ++ /* Emergency restart shouldn't be blocked. */ + case KMSG_DUMP_EMERG: + return true; + default: + return false; + } + } +-EXPORT_SYMBOL_GPL(pstore_cannot_block_path); + + #ifdef CONFIG_PSTORE_ZLIB_COMPRESS + /* Derived from logfs_compress() */ +@@ -499,23 +500,23 @@ static void pstore_dump(struct kmsg_dumper *dumper, + unsigned long total = 0; + const char *why; + unsigned int part = 1; +- unsigned long flags = 0; +- int is_locked; + int ret; + + why = get_reason_str(reason); + +- if (pstore_cannot_block_path(reason)) { +- is_locked = spin_trylock_irqsave(&psinfo->buf_lock, flags); +- if (!is_locked) { +- pr_err("pstore dump routine blocked in %s path, may corrupt error record\n" +- , in_nmi() ? "NMI" : why); ++ if (down_trylock(&psinfo->buf_lock)) { ++ /* Failed to acquire lock: give up if we cannot wait. */ ++ if (pstore_cannot_wait(reason)) { ++ pr_err("dump skipped in %s path: may corrupt error record\n", ++ in_nmi() ? "NMI" : why); ++ return; ++ } ++ if (down_interruptible(&psinfo->buf_lock)) { ++ pr_err("could not grab semaphore?!\n"); + return; + } +- } else { +- spin_lock_irqsave(&psinfo->buf_lock, flags); +- is_locked = 1; + } ++ + oopscount++; + while (total < kmsg_bytes) { + char *dst; +@@ -532,7 +533,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, + record.part = part; + record.buf = psinfo->buf; + +- if (big_oops_buf && is_locked) { ++ if (big_oops_buf) { + dst = big_oops_buf; + dst_size = big_oops_buf_sz; + } else { +@@ -550,7 +551,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, + dst_size, &dump_size)) + break; + +- if (big_oops_buf && is_locked) { ++ if (big_oops_buf) { + zipped_len = pstore_compress(dst, psinfo->buf, + header_size + dump_size, + psinfo->bufsize); +@@ -573,8 +574,8 @@ static void pstore_dump(struct kmsg_dumper *dumper, + total += record.size; + part++; + } +- if (is_locked) +- spin_unlock_irqrestore(&psinfo->buf_lock, flags); ++ ++ up(&psinfo->buf_lock); + } + + static struct kmsg_dumper pstore_dumper = { +@@ -597,31 +598,14 @@ static void pstore_unregister_kmsg(void) + #ifdef CONFIG_PSTORE_CONSOLE + static void pstore_console_write(struct console *con, const char *s, unsigned c) + { +- const char *e = s + c; ++ struct pstore_record record; + +- while (s < e) { +- struct pstore_record record; +- unsigned long flags; +- +- pstore_record_init(&record, psinfo); +- record.type = PSTORE_TYPE_CONSOLE; +- +- if (c > psinfo->bufsize) +- c = psinfo->bufsize; ++ pstore_record_init(&record, psinfo); ++ record.type = PSTORE_TYPE_CONSOLE; + +- if (oops_in_progress) { +- if (!spin_trylock_irqsave(&psinfo->buf_lock, flags)) +- break; +- } else { +- spin_lock_irqsave(&psinfo->buf_lock, flags); +- } +- record.buf = (char *)s; +- record.size = c; +- psinfo->write(&record); +- spin_unlock_irqrestore(&psinfo->buf_lock, flags); +- s += c; +- c = e - s; +- } ++ record.buf = (char *)s; ++ record.size = c; ++ psinfo->write(&record); + } + + static struct console pstore_console = { +@@ -710,6 +694,7 @@ int pstore_register(struct pstore_info *psi) + psi->write_user = pstore_write_user_compat; + psinfo = psi; + mutex_init(&psinfo->read_mutex); ++ sema_init(&psinfo->buf_lock, 1); + spin_unlock(&pstore_lock); + + if (owner && !try_module_get(owner)) { +@@ -717,7 +702,8 @@ int pstore_register(struct pstore_info *psi) + return -EINVAL; + } + +- allocate_buf_for_compression(); ++ if (psi->flags & PSTORE_FLAGS_DMESG) ++ allocate_buf_for_compression(); + + if (pstore_is_mounted()) + pstore_get_records(0); +diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c +index f371e03cf3bf..40bfc6c58374 100644 +--- a/fs/pstore/ram.c ++++ b/fs/pstore/ram.c +@@ -801,27 +801,36 @@ static int ramoops_probe(struct platform_device *pdev) + + cxt->pstore.data = cxt; + /* +- * Since bufsize is only used for dmesg crash dumps, it +- * must match the size of the dprz record (after PRZ header +- * and ECC bytes have been accounted for). ++ * Prepare frontend flags based on which areas are initialized. ++ * For ramoops_init_przs() cases, the "max count" variable tells ++ * if there are regions present. For ramoops_init_prz() cases, ++ * the single region size is how to check. + */ +- cxt->pstore.bufsize = cxt->dprzs[0]->buffer_size; +- cxt->pstore.buf = kzalloc(cxt->pstore.bufsize, GFP_KERNEL); +- if (!cxt->pstore.buf) { +- pr_err("cannot allocate pstore crash dump buffer\n"); +- err = -ENOMEM; +- goto fail_clear; +- } +- spin_lock_init(&cxt->pstore.buf_lock); +- +- cxt->pstore.flags = PSTORE_FLAGS_DMESG; ++ cxt->pstore.flags = 0; ++ if (cxt->max_dump_cnt) ++ cxt->pstore.flags |= PSTORE_FLAGS_DMESG; + if (cxt->console_size) + cxt->pstore.flags |= PSTORE_FLAGS_CONSOLE; +- if (cxt->ftrace_size) ++ if (cxt->max_ftrace_cnt) + cxt->pstore.flags |= PSTORE_FLAGS_FTRACE; + if (cxt->pmsg_size) + cxt->pstore.flags |= PSTORE_FLAGS_PMSG; + ++ /* ++ * Since bufsize is only used for dmesg crash dumps, it ++ * must match the size of the dprz record (after PRZ header ++ * and ECC bytes have been accounted for). ++ */ ++ if (cxt->pstore.flags & PSTORE_FLAGS_DMESG) { ++ cxt->pstore.bufsize = cxt->dprzs[0]->buffer_size; ++ cxt->pstore.buf = kzalloc(cxt->pstore.bufsize, GFP_KERNEL); ++ if (!cxt->pstore.buf) { ++ pr_err("cannot allocate pstore crash dump buffer\n"); ++ err = -ENOMEM; ++ goto fail_clear; ++ } ++ } ++ + err = pstore_register(&cxt->pstore); + if (err) { + pr_err("registering with pstore failed\n"); +diff --git a/fs/read_write.c b/fs/read_write.c +index 1c3eada2fe25..d6f8bfb0f794 100644 +--- a/fs/read_write.c ++++ b/fs/read_write.c +@@ -555,12 +555,13 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ + + static inline loff_t file_pos_read(struct file *file) + { +- return file->f_pos; ++ return file->f_mode & FMODE_STREAM ? 0 : file->f_pos; + } + + static inline void file_pos_write(struct file *file, loff_t pos) + { +- file->f_pos = pos; ++ if ((file->f_mode & FMODE_STREAM) == 0) ++ file->f_pos = pos; + } + + SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) +diff --git a/include/linux/cpu.h b/include/linux/cpu.h +index 9573b5b0fc6f..efc48efb0ec6 100644 +--- a/include/linux/cpu.h ++++ b/include/linux/cpu.h +@@ -191,10 +191,14 @@ enum cpuhp_smt_control { + extern enum cpuhp_smt_control cpu_smt_control; + extern void cpu_smt_disable(bool force); + extern void cpu_smt_check_topology(void); ++extern int cpuhp_smt_enable(void); ++extern int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval); + #else + # define cpu_smt_control (CPU_SMT_ENABLED) + static inline void cpu_smt_disable(bool force) { } + static inline void cpu_smt_check_topology(void) { } ++static inline int cpuhp_smt_enable(void) { return 0; } ++static inline int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) { return 0; } + #endif + + /* +diff --git a/include/linux/fs.h b/include/linux/fs.h +index dafac283b0ff..da56c796c5d8 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -148,6 +148,9 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, + /* Has write method(s) */ + #define FMODE_CAN_WRITE ((__force fmode_t)0x40000) + ++/* File is stream-like */ ++#define FMODE_STREAM ((__force fmode_t)0x200000) ++ + /* File was opened by fanotify and shouldn't generate fanotify events */ + #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) + +@@ -2945,6 +2948,7 @@ extern loff_t no_seek_end_llseek_size(struct file *, loff_t, int, loff_t); + extern loff_t no_seek_end_llseek(struct file *, loff_t, int); + extern int generic_file_open(struct inode * inode, struct file * filp); + extern int nonseekable_open(struct inode * inode, struct file * filp); ++extern int stream_open(struct inode * inode, struct file * filp); + + #ifdef CONFIG_BLOCK + typedef void (dio_submit_t)(struct bio *bio, struct inode *inode, +diff --git a/include/linux/pstore.h b/include/linux/pstore.h +index 170bb981d2fd..70913ec87785 100644 +--- a/include/linux/pstore.h ++++ b/include/linux/pstore.h +@@ -26,7 +26,7 @@ + #include + #include + #include +-#include ++#include + #include + #include + +@@ -88,7 +88,7 @@ struct pstore_record { + * @owner: module which is repsonsible for this backend driver + * @name: name of the backend driver + * +- * @buf_lock: spinlock to serialize access to @buf ++ * @buf_lock: semaphore to serialize access to @buf + * @buf: preallocated crash dump buffer + * @bufsize: size of @buf available for crash dump bytes (must match + * smallest number of bytes available for writing to a +@@ -173,7 +173,7 @@ struct pstore_info { + struct module *owner; + char *name; + +- spinlock_t buf_lock; ++ struct semaphore buf_lock; + char *buf; + size_t bufsize; + +@@ -199,7 +199,6 @@ struct pstore_info { + + extern int pstore_register(struct pstore_info *); + extern void pstore_unregister(struct pstore_info *); +-extern bool pstore_cannot_block_path(enum kmsg_dump_reason reason); + + struct pstore_ftrace_record { + unsigned long ip; +diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h +index a6ddc42f87a5..f960c85cd9ec 100644 +--- a/include/linux/rcupdate.h ++++ b/include/linux/rcupdate.h +@@ -79,14 +79,12 @@ void synchronize_rcu(void); + + static inline void __rcu_read_lock(void) + { +- if (IS_ENABLED(CONFIG_PREEMPT_COUNT)) +- preempt_disable(); ++ preempt_disable(); + } + + static inline void __rcu_read_unlock(void) + { +- if (IS_ENABLED(CONFIG_PREEMPT_COUNT)) +- preempt_enable(); ++ preempt_enable(); + } + + static inline void synchronize_rcu(void) +diff --git a/include/net/arp.h b/include/net/arp.h +index 977aabfcdc03..c8f580a0e6b1 100644 +--- a/include/net/arp.h ++++ b/include/net/arp.h +@@ -18,6 +18,7 @@ static inline u32 arp_hashfn(const void *pkey, const struct net_device *dev, u32 + return val * hash_rnd[0]; + } + ++#ifdef CONFIG_INET + static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key) + { + if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) +@@ -25,6 +26,13 @@ static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev + + return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev); + } ++#else ++static inline ++struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key) ++{ ++ return NULL; ++} ++#endif + + static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key) + { +diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h +index d060d711a624..b418f4a04b56 100644 +--- a/include/net/ip6_fib.h ++++ b/include/net/ip6_fib.h +@@ -199,8 +199,7 @@ static inline u32 rt6_get_cookie(const struct rt6_info *rt) + { + u32 cookie = 0; + +- if (rt->rt6i_flags & RTF_PCPU || +- (unlikely(!list_empty(&rt->rt6i_uncached)) && rt->dst.from)) ++ if (rt->dst.from) + rt = (struct rt6_info *)(rt->dst.from); + + rt6_get_cookie_safe(rt, &cookie); +diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h +index 9816590d3ad2..adb0c89d0d91 100644 +--- a/include/uapi/drm/i915_drm.h ++++ b/include/uapi/drm/i915_drm.h +@@ -853,7 +853,7 @@ struct drm_i915_gem_execbuffer2 { + * struct drm_i915_gem_exec_fence *fences. + */ + __u64 cliprects_ptr; +-#define I915_EXEC_RING_MASK (7<<0) ++#define I915_EXEC_RING_MASK (0x3f) + #define I915_EXEC_DEFAULT (0<<0) + #define I915_EXEC_RENDER (1<<0) + #define I915_EXEC_BSD (2<<0) +diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h +index 4b5001c57f46..daac48210b2c 100644 +--- a/include/uapi/linux/fuse.h ++++ b/include/uapi/linux/fuse.h +@@ -216,10 +216,12 @@ struct fuse_file_lock { + * FOPEN_DIRECT_IO: bypass page cache for this open file + * FOPEN_KEEP_CACHE: don't invalidate the data cache on open + * FOPEN_NONSEEKABLE: the file is not seekable ++ * FOPEN_STREAM: the file is stream-like (no file position at all) + */ + #define FOPEN_DIRECT_IO (1 << 0) + #define FOPEN_KEEP_CACHE (1 << 1) + #define FOPEN_NONSEEKABLE (1 << 2) ++#define FOPEN_STREAM (1 << 4) + + /** + * INIT request/reply flags +diff --git a/kernel/cpu.c b/kernel/cpu.c +index 6503ca8d59a7..127a69b8b192 100644 +--- a/kernel/cpu.c ++++ b/kernel/cpu.c +@@ -2054,7 +2054,7 @@ static void cpuhp_online_cpu_device(unsigned int cpu) + kobject_uevent(&dev->kobj, KOBJ_ONLINE); + } + +-static int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) ++int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) + { + int cpu, ret = 0; + +@@ -2088,7 +2088,7 @@ static int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) + return ret; + } + +-static int cpuhp_smt_enable(void) ++int cpuhp_smt_enable(void) + { + int cpu, ret = 0; + +diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c +index a5c36e9c56a6..2d6d14ad7b4f 100644 +--- a/kernel/power/hibernate.c ++++ b/kernel/power/hibernate.c +@@ -258,6 +258,11 @@ void swsusp_show_speed(ktime_t start, ktime_t stop, + (kps % 1000) / 10); + } + ++__weak int arch_resume_nosmt(void) ++{ ++ return 0; ++} ++ + /** + * create_image - Create a hibernation image. + * @platform_mode: Whether or not to use the platform driver. +@@ -322,6 +327,10 @@ static int create_image(int platform_mode) + Enable_cpus: + enable_nonboot_cpus(); + ++ /* Allow architectures to do nosmt-specific post-resume dances */ ++ if (!in_suspend) ++ error = arch_resume_nosmt(); ++ + Platform_finish: + platform_finish(platform_mode); + +diff --git a/lib/test_firmware.c b/lib/test_firmware.c +index 71d371f97138..f978aebe60c5 100644 +--- a/lib/test_firmware.c ++++ b/lib/test_firmware.c +@@ -222,30 +222,30 @@ static ssize_t config_show(struct device *dev, + + mutex_lock(&test_fw_mutex); + +- len += snprintf(buf, PAGE_SIZE, ++ len += scnprintf(buf, PAGE_SIZE - len, + "Custom trigger configuration for: %s\n", + dev_name(dev)); + + if (test_fw_config->name) +- len += snprintf(buf+len, PAGE_SIZE, ++ len += scnprintf(buf+len, PAGE_SIZE - len, + "name:\t%s\n", + test_fw_config->name); + else +- len += snprintf(buf+len, PAGE_SIZE, ++ len += scnprintf(buf+len, PAGE_SIZE - len, + "name:\tEMTPY\n"); + +- len += snprintf(buf+len, PAGE_SIZE, ++ len += scnprintf(buf+len, PAGE_SIZE - len, + "num_requests:\t%u\n", test_fw_config->num_requests); + +- len += snprintf(buf+len, PAGE_SIZE, ++ len += scnprintf(buf+len, PAGE_SIZE - len, + "send_uevent:\t\t%s\n", + test_fw_config->send_uevent ? + "FW_ACTION_HOTPLUG" : + "FW_ACTION_NOHOTPLUG"); +- len += snprintf(buf+len, PAGE_SIZE, ++ len += scnprintf(buf+len, PAGE_SIZE - len, + "sync_direct:\t\t%s\n", + test_fw_config->sync_direct ? "true" : "false"); +- len += snprintf(buf+len, PAGE_SIZE, ++ len += scnprintf(buf+len, PAGE_SIZE - len, + "read_fw_idx:\t%u\n", test_fw_config->read_fw_idx); + + mutex_unlock(&test_fw_mutex); +diff --git a/net/core/ethtool.c b/net/core/ethtool.c +index 145cb343c1b0..97569d3e1937 100644 +--- a/net/core/ethtool.c ++++ b/net/core/ethtool.c +@@ -890,8 +890,13 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev, + if (rc >= 0) + info.n_priv_flags = rc; + } +- if (ops->get_regs_len) +- info.regdump_len = ops->get_regs_len(dev); ++ if (ops->get_regs_len) { ++ int ret = ops->get_regs_len(dev); ++ ++ if (ret > 0) ++ info.regdump_len = ret; ++ } ++ + if (ops->get_eeprom_len) + info.eedump_len = ops->get_eeprom_len(dev); + +@@ -1392,6 +1397,9 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) + return -EFAULT; + + reglen = ops->get_regs_len(dev); ++ if (reglen <= 0) ++ return reglen; ++ + if (regs.len > reglen) + regs.len = reglen; + +@@ -1402,13 +1410,16 @@ static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) + return -ENOMEM; + } + ++ if (regs.len < reglen) ++ reglen = regs.len; ++ + ops->get_regs(dev, ®s, regbuf); + + ret = -EFAULT; + if (copy_to_user(useraddr, ®s, sizeof(regs))) + goto out; + useraddr += offsetof(struct ethtool_regs, data); +- if (regbuf && copy_to_user(useraddr, regbuf, regs.len)) ++ if (copy_to_user(useraddr, regbuf, reglen)) + goto out; + ret = 0; + +diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c +index b08c69730a72..9a6d97c1d810 100644 +--- a/net/core/fib_rules.c ++++ b/net/core/fib_rules.c +@@ -563,10 +563,9 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh, + rule->uid_range = fib_kuid_range_unset; + } + +- if (rule_exists(ops, frh, tb, rule)) { +- err = 0; +- if (nlh->nlmsg_flags & NLM_F_EXCL) +- err = -EEXIST; ++ if ((nlh->nlmsg_flags & NLM_F_EXCL) && ++ rule_exists(ops, frh, tb, rule)) { ++ err = -EEXIST; + goto errout_free; + } + +diff --git a/net/core/neighbour.c b/net/core/neighbour.c +index dcb89cbc2730..dd83a81db55f 100644 +--- a/net/core/neighbour.c ++++ b/net/core/neighbour.c +@@ -30,6 +30,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2528,7 +2529,13 @@ int neigh_xmit(int index, struct net_device *dev, + if (!tbl) + goto out; + rcu_read_lock_bh(); +- neigh = __neigh_lookup_noref(tbl, addr, dev); ++ if (index == NEIGH_ARP_TABLE) { ++ u32 key = *((u32 *)addr); ++ ++ neigh = __ipv4_neigh_lookup_noref(dev, key); ++ } else { ++ neigh = __neigh_lookup_noref(tbl, addr, dev); ++ } + if (!neigh) + neigh = __neigh_create(tbl, addr, dev, false); + err = PTR_ERR(neigh); +diff --git a/net/core/pktgen.c b/net/core/pktgen.c +index 6e1e10ff433a..884afb8e9fc4 100644 +--- a/net/core/pktgen.c ++++ b/net/core/pktgen.c +@@ -3149,7 +3149,13 @@ static int pktgen_wait_thread_run(struct pktgen_thread *t) + { + while (thread_is_running(t)) { + ++ /* note: 't' will still be around even after the unlock/lock ++ * cycle because pktgen_thread threads are only cleared at ++ * net exit ++ */ ++ mutex_unlock(&pktgen_thread_lock); + msleep_interruptible(100); ++ mutex_lock(&pktgen_thread_lock); + + if (signal_pending(current)) + goto signal; +@@ -3164,6 +3170,10 @@ static int pktgen_wait_all_threads_run(struct pktgen_net *pn) + struct pktgen_thread *t; + int sig = 1; + ++ /* prevent from racing with rmmod */ ++ if (!try_module_get(THIS_MODULE)) ++ return sig; ++ + mutex_lock(&pktgen_thread_lock); + + list_for_each_entry(t, &pn->pktgen_threads, th_list) { +@@ -3177,6 +3187,7 @@ static int pktgen_wait_all_threads_run(struct pktgen_net *pn) + t->control |= (T_STOP); + + mutex_unlock(&pktgen_thread_lock); ++ module_put(THIS_MODULE); + return sig; + } + +diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c +index 8f409031d245..ac428311965f 100644 +--- a/net/ipv6/raw.c ++++ b/net/ipv6/raw.c +@@ -782,6 +782,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + struct sockcm_cookie sockc; + struct ipcm6_cookie ipc6; + int addr_len = msg->msg_namelen; ++ int hdrincl; + u16 proto; + int err; + +@@ -795,6 +796,13 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + ++ /* hdrincl should be READ_ONCE(inet->hdrincl) ++ * but READ_ONCE() doesn't work with bit fields. ++ * Doing this indirectly yields the same result. ++ */ ++ hdrincl = inet->hdrincl; ++ hdrincl = READ_ONCE(hdrincl); ++ + /* + * Get and verify the address. + */ +@@ -889,11 +897,14 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + opt = ipv6_fixup_options(&opt_space, opt); + + fl6.flowi6_proto = proto; +- rfv.msg = msg; +- rfv.hlen = 0; +- err = rawv6_probe_proto_opt(&rfv, &fl6); +- if (err) +- goto out; ++ ++ if (!hdrincl) { ++ rfv.msg = msg; ++ rfv.hlen = 0; ++ err = rawv6_probe_proto_opt(&rfv, &fl6); ++ if (err) ++ goto out; ++ } + + if (!ipv6_addr_any(daddr)) + fl6.daddr = *daddr; +@@ -910,7 +921,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + fl6.flowi6_oif = np->ucast_oif; + security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); + +- if (inet->hdrincl) ++ if (hdrincl) + fl6.flowi6_flags |= FLOWI_FLAG_KNOWN_NH; + + if (ipc6.tclass < 0) +@@ -933,7 +944,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) + goto do_confirm; + + back_from_confirm: +- if (inet->hdrincl) ++ if (hdrincl) + err = rawv6_send_hdrinc(sk, msg, len, &fl6, &dst, msg->msg_flags); + else { + ipc6.opt = opt; +diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c +index fe5d2e8a95d9..2c78266ea205 100644 +--- a/net/rds/ib_rdma.c ++++ b/net/rds/ib_rdma.c +@@ -416,12 +416,14 @@ int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, + wait_clean_list_grace(); + + list_to_llist_nodes(pool, &unmap_list, &clean_nodes, &clean_tail); +- if (ibmr_ret) ++ if (ibmr_ret) { + *ibmr_ret = llist_entry(clean_nodes, struct rds_ib_mr, llnode); +- ++ clean_nodes = clean_nodes->next; ++ } + /* more than one entry in llist nodes */ +- if (clean_nodes->next) +- llist_add_batch(clean_nodes->next, clean_tail, &pool->clean_list); ++ if (clean_nodes) ++ llist_add_batch(clean_nodes, clean_tail, ++ &pool->clean_list); + + } + +diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c +index e4a400f88168..4edb4f5596b8 100644 +--- a/net/sctp/sm_make_chunk.c ++++ b/net/sctp/sm_make_chunk.c +@@ -2318,7 +2318,6 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk, + union sctp_addr addr; + struct sctp_af *af; + int src_match = 0; +- char *cookie; + + /* We must include the address that the INIT packet came from. + * This is the only address that matters for an INIT packet. +@@ -2422,14 +2421,6 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk, + /* Peer Rwnd : Current calculated value of the peer's rwnd. */ + asoc->peer.rwnd = asoc->peer.i.a_rwnd; + +- /* Copy cookie in case we need to resend COOKIE-ECHO. */ +- cookie = asoc->peer.cookie; +- if (cookie) { +- asoc->peer.cookie = kmemdup(cookie, asoc->peer.cookie_len, gfp); +- if (!asoc->peer.cookie) +- goto clean_up; +- } +- + /* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily + * high (for example, implementations MAY use the size of the receiver + * advertised window). +@@ -2595,7 +2586,9 @@ do_addr_param: + case SCTP_PARAM_STATE_COOKIE: + asoc->peer.cookie_len = + ntohs(param.p->length) - sizeof(struct sctp_paramhdr); +- asoc->peer.cookie = param.cookie->body; ++ asoc->peer.cookie = kmemdup(param.cookie->body, asoc->peer.cookie_len, gfp); ++ if (!asoc->peer.cookie) ++ retval = 0; + break; + + case SCTP_PARAM_HEARTBEAT_INFO: +diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c +index fb857cf09ecd..d13c1f1a77fb 100644 +--- a/net/sctp/sm_sideeffect.c ++++ b/net/sctp/sm_sideeffect.c +@@ -878,6 +878,11 @@ static void sctp_cmd_new_state(struct sctp_cmd_seq *cmds, + asoc->rto_initial; + } + ++ if (sctp_state(asoc, ESTABLISHED)) { ++ kfree(asoc->peer.cookie); ++ asoc->peer.cookie = NULL; ++ } ++ + if (sctp_state(asoc, ESTABLISHED) || + sctp_state(asoc, CLOSED) || + sctp_state(asoc, SHUTDOWN_RECEIVED)) { +diff --git a/scripts/coccinelle/api/stream_open.cocci b/scripts/coccinelle/api/stream_open.cocci +new file mode 100644 +index 000000000000..350145da7669 +--- /dev/null ++++ b/scripts/coccinelle/api/stream_open.cocci +@@ -0,0 +1,363 @@ ++// SPDX-License-Identifier: GPL-2.0 ++// Author: Kirill Smelkov (kirr@nexedi.com) ++// ++// Search for stream-like files that are using nonseekable_open and convert ++// them to stream_open. A stream-like file is a file that does not use ppos in ++// its read and write. Rationale for the conversion is to avoid deadlock in ++// between read and write. ++ ++virtual report ++virtual patch ++virtual explain // explain decisions in the patch (SPFLAGS="-D explain") ++ ++// stream-like reader & writer - ones that do not depend on f_pos. ++@ stream_reader @ ++identifier readstream, ppos; ++identifier f, buf, len; ++type loff_t; ++@@ ++ ssize_t readstream(struct file *f, char *buf, size_t len, loff_t *ppos) ++ { ++ ... when != ppos ++ } ++ ++@ stream_writer @ ++identifier writestream, ppos; ++identifier f, buf, len; ++type loff_t; ++@@ ++ ssize_t writestream(struct file *f, const char *buf, size_t len, loff_t *ppos) ++ { ++ ... when != ppos ++ } ++ ++ ++// a function that blocks ++@ blocks @ ++identifier block_f; ++identifier wait_event =~ "^wait_event_.*"; ++@@ ++ block_f(...) { ++ ... when exists ++ wait_event(...) ++ ... when exists ++ } ++ ++// stream_reader that can block inside. ++// ++// XXX wait_* can be called not directly from current function (e.g. func -> f -> g -> wait()) ++// XXX currently reader_blocks supports only direct and 1-level indirect cases. ++@ reader_blocks_direct @ ++identifier stream_reader.readstream; ++identifier wait_event =~ "^wait_event_.*"; ++@@ ++ readstream(...) ++ { ++ ... when exists ++ wait_event(...) ++ ... when exists ++ } ++ ++@ reader_blocks_1 @ ++identifier stream_reader.readstream; ++identifier blocks.block_f; ++@@ ++ readstream(...) ++ { ++ ... when exists ++ block_f(...) ++ ... when exists ++ } ++ ++@ reader_blocks depends on reader_blocks_direct || reader_blocks_1 @ ++identifier stream_reader.readstream; ++@@ ++ readstream(...) { ++ ... ++ } ++ ++ ++// file_operations + whether they have _any_ .read, .write, .llseek ... at all. ++// ++// XXX add support for file_operations xxx[N] = ... (sound/core/pcm_native.c) ++@ fops0 @ ++identifier fops; ++@@ ++ struct file_operations fops = { ++ ... ++ }; ++ ++@ has_read @ ++identifier fops0.fops; ++identifier read_f; ++@@ ++ struct file_operations fops = { ++ .read = read_f, ++ }; ++ ++@ has_read_iter @ ++identifier fops0.fops; ++identifier read_iter_f; ++@@ ++ struct file_operations fops = { ++ .read_iter = read_iter_f, ++ }; ++ ++@ has_write @ ++identifier fops0.fops; ++identifier write_f; ++@@ ++ struct file_operations fops = { ++ .write = write_f, ++ }; ++ ++@ has_write_iter @ ++identifier fops0.fops; ++identifier write_iter_f; ++@@ ++ struct file_operations fops = { ++ .write_iter = write_iter_f, ++ }; ++ ++@ has_llseek @ ++identifier fops0.fops; ++identifier llseek_f; ++@@ ++ struct file_operations fops = { ++ .llseek = llseek_f, ++ }; ++ ++@ has_no_llseek @ ++identifier fops0.fops; ++@@ ++ struct file_operations fops = { ++ .llseek = no_llseek, ++ }; ++ ++@ has_mmap @ ++identifier fops0.fops; ++identifier mmap_f; ++@@ ++ struct file_operations fops = { ++ .mmap = mmap_f, ++ }; ++ ++@ has_copy_file_range @ ++identifier fops0.fops; ++identifier copy_file_range_f; ++@@ ++ struct file_operations fops = { ++ .copy_file_range = copy_file_range_f, ++ }; ++ ++@ has_remap_file_range @ ++identifier fops0.fops; ++identifier remap_file_range_f; ++@@ ++ struct file_operations fops = { ++ .remap_file_range = remap_file_range_f, ++ }; ++ ++@ has_splice_read @ ++identifier fops0.fops; ++identifier splice_read_f; ++@@ ++ struct file_operations fops = { ++ .splice_read = splice_read_f, ++ }; ++ ++@ has_splice_write @ ++identifier fops0.fops; ++identifier splice_write_f; ++@@ ++ struct file_operations fops = { ++ .splice_write = splice_write_f, ++ }; ++ ++ ++// file_operations that is candidate for stream_open conversion - it does not ++// use mmap and other methods that assume @offset access to file. ++// ++// XXX for simplicity require no .{read/write}_iter and no .splice_{read/write} for now. ++// XXX maybe_steam.fops cannot be used in other rules - it gives "bad rule maybe_stream or bad variable fops". ++@ maybe_stream depends on (!has_llseek || has_no_llseek) && !has_mmap && !has_copy_file_range && !has_remap_file_range && !has_read_iter && !has_write_iter && !has_splice_read && !has_splice_write @ ++identifier fops0.fops; ++@@ ++ struct file_operations fops = { ++ }; ++ ++ ++// ---- conversions ---- ++ ++// XXX .open = nonseekable_open -> .open = stream_open ++// XXX .open = func -> openfunc -> nonseekable_open ++ ++// read & write ++// ++// if both are used in the same file_operations together with an opener - ++// under that conditions we can use stream_open instead of nonseekable_open. ++@ fops_rw depends on maybe_stream @ ++identifier fops0.fops, openfunc; ++identifier stream_reader.readstream; ++identifier stream_writer.writestream; ++@@ ++ struct file_operations fops = { ++ .open = openfunc, ++ .read = readstream, ++ .write = writestream, ++ }; ++ ++@ report_rw depends on report @ ++identifier fops_rw.openfunc; ++position p1; ++@@ ++ openfunc(...) { ++ <... ++ nonseekable_open@p1 ++ ...> ++ } ++ ++@ script:python depends on report && reader_blocks @ ++fops << fops0.fops; ++p << report_rw.p1; ++@@ ++coccilib.report.print_report(p[0], ++ "ERROR: %s: .read() can deadlock .write(); change nonseekable_open -> stream_open to fix." % (fops,)) ++ ++@ script:python depends on report && !reader_blocks @ ++fops << fops0.fops; ++p << report_rw.p1; ++@@ ++coccilib.report.print_report(p[0], ++ "WARNING: %s: .read() and .write() have stream semantic; safe to change nonseekable_open -> stream_open." % (fops,)) ++ ++ ++@ explain_rw_deadlocked depends on explain && reader_blocks @ ++identifier fops_rw.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ nonseekable_open /* read & write (was deadlock) */ ++ ...> ++ } ++ ++ ++@ explain_rw_nodeadlock depends on explain && !reader_blocks @ ++identifier fops_rw.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ nonseekable_open /* read & write (no direct deadlock) */ ++ ...> ++ } ++ ++@ patch_rw depends on patch @ ++identifier fops_rw.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ stream_open ++ ...> ++ } ++ ++ ++// read, but not write ++@ fops_r depends on maybe_stream && !has_write @ ++identifier fops0.fops, openfunc; ++identifier stream_reader.readstream; ++@@ ++ struct file_operations fops = { ++ .open = openfunc, ++ .read = readstream, ++ }; ++ ++@ report_r depends on report @ ++identifier fops_r.openfunc; ++position p1; ++@@ ++ openfunc(...) { ++ <... ++ nonseekable_open@p1 ++ ...> ++ } ++ ++@ script:python depends on report @ ++fops << fops0.fops; ++p << report_r.p1; ++@@ ++coccilib.report.print_report(p[0], ++ "WARNING: %s: .read() has stream semantic; safe to change nonseekable_open -> stream_open." % (fops,)) ++ ++@ explain_r depends on explain @ ++identifier fops_r.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ nonseekable_open /* read only */ ++ ...> ++ } ++ ++@ patch_r depends on patch @ ++identifier fops_r.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ stream_open ++ ...> ++ } ++ ++ ++// write, but not read ++@ fops_w depends on maybe_stream && !has_read @ ++identifier fops0.fops, openfunc; ++identifier stream_writer.writestream; ++@@ ++ struct file_operations fops = { ++ .open = openfunc, ++ .write = writestream, ++ }; ++ ++@ report_w depends on report @ ++identifier fops_w.openfunc; ++position p1; ++@@ ++ openfunc(...) { ++ <... ++ nonseekable_open@p1 ++ ...> ++ } ++ ++@ script:python depends on report @ ++fops << fops0.fops; ++p << report_w.p1; ++@@ ++coccilib.report.print_report(p[0], ++ "WARNING: %s: .write() has stream semantic; safe to change nonseekable_open -> stream_open." % (fops,)) ++ ++@ explain_w depends on explain @ ++identifier fops_w.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ nonseekable_open /* write only */ ++ ...> ++ } ++ ++@ patch_w depends on patch @ ++identifier fops_w.openfunc; ++@@ ++ openfunc(...) { ++ <... ++- nonseekable_open +++ stream_open ++ ...> ++ } ++ ++ ++// no read, no write - don't change anything