From: Jay Fang f.fangjian@huawei.com
mainline inclusion from mainline-v5.14-rc1 commit 2b2142f247eb category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I4UR1H CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
-----------------------------------------------------------------------
This patch uses debugfs_regset32 interface to create the registers dump file. Use it instead of creating a generic debugfs file with manually written read callback function.
With these entries, users can check all the SPI controller registers during run time.
Signed-off-by: Jay Fang f.fangjian@huawei.com Link: https://lore.kernel.org/r/1622789718-13977-1-git-send-email-f.fangjian@huawe... Signed-off-by: Mark Brown broonie@kernel.org Reviewed-by: Jay Fang f.fangjian@huawei.com Acked-by: Xie XiuQi xiexiuqi@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/spi/spi-hisi-kunpeng.c | 51 +++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c index 3f986ba1c328..58b823a16fc4 100644 --- a/drivers/spi/spi-hisi-kunpeng.c +++ b/drivers/spi/spi-hisi-kunpeng.c @@ -9,6 +9,7 @@
#include <linux/acpi.h> #include <linux/bitfield.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/interrupt.h> @@ -126,6 +127,7 @@ struct hisi_spi { void __iomem *regs; int irq; u32 fifo_len; /* depth of the FIFO buffer */ + u16 bus_num;
/* Current message transfer state info */ const void *tx; @@ -133,8 +135,49 @@ struct hisi_spi { void *rx; unsigned int rx_len; u8 n_bytes; /* current is a 1/2/4 bytes op */ + + struct dentry *debugfs; + struct debugfs_regset32 regset; +}; + +#define HISI_SPI_DBGFS_REG(_name, _off) \ +{ \ + .name = _name, \ + .offset = _off, \ +} + +static const struct debugfs_reg32 hisi_spi_regs[] = { + HISI_SPI_DBGFS_REG("CSCR", HISI_SPI_CSCR), + HISI_SPI_DBGFS_REG("CR", HISI_SPI_CR), + HISI_SPI_DBGFS_REG("ENR", HISI_SPI_ENR), + HISI_SPI_DBGFS_REG("FIFOC", HISI_SPI_FIFOC), + HISI_SPI_DBGFS_REG("IMR", HISI_SPI_IMR), + HISI_SPI_DBGFS_REG("DIN", HISI_SPI_DIN), + HISI_SPI_DBGFS_REG("DOUT", HISI_SPI_DOUT), + HISI_SPI_DBGFS_REG("SR", HISI_SPI_SR), + HISI_SPI_DBGFS_REG("RISR", HISI_SPI_RISR), + HISI_SPI_DBGFS_REG("ISR", HISI_SPI_ISR), + HISI_SPI_DBGFS_REG("ICR", HISI_SPI_ICR), + HISI_SPI_DBGFS_REG("VERSION", HISI_SPI_VERSION), };
+static int hisi_spi_debugfs_init(struct hisi_spi *hs) +{ + char name[32]; + + snprintf(name, 32, "hisi_spi%d", hs->bus_num); + hs->debugfs = debugfs_create_dir(name, NULL); + if (!hs->debugfs) + return -ENOMEM; + + hs->regset.regs = hisi_spi_regs; + hs->regset.nregs = ARRAY_SIZE(hisi_spi_regs); + hs->regset.base = hs->regs; + debugfs_create_regset32("registers", 0400, hs->debugfs, &hs->regset); + + return 0; +} + static u32 hisi_spi_busy(struct hisi_spi *hs) { return readl(hs->regs + HISI_SPI_SR) & SR_BUSY; @@ -424,6 +467,7 @@ static int hisi_spi_probe(struct platform_device *pdev) hs = spi_controller_get_devdata(master); hs->dev = dev; hs->irq = irq; + hs->bus_num = pdev->id;
hs->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hs->regs)) @@ -446,7 +490,7 @@ static int hisi_spi_probe(struct platform_device *pdev) master->use_gpio_descriptors = true; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); - master->bus_num = pdev->id; + master->bus_num = hs->bus_num; master->setup = hisi_spi_setup; master->cleanup = hisi_spi_cleanup; master->transfer_one = hisi_spi_transfer_one; @@ -462,6 +506,9 @@ static int hisi_spi_probe(struct platform_device *pdev) return ret; }
+ if (hisi_spi_debugfs_init(hs)) + dev_info(dev, "failed to create debugfs dir\n"); + ret = spi_register_controller(master); if (ret) { dev_err(dev, "failed to register spi master, ret=%d\n", ret); @@ -478,7 +525,9 @@ static int hisi_spi_probe(struct platform_device *pdev) static int hisi_spi_remove(struct platform_device *pdev) { struct spi_controller *master = platform_get_drvdata(pdev); + struct hisi_spi *hs = spi_controller_get_devdata(master);
+ debugfs_remove_recursive(hs->debugfs); spi_unregister_controller(master);
return 0;
From: oujiefeng oujiefeng@huawei.com
mainline inclusion from mainline-v5.16-rc1 commit 40fafc8eca3f category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4UR1H CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
----------------------------------------------------------------------------
Change the debugfs directory name from hisi_spi65535 to hisi_spi0.
Fixes: 2b2142f247eb ("spi: hisi-kunpeng: Add debugfs support") Signed-off-by: oujiefeng oujiefeng@huawei.com Signed-off-by: Jay Fang f.fangjian@huawei.com Link: https://lore.kernel.org/r/20211117012119.55558-1-f.fangjian@huawei.com Signed-off-by: Mark Brown broonie@kernel.org Reviewed-by: Jay Fang f.fangjian@huawei.com Acked-by: Xie XiuQi xiexiuqi@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/spi/spi-hisi-kunpeng.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/spi/spi-hisi-kunpeng.c b/drivers/spi/spi-hisi-kunpeng.c index 58b823a16fc4..525cc0143a30 100644 --- a/drivers/spi/spi-hisi-kunpeng.c +++ b/drivers/spi/spi-hisi-kunpeng.c @@ -127,7 +127,6 @@ struct hisi_spi { void __iomem *regs; int irq; u32 fifo_len; /* depth of the FIFO buffer */ - u16 bus_num;
/* Current message transfer state info */ const void *tx; @@ -165,7 +164,10 @@ static int hisi_spi_debugfs_init(struct hisi_spi *hs) { char name[32];
- snprintf(name, 32, "hisi_spi%d", hs->bus_num); + struct spi_controller *master; + + master = container_of(hs->dev, struct spi_controller, dev); + snprintf(name, 32, "hisi_spi%d", master->bus_num); hs->debugfs = debugfs_create_dir(name, NULL); if (!hs->debugfs) return -ENOMEM; @@ -467,7 +469,6 @@ static int hisi_spi_probe(struct platform_device *pdev) hs = spi_controller_get_devdata(master); hs->dev = dev; hs->irq = irq; - hs->bus_num = pdev->id;
hs->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(hs->regs)) @@ -490,7 +491,7 @@ static int hisi_spi_probe(struct platform_device *pdev) master->use_gpio_descriptors = true; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); - master->bus_num = hs->bus_num; + master->bus_num = pdev->id; master->setup = hisi_spi_setup; master->cleanup = hisi_spi_cleanup; master->transfer_one = hisi_spi_transfer_one; @@ -506,15 +507,15 @@ static int hisi_spi_probe(struct platform_device *pdev) return ret; }
- if (hisi_spi_debugfs_init(hs)) - dev_info(dev, "failed to create debugfs dir\n"); - ret = spi_register_controller(master); if (ret) { dev_err(dev, "failed to register spi master, ret=%d\n", ret); return ret; }
+ if (hisi_spi_debugfs_init(hs)) + dev_info(dev, "failed to create debugfs dir\n"); + dev_info(dev, "hw version:0x%x max-freq:%u kHz\n", readl(hs->regs + HISI_SPI_VERSION), master->max_speed_hz / 1000);
From: Liu Yuntao liuyuntao10@huawei.com
mainline inclusion from mainline-v5.17-rc6 commit e79ce9832316e09529b212a21278d68240ccbf1f category: bugfix bugzilla: 186043, https://gitee.com/openeuler/kernel/issues/I518AB CVE: NA
-----------------------------------
When we specify a large number for node in hugepages parameter, it may be parsed to another number due to truncation in this statement:
node = tmp;
For example, add following parameter in command line:
hugepagesz=1G hugepages=4294967297:5
and kernel will allocate 5 hugepages for node 1 instead of ignoring it.
I move the validation check earlier to fix this issue, and slightly simplifies the condition here.
Link: https://lkml.kernel.org/r/20220209134018.8242-1-liuyuntao10@huawei.com Fixes: b5389086ad7be0 ("hugetlbfs: extend the definition of hugepages parameter to support node allocation") Signed-off-by: Liu Yuntao liuyuntao10@huawei.com Reviewed-by: Mike Kravetz mike.kravetz@oracle.com Cc: stable@vger.kernel.org Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Liu Shixin liushixin2@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- mm/hugetlb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 3b787cb56699..34f3dfba5e82 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3600,10 +3600,10 @@ static int __init hugepages_setup(char *s) pr_warn("HugeTLB: architecture can't support node specific alloc, ignoring!\n"); return 0; } + if (tmp >= nr_online_nodes) + goto invalid; node = tmp; p += count + 1; - if (node < 0 || node >= nr_online_nodes) - goto invalid; /* Parse hugepages */ if (sscanf(p, "%lu%n", &tmp, &count) != 1) goto invalid;
From: Peng Liu liupeng256@huawei.com
hulk inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I51C37 CVE: NA
--------------------------------
Patch "kfence: Add a module parameter to adjust kfence objects" use memblock_free to free memory allocated from memblock, but a virtual address is passed to memblock_free where a physical address is expected. This mistake will lead to memory leak when fail to alloc kfence pool. Use __pa() to fix this, and the impact can be observed by "cat /proc/meminfo".
Fixes: 901b983c886b ("kfence: Add a module parameter to adjust kfence objects") Signed-off-by: Peng Liu liupeng256@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- mm/kfence/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 2454b1c57fb1..02bd7b468162 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -838,7 +838,7 @@ static int __init kfence_dynamic_init(void) covered_size = sizeof(atomic_t) * ALLOC_COVERED_SIZE; alloc_covered = memblock_alloc(covered_size, PAGE_SIZE); if (!alloc_covered) { - memblock_free((phys_addr_t)kfence_metadata, metadata_size); + memblock_free(__pa(kfence_metadata), metadata_size); kfence_metadata = NULL; pr_err("failed to allocate covered\n"); return -ENOMEM; @@ -849,9 +849,9 @@ static int __init kfence_dynamic_init(void)
static void __init kfence_dynamic_destroy(void) { - memblock_free((phys_addr_t)alloc_covered, covered_size); + memblock_free(__pa(alloc_covered), covered_size); alloc_covered = NULL; - memblock_free((phys_addr_t)kfence_metadata, metadata_size); + memblock_free(__pa(kfence_metadata), metadata_size); kfence_metadata = NULL; } #else
From: Jens Axboe axboe@kernel.dk
mainline inclusion from mainline-v5.12-rc1 commit ca0a26511c679a797f86589894a4523db36d833e category: bugfix bugzilla: 186454,https://gitee.com/openeuler/kernel/issues/I5026G CVE: NA
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
It doesn't make sense to wait for more events to come in, if we can't even flush the overflow we already have to the ring. Return -EBUSY for that condition, just like we do for attempts to submit with overflow pending.
Cc: stable@vger.kernel.org # 5.11 Signed-off-by: Jens Axboe axboe@kernel.dk Conflicts: fs/io_uring.c Signed-off-by: Guo Xuenan guoxuenan@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- fs/io_uring.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c index 600dd0898d7e..af6a1858c791 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -1713,18 +1713,22 @@ static bool __io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force, return cqe != NULL; }
-static void io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force, +static bool io_cqring_overflow_flush(struct io_ring_ctx *ctx, bool force, struct task_struct *tsk, struct files_struct *files) { + bool ret = true; + if (test_bit(0, &ctx->cq_check_overflow)) { /* iopoll syncs against uring_lock, not completion_lock */ if (ctx->flags & IORING_SETUP_IOPOLL) mutex_lock(&ctx->uring_lock); - __io_cqring_overflow_flush(ctx, force, tsk, files); + ret = __io_cqring_overflow_flush(ctx, force, tsk, files); if (ctx->flags & IORING_SETUP_IOPOLL) mutex_unlock(&ctx->uring_lock); } + + return ret; }
static void __io_cqring_fill_event(struct io_kiocb *req, long res, @@ -7051,7 +7055,11 @@ static int io_cqring_wait(struct io_ring_ctx *ctx, int min_events, iowq.nr_timeouts = atomic_read(&ctx->cq_timeouts); trace_io_uring_cqring_wait(ctx, min_events); do { - io_cqring_overflow_flush(ctx, false, NULL, NULL); + /* if we can't even flush overflow, don't wait for more */ + if (!io_cqring_overflow_flush(ctx, false, NULL, NULL)) { + ret = -EBUSY; + break; + } prepare_to_wait_exclusive(&ctx->wait, &iowq.wq, TASK_INTERRUPTIBLE); /* make sure we run task_work before checking for signals */
From: Zhang Wensheng zhangwensheng5@huawei.com
hulk inclusion category: bugfix bugzilla: 186386, https://gitee.com/openeuler/kernel/issues/I520OX CVE: NA backport: openEuler-22.03-LTS
--------------------------------
When 'index' is a big numbers, it may become negative which forced to 'int'. then 'index << part_shift' might overflow to a positive value that is not greater than '0xfffff', then sysfs might complains about duplicate creation. Because of this, move the 'index' judgment to the front will fix it and be better.
Fixes: b0d9111a2d53 ("nbd: use an idr to keep track of nbd devices") Signed-off-by: Zhang Wensheng zhangwensheng5@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/block/nbd.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 1bb9f45f2e3d..0ab548c78f24 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -1760,14 +1760,6 @@ static int nbd_dev_add(int index) int err = -ENOMEM; int first_minor = index << part_shift;
- /* - * Too big index can cause duplicate creation of sysfs files/links, - * because MKDEV() expect that the max first minor is MINORMASK, or - * index << part_shift can overflow. - */ - if (first_minor < index || first_minor > MINORMASK) - return -EINVAL; - nbd = kzalloc(sizeof(struct nbd_device), GFP_KERNEL); if (!nbd) goto out; @@ -1924,8 +1916,20 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info) if (!netlink_capable(skb, CAP_SYS_ADMIN)) return -EPERM;
- if (info->attrs[NBD_ATTR_INDEX]) + if (info->attrs[NBD_ATTR_INDEX]) { index = nla_get_u32(info->attrs[NBD_ATTR_INDEX]); + + /* + * Too big first_minor can cause duplicate creation of + * sysfs files/links, since index << part_shift might + * overflow, or MKDEV() expect that the max bits of + * first_minor is 20. + */ + if (index < 0 || index > MINORMASK >> part_shift) { + printk(KERN_ERR "nbd: illegal input index %d\n", index); + return -EINVAL; + } + } if (!info->attrs[NBD_ATTR_SOCKETS]) { printk(KERN_ERR "nbd: must specify at least one socket\n"); return -EINVAL;
From: Johannes Weiner hannes@cmpxchg.org
mainline inclusion from mainline-v5.13-rc1 commit 9317d0fffeb4c3929069cfc7377cfa2a7cd36d1d category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5244N CVE: NA backport: openEuler-22.03-LTS
--------------------------------
When the unsigned page_counter underflows, even just by a few pages, a cgroup will not be able to run anything afterwards and trigger the OOM killer in a loop.
Underflows shouldn't happen, but when they do in practice, we may just be off by a small amount that doesn't interfere with the normal operation - consequences don't need to be that dire.
Reset the page_counter to 0 upon underflow. We'll issue a warning that the accounting will be off and then try to keep limping along.
[ We used to do this with the original res_counter, where it was a more straight-forward correction inside the spinlock section. I didn't carry it forward into the lockless page counters for simplicity, but it turns out this is quite useful in practice. ]
Link: https://lkml.kernel.org/r/20210408143155.2679744-1-hannes@cmpxchg.org Signed-off-by: Johannes Weiner hannes@cmpxchg.org Acked-by: Michal Hocko mhocko@suse.com Acked-by: Chris Down chris@chrisdown.name Reviewed-by: Shakeel Butt shakeelb@google.com Cc: Hugh Dickins hughd@google.com Cc: Roman Gushchin guro@fb.com Signed-off-by: Andrew Morton akpm@linux-foundation.org Signed-off-by: Linus Torvalds torvalds@linux-foundation.org Signed-off-by: Ma Wupeng mawupeng1@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- mm/page_counter.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/mm/page_counter.c b/mm/page_counter.c index b24a60b28bb0..6d8715e3255d 100644 --- a/mm/page_counter.c +++ b/mm/page_counter.c @@ -52,9 +52,13 @@ void page_counter_cancel(struct page_counter *counter, unsigned long nr_pages) long new;
new = atomic_long_sub_return(nr_pages, &counter->usage); - propagate_protected_usage(counter, new); /* More uncharges than charges? */ - WARN_ON_ONCE(new < 0); + if (WARN_ONCE(new < 0, "page_counter underflow: %ld nr_pages=%lu\n", + new, nr_pages)) { + new = 0; + atomic_long_set(&counter->usage, new); + } + propagate_protected_usage(counter, new); }
/**
From: Lin Ma linma@zju.edu.cn
mainline inclusion from mainline-v5.16-rc1 commit 0b9111922b1f399aba6ed1e1b8f2079c3da1aed8 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5224J CVE: CVE-2022-1198
--------------------------------
There is a possible race condition (use-after-free) like below
(USE) | (FREE) dev_queue_xmit | __dev_queue_xmit | __dev_xmit_skb | sch_direct_xmit | ... xmit_one | netdev_start_xmit | tty_ldisc_kill __netdev_start_xmit | 6pack_close sp_xmit | kfree sp_encaps | |
According to the patch "defer ax25 kfree after unregister_netdev", this patch reorder the kfree after the unregister_netdev to avoid the possible UAF as the unregister_netdev() is well synchronized and won't return if there is a running routine.
Signed-off-by: Lin Ma linma@zju.edu.cn Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Xu Jia xujia39@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Reviewed-by: Wang Weiyang wangweiyang2@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/net/hamradio/6pack.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index bd0beb16d68a..8221f7c2709e 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -677,11 +677,13 @@ static void sixpack_close(struct tty_struct *tty) del_timer_sync(&sp->tx_t); del_timer_sync(&sp->resync_t);
- /* Free all 6pack frame buffers. */ + unregister_netdev(sp->dev); + + /* Free all 6pack frame buffers after unreg. */ kfree(sp->rbuff); kfree(sp->xbuff);
- unregister_netdev(sp->dev); + free_netdev(sp->dev); }
/* Perform I/O control on an active 6pack channel. */
From: Lin Ma linma@zju.edu.cn
mainline inclusion from mainline-v5.16-rc2 commit 81b1d548d00bcd028303c4f3150fa753b9b8aa71 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5224J CVE: CVE-2022-1198
--------------------------------
The former patch "defer 6pack kfree after unregister_netdev" reorders the kfree of two buffer after the unregister_netdev to prevent the race condition. It also adds free_netdev() function in sixpack_close(), which is a direct copy from the similar code in mkiss_close().
However, in sixpack driver, the flag needs_free_netdev is set to true in sp_setup(), hence the unregister_netdev() will free the netdev automatically. Therefore, as the sp is netdev_priv, use-after-free occurs.
This patch removes the needs_free_netdev = true and just let the free_netdev to finish this deallocation task.
Fixes: 0b9111922b1f ("hamradio: defer 6pack kfree after unregister_netdev") Signed-off-by: Lin Ma linma@zju.edu.cn Link: https://lore.kernel.org/r/20211111141402.7551-1-linma@zju.edu.cn Signed-off-by: Jakub Kicinski kuba@kernel.org Signed-off-by: Xu Jia xujia39@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Reviewed-by: Wang Weiyang wangweiyang2@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/net/hamradio/6pack.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 8221f7c2709e..2bcb0fa1c83d 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -311,7 +311,6 @@ static void sp_setup(struct net_device *dev) { /* Finish setting up the DEVICE info. */ dev->netdev_ops = &sp_netdev_ops; - dev->needs_free_netdev = true; dev->mtu = SIXP_MTU; dev->hard_header_len = AX25_MAX_HEADER_LEN; dev->header_ops = &ax25_header_ops;
From: Duoming Zhou duoming@zju.edu.cn
stable inclusion from stable-v5.10.110 commit f67a1400788f550d201c71aeaf56706afe57f0da category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I5224J CVE: CVE-2022-1198
--------------------------------
commit efe4186e6a1b54bf38b9e05450d43b0da1fd7739 upstream.
When a 6pack device is detaching, the sixpack_close() will act to cleanup necessary resources. Although del_timer_sync() in sixpack_close() won't return if there is an active timer, one could use mod_timer() in sp_xmit_on_air() to wake up timer again by calling userspace syscall such as ax25_sendmsg(), ax25_connect() and ax25_ioctl().
This unexpected waked handler, sp_xmit_on_air(), realizes nothing about the undergoing cleanup and may still call pty_write() to use driver layer resources that have already been released.
One of the possible race conditions is shown below:
(USE) | (FREE) ax25_sendmsg() | ax25_queue_xmit() | ... | sp_xmit() | sp_encaps() | sixpack_close() sp_xmit_on_air() | del_timer_sync(&sp->tx_t) mod_timer(&sp->tx_t,...) | ... | unregister_netdev() | ... (wait a while) | tty_release() | tty_release_struct() | release_tty() sp_xmit_on_air() | tty_kref_put(tty_struct) //FREE pty_write(tty_struct) //USE | ...
The corresponding fail log is shown below: Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Reviewed-by: Wang Weiyang wangweiyang2@huawei.com
=============================================================== BUG: KASAN: use-after-free in __run_timers.part.0+0x170/0x470 Write of size 8 at addr ffff88800a652ab8 by task swapper/2/0 ... Call Trace: ... queue_work_on+0x3f/0x50 pty_write+0xcd/0xe0pty_write+0xcd/0xe0 sp_xmit_on_air+0xb2/0x1f0 call_timer_fn+0x28/0x150 __run_timers.part.0+0x3c2/0x470 run_timer_softirq+0x3b/0x80 __do_softirq+0xf1/0x380 ...
This patch reorders the del_timer_sync() after the unregister_netdev() to avoid UAF bugs. Because the unregister_netdev() is well synchronized, it flushs out any pending queues, waits the refcount of net_device decreases to zero and removes net_device from kernel. There is not any running routines after executing unregister_netdev(). Therefore, we could not arouse timer from userspace again.
Signed-off-by: Duoming Zhou duoming@zju.edu.cn Reviewed-by: Lin Ma linma@zju.edu.cn Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Xu Jia xujia39@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Reviewed-by: Wang Weiyang wangweiyang2@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/net/hamradio/6pack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 2bcb0fa1c83d..83dc1c2c3b84 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -673,11 +673,11 @@ static void sixpack_close(struct tty_struct *tty) */ netif_stop_queue(sp->dev);
+ unregister_netdev(sp->dev); + del_timer_sync(&sp->tx_t); del_timer_sync(&sp->resync_t);
- unregister_netdev(sp->dev); - /* Free all 6pack frame buffers after unreg. */ kfree(sp->rbuff); kfree(sp->xbuff);
From: Hangyu Hua hbh25y@gmail.com
mainline inclusion from mainline-v5.18-rc1 commit c70222752228a62135cee3409dccefd494a24646 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I51YBP CVE: CVE-2022-28390 backport: openEuler-22.03-LTS
--------------------------------
There is no need to call dev_kfree_skb() when usb_submit_urb() fails beacause can_put_echo_skb() deletes the original skb and can_free_echo_skb() deletes the cloned skb.
Link: https://lore.kernel.org/all/20220228083639.38183-1-hbh25y@gmail.com Fixes: 702171adeed3 ("ems_usb: Added support for EMS CPC-USB/ARM7 CAN/USB interface") Cc: stable@vger.kernel.org Cc: Sebastian Haas haas@ems-wuensche.com Signed-off-by: Hangyu Hua hbh25y@gmail.com Signed-off-by: Marc Kleine-Budde mkl@pengutronix.de Signed-off-by: Baisong Zhong zhongbaisong@huawei.com Reviewed-by: Yue Haibing yuehaibing@huawei.com Reviewed-by: Xiu Jianfeng xiujianfeng@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/net/can/usb/ems_usb.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c index 249d2fba28c7..6458da9c13b9 100644 --- a/drivers/net/can/usb/ems_usb.c +++ b/drivers/net/can/usb/ems_usb.c @@ -823,7 +823,6 @@ static netdev_tx_t ems_usb_start_xmit(struct sk_buff *skb, struct net_device *ne
usb_unanchor_urb(urb); usb_free_coherent(dev->udev, size, buf, urb->transfer_dma); - dev_kfree_skb(skb);
atomic_dec(&dev->active_tx_urbs);
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit 36c6b7613ef1ffd88637315f11c71896f3ce4856 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
Perform driver-specific SCSI device initialization in the designated SCSI midlayer callback instead of relying on the libsas "device found" callback.
The SCSI midlayer .slave_alloc interface is called prior to sending any I/O to the device.
Link: https://lore.kernel.org/r/1634041588-74824-2-git-send-email-john.garry@huawe... Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: John Garry john.garry@huawei.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 17 ++++++++++++++--- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 2 +- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 2 +- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 +- 5 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 436d174f2194..06b1392bb487 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -649,6 +649,7 @@ extern int hisi_sas_probe(struct platform_device *pdev, extern int hisi_sas_remove(struct platform_device *pdev);
extern int hisi_sas_slave_configure(struct scsi_device *sdev); +extern int hisi_sas_slave_alloc(struct scsi_device *sdev); extern int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time); extern void hisi_sas_scan_start(struct Scsi_Host *shost); extern int hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 98a1754907d1..2df7e3e8d372 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -756,6 +756,20 @@ static int hisi_sas_init_device(struct domain_device *device) return rc; }
+int hisi_sas_slave_alloc(struct scsi_device *sdev) +{ + struct domain_device *ddev; + int rc; + + rc = sas_slave_alloc(sdev); + if (rc) + return rc; + ddev = sdev_to_domain_dev(sdev); + + return hisi_sas_init_device(ddev); +} +EXPORT_SYMBOL_GPL(hisi_sas_slave_alloc); + static int hisi_sas_dev_found(struct domain_device *device) { struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); @@ -802,9 +816,6 @@ static int hisi_sas_dev_found(struct domain_device *device) dev_info(dev, "dev[%d:%x] found\n", sas_dev->device_id, sas_dev->dev_type);
- rc = hisi_sas_init_device(device); - if (rc) - goto err_out; sas_dev->dev_status = HISI_SAS_DEV_NORMAL; return 0;
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index afe639994f3d..bbb5220cc140 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1771,7 +1771,7 @@ static struct scsi_host_template sht_v1_hw = { .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, - .slave_alloc = sas_slave_alloc, + .slave_alloc = hisi_sas_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, #ifdef CONFIG_COMPAT diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index b0b2361e63fe..8a9e481533b4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -3584,7 +3584,7 @@ static struct scsi_host_template sht_v2_hw = { .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, - .slave_alloc = sas_slave_alloc, + .slave_alloc = hisi_sas_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, #ifdef CONFIG_COMPAT diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 8b56d3e81ce1..f47a91afe9d5 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -3155,7 +3155,7 @@ static struct scsi_host_template sht_v3_hw = { .max_sectors = SCSI_DEFAULT_MAX_SECTORS, .eh_device_reset_handler = sas_eh_device_reset_handler, .eh_target_reset_handler = sas_eh_target_reset_handler, - .slave_alloc = sas_slave_alloc, + .slave_alloc = hisi_sas_slave_alloc, .target_destroy = sas_target_destroy, .ioctl = sas_ioctl, #ifdef CONFIG_COMPAT
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit 046ab7d0f5943dd74c351e1f3a771dea785fe25d category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
When issuing a hardreset/linkreset/phy_set_linkrate from sysfs, the phy will be disabled and re-enabled for the directly attached scenario.
It takes some time for the phy to come back up after re-enabling the phy. If the controller becomes suspended while waiting for the phy to come back, the phy up may be lost (along with the disk).
To solve this problem, wait for the phy up to occur with a timeout. Indeed this is already done in hisi_sas_debug_I_T_nexus_reset() for local phys, so just relocate the functionality to hisi_sas_control_phy().
Since the HA workqueue is drained when suspending the controller, and the phy control function is called from the same workqueue, we can guarantee that the controller will not be suspended during this period.
Link: https://lore.kernel.org/r/1634041588-74824-3-git-send-email-john.garry@huawe... Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: John Garry john.garry@huawei.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/hisi_sas/hisi_sas_main.c | 43 +++++++++++++++++++------- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 11 ++----- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 17 ++-------- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 9 ++---- 4 files changed, 39 insertions(+), 41 deletions(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 2df7e3e8d372..646bf00482bb 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1146,9 +1146,17 @@ static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no, static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, void *funcdata) { + struct hisi_sas_phy *phy = container_of(sas_phy, + struct hisi_sas_phy, sas_phy); struct sas_ha_struct *sas_ha = sas_phy->ha; struct hisi_hba *hisi_hba = sas_ha->lldd_ha; + struct device *dev = hisi_hba->dev; + DECLARE_COMPLETION_ONSTACK(completion); int phy_no = sas_phy->id; + u8 sts = phy->phy_attached; + int ret = 0; + + phy->reset_completion = &completion;
switch (func) { case PHY_FUNC_HARD_RESET: @@ -1163,21 +1171,35 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
case PHY_FUNC_DISABLE: hisi_sas_phy_enable(hisi_hba, phy_no, 0); - break; + goto out;
case PHY_FUNC_SET_LINK_RATE: - return hisi_sas_phy_set_linkrate(hisi_hba, phy_no, funcdata); + ret = hisi_sas_phy_set_linkrate(hisi_hba, phy_no, funcdata); + break; + case PHY_FUNC_GET_EVENTS: if (hisi_hba->hw->get_events) { hisi_hba->hw->get_events(hisi_hba, phy_no); - break; + goto out; } fallthrough; case PHY_FUNC_RELEASE_SPINUP_HOLD: default: - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto out; } - return 0; + + if (sts && !wait_for_completion_timeout(&completion, 2 * HZ)) { + dev_warn(dev, "phy%d wait phyup timed out for func %d\n", + phy_no, func); + if (phy->in_reset) + ret = -ETIMEDOUT; + } + +out: + phy->reset_completion = NULL; + + return ret; }
static void hisi_sas_task_done(struct sas_task *task) @@ -1784,7 +1806,6 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct sas_ha_struct *sas_ha = &hisi_hba->sha; - DECLARE_COMPLETION_ONSTACK(phyreset); int rc, reset_type;
if (!local_phy->enabled) { @@ -1797,8 +1818,11 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) sas_ha->sas_phy[local_phy->number]; struct hisi_sas_phy *phy = container_of(sas_phy, struct hisi_sas_phy, sas_phy); + unsigned long flags; + + spin_lock_irqsave(&phy->lock, flags); phy->in_reset = 1; - phy->reset_completion = &phyreset; + spin_unlock_irqrestore(&phy->lock, flags); }
reset_type = (sas_dev->dev_status == HISI_SAS_DEV_INIT || @@ -1812,17 +1836,14 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) sas_ha->sas_phy[local_phy->number]; struct hisi_sas_phy *phy = container_of(sas_phy, struct hisi_sas_phy, sas_phy); - int ret = wait_for_completion_timeout(&phyreset, - I_T_NEXUS_RESET_PHYUP_TIMEOUT); unsigned long flags;
spin_lock_irqsave(&phy->lock, flags); - phy->reset_completion = NULL; phy->in_reset = 0; spin_unlock_irqrestore(&phy->lock, flags);
/* report PHY down if timed out */ - if (!ret) + if (rc == -ETIMEDOUT) hisi_sas_phy_down(hisi_hba, sas_phy->id, 0, GFP_KERNEL); } else if (sas_dev->dev_status != HISI_SAS_DEV_INIT) { /* diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index bbb5220cc140..fdff327bb030 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -1327,7 +1327,6 @@ static irqreturn_t int_phyup_v1_hw(int irq_no, void *p) u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd; struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd; irqreturn_t res = IRQ_HANDLED; - unsigned long flags;
irq_value = hisi_sas_phy_read32(hisi_hba, phy_no, CHL_INT2); if (!(irq_value & CHL_INT2_SL_PHY_ENA_MSK)) { @@ -1380,15 +1379,9 @@ static irqreturn_t int_phyup_v1_hw(int irq_no, void *p) phy->identify.target_port_protocols = SAS_PROTOCOL_SMP; hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP); - - spin_lock_irqsave(&phy->lock, flags); - if (phy->reset_completion) { - phy->in_reset = 0; - complete(phy->reset_completion); - } - spin_unlock_irqrestore(&phy->lock, flags); - end: + if (phy->reset_completion) + complete(phy->reset_completion); hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT2, CHL_INT2_SL_PHY_ENA_MSK);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 8a9e481533b4..9bfa796505aa 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -2641,7 +2641,6 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) struct device *dev = hisi_hba->dev; u32 *frame_rcvd = (u32 *)sas_phy->frame_rcvd; struct sas_identify_frame *id = (struct sas_identify_frame *)frame_rcvd; - unsigned long flags;
hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1);
@@ -2696,14 +2695,9 @@ static int phy_up_v2_hw(int phy_no, struct hisi_hba *hisi_hba) set_link_timer_quirk(hisi_hba); } hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP); - spin_lock_irqsave(&phy->lock, flags); - if (phy->reset_completion) { - phy->in_reset = 0; - complete(phy->reset_completion); - } - spin_unlock_irqrestore(&phy->lock, flags); - end: + if (phy->reset_completion) + complete(phy->reset_completion); hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_SL_PHY_ENABLE_MSK); hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0); @@ -3204,7 +3198,6 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p) u32 ent_tmp, ent_msk, ent_int, port_id, link_rate, hard_phy_linkrate; irqreturn_t res = IRQ_HANDLED; u8 attached_sas_addr[SAS_ADDR_SIZE] = {0}; - unsigned long flags; int phy_no, offset;
del_timer(&phy->timer); @@ -3280,12 +3273,8 @@ static irqreturn_t sata_int_v2_hw(int irq_no, void *p) phy->identify.target_port_protocols = SAS_PROTOCOL_SATA; hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP);
- spin_lock_irqsave(&phy->lock, flags); - if (phy->reset_completion) { - phy->in_reset = 0; + if (phy->reset_completion) complete(phy->reset_completion); - } - spin_unlock_irqrestore(&phy->lock, flags); end: hisi_sas_write32(hisi_hba, ENT_INT_SRC1 + offset, ent_tmp); hisi_sas_write32(hisi_hba, ENT_INT_SRC_MSK1 + offset, ent_msk); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index f47a91afe9d5..8c36325221b7 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1480,7 +1480,6 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; struct device *dev = hisi_hba->dev; - unsigned long flags;
del_timer(&phy->timer); hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 1); @@ -1562,13 +1561,9 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) phy->phy_attached = 1; hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP); res = IRQ_HANDLED; - spin_lock_irqsave(&phy->lock, flags); - if (phy->reset_completion) { - phy->in_reset = 0; - complete(phy->reset_completion); - } - spin_unlock_irqrestore(&phy->lock, flags); end: + if (phy->reset_completion) + complete(phy->reset_completion); hisi_sas_phy_write32(hisi_hba, phy_no, CHL_INT0, CHL_INT0_SL_PHY_ENABLE_MSK); hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_PHY_ENA_MSK, 0);
From: John Garry john.garry@huawei.com
mainline inclusion from mainline-v5.17-rc1 commit fbefe22811c3140a686e407e114789ebf328a9a2 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
For the hisi_sas driver, if a directly attached disk is removed during suspend, a hang will occur in the resume process:
The background is that in commit 16fd4a7c5917 ("scsi: hisi_sas: Add device link between SCSI devices and hisi_hba"), it is ensured that the HBA device cannot be runtime suspended when any SCSI device associated is active.
Other drivers which use libsas don't worry about this as none support runtime suspend.
The mentioned hang occurs when an disk is removed during suspend. In the removal process - from PHYE_RESUME_TIMEOUT event processing - we call into scsi_remove_device(), which is being processed in the HA event workqueue. Here we wait for all suppliers of the SCSI device to resume, which includes the HBA device (from the above commit). However the HBA device cannot resume, as it is waiting for the PHYE_RESUME_TIMEOUT to be processed (from calling sas_resume_ha() -> sas_drain_work()). This is the deadlock.
There does not appear to be any need for the sas_drain_work() to be called at all in sas_resume_ha() as it is not syncing against anything, so allow LLDDs to avoid this by providing a variant of sas_resume_ha() which does "sync", i.e. doesn't drain the event workqueue.
Link: https://lore.kernel.org/r/1639999298-244569-2-git-send-email-chenxiang66@his... Signed-off-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 10 +++++++++- drivers/scsi/libsas/sas_init.c | 17 +++++++++++++++-- include/scsi/libsas.h | 1 + 3 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 8c36325221b7..5b4168adfcc8 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4945,7 +4945,15 @@ static int _resume_v3_hw(struct device *device) return rc; } phys_init_v3_hw(hisi_hba); - sas_resume_ha(sha); + + /* + * If a directly-attached disk is removed during suspend, a deadlock + * may occur, as the PHYE_RESUME_TIMEOUT processing will require the + * hisi_hba->device to be active, which can only happen when resume + * completes. So don't wait for the HA event workqueue to drain upon + * resume. + */ + sas_resume_ha_no_sync(sha); clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
return 0; diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 23f8d34ccb0d..c13f9f8a1d2e 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -384,7 +384,7 @@ static int phys_suspended(struct sas_ha_struct *ha) return rc; }
-void sas_resume_ha(struct sas_ha_struct *ha) +static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain) { const unsigned long tmo = msecs_to_jiffies(25000); int i; @@ -414,10 +414,23 @@ void sas_resume_ha(struct sas_ha_struct *ha) * flush out disks that did not return */ scsi_unblock_requests(ha->core.shost); - sas_drain_work(ha); + if (drain) + sas_drain_work(ha); +} + +void sas_resume_ha(struct sas_ha_struct *ha) +{ + _sas_resume_ha(ha, true); } EXPORT_SYMBOL(sas_resume_ha);
+/* A no-sync variant, which does not call sas_drain_ha(). */ +void sas_resume_ha_no_sync(struct sas_ha_struct *ha) +{ + _sas_resume_ha(ha, false); +} +EXPORT_SYMBOL(sas_resume_ha_no_sync); + void sas_suspend_ha(struct sas_ha_struct *ha) { int i; diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index 79e4903bd414..a795a2d9e5b1 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -660,6 +660,7 @@ extern int sas_register_ha(struct sas_ha_struct *); extern int sas_unregister_ha(struct sas_ha_struct *); extern void sas_prep_resume_ha(struct sas_ha_struct *sas_ha); extern void sas_resume_ha(struct sas_ha_struct *sas_ha); +extern void sas_resume_ha_no_sync(struct sas_ha_struct *sas_ha); extern void sas_suspend_ha(struct sas_ha_struct *sas_ha);
int sas_set_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates);
From: John Garry john.garry@huawei.com
mainline inclusion from mainline-v5.17-rc1 commit 6cc739087784160eff296c7fbd7a95b209f44ba5 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
This reverts commit b14a37e011d829404c29a5ae17849d7efb034893.
In that commit, we had to filter out phy-up events during suspend, as it work cause a deadlock between processing the phyup event and the resume HA function try to drain the HA event workqueue to complete the resume process.
Now that we no longer try to drain the HA event queue during the HA resume processor, the deadlock would not occur, so remove the special handling for it.
Link: https://lore.kernel.org/r/1639999298-244569-3-git-send-email-chenxiang66@his... Signed-off-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/hisi_sas/hisi_sas_main.c | 6 ------ 1 file changed, 6 deletions(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 646bf00482bb..26d737004226 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -619,12 +619,6 @@ static void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no, if (!phy->phy_attached) return;
- if (test_bit(HISI_SAS_PM_BIT, &hisi_hba->flags) && - !sas_phy->suspended) { - dev_warn(hisi_hba->dev, "phy%d during suspend filtered out\n", phy_no); - return; - } - sas_notify_phy_event(sas_phy, PHYE_OOB_DONE, gfp_flags);
if (sas_phy->phy) {
From: Alan Stern stern@rowland.harvard.edu
mainline inclusion from mainline-v5.17-rc1 commit 6e1fcab00a23f7fe9f4fe9704905a790efa1eeab category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
John Garry reported a deadlock that occurs when trying to access a runtime-suspended SATA device. For obscure reasons, the rescan procedure causes the link to be hard-reset, which disconnects the device.
The rescan tries to carry out a runtime resume when accessing the device. scsi_rescan_device() holds the SCSI device lock and won't release it until it can put commands onto the device's block queue. This can't happen until the queue is successfully runtime-resumed or the device is unregistered. But the runtime resume fails because the device is disconnected, and __scsi_remove_device() can't do the unregistration because it can't get the device lock.
The best way to resolve this deadlock appears to be to allow the block queue to start running again even after an unsuccessful runtime resume. The idea is that the driver or the SCSI error handler will need to be able to use the queue to resolve the runtime resume failure.
This patch removes the err argument to blk_post_runtime_resume() and makes the routine act as though the resume was successful always. This fixes the deadlock.
Link: https://lore.kernel.org/r/1639999298-244569-4-git-send-email-chenxiang66@his... Fixes: e27829dc92e5 ("scsi: serialize ->rescan against ->remove") Reported-and-tested-by: John Garry john.garry@huawei.com Reviewed-by: Bart Van Assche bvanassche@acm.org Signed-off-by: Alan Stern stern@rowland.harvard.edu Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- block/blk-pm.c | 22 +++++++--------------- drivers/scsi/scsi_pm.c | 2 +- include/linux/blk-pm.h | 2 +- 3 files changed, 9 insertions(+), 17 deletions(-)
diff --git a/block/blk-pm.c b/block/blk-pm.c index 17bd020268d4..2dad62cc1572 100644 --- a/block/blk-pm.c +++ b/block/blk-pm.c @@ -163,27 +163,19 @@ EXPORT_SYMBOL(blk_pre_runtime_resume); /** * blk_post_runtime_resume - Post runtime resume processing * @q: the queue of the device - * @err: return value of the device's runtime_resume function * * Description: - * Update the queue's runtime status according to the return value of the - * device's runtime_resume function. If the resume was successful, call - * blk_set_runtime_active() to do the real work of restarting the queue. + * For historical reasons, this routine merely calls blk_set_runtime_active() + * to do the real work of restarting the queue. It does this regardless of + * whether the device's runtime-resume succeeded; even if it failed the + * driver or error handler will need to communicate with the device. * * This function should be called near the end of the device's * runtime_resume callback. */ -void blk_post_runtime_resume(struct request_queue *q, int err) +void blk_post_runtime_resume(struct request_queue *q) { - if (!q->dev) - return; - if (!err) { - blk_set_runtime_active(q); - } else { - spin_lock_irq(&q->queue_lock); - q->rpm_status = RPM_SUSPENDED; - spin_unlock_irq(&q->queue_lock); - } + blk_set_runtime_active(q); } EXPORT_SYMBOL(blk_post_runtime_resume);
@@ -201,7 +193,7 @@ EXPORT_SYMBOL(blk_post_runtime_resume); * runtime PM status and re-enable peeking requests from the queue. It * should be called before first request is added to the queue. * - * This function is also called by blk_post_runtime_resume() for successful + * This function is also called by blk_post_runtime_resume() for * runtime resumes. It does everything necessary to restart the queue. */ void blk_set_runtime_active(struct request_queue *q) diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index 3717eea37ecb..e91a0a5bc7a3 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -262,7 +262,7 @@ static int sdev_runtime_resume(struct device *dev) blk_pre_runtime_resume(sdev->request_queue); if (pm && pm->runtime_resume) err = pm->runtime_resume(dev); - blk_post_runtime_resume(sdev->request_queue, err); + blk_post_runtime_resume(sdev->request_queue);
return err; } diff --git a/include/linux/blk-pm.h b/include/linux/blk-pm.h index b80c65aba249..2580e05a8ab6 100644 --- a/include/linux/blk-pm.h +++ b/include/linux/blk-pm.h @@ -14,7 +14,7 @@ extern void blk_pm_runtime_init(struct request_queue *q, struct device *dev); extern int blk_pre_runtime_suspend(struct request_queue *q); extern void blk_post_runtime_suspend(struct request_queue *q, int err); extern void blk_pre_runtime_resume(struct request_queue *q); -extern void blk_post_runtime_resume(struct request_queue *q, int err); +extern void blk_post_runtime_resume(struct request_queue *q); extern void blk_set_runtime_active(struct request_queue *q); #else static inline void blk_pm_runtime_init(struct request_queue *q,
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit 42159d3c8d879e8d5fc225733f0cedc8baf19002 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
Most places that use asd_sas_port->phy_list in libsas are protected by spinlock asd_sas_port->phy_list_lock. However, there are still a few places which miss the lock. Add it in those places.
Link: https://lore.kernel.org/r/1639999298-244569-5-git-send-email-chenxiang66@his... Reviewed-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/libsas/sas_event.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index f703115e7a25..af605620ea13 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -104,11 +104,15 @@ void sas_enable_revalidation(struct sas_ha_struct *ha) if (!test_and_clear_bit(ev, &d->pending)) continue;
- if (list_empty(&port->phy_list)) + spin_lock(&port->phy_list_lock); + if (list_empty(&port->phy_list)) { + spin_unlock(&port->phy_list_lock); continue; + }
sas_phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el); + spin_unlock(&port->phy_list_lock); sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD, GFP_KERNEL); }
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit 29e2bac87421c613782ccb510c76c5efbecac0cf category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
Most places that use asd_sas_port->phy_list are protected by spinlock asd_sas_port->phy_list_lock, however there are still some places which miss grabbing the lock. Add it in function hisi_sas_refresh_port_id() when accessing asd_sas_port->phy_list. This carries a risk that list mutates while at the same time dropping the lock in function hisi_sas_send_ata_reset_each_phy(). Read asd_sas_port->phy_mask instead of accessing asd_sas_port->phy_list to avoid this risk.
Link: https://lore.kernel.org/r/1639999298-244569-6-git-send-email-chenxiang66@his... Acked-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/hisi_sas/hisi_sas_main.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 26d737004226..65a81971530b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1427,11 +1427,13 @@ static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba) sas_port = device->port; port = to_hisi_sas_port(sas_port);
+ spin_lock(&sas_port->phy_list_lock); list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el) if (state & BIT(sas_phy->id)) { phy = sas_phy->lldd_phy; break; } + spin_unlock(&sas_port->phy_list_lock);
if (phy) { port->id = phy->port_id; @@ -1508,22 +1510,25 @@ static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba, struct ata_link *link; u8 fis[20] = {0}; u32 state; + int i;
state = hisi_hba->hw->get_phys_state(hisi_hba); - list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el) { + for (i = 0; i < hisi_hba->n_phy; i++) { if (!(state & BIT(sas_phy->id))) continue; + if (!(sas_port->phy_mask & BIT(i))) + continue;
ata_for_each_link(link, ap, EDGE) { int pmp = sata_srst_pmp(link);
- tmf_task.phy_id = sas_phy->id; + tmf_task.phy_id = i; hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis); rc = hisi_sas_exec_internal_tmf_task(device, fis, s, &tmf_task); if (rc != TMF_RESP_FUNC_COMPLETE) { dev_err(dev, "phy%d ata reset failed rc=%d\n", - sas_phy->id, rc); + i, rc); break; } }
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit 133b688b2d03f7ae2a6c9d344f92c1949ec05a51 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
phy_list_lock is not held when using asd_sas_port->phy_list in the mvsas driver. Add spin_lock/unlock in those places.
Link: https://lore.kernel.org/r/1639999298-244569-7-git-send-email-chenxiang66@his... Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/mvsas/mv_sas.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 31d1ea5a5dd2..1e52bc7febfa 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -67,8 +67,10 @@ static struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev)
while (sha->sas_port[i]) { if (sha->sas_port[i] == dev->port) { + spin_lock(&sha->sas_port[i]->phy_list_lock); phy = container_of(sha->sas_port[i]->phy_list.next, struct asd_sas_phy, port_phy_el); + spin_unlock(&sha->sas_port[i]->phy_list_lock); j = 0; while (sha->sas_phy[j]) { if (sha->sas_phy[j] == phy) @@ -96,6 +98,8 @@ static int mvs_find_dev_phyno(struct domain_device *dev, int *phyno) while (sha->sas_port[i]) { if (sha->sas_port[i] == dev->port) { struct asd_sas_phy *phy; + + spin_lock(&sha->sas_port[i]->phy_list_lock); list_for_each_entry(phy, &sha->sas_port[i]->phy_list, port_phy_el) { j = 0; @@ -109,6 +113,7 @@ static int mvs_find_dev_phyno(struct domain_device *dev, int *phyno) num++; n++; } + spin_unlock(&sha->sas_port[i]->phy_list_lock); break; } i++;
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit e31e18128eb9dbcda8c169cb33421ae4813afa71 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
If a new disk is inserted through an expander when the host was suspended, it will not necessarily be detected as the topology is not re-scanned during resume. To detect possible changes in topology during suspension, insert a PORTE_BROADCAST_RCVD event per port when resuming to trigger a revalidation.
Link: https://lore.kernel.org/r/1639999298-244569-8-git-send-email-chenxiang66@his... Reviewed-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/libsas/sas_init.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index c13f9f8a1d2e..a66d50b5426c 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -384,6 +384,30 @@ static int phys_suspended(struct sas_ha_struct *ha) return rc; }
+static void sas_resume_insert_broadcast_ha(struct sas_ha_struct *ha) +{ + int i; + + for (i = 0; i < ha->num_phys; i++) { + struct asd_sas_port *port = ha->sas_port[i]; + struct domain_device *dev = port->port_dev; + + if (dev && dev_is_expander(dev->dev_type)) { + struct asd_sas_phy *first_phy; + + spin_lock(&port->phy_list_lock); + first_phy = list_first_entry_or_null( + &port->phy_list, struct asd_sas_phy, + port_phy_el); + spin_unlock(&port->phy_list_lock); + + if (first_phy) + sas_notify_port_event(first_phy, + PORTE_BROADCAST_RCVD, GFP_KERNEL); + } + } +} + static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain) { const unsigned long tmo = msecs_to_jiffies(25000); @@ -416,6 +440,11 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain) scsi_unblock_requests(ha->core.shost); if (drain) sas_drain_work(ha); + + /* send event PORTE_BROADCAST_RCVD to identify some new inserted + * disks for expander + */ + sas_resume_insert_broadcast_ha(ha); }
void sas_resume_ha(struct sas_ha_struct *ha)
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit 97f4100939844a6381ba61b99d6d2b1f2fccb79f category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
Add some logs at the beginning and end of suspend/resume.
Link: https://lore.kernel.org/r/1639999298-244569-9-git-send-email-chenxiang66@his... Acked-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 5b4168adfcc8..df3c8f2707a4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4899,6 +4899,8 @@ static int _suspend_v3_hw(struct device *device) if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) return -1;
+ dev_warn(dev, "entering suspend state\n"); + scsi_block_requests(shost); set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); flush_workqueue(hisi_hba->wq); @@ -4914,11 +4916,11 @@ static int _suspend_v3_hw(struct device *device)
hisi_sas_init_mem(hisi_hba);
- dev_warn(dev, "entering suspend state\n"); - hisi_sas_release_tasks(hisi_hba);
sas_suspend_ha(sha); + + dev_warn(dev, "end of suspending controller\n"); return 0; }
@@ -4956,6 +4958,8 @@ static int _resume_v3_hw(struct device *device) sas_resume_ha_no_sync(sha); clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
+ dev_warn(dev, "end of resuming controller\n"); + return 0; }
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit 0da7ca4c4fd95d70d473dc07488ad94ba3ee9b82 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
When sending SMP I/Os to the host we need to ensure that the host is not suspended and can process the commands. This is a better approach than replying on the host to resume itself to handle such commands. Use pm_runtime_get_sync() and pm_runtime_put_sync() calls for the host when executing SMP I/Os.
Link: https://lore.kernel.org/r/1639999298-244569-10-git-send-email-chenxiang66@hi... Reviewed-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/libsas/sas_expander.c | 3 +++ drivers/scsi/libsas/sas_internal.h | 1 + 2 files changed, 4 insertions(+)
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index f5bf74f278be..2128992bc2f5 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -58,7 +58,9 @@ static int smp_execute_task_sg(struct domain_device *dev, struct sas_task *task = NULL; struct sas_internal *i = to_sas_internal(dev->port->ha->core.shost->transportt); + struct sas_ha_struct *ha = dev->port->ha;
+ pm_runtime_get_sync(ha->dev); mutex_lock(&dev->ex_dev.cmd_mutex); for (retry = 0; retry < 3; retry++) { if (test_bit(SAS_DEV_GONE, &dev->state)) { @@ -131,6 +133,7 @@ static int smp_execute_task_sg(struct domain_device *dev, } } mutex_unlock(&dev->ex_dev.cmd_mutex); + pm_runtime_put_sync(ha->dev);
BUG_ON(retry == 3 && task != NULL); sas_free_task(task); diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index d7a1fb5c10c6..ad9764a976c3 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -14,6 +14,7 @@ #include <scsi/scsi_transport_sas.h> #include <scsi/libsas.h> #include <scsi/sas_ata.h> +#include <linux/pm_runtime.h>
#ifdef pr_fmt #undef pr_fmt
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit 4ea775abbb5c50c26edbf043d5a2ae7fde407f4a category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
Add a flag SAS_HA_RESUMING and use it to indicate the state of resuming the host controller.
Link: https://lore.kernel.org/r/1639999298-244569-11-git-send-email-chenxiang66@hi... Reviewed-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/libsas/sas_init.c | 2 ++ include/scsi/libsas.h | 1 + 2 files changed, 3 insertions(+)
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index a66d50b5426c..f85a36e10e7f 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -359,6 +359,7 @@ void sas_prep_resume_ha(struct sas_ha_struct *ha) int i;
set_bit(SAS_HA_REGISTERED, &ha->state); + set_bit(SAS_HA_RESUMING, &ha->state);
/* clear out any stale link events/data from the suspension path */ for (i = 0; i < ha->num_phys; i++) { @@ -440,6 +441,7 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain) scsi_unblock_requests(ha->core.shost); if (drain) sas_drain_work(ha); + clear_bit(SAS_HA_RESUMING, &ha->state);
/* send event PORTE_BROADCAST_RCVD to identify some new inserted * disks for expander diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index a795a2d9e5b1..698f2032807b 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -356,6 +356,7 @@ enum sas_ha_state { SAS_HA_DRAINING, SAS_HA_ATA_EH_ACTIVE, SAS_HA_FROZEN, + SAS_HA_RESUMING, };
struct sas_ha_struct {
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit 1bc35475c6bf6d078b3800e516978f37c1ecda36 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
In the second part of function __sas_drain_work(), deferred work is queued. This functionality is required other places so factor it out into the function sas_queue_deferred_work().
Link: https://lore.kernel.org/r/1639999298-244569-12-git-send-email-chenxiang66@hi... Reviewed-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/libsas/sas_event.c | 25 ++++++++++++++----------- drivers/scsi/libsas/sas_internal.h | 1 + 2 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index af605620ea13..01e544ca518a 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -41,12 +41,23 @@ static int sas_queue_event(int event, struct sas_work *work, return rc; }
- -void __sas_drain_work(struct sas_ha_struct *ha) +void sas_queue_deferred_work(struct sas_ha_struct *ha) { struct sas_work *sw, *_sw; int ret;
+ spin_lock_irq(&ha->lock); + list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { + list_del_init(&sw->drain_node); + ret = sas_queue_work(ha, sw); + if (ret != 1) + sas_free_event(to_asd_sas_event(&sw->work)); + } + spin_unlock_irq(&ha->lock); +} + +void __sas_drain_work(struct sas_ha_struct *ha) +{ set_bit(SAS_HA_DRAINING, &ha->state); /* flush submitters */ spin_lock_irq(&ha->lock); @@ -55,16 +66,8 @@ void __sas_drain_work(struct sas_ha_struct *ha) drain_workqueue(ha->event_q); drain_workqueue(ha->disco_q);
- spin_lock_irq(&ha->lock); clear_bit(SAS_HA_DRAINING, &ha->state); - list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { - list_del_init(&sw->drain_node); - ret = sas_queue_work(ha, sw); - if (ret != 1) - sas_free_event(to_asd_sas_event(&sw->work)); - - } - spin_unlock_irq(&ha->lock); + sas_queue_deferred_work(ha); }
int sas_drain_work(struct sas_ha_struct *ha) diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h index ad9764a976c3..acd515c01861 100644 --- a/drivers/scsi/libsas/sas_internal.h +++ b/drivers/scsi/libsas/sas_internal.h @@ -57,6 +57,7 @@ void sas_unregister_ports(struct sas_ha_struct *sas_ha);
void sas_disable_revalidation(struct sas_ha_struct *ha); void sas_enable_revalidation(struct sas_ha_struct *ha); +void sas_queue_deferred_work(struct sas_ha_struct *ha); void __sas_drain_work(struct sas_ha_struct *ha);
void sas_deform_port(struct asd_sas_phy *phy, int gone);
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit bf19aea4607cb5f4a652ab70d8d8035a72a6b8da category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
During the processing of event PORT_BYTES_DMAED, the driver queues work DISCE_DISCOVER_DOMAIN and then flushes workqueue ha->disco_q. If a new phyup event occurs during resuming the controller, the work PORTE_BYTES_DMAED of new phy occurs before suspended phy's. The work DISCE_DISCOVER_DOMAIN of new phy requires an active SAS controller (it needs to resume SAS controller by function scsi_sysfs_add_sdev() and some other functions such as function add_device_link()). However, the activation of the SAS controller requires completion of work PORTE_BYTES_DMAED of suspended phys while it is blocked by new phy's work on ha->event_q. So there is a deadlock and it is released only after resume timeout.
To solve the issue, defer works of new phys during suspend and queue those defer works after SAS controller becomes active.
Link: https://lore.kernel.org/r/1639999298-244569-13-git-send-email-chenxiang66@hi... Reviewed-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/libsas/sas_event.c | 24 ++++++++++++++++++++++++ drivers/scsi/libsas/sas_init.c | 1 + 2 files changed, 25 insertions(+)
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index 01e544ca518a..626ef96b9348 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -139,6 +139,24 @@ static void sas_phy_event_worker(struct work_struct *work) sas_free_event(ev); }
+/* defer works of new phys during suspend */ +static bool sas_defer_event(struct asd_sas_phy *phy, struct asd_sas_event *ev) +{ + struct sas_ha_struct *ha = phy->ha; + unsigned long flags; + bool deferred = false; + + spin_lock_irqsave(&ha->lock, flags); + if (test_bit(SAS_HA_RESUMING, &ha->state) && !phy->suspended) { + struct sas_work *sw = &ev->work; + + list_add_tail(&sw->drain_node, &ha->defer_q); + deferred = true; + } + spin_unlock_irqrestore(&ha->lock, flags); + return deferred; +} + int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event, gfp_t gfp_flags) { @@ -154,6 +172,9 @@ int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event,
INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event);
+ if (sas_defer_event(phy, ev)) + return 0; + ret = sas_queue_event(event, &ev->work, ha); if (ret != 1) sas_free_event(ev); @@ -177,6 +198,9 @@ int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event,
INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event);
+ if (sas_defer_event(phy, ev)) + return 0; + ret = sas_queue_event(event, &ev->work, ha); if (ret != 1) sas_free_event(ev); diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index f85a36e10e7f..f1989a98f511 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -443,6 +443,7 @@ static void _sas_resume_ha(struct sas_ha_struct *ha, bool drain) sas_drain_work(ha); clear_bit(SAS_HA_RESUMING, &ha->state);
+ sas_queue_deferred_work(ha); /* send event PORTE_BROADCAST_RCVD to identify some new inserted * disks for expander */
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit ae9b69e85eb7ecb32ddce7c04a10a3c69ad60e52 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
It is possible that controller may become suspended between processing a phyup interrupt and the event being processed by libsas. As such, we can't ensure the controller is active when processing the phyup event - this may cause the phyup event to be lost or other issues. To avoid any possible issues, add pm_runtime_get_noresume() in phyup interrupt handler and pm_runtime_put_sync() in the work handler exit to ensure that we stay always active. Since we only want to call pm_runtime_get_noresume() for v3 hw, signal this will a new event, HISI_PHYE_PHY_UP_PM.
Link: https://lore.kernel.org/r/1639999298-244569-14-git-send-email-chenxiang66@hi... Acked-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 22 ++++++++++++++++++++-- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 4 +++- 3 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 06b1392bb487..679e38be439a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -154,6 +154,7 @@ enum hisi_sas_bit_err_type { enum hisi_sas_phy_event { HISI_PHYE_PHY_UP = 0U, HISI_PHYE_LINK_RESET, + HISI_PHYE_PHY_UP_PM, HISI_PHYES_NUM, };
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 65a81971530b..4cbe8711b6d4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -854,10 +854,11 @@ int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time) } EXPORT_SYMBOL_GPL(hisi_sas_scan_finished);
-static void hisi_sas_phyup_work(struct work_struct *work) +static void hisi_sas_phyup_work_common(struct work_struct *work, + enum hisi_sas_phy_event event) { struct hisi_sas_phy *phy = - container_of(work, typeof(*phy), works[HISI_PHYE_PHY_UP]); + container_of(work, typeof(*phy), works[event]); struct hisi_hba *hisi_hba = phy->hisi_hba; struct asd_sas_phy *sas_phy = &phy->sas_phy; int phy_no = sas_phy->id; @@ -868,6 +869,11 @@ static void hisi_sas_phyup_work(struct work_struct *work) hisi_sas_bytes_dmaed(hisi_hba, phy_no, GFP_KERNEL); }
+static void hisi_sas_phyup_work(struct work_struct *work) +{ + hisi_sas_phyup_work_common(work, HISI_PHYE_PHY_UP); +} + static void hisi_sas_linkreset_work(struct work_struct *work) { struct hisi_sas_phy *phy = @@ -877,9 +883,21 @@ static void hisi_sas_linkreset_work(struct work_struct *work) hisi_sas_control_phy(sas_phy, PHY_FUNC_LINK_RESET, NULL); }
+static void hisi_sas_phyup_pm_work(struct work_struct *work) +{ + struct hisi_sas_phy *phy = + container_of(work, typeof(*phy), works[HISI_PHYE_PHY_UP_PM]); + struct hisi_hba *hisi_hba = phy->hisi_hba; + struct device *dev = hisi_hba->dev; + + hisi_sas_phyup_work_common(work, HISI_PHYE_PHY_UP_PM); + pm_runtime_put_sync(dev); +} + static const work_func_t hisi_sas_phye_fns[HISI_PHYES_NUM] = { [HISI_PHYE_PHY_UP] = hisi_sas_phyup_work, [HISI_PHYE_LINK_RESET] = hisi_sas_linkreset_work, + [HISI_PHYE_PHY_UP_PM] = hisi_sas_phyup_pm_work, };
bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy, diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index df3c8f2707a4..380abd19fac6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1559,7 +1559,9 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba)
phy->port_id = port_id; phy->phy_attached = 1; - hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP); + /* Call pm_runtime_put_sync() with pairs in hisi_sas_phyup_pm_work() */ + pm_runtime_get_noresume(dev); + hisi_sas_notify_phy_event(phy, HISI_PHYE_PHY_UP_PM); res = IRQ_HANDLED; end: if (phy->reset_completion)
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit 307d9f49cce966c2ba969f58bd6227bc0092afaa category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
Processing events such as PORTE_BROADCAST_RCVD may cause dependency issues for runtime power management support. Such a problem would be that handling a PORTE_BROADCAST_RCVD event requires that the host is resumed to send SMP commands. However, in resuming the host, the phyup events generated from re-enabling the phys are processed in the same workqueue as the original PORTE_BROADCAST_RCVD event. As such, the host will never finish resuming (as it waits for the phyup event processing), and then the PORTE_BROADCAST_RCVD event can't be processed as the SMP commands are blocked, and so we have a deadlock. Solve this problem by ensuring that libsas keeps the host active until completely finished phy or port events, such as PORTE_BYTES_DMAED. As such, we don't have to worry about resuming the host for processing individual SMP commands in this example.
Link: https://lore.kernel.org/r/1639999298-244569-15-git-send-email-chenxiang66@hi... Reviewed-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/libsas/sas_event.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c index 626ef96b9348..3613b9b315bc 100644 --- a/drivers/scsi/libsas/sas_event.c +++ b/drivers/scsi/libsas/sas_event.c @@ -50,8 +50,10 @@ void sas_queue_deferred_work(struct sas_ha_struct *ha) list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { list_del_init(&sw->drain_node); ret = sas_queue_work(ha, sw); - if (ret != 1) + if (ret != 1) { + pm_runtime_put(ha->dev); sas_free_event(to_asd_sas_event(&sw->work)); + } } spin_unlock_irq(&ha->lock); } @@ -126,16 +128,22 @@ void sas_enable_revalidation(struct sas_ha_struct *ha) static void sas_port_event_worker(struct work_struct *work) { struct asd_sas_event *ev = to_asd_sas_event(work); + struct asd_sas_phy *phy = ev->phy; + struct sas_ha_struct *ha = phy->ha;
sas_port_event_fns[ev->event](work); + pm_runtime_put(ha->dev); sas_free_event(ev); }
static void sas_phy_event_worker(struct work_struct *work) { struct asd_sas_event *ev = to_asd_sas_event(work); + struct asd_sas_phy *phy = ev->phy; + struct sas_ha_struct *ha = phy->ha;
sas_phy_event_fns[ev->event](work); + pm_runtime_put(ha->dev); sas_free_event(ev); }
@@ -170,14 +178,19 @@ int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event, if (!ev) return -ENOMEM;
+ /* Call pm_runtime_put() with pairs in sas_port_event_worker() */ + pm_runtime_get_noresume(ha->dev); + INIT_SAS_EVENT(ev, sas_port_event_worker, phy, event);
if (sas_defer_event(phy, ev)) return 0;
ret = sas_queue_event(event, &ev->work, ha); - if (ret != 1) + if (ret != 1) { + pm_runtime_put(ha->dev); sas_free_event(ev); + }
return ret; } @@ -196,14 +209,19 @@ int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event, if (!ev) return -ENOMEM;
+ /* Call pm_runtime_put() with pairs in sas_phy_event_worker() */ + pm_runtime_get_noresume(ha->dev); + INIT_SAS_EVENT(ev, sas_phy_event_worker, phy, event);
if (sas_defer_event(phy, ev)) return 0;
ret = sas_queue_event(event, &ev->work, ha); - if (ret != 1) + if (ret != 1) { + pm_runtime_put(ha->dev); sas_free_event(ev); + }
return ret; }
From: Xiang Chen chenxiang66@hisilicon.com
mainline inclusion from mainline-v5.17-rc1 commit b4cc09492263e07bad4fc4bf34fed3246fa95057 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I4ZHSV CVE: NA
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/dr...
--------------------------------
The controller may frequently enter and exit suspend for each I/O which we need to deal with. This is inefficient and may cause too much suspend and resume activity for the controller. To avoid this, use a default 5s autosuspend for the controller to stop frequently suspending and resuming. This value may still be modified via sysfs interfaces.
Link: https://lore.kernel.org/r/1639999298-244569-16-git-send-email-chenxiang66@hi... Acked-by: John Garry john.garry@huawei.com Signed-off-by: Xiang Chen chenxiang66@hisilicon.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com Signed-off-by: Fujai Ninifuijia1@hisilicon.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 380abd19fac6..16d00dbe094d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -4772,6 +4772,8 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id)
scsi_scan_host(shost);
+ pm_runtime_set_autosuspend_delay(dev, 5000); + pm_runtime_use_autosuspend(dev); /* * For the situation that there are ATA disks connected with SAS * controller, it additionally creates ata_port which will affect the
From: Trond Myklebust trond.myklebust@hammerspace.com
mainline inclusion from mainline-v5.18-rc2 commit f00432063db1a0db484e85193eccc6845435b80e category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I52Y3C CVE: CVE-2022-28893 backport: openEuler-22.03-LTS
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
We must ensure that all sockets are closed before we call xprt_free() and release the reference to the net namespace. The problem is that calling fput() will defer closing the socket until delayed_fput() gets called. Let's fix the situation by allowing rpciod and the transport teardown code (which runs on the system wq) to call __fput_sync(), and directly close the socket.
Reported-by: Felix Fu foyjog@gmail.com Acked-by: Al Viro viro@zeniv.linux.org.uk Fixes: a73881c96d73 ("SUNRPC: Fix an Oops in udp_poll()") Cc: stable@vger.kernel.org # 5.1.x: 3be232f11a3c: SUNRPC: Prevent immediate close+reconnect Cc: stable@vger.kernel.org # 5.1.x: 89f42494f92f: SUNRPC: Don't call connect() more than once on a TCP socket Cc: stable@vger.kernel.org # 5.1.x Signed-off-by: Trond Myklebust trond.myklebust@hammerspace.com Signed-off-by: Baisong Zhong zhongbaisong@huawei.com Reviewed-by: Wei Yongjun weiyongjun1@huawei.com Reviewed-by: Xiu Jianfeng xiujianfeng@huawei.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- fs/file_table.c | 1 + include/trace/events/sunrpc.h | 1 - net/sunrpc/xprt.c | 7 +------ net/sunrpc/xprtsock.c | 16 +++++++++++++--- 4 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/fs/file_table.c b/fs/file_table.c index 709ada3151da..7a3b4a7f6808 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -376,6 +376,7 @@ void __fput_sync(struct file *file) }
EXPORT_SYMBOL(fput); +EXPORT_SYMBOL(__fput_sync);
void __init files_init(void) { diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index 23db248a7fdb..9fe6cdcf2222 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -1006,7 +1006,6 @@ DEFINE_RPC_XPRT_LIFETIME_EVENT(connect); DEFINE_RPC_XPRT_LIFETIME_EVENT(disconnect_auto); DEFINE_RPC_XPRT_LIFETIME_EVENT(disconnect_done); DEFINE_RPC_XPRT_LIFETIME_EVENT(disconnect_force); -DEFINE_RPC_XPRT_LIFETIME_EVENT(disconnect_cleanup); DEFINE_RPC_XPRT_LIFETIME_EVENT(destroy);
DECLARE_EVENT_CLASS(rpc_xprt_event, diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index cdf5cc67a005..5c8c5b38faf1 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -907,12 +907,7 @@ void xprt_connect(struct rpc_task *task) if (!xprt_lock_write(xprt, task)) return;
- if (test_and_clear_bit(XPRT_CLOSE_WAIT, &xprt->state)) { - trace_xprt_disconnect_cleanup(xprt); - xprt->ops->close(xprt); - } - - if (!xprt_connected(xprt)) { + if (!xprt_connected(xprt) && !test_bit(XPRT_CLOSE_WAIT, &xprt->state)) { task->tk_rqstp->rq_connect_cookie = xprt->connect_cookie; rpc_sleep_on_timeout(&xprt->pending, task, NULL, xprt_request_timeout(task->tk_rqstp)); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 16c7758e7bf3..b7c262f6d555 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -847,7 +847,7 @@ static int xs_local_send_request(struct rpc_rqst *req)
/* Close the stream if the previous transmission was incomplete */ if (xs_send_request_was_aborted(transport, req)) { - xs_close(xprt); + xprt_force_disconnect(xprt); return -ENOTCONN; }
@@ -885,7 +885,7 @@ static int xs_local_send_request(struct rpc_rqst *req) -status); fallthrough; case -EPIPE: - xs_close(xprt); + xprt_force_disconnect(xprt); status = -ENOTCONN; }
@@ -1167,6 +1167,16 @@ static void xs_reset_transport(struct sock_xprt *transport)
if (sk == NULL) return; + /* + * Make sure we're calling this in a context from which it is safe + * to call __fput_sync(). In practice that means rpciod and the + * system workqueue. + */ + if (!(current->flags & PF_WQ_WORKER)) { + WARN_ON_ONCE(1); + set_bit(XPRT_CLOSE_WAIT, &xprt->state); + return; + }
if (atomic_read(&transport->xprt.swapper)) sk_clear_memalloc(sk); @@ -1190,7 +1200,7 @@ static void xs_reset_transport(struct sock_xprt *transport) mutex_unlock(&transport->recv_mutex);
trace_rpc_socket_close(xprt, sock); - fput(filp); + __fput_sync(filp);
xprt_disconnect_done(xprt); }