From nobody Sun Feb 8 03:30:28 2026 Received: from mail-ot1-f50.google.com (mail-ot1-f50.google.com [209.85.210.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8C1C12848B4 for ; Fri, 5 Sep 2025 18:52:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.50 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757098334; cv=none; b=PkAR2svfkQcw7EDTowPka8s5yTnFYgVz0RHqm8krwrwWwE3MDQ5IcHdgsgm+vyBhNFtCVaMKUJ1eeCpREV++sf0jVZei0NcmmS7Ww6uXuJAkAcsBqQBptwtlV/zmnStyTICwXPIFtYlOPV62YsWr0oX/ZuhH95Ri/StCEK+HjoA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1757098334; c=relaxed/simple; bh=FCtqrA47dDgf2+DB29PSn1rt0dYQ3ePVuxi3u8wdN0s=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=qmsszuJNoTFsKXqVcjM8agP3qqnggqLycdrju6EK49Xk298G2AXeAW/yN5La1sm9gncaAA/8mcFl6zz8x1BDdyxZSb+y2/ddJzPSXNcv59CWsupWNI/I7X1JUuqUhvhZSlOLjamucXLIuoEwGzjo8CwazovH5YwTZozP2cPLJoE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=minyard.net; spf=none smtp.mailfrom=minyard.net; dkim=pass (2048-bit key) header.d=minyard-net.20230601.gappssmtp.com header.i=@minyard-net.20230601.gappssmtp.com header.b=c4UPrGsY; arc=none smtp.client-ip=209.85.210.50 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=minyard.net Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=minyard.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=minyard-net.20230601.gappssmtp.com header.i=@minyard-net.20230601.gappssmtp.com header.b="c4UPrGsY" Received: by mail-ot1-f50.google.com with SMTP id 46e09a7af769-746d7c469a8so1234937a34.3 for ; Fri, 05 Sep 2025 11:52:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=minyard-net.20230601.gappssmtp.com; s=20230601; t=1757098331; x=1757703131; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=tbsFfKFitsanLy6pRqo9t1TcuXiGYckqN4l73oCfxk4=; b=c4UPrGsYiczE58EUiVw+QEl+gPo43lnqvfHzDbgLBZbNpBhdqm4hXZrky7xajejtwG YexdQRH/gt2qTufCxVWPfXBA9ztDatiBhSsarxHZNP7LvjVHBSTX4d0ArnGmdA/JLo9f UcM+/M1WhAdWcL27QTwxua3k5Fqth11yiASdzuYpxGYbAEqTO3pDzqaoK5EC07K9yg+r 6f10HA6kGvyaic56U5QUbszOjnnLi8AUb7Adva6cR1EszRY8BLz1JTTIKyi14ncY8BKO eDlr6/3GZJMOchiq9kXUOODlASOXGo71VSpZPHafsjncq0MdmTe9uzYBsiWm/rP0xpTj vfYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1757098331; x=1757703131; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=tbsFfKFitsanLy6pRqo9t1TcuXiGYckqN4l73oCfxk4=; b=gQrQqbVsKyhgTitPowH2PPJlyjWRsHIFxM92FYo+OucBRC5CLzFZ4CYzE+whGCv/yW rPC20dwrGkvhAbN2VYZUCgmUKlI9g1Ginf/QwH+J2dAoEwJx6FMu2V0J/0mtf2yXfxVX sMTM8tmLhfKlqj6DkIkpTlW9dVWuZzttwJWHJHE1aKdCeW6+uDj9mn3cOBrjMDVjRaLl WW2jjUCA93vAu7LRsjAGSTXLPOr0LJmhYB4eYjEUhTe6t79x6k9UCMqQ8m3OUyFYVU9D xRpSWvXW1Lw6WuBxtw79pXpRgVzbmJN0RtA4eM4KGASVhVMg3No0sv1BFHTxQCwGr7F1 OFAA== X-Gm-Message-State: AOJu0YxTxeUECRim4iM5z0fwN5Ls2kdDI6ti0hTru/8nChypuFQA4gJK xldAXCiDIlUvgT4EyGhibX+AUhOTgS8GuPQRWuVL5Zk/RVsDI1ESav51/rTO3I9N8Xc= X-Gm-Gg: ASbGncsS7YLO+yQlRMZCbQaN5fozriBv5S57ndVGAU8TjYX/fvrK2uM7aFaTFCfYP1I sOz+s2YtoGxDCgdErCx7kNlduJ7PKzgtUJ0YBml4owBPKbjn3Bk87Ug0hbSQJd0CxsiZlrN1OHS QNR8xjD1qDVHu7gO23V5ALuGhT7TCqMthLxOx5+3FkHB4kwyG4UfuPdakeYsVCJHFasQZA5kzqK 6f+MwKQUlfpINXcNYiwzfGqK8jDCUPlEXxLyExWxaEPeCyNWsRKoywwfJ+HYgH1UsICgCKgf4co nNgc6daZUA8REWEbdCv+R6RZN+oDmcEOSvIfIW4uRDFCcAObDwGFrpv0JfV7exEwaqkKey1D9sS i8ZVmcU6wUIRkIpw= X-Google-Smtp-Source: AGHT+IHefDWTJM7HUywPIeAQAUzgLBlayMQSkHjSlIoG9XeQwX9yFdfxtx23/WYXF9j9yKO7ADzHNg== X-Received: by 2002:a05:6808:13d5:b0:438:3830:9b4b with SMTP id 5614622812f47-43838309d29mr3495394b6e.33.1757098331288; Fri, 05 Sep 2025 11:52:11 -0700 (PDT) Received: from localhost ([2001:470:b8f6:1b:e171:344b:daa:1a1a]) by smtp.gmail.com with UTF8SMTPSA id 5614622812f47-4383d9886bbsm1534918b6e.32.2025.09.05.11.52.09 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 05 Sep 2025 11:52:09 -0700 (PDT) From: Corey Minyard To: Gilles BULOZ Cc: Linux Kernel , OpenIPMI Developers , Corey Minyard Subject: [PATCH] ipmi: Rework user message limit handling Date: Fri, 5 Sep 2025 13:51:45 -0500 Message-ID: <20250905185207.665207-1-corey@minyard.net> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The limit on the number of user messages had a number of issues, improper counting in some cases and a use after free. Restructure how this is all done to handle more in the receive message allocation routine, so all refcouting and user message limit counts are done in that routine. It's a lot cleaner and safer. Reported-by: Gilles BULOZ Fixes: 8e76741c3d8b20df "ipmi: Add a limit on the number of users that may = use IPMI" Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 420 +++++++++++++--------------- 1 file changed, 200 insertions(+), 220 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_m= sghandler.c index 90e2e126ef86..a0b67a35a5f0 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -38,7 +38,9 @@ =20 #define IPMI_DRIVER_VERSION "39.2" =20 -static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); +static struct ipmi_recv_msg *ipmi_alloc_recv_msg(struct ipmi_user *user); +static void ipmi_set_recv_msg_user(struct ipmi_recv_msg *msg, + struct ipmi_user *user); static int ipmi_init_msghandler(void); static void smi_work(struct work_struct *t); static void handle_new_recv_msgs(struct ipmi_smi *intf); @@ -962,7 +964,6 @@ static int deliver_response(struct ipmi_smi *intf, stru= ct ipmi_recv_msg *msg) * risk. At this moment, simply skip it in that case. */ ipmi_free_recv_msg(msg); - atomic_dec(&msg->user->nr_msgs); } else { /* * Deliver it in smi_work. The message will hold a @@ -1626,8 +1627,7 @@ int ipmi_set_gets_events(struct ipmi_user *user, bool= val) } =20 list_for_each_entry_safe(msg, msg2, &msgs, link) { - msg->user =3D user; - kref_get(&user->refcount); + ipmi_set_recv_msg_user(msg, user); deliver_local_response(intf, msg); } } @@ -2298,22 +2298,15 @@ static int i_ipmi_request(struct ipmi_user *use= r, int run_to_completion =3D READ_ONCE(intf->run_to_completion); int rv =3D 0; =20 - if (user) { - if (atomic_add_return(1, &user->nr_msgs) > max_msgs_per_user) { - /* Decrement will happen at the end of the routine. */ - rv =3D -EBUSY; - goto out; - } - } - - if (supplied_recv) + if (supplied_recv) { recv_msg =3D supplied_recv; - else { - recv_msg =3D ipmi_alloc_recv_msg(); - if (recv_msg =3D=3D NULL) { - rv =3D -ENOMEM; - goto out; - } + recv_msg->user =3D user; + if (user) + atomic_inc(&user->nr_msgs); + } else { + recv_msg =3D ipmi_alloc_recv_msg(user); + if (IS_ERR(recv_msg)) + return PTR_ERR(recv_msg); } recv_msg->user_msg_data =3D user_msg_data; =20 @@ -2324,8 +2317,7 @@ static int i_ipmi_request(struct ipmi_user *user, if (smi_msg =3D=3D NULL) { if (!supplied_recv) ipmi_free_recv_msg(recv_msg); - rv =3D -ENOMEM; - goto out; + return -ENOMEM; } } =20 @@ -2341,10 +2333,6 @@ static int i_ipmi_request(struct ipmi_user *user, goto out_err; } =20 - recv_msg->user =3D user; - if (user) - /* The put happens when the message is freed. */ - kref_get(&user->refcount); recv_msg->msgid =3D msgid; /* * Store the message to send in the receive message so timeout @@ -2373,8 +2361,10 @@ static int i_ipmi_request(struct ipmi_user *user, =20 if (rv) { out_err: - ipmi_free_smi_msg(smi_msg); - ipmi_free_recv_msg(recv_msg); + if (!supplied_smi) + ipmi_free_smi_msg(smi_msg); + if (!supplied_recv) + ipmi_free_recv_msg(recv_msg); } else { dev_dbg(intf->si_dev, "Send: %*ph\n", smi_msg->data_size, smi_msg->data); @@ -2384,9 +2374,6 @@ static int i_ipmi_request(struct ipmi_user *user, if (!run_to_completion) mutex_unlock(&intf->users_mutex); =20 -out: - if (rv && user) - atomic_dec(&user->nr_msgs); return rv; } =20 @@ -3905,7 +3892,7 @@ static int handle_ipmb_get_msg_cmd(struct ipmi_smi *i= ntf, unsigned char chan; struct ipmi_user *user =3D NULL; struct ipmi_ipmb_addr *ipmb_addr; - struct ipmi_recv_msg *recv_msg; + struct ipmi_recv_msg *recv_msg =3D NULL; =20 if (msg->rsp_size < 10) { /* Message not big enough, just ignore it. */ @@ -3926,9 +3913,8 @@ static int handle_ipmb_get_msg_cmd(struct ipmi_smi *i= ntf, rcvr =3D find_cmd_rcvr(intf, netfn, cmd, chan); if (rcvr) { user =3D rcvr->user; - kref_get(&user->refcount); - } else - user =3D NULL; + recv_msg =3D ipmi_alloc_recv_msg(user); + } rcu_read_unlock(); =20 if (user =3D=3D NULL) { @@ -3958,47 +3944,41 @@ static int handle_ipmb_get_msg_cmd(struct ipmi_smi = *intf, * causes it to not be freed or queued. */ rv =3D -1; - } else { - recv_msg =3D ipmi_alloc_recv_msg(); - if (!recv_msg) { - /* - * We couldn't allocate memory for the - * message, so requeue it for handling - * later. - */ - rv =3D 1; - kref_put(&user->refcount, free_ipmi_user); - } else { - /* Extract the source address from the data. */ - ipmb_addr =3D (struct ipmi_ipmb_addr *) &recv_msg->addr; - ipmb_addr->addr_type =3D IPMI_IPMB_ADDR_TYPE; - ipmb_addr->slave_addr =3D msg->rsp[6]; - ipmb_addr->lun =3D msg->rsp[7] & 3; - ipmb_addr->channel =3D msg->rsp[3] & 0xf; + } else if (!IS_ERR(recv_msg)) { + /* Extract the source address from the data. */ + ipmb_addr =3D (struct ipmi_ipmb_addr *) &recv_msg->addr; + ipmb_addr->addr_type =3D IPMI_IPMB_ADDR_TYPE; + ipmb_addr->slave_addr =3D msg->rsp[6]; + ipmb_addr->lun =3D msg->rsp[7] & 3; + ipmb_addr->channel =3D msg->rsp[3] & 0xf; =20 - /* - * Extract the rest of the message information - * from the IPMB header. - */ - recv_msg->user =3D user; - recv_msg->recv_type =3D IPMI_CMD_RECV_TYPE; - recv_msg->msgid =3D msg->rsp[7] >> 2; - recv_msg->msg.netfn =3D msg->rsp[4] >> 2; - recv_msg->msg.cmd =3D msg->rsp[8]; - recv_msg->msg.data =3D recv_msg->msg_data; + /* + * Extract the rest of the message information + * from the IPMB header. + */ + recv_msg->recv_type =3D IPMI_CMD_RECV_TYPE; + recv_msg->msgid =3D msg->rsp[7] >> 2; + recv_msg->msg.netfn =3D msg->rsp[4] >> 2; + recv_msg->msg.cmd =3D msg->rsp[8]; + recv_msg->msg.data =3D recv_msg->msg_data; =20 - /* - * We chop off 10, not 9 bytes because the checksum - * at the end also needs to be removed. - */ - recv_msg->msg.data_len =3D msg->rsp_size - 10; - memcpy(recv_msg->msg_data, &msg->rsp[9], - msg->rsp_size - 10); - if (deliver_response(intf, recv_msg)) - ipmi_inc_stat(intf, unhandled_commands); - else - ipmi_inc_stat(intf, handled_commands); - } + /* + * We chop off 10, not 9 bytes because the checksum + * at the end also needs to be removed. + */ + recv_msg->msg.data_len =3D msg->rsp_size - 10; + memcpy(recv_msg->msg_data, &msg->rsp[9], + msg->rsp_size - 10); + if (deliver_response(intf, recv_msg)) + ipmi_inc_stat(intf, unhandled_commands); + else + ipmi_inc_stat(intf, handled_commands); + } else { + /* + * We couldn't allocate memory for the message, so + * requeue it for handling later. + */ + rv =3D 1; } =20 return rv; @@ -4011,7 +3991,7 @@ static int handle_ipmb_direct_rcv_cmd(struct ipmi_smi= *intf, int rv =3D 0; struct ipmi_user *user =3D NULL; struct ipmi_ipmb_direct_addr *daddr; - struct ipmi_recv_msg *recv_msg; + struct ipmi_recv_msg *recv_msg =3D NULL; unsigned char netfn =3D msg->rsp[0] >> 2; unsigned char cmd =3D msg->rsp[3]; =20 @@ -4020,9 +4000,8 @@ static int handle_ipmb_direct_rcv_cmd(struct ipmi_smi= *intf, rcvr =3D find_cmd_rcvr(intf, netfn, cmd, 0); if (rcvr) { user =3D rcvr->user; - kref_get(&user->refcount); - } else - user =3D NULL; + recv_msg =3D ipmi_alloc_recv_msg(user); + } rcu_read_unlock(); =20 if (user =3D=3D NULL) { @@ -4044,44 +4023,38 @@ static int handle_ipmb_direct_rcv_cmd(struct ipmi_s= mi *intf, * causes it to not be freed or queued. */ rv =3D -1; - } else { - recv_msg =3D ipmi_alloc_recv_msg(); - if (!recv_msg) { - /* - * We couldn't allocate memory for the - * message, so requeue it for handling - * later. - */ - rv =3D 1; - kref_put(&user->refcount, free_ipmi_user); - } else { - /* Extract the source address from the data. */ - daddr =3D (struct ipmi_ipmb_direct_addr *)&recv_msg->addr; - daddr->addr_type =3D IPMI_IPMB_DIRECT_ADDR_TYPE; - daddr->channel =3D 0; - daddr->slave_addr =3D msg->rsp[1]; - daddr->rs_lun =3D msg->rsp[0] & 3; - daddr->rq_lun =3D msg->rsp[2] & 3; + } else if (!IS_ERR(recv_msg)) { + /* Extract the source address from the data. */ + daddr =3D (struct ipmi_ipmb_direct_addr *)&recv_msg->addr; + daddr->addr_type =3D IPMI_IPMB_DIRECT_ADDR_TYPE; + daddr->channel =3D 0; + daddr->slave_addr =3D msg->rsp[1]; + daddr->rs_lun =3D msg->rsp[0] & 3; + daddr->rq_lun =3D msg->rsp[2] & 3; =20 - /* - * Extract the rest of the message information - * from the IPMB header. - */ - recv_msg->user =3D user; - recv_msg->recv_type =3D IPMI_CMD_RECV_TYPE; - recv_msg->msgid =3D (msg->rsp[2] >> 2); - recv_msg->msg.netfn =3D msg->rsp[0] >> 2; - recv_msg->msg.cmd =3D msg->rsp[3]; - recv_msg->msg.data =3D recv_msg->msg_data; - - recv_msg->msg.data_len =3D msg->rsp_size - 4; - memcpy(recv_msg->msg_data, msg->rsp + 4, - msg->rsp_size - 4); - if (deliver_response(intf, recv_msg)) - ipmi_inc_stat(intf, unhandled_commands); - else - ipmi_inc_stat(intf, handled_commands); - } + /* + * Extract the rest of the message information + * from the IPMB header. + */ + recv_msg->recv_type =3D IPMI_CMD_RECV_TYPE; + recv_msg->msgid =3D (msg->rsp[2] >> 2); + recv_msg->msg.netfn =3D msg->rsp[0] >> 2; + recv_msg->msg.cmd =3D msg->rsp[3]; + recv_msg->msg.data =3D recv_msg->msg_data; + + recv_msg->msg.data_len =3D msg->rsp_size - 4; + memcpy(recv_msg->msg_data, msg->rsp + 4, + msg->rsp_size - 4); + if (deliver_response(intf, recv_msg)) + ipmi_inc_stat(intf, unhandled_commands); + else + ipmi_inc_stat(intf, handled_commands); + } else { + /* + * We couldn't allocate memory for the message, so + * requeue it for handling later. + */ + rv =3D 1; } =20 return rv; @@ -4195,7 +4168,7 @@ static int handle_lan_get_msg_cmd(struct ipmi_smi *in= tf, unsigned char chan; struct ipmi_user *user =3D NULL; struct ipmi_lan_addr *lan_addr; - struct ipmi_recv_msg *recv_msg; + struct ipmi_recv_msg *recv_msg =3D NULL; =20 if (msg->rsp_size < 12) { /* Message not big enough, just ignore it. */ @@ -4216,9 +4189,8 @@ static int handle_lan_get_msg_cmd(struct ipmi_smi *in= tf, rcvr =3D find_cmd_rcvr(intf, netfn, cmd, chan); if (rcvr) { user =3D rcvr->user; - kref_get(&user->refcount); - } else - user =3D NULL; + recv_msg =3D ipmi_alloc_recv_msg(user); + } rcu_read_unlock(); =20 if (user =3D=3D NULL) { @@ -4249,49 +4221,44 @@ static int handle_lan_get_msg_cmd(struct ipmi_smi *= intf, * causes it to not be freed or queued. */ rv =3D -1; - } else { - recv_msg =3D ipmi_alloc_recv_msg(); - if (!recv_msg) { - /* - * We couldn't allocate memory for the - * message, so requeue it for handling later. - */ - rv =3D 1; - kref_put(&user->refcount, free_ipmi_user); - } else { - /* Extract the source address from the data. */ - lan_addr =3D (struct ipmi_lan_addr *) &recv_msg->addr; - lan_addr->addr_type =3D IPMI_LAN_ADDR_TYPE; - lan_addr->session_handle =3D msg->rsp[4]; - lan_addr->remote_SWID =3D msg->rsp[8]; - lan_addr->local_SWID =3D msg->rsp[5]; - lan_addr->lun =3D msg->rsp[9] & 3; - lan_addr->channel =3D msg->rsp[3] & 0xf; - lan_addr->privilege =3D msg->rsp[3] >> 4; + } else if (!IS_ERR(recv_msg)) { + /* Extract the source address from the data. */ + lan_addr =3D (struct ipmi_lan_addr *) &recv_msg->addr; + lan_addr->addr_type =3D IPMI_LAN_ADDR_TYPE; + lan_addr->session_handle =3D msg->rsp[4]; + lan_addr->remote_SWID =3D msg->rsp[8]; + lan_addr->local_SWID =3D msg->rsp[5]; + lan_addr->lun =3D msg->rsp[9] & 3; + lan_addr->channel =3D msg->rsp[3] & 0xf; + lan_addr->privilege =3D msg->rsp[3] >> 4; =20 - /* - * Extract the rest of the message information - * from the IPMB header. - */ - recv_msg->user =3D user; - recv_msg->recv_type =3D IPMI_CMD_RECV_TYPE; - recv_msg->msgid =3D msg->rsp[9] >> 2; - recv_msg->msg.netfn =3D msg->rsp[6] >> 2; - recv_msg->msg.cmd =3D msg->rsp[10]; - recv_msg->msg.data =3D recv_msg->msg_data; + /* + * Extract the rest of the message information + * from the IPMB header. + */ + recv_msg->recv_type =3D IPMI_CMD_RECV_TYPE; + recv_msg->msgid =3D msg->rsp[9] >> 2; + recv_msg->msg.netfn =3D msg->rsp[6] >> 2; + recv_msg->msg.cmd =3D msg->rsp[10]; + recv_msg->msg.data =3D recv_msg->msg_data; =20 - /* - * We chop off 12, not 11 bytes because the checksum - * at the end also needs to be removed. - */ - recv_msg->msg.data_len =3D msg->rsp_size - 12; - memcpy(recv_msg->msg_data, &msg->rsp[11], - msg->rsp_size - 12); - if (deliver_response(intf, recv_msg)) - ipmi_inc_stat(intf, unhandled_commands); - else - ipmi_inc_stat(intf, handled_commands); - } + /* + * We chop off 12, not 11 bytes because the checksum + * at the end also needs to be removed. + */ + recv_msg->msg.data_len =3D msg->rsp_size - 12; + memcpy(recv_msg->msg_data, &msg->rsp[11], + msg->rsp_size - 12); + if (deliver_response(intf, recv_msg)) + ipmi_inc_stat(intf, unhandled_commands); + else + ipmi_inc_stat(intf, handled_commands); + } else { + /* + * We couldn't allocate memory for the message, so + * requeue it for handling later. + */ + rv =3D 1; } =20 return rv; @@ -4313,7 +4280,7 @@ static int handle_oem_get_msg_cmd(struct ipmi_smi *in= tf, unsigned char chan; struct ipmi_user *user =3D NULL; struct ipmi_system_interface_addr *smi_addr; - struct ipmi_recv_msg *recv_msg; + struct ipmi_recv_msg *recv_msg =3D NULL; =20 /* * We expect the OEM SW to perform error checking @@ -4342,9 +4309,8 @@ static int handle_oem_get_msg_cmd(struct ipmi_smi *in= tf, rcvr =3D find_cmd_rcvr(intf, netfn, cmd, chan); if (rcvr) { user =3D rcvr->user; - kref_get(&user->refcount); - } else - user =3D NULL; + recv_msg =3D ipmi_alloc_recv_msg(user); + } rcu_read_unlock(); =20 if (user =3D=3D NULL) { @@ -4357,48 +4323,42 @@ static int handle_oem_get_msg_cmd(struct ipmi_smi *= intf, */ =20 rv =3D 0; - } else { - recv_msg =3D ipmi_alloc_recv_msg(); - if (!recv_msg) { - /* - * We couldn't allocate memory for the - * message, so requeue it for handling - * later. - */ - rv =3D 1; - kref_put(&user->refcount, free_ipmi_user); - } else { - /* - * OEM Messages are expected to be delivered via - * the system interface to SMS software. We might - * need to visit this again depending on OEM - * requirements - */ - smi_addr =3D ((struct ipmi_system_interface_addr *) - &recv_msg->addr); - smi_addr->addr_type =3D IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr->channel =3D IPMI_BMC_CHANNEL; - smi_addr->lun =3D msg->rsp[0] & 3; - - recv_msg->user =3D user; - recv_msg->user_msg_data =3D NULL; - recv_msg->recv_type =3D IPMI_OEM_RECV_TYPE; - recv_msg->msg.netfn =3D msg->rsp[0] >> 2; - recv_msg->msg.cmd =3D msg->rsp[1]; - recv_msg->msg.data =3D recv_msg->msg_data; + } else if (!IS_ERR(recv_msg)) { + /* + * OEM Messages are expected to be delivered via + * the system interface to SMS software. We might + * need to visit this again depending on OEM + * requirements + */ + smi_addr =3D ((struct ipmi_system_interface_addr *) + &recv_msg->addr); + smi_addr->addr_type =3D IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr->channel =3D IPMI_BMC_CHANNEL; + smi_addr->lun =3D msg->rsp[0] & 3; + + recv_msg->user_msg_data =3D NULL; + recv_msg->recv_type =3D IPMI_OEM_RECV_TYPE; + recv_msg->msg.netfn =3D msg->rsp[0] >> 2; + recv_msg->msg.cmd =3D msg->rsp[1]; + recv_msg->msg.data =3D recv_msg->msg_data; =20 - /* - * The message starts at byte 4 which follows the - * Channel Byte in the "GET MESSAGE" command - */ - recv_msg->msg.data_len =3D msg->rsp_size - 4; - memcpy(recv_msg->msg_data, &msg->rsp[4], - msg->rsp_size - 4); - if (deliver_response(intf, recv_msg)) - ipmi_inc_stat(intf, unhandled_commands); - else - ipmi_inc_stat(intf, handled_commands); - } + /* + * The message starts at byte 4 which follows the + * Channel Byte in the "GET MESSAGE" command + */ + recv_msg->msg.data_len =3D msg->rsp_size - 4; + memcpy(recv_msg->msg_data, &msg->rsp[4], + msg->rsp_size - 4); + if (deliver_response(intf, recv_msg)) + ipmi_inc_stat(intf, unhandled_commands); + else + ipmi_inc_stat(intf, handled_commands); + } else { + /* + * We couldn't allocate memory for the message, so + * requeue it for handling later. + */ + rv =3D 1; } =20 return rv; @@ -4456,8 +4416,8 @@ static int handle_read_event_rsp(struct ipmi_smi *int= f, if (!user->gets_events) continue; =20 - recv_msg =3D ipmi_alloc_recv_msg(); - if (!recv_msg) { + recv_msg =3D ipmi_alloc_recv_msg(user); + if (IS_ERR(recv_msg)) { mutex_unlock(&intf->users_mutex); list_for_each_entry_safe(recv_msg, recv_msg2, &msgs, link) { @@ -4478,8 +4438,6 @@ static int handle_read_event_rsp(struct ipmi_smi *int= f, deliver_count++; =20 copy_event_into_recv_msg(recv_msg, msg); - recv_msg->user =3D user; - kref_get(&user->refcount); list_add_tail(&recv_msg->link, &msgs); } mutex_unlock(&intf->users_mutex); @@ -4495,8 +4453,8 @@ static int handle_read_event_rsp(struct ipmi_smi *int= f, * No one to receive the message, put it in queue if there's * not already too many things in the queue. */ - recv_msg =3D ipmi_alloc_recv_msg(); - if (!recv_msg) { + recv_msg =3D ipmi_alloc_recv_msg(NULL); + if (IS_ERR(recv_msg)) { /* * We couldn't allocate memory for the * message, so requeue it for handling @@ -4922,12 +4880,10 @@ static void smi_work(struct work_struct *t) =20 list_del(&msg->link); =20 - if (refcount_read(&user->destroyed) =3D=3D 0) { + if (refcount_read(&user->destroyed) =3D=3D 0) ipmi_free_recv_msg(msg); - } else { - atomic_dec(&user->nr_msgs); + else user->handler->ipmi_recv_hndl(msg, user->handler_data); - } } mutex_unlock(&intf->user_msgs_mutex); =20 @@ -5245,27 +5201,51 @@ static void free_recv_msg(struct ipmi_recv_msg *msg) kfree(msg); } =20 -static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void) +static struct ipmi_recv_msg *ipmi_alloc_recv_msg(struct ipmi_user *user) { struct ipmi_recv_msg *rv; =20 + if (user) { + if (atomic_add_return(1, &user->nr_msgs) > max_msgs_per_user) { + atomic_dec(&user->nr_msgs); + return ERR_PTR(-EBUSY); + } + } + rv =3D kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC); - if (rv) { - rv->user =3D NULL; - rv->done =3D free_recv_msg; - atomic_inc(&recv_msg_inuse_count); + if (!rv) { + if (user) + atomic_dec(&user->nr_msgs); + return ERR_PTR(-ENOMEM); } + + rv->user =3D user; + rv->done =3D free_recv_msg; + if (user) + kref_get(&user->refcount); + atomic_inc(&recv_msg_inuse_count); return rv; } =20 void ipmi_free_recv_msg(struct ipmi_recv_msg *msg) { - if (msg->user && !oops_in_progress) + if (msg->user && !oops_in_progress) { + atomic_dec(&msg->user->nr_msgs); kref_put(&msg->user->refcount, free_ipmi_user); + } msg->done(msg); } EXPORT_SYMBOL(ipmi_free_recv_msg); =20 +static void ipmi_set_recv_msg_user(struct ipmi_recv_msg *msg, + struct ipmi_user *user) +{ + WARN_ON_ONCE(msg->user); /* User should not be set. */ + msg->user =3D user; + atomic_inc(&user->nr_msgs); + kref_get(&user->refcount); +} + static atomic_t panic_done_count =3D ATOMIC_INIT(0); =20 static void dummy_smi_done_handler(struct ipmi_smi_msg *msg) --=20 2.43.0