From: Huajingjing huajingjing1@huawei.com
driver inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I67J42 CVE: NA
-------------------------------------------------
The BMA software is a system management software offered by Huawei. It supports the status monitoring, performance monitoring and event monitoring of various components, including server CPUs, memory hard disks, NICs, IB cards, PCIe cards, RAID controller cards and optical modules.
In this version, the system resets due to the BMA spin lock when the memory usage is too high, the vulnerability has been rectified.
Signed-off-by: Hua Jingjing huajingjingjing1@huawei.com Reviewed-by: Chen Jiesong chenjiesong@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- .../ethernet/huawei/bma/cdev_drv/bma_cdev.c | 2 +- .../huawei/bma/edma_drv/bma_devintf.c | 110 +++++++++++------- .../ethernet/huawei/bma/edma_drv/bma_pci.h | 2 +- .../huawei/bma/kbox_drv/kbox_include.h | 2 +- .../ethernet/huawei/bma/kbox_drv/kbox_panic.c | 4 +- .../huawei/bma/kbox_drv/kbox_printk.c | 4 +- .../huawei/bma/kbox_drv/kbox_ram_op.c | 2 +- .../ethernet/huawei/bma/veth_drv/veth_hb.c | 7 +- .../ethernet/huawei/bma/veth_drv/veth_hb.h | 2 +- 9 files changed, 81 insertions(+), 54 deletions(-)
diff --git a/drivers/net/ethernet/huawei/bma/cdev_drv/bma_cdev.c b/drivers/net/ethernet/huawei/bma/cdev_drv/bma_cdev.c index 0348a83005d6..9468a5a0c768 100644 --- a/drivers/net/ethernet/huawei/bma/cdev_drv/bma_cdev.c +++ b/drivers/net/ethernet/huawei/bma/cdev_drv/bma_cdev.c @@ -28,7 +28,7 @@ #ifdef DRV_VERSION #define CDEV_VERSION MICRO_TO_STR(DRV_VERSION) #else -#define CDEV_VERSION "0.3.4" +#define CDEV_VERSION "0.3.5" #endif
#define CDEV_DEFAULT_NUM 4 diff --git a/drivers/net/ethernet/huawei/bma/edma_drv/bma_devintf.c b/drivers/net/ethernet/huawei/bma/edma_drv/bma_devintf.c index 7817f58f8635..556130ab8a65 100644 --- a/drivers/net/ethernet/huawei/bma/edma_drv/bma_devintf.c +++ b/drivers/net/ethernet/huawei/bma/edma_drv/bma_devintf.c @@ -419,8 +419,10 @@ EXPORT_SYMBOL(bma_intf_int_to_bmc);
int bma_intf_is_link_ok(void) { - return (g_bma_dev->edma_host.statistics.remote_status == - REGISTERED) ? 1 : 0; + if ((&g_bma_dev->edma_host != NULL) && + (g_bma_dev->edma_host.statistics.remote_status == REGISTERED)) + return 1; + return 0; } EXPORT_SYMBOL(bma_intf_is_link_ok);
@@ -460,14 +462,10 @@ int bma_cdev_recv_msg(void *handle, char __user *data, size_t count) } EXPORT_SYMBOL_GPL(bma_cdev_recv_msg);
-int bma_cdev_add_msg(void *handle, const char __user *msg, size_t msg_len) +static int check_cdev_add_msg_param(struct bma_priv_data_s *handle, +const char __user *msg, size_t msg_len) { struct bma_priv_data_s *priv = NULL; - struct edma_msg_hdr_s *hdr = NULL; - unsigned long flags = 0; - int total_len = 0; - int ret = 0; - struct edma_host_s *phost = &g_bma_dev->edma_host;
if (!handle || !msg || msg_len == 0) { BMA_LOG(DLOG_DEBUG, "input NULL point!\n"); @@ -479,54 +477,80 @@ int bma_cdev_add_msg(void *handle, const char __user *msg, size_t msg_len) return -EINVAL; }
- priv = (struct bma_priv_data_s *)handle; + priv = handle;
if (priv->user.type >= TYPE_MAX) { BMA_LOG(DLOG_DEBUG, "error type = %d\n", priv->user.type); return -EFAULT; } - total_len = SIZE_OF_MSG_HDR + msg_len; + + return 0; +} + +static void edma_msg_hdr_init(struct edma_msg_hdr_s *hdr, + struct bma_priv_data_s *private_data, + char *msg_buf, size_t msg_len) +{ + hdr->type = private_data->user.type; + hdr->sub_type = private_data->user.sub_type; + hdr->user_id = private_data->user.user_id; + hdr->datalen = msg_len; + BMA_LOG(DLOG_DEBUG, "msg_len is %ld\n", msg_len); + + memcpy(hdr->data, msg_buf, msg_len); +} + +int bma_cdev_add_msg(void *handle, const char __user *msg, size_t msg_len) +{ + struct bma_priv_data_s *priv = NULL; + struct edma_msg_hdr_s *hdr = NULL; + unsigned long flags = 0; + unsigned int total_len = 0; + int ret = 0; + struct edma_host_s *phost = &g_bma_dev->edma_host; + char *msg_buf = NULL; + + ret = check_cdev_add_msg_param(handle, msg, msg_len); + if (ret != 0) + return ret; + + priv = (struct bma_priv_data_s *)handle; + + total_len = (unsigned int)(SIZE_OF_MSG_HDR + msg_len); + if (phost->msg_send_write + total_len > HOST_MAX_SEND_MBX_LEN - SIZE_OF_MBX_HDR) { + BMA_LOG(DLOG_DEBUG, "msg lost,msg_send_write: %u,msg_len:%u,max_len: %d\n", + phost->msg_send_write, total_len, HOST_MAX_SEND_MBX_LEN); + return -ENOSPC; + } + + msg_buf = (char *)kmalloc(msg_len, GFP_KERNEL); + if (!msg_buf) { + BMA_LOG(DLOG_ERROR, "malloc msg_buf failed\n"); + return -ENOMEM; + } + + if (copy_from_user(msg_buf, msg, msg_len)) { + BMA_LOG(DLOG_ERROR, "copy_from_user error\n"); + kfree(msg_buf); + return -EFAULT; + }
spin_lock_irqsave(&phost->send_msg_lock, flags);
- if (phost->msg_send_write + total_len <= - HOST_MAX_SEND_MBX_LEN - SIZE_OF_MBX_HDR) { - hdr = (struct edma_msg_hdr_s *)(phost->msg_send_buf + - phost->msg_send_write); - hdr->type = priv->user.type; - hdr->sub_type = priv->user.sub_type; - hdr->user_id = priv->user.user_id; - hdr->datalen = msg_len; - BMA_LOG(DLOG_DEBUG, "msg_len is %ld\n", msg_len); - - if (copy_from_user(hdr->data, msg, msg_len)) { - BMA_LOG(DLOG_ERROR, "copy_from_user error\n"); - ret = -EFAULT; - goto end; - } + hdr = (struct edma_msg_hdr_s *)(phost->msg_send_buf + phost->msg_send_write); + edma_msg_hdr_init(hdr, priv, msg_buf, msg_len);
- phost->msg_send_write += total_len; - phost->statistics.send_bytes += total_len; - phost->statistics.send_pkgs++; + phost->msg_send_write += total_len; + phost->statistics.send_bytes += total_len; + phost->statistics.send_pkgs++; #ifdef EDMA_TIMER - (void)mod_timer(&phost->timer, jiffies_64); + (void)mod_timer(&phost->timer, jiffies_64); #endif - BMA_LOG(DLOG_DEBUG, "msg_send_write = %d\n", - phost->msg_send_write); - - ret = msg_len; - goto end; - } else { - BMA_LOG(DLOG_DEBUG, - "msg lost,msg_send_write: %d,msg_len:%d,max_len: %d\n", - phost->msg_send_write, total_len, - HOST_MAX_SEND_MBX_LEN); - ret = -ENOSPC; - goto end; - } + BMA_LOG(DLOG_DEBUG, "msg_send_write = %d\n", phost->msg_send_write);
-end: + ret = msg_len; spin_unlock_irqrestore(&g_bma_dev->edma_host.send_msg_lock, flags); + kfree(msg_buf); return ret; } EXPORT_SYMBOL_GPL(bma_cdev_add_msg); diff --git a/drivers/net/ethernet/huawei/bma/edma_drv/bma_pci.h b/drivers/net/ethernet/huawei/bma/edma_drv/bma_pci.h index 2851e583666a..b6a0d11704a2 100644 --- a/drivers/net/ethernet/huawei/bma/edma_drv/bma_pci.h +++ b/drivers/net/ethernet/huawei/bma/edma_drv/bma_pci.h @@ -71,7 +71,7 @@ struct bma_pci_dev_s { #ifdef DRV_VERSION #define BMA_VERSION MICRO_TO_STR(DRV_VERSION) #else -#define BMA_VERSION "0.3.4" +#define BMA_VERSION "0.3.5" #endif
#ifdef CONFIG_ARM64 diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_include.h b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_include.h index ffadf3727734..b027306e52c1 100644 --- a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_include.h +++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_include.h @@ -23,7 +23,7 @@ #ifdef DRV_VERSION #define KBOX_VERSION MICRO_TO_STR(DRV_VERSION) #else -#define KBOX_VERSION "0.3.4" +#define KBOX_VERSION "0.3.5" #endif
#define UNUSED(x) (x = x) diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.c index 0c17cd2bae49..2b142ae9bff6 100644 --- a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.c +++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_panic.c @@ -135,7 +135,7 @@ int kbox_panic_init(void) int ret = KBOX_TRUE;
g_panic_info_buf = kmalloc(SLOT_LENGTH, GFP_KERNEL); - if (IS_ERR(g_panic_info_buf) || !g_panic_info_buf) { + if (!g_panic_info_buf) { KBOX_MSG("kmalloc g_panic_info_buf fail!\n"); ret = -ENOMEM; goto fail; @@ -144,7 +144,7 @@ int kbox_panic_init(void) memset(g_panic_info_buf, 0, SLOT_LENGTH);
g_panic_info_buf_tmp = kmalloc(SLOT_LENGTH, GFP_KERNEL); - if (IS_ERR(g_panic_info_buf_tmp) || !g_panic_info_buf_tmp) { + if (!g_panic_info_buf_tmp) { KBOX_MSG("kmalloc g_panic_info_buf_tmp fail!\n"); ret = -ENOMEM; goto fail; diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.c index 3b04ba206108..630a1e16ea24 100644 --- a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.c +++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_printk.c @@ -304,7 +304,7 @@ int kbox_printk_init(int kbox_proc_exist)
g_printk_info_buf = kmalloc(SECTION_PRINTK_LEN, GFP_KERNEL); - if (IS_ERR(g_printk_info_buf) || !g_printk_info_buf) { + if (!g_printk_info_buf) { KBOX_MSG("kmalloc g_printk_info_buf fail!\n"); ret = -ENOMEM; goto fail; @@ -314,7 +314,7 @@ int kbox_printk_init(int kbox_proc_exist)
g_printk_info_buf_tmp = kmalloc(SECTION_PRINTK_LEN, GFP_KERNEL); - if (IS_ERR(g_printk_info_buf_tmp) || !g_printk_info_buf_tmp) { + if (!g_printk_info_buf_tmp) { KBOX_MSG("kmalloc g_printk_info_buf_tmp fail!\n"); ret = -ENOMEM; goto fail; diff --git a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.c b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.c index 49690bab1cef..9f6dfe55e3fb 100644 --- a/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.c +++ b/drivers/net/ethernet/huawei/bma/kbox_drv/kbox_ram_op.c @@ -432,7 +432,7 @@ int kbox_write_op(long long offset, unsigned int count, return KBOX_FALSE;
temp_buf_char = kmalloc(TEMP_BUF_DATA_SIZE, GFP_KERNEL); - if (!temp_buf_char || IS_ERR(temp_buf_char)) { + if (!temp_buf_char) { KBOX_MSG("kmalloc temp_buf_char fail!\n"); up(&user_sem); return -ENOMEM; diff --git a/drivers/net/ethernet/huawei/bma/veth_drv/veth_hb.c b/drivers/net/ethernet/huawei/bma/veth_drv/veth_hb.c index 9681ce3bfc7b..e226582693b6 100644 --- a/drivers/net/ethernet/huawei/bma/veth_drv/veth_hb.c +++ b/drivers/net/ethernet/huawei/bma/veth_drv/veth_hb.c @@ -638,6 +638,7 @@ s32 veth_refill_rxskb(struct bspveth_rxtx_q *prx_queue, int queue) next_to_fill = (next_to_fill + 1) & BSPVETH_POINT_MASK; }
+ mb();/* memory barriers. */ prx_queue->next_to_fill = next_to_fill;
tail = prx_queue->tail; @@ -672,6 +673,7 @@ s32 bspveth_setup_rx_skb(struct bspveth_device *pvethdev, if (!idx) /* Can't alloc even one packets */ return -EFAULT;
+ mb();/* memory barriers. */ prx_queue->next_to_fill = idx;
VETH_LOG(DLOG_DEBUG, "prx_queue->next_to_fill=%d\n", @@ -886,8 +888,6 @@ s32 bspveth_setup_all_rx_resources(struct bspveth_device *pvethdev) err = bspveth_setup_rx_resources(pvethdev, pvethdev->prx_queue[qid]); if (err) { - kfree(pvethdev->prx_queue[qid]); - pvethdev->prx_queue[qid] = NULL; VETH_LOG(DLOG_ERROR, "Allocation for Rx Queue %u failed\n", qid);
@@ -1328,6 +1328,7 @@ s32 veth_send_one_pkt(struct sk_buff *skb, int queue) pbd_v->off = off; pbd_v->len = skb->len;
+ mb();/* memory barriers. */ head = (head + 1) & BSPVETH_POINT_MASK; ptx_queue->head = head;
@@ -1424,6 +1425,7 @@ s32 veth_free_txskb(struct bspveth_rxtx_q *ptx_queue, int queue) next_to_free = (next_to_free + 1) & BSPVETH_POINT_MASK; }
+ mb(); /* memory barriers. */ ptx_queue->next_to_free = next_to_free; tail = ptx_queue->tail;
@@ -1522,6 +1524,7 @@ s32 veth_recv_pkt(struct bspveth_rxtx_q *prx_queue, int queue) } }
+ mb();/* memory barriers. */ prx_queue->tail = tail; head = prx_queue->head;
diff --git a/drivers/net/ethernet/huawei/bma/veth_drv/veth_hb.h b/drivers/net/ethernet/huawei/bma/veth_drv/veth_hb.h index 9a4d699e6421..503636549320 100644 --- a/drivers/net/ethernet/huawei/bma/veth_drv/veth_hb.h +++ b/drivers/net/ethernet/huawei/bma/veth_drv/veth_hb.h @@ -31,7 +31,7 @@ extern "C" { #ifdef DRV_VERSION #define VETH_VERSION MICRO_TO_STR(DRV_VERSION) #else -#define VETH_VERSION "0.3.4" +#define VETH_VERSION "0.3.5" #endif
#define MODULE_NAME "veth"
From: Chen Wandun chenwandun@huawei.com
mainline inclusion from mainline-v6.1-rc7 commit de1ccfb648243a031cfbdc2d5571dfdaf5023106 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I6AWEO CVE: NA
--------------------------------
A softlockup occurs in scan free swap slot under huge memory pressure. The test scenario is: 64 CPU cores, 64GB memory, and 28 zram devices, the disksize of each zram device is 50MB.
LATENCY_LIMIT is used to prevent softlockups in scan_swap_map_slots(), but the real loop number would more than LATENCY_LIMIT because of "goto checks and goto scan" repeatly without decreasing latency limit.
In order to fix it, decrease latency_ration in advance.
There is also a suspicious place that will cause softlockups in get_swap_pages(). In this function, the "goto start_over" may result in continuous scanning of the swap partition. If there is no cond_sched in scan_swap_map_slots(), it would cause a softlockup (I am not sure about this).
WARN: soft lockup - CPU#11 stuck for 11s! [kswapd0:466] CPU: 11 PID: 466 Comm: kswapd@ Kdump: loaded Tainted: G dump backtrace+0x0/0x1le4 show stack+0x20/@x2c dump_stack+0xd8/0x140 watchdog print_info+0x48/0x54 watchdog_process_before_softlockup+0x98/0xa0 watchdog_timer_fn+0xlac/0x2d0 hrtimer_rum_queues+0xb0/0x130 hrtimer_interrupt+0x13c/0x3c0 arch_timer_handler_virt+0x3c/0x50 handLe_percpu_devid_irq+0x90/0x1f4 handle domain irq+0x84/0x100 gic_handle_irq+0x88/0x2b0 e11 ira+0xhB/Bx140 scan_swap_map_slots+0x678/0x890 get_swap_pages+0x29c/0x440 get_swap_page+0x120/0x2e0 add_to_swap+UX2U/0XyC shrink_page_list+0x5d0/0x152c shrink_inactive_list+0xl6c/Bx500 shrink_lruvec+0x270/0x304
WARN: soft lockup - CPU#32 stuck for 11s! [stress-ng:309915] watchdog_timer_fn+0x1ac/0x2d0 __run_hrtimer+0x98/0x2a0 __hrtimer_run_queues+0xb0/0x130 hrtimer_interrupt+0x13c/0x3c0 arch_timer_handler_virt+0x3c/0x50 handle_percpu_devid_irq+0x90/0x1f4 __handle_domain_irq+0x84/0x100 gic_handle_irq+0x88/0x2b0 el1_irq+0xb8/0x140 get_swap_pages+0x1e8/0x440 get_swap_page+0x1c8/0x2e0 add_to_swap+0x20/0x9c shrink_page_list+0x5d0/0x152c reclaim_pages+0x160/0x310 madvise_cold_or_pageout_pte_range+0x7bc/0xe3c walk_pmd_range.isra.0+0xac/0x22c walk_pud_range+0xfc/0x1c0 walk_pgd_range+0x158/0x1b0 __walk_page_range+0x64/0x100 walk_page_range+0x104/0x150
Link: https://lkml.kernel.org/r/20221118133850.3360369-1-chenwandun@huawei.com Fixes: 048c27fd7281 ("[PATCH] swap: scan_swap_map latency breaks") Signed-off-by: Chen Wandun chenwandun@huawei.com Reviewed-by: "Huang, Ying" ying.huang@intel.com Cc: Hugh Dickins hugh@veritas.com Cc: Kefeng Wang wangkefeng.wang@huawei.com Cc: Nanyong Sun sunnanyong@huawei.com Cc: xialonglong1@huawei.com Signed-off-by: Andrew Morton akpm@linux-foundation.org
Conflicts: mm/swapfile.c
Signed-off-by: Longlong Xia xialonglong1@huawei.com Reviewed-by: Kefeng Wang wangkefeng.wang@huawei.com Signed-off-by: Yongqiang Liu liuyongqiang13@huawei.com --- mm/swapfile.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/mm/swapfile.c b/mm/swapfile.c index 2619729400d3..ba97c8f635b0 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -851,6 +851,10 @@ static int scan_swap_map_slots(struct swap_info_struct *si, scan: spin_unlock(&si->lock); while (++offset <= READ_ONCE(si->highest_bit)) { + if (unlikely(--latency_ration < 0)) { + cond_resched(); + latency_ration = LATENCY_LIMIT; + } if (!si->swap_map[offset]) { spin_lock(&si->lock); goto checks; @@ -860,13 +864,13 @@ static int scan_swap_map_slots(struct swap_info_struct *si, spin_lock(&si->lock); goto checks; } + } + offset = si->lowest_bit; + while (offset < scan_base) { if (unlikely(--latency_ration < 0)) { cond_resched(); latency_ration = LATENCY_LIMIT; } - } - offset = si->lowest_bit; - while (offset < scan_base) { if (!si->swap_map[offset]) { spin_lock(&si->lock); goto checks; @@ -876,10 +880,6 @@ static int scan_swap_map_slots(struct swap_info_struct *si, spin_lock(&si->lock); goto checks; } - if (unlikely(--latency_ration < 0)) { - cond_resched(); - latency_ration = LATENCY_LIMIT; - } offset++; } spin_lock(&si->lock);