From nobody Sat Jun 13 17:35:29 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8CF8B3F1667 for ; Wed, 6 May 2026 10:04:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778061894; cv=none; b=ECb8zA3K573G9QA0gbBEZZjPUqpe3/+30sU2OvXgWO/6QzqD/d+HBvBiwHKSGbX67j0YKvUrgC2NxS3tsSGKQPdp7DdItcsEh4YkF+ghU0ucAHhrs8/vA9n3dFBn0vTtZTGPO/Ci06Ok0MhQ0eYn93EIT3su24a15pgCJR2ZEaE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778061894; c=relaxed/simple; bh=qM0QHSS2lOwtZwClWM3tEyZnrTRS8RnRUKoF5Opy19A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=JwYeZXJIPdmZnjrCGH0ma7xYPFWHLtPiwjB9vgahyKeHDRstBxB5tMQBZzpDiPDLhKYzsFheVx6ooLwNF/vrX2T1cgNti6KMMbN68p2QZLk1fPf7yQMfsVTpdwxl1HOfVbBvJu66p8tAMYmn51KJxjyCQGxW3eJ4nVGW3t75rws= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=SXI+QDsq; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=iOKKWNzY; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="SXI+QDsq"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="iOKKWNzY" Received: from pps.filterd (m0279873.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 646A0M2n1987488 for ; Wed, 6 May 2026 10:04:46 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:message-id :mime-version:subject:to; s=qcppdkim1; bh=e7RuSzzgTNaS5/Anxoznyk MakHr9Zb06kIRc/K3tw04=; b=SXI+QDsqwGAgghBr5gz0E1ekxkxwkEjUHAM8lU 1R5RyVGvlJ+YGn4tDOU8msIljreR6l2JKB0P3dEb6xx3w8l5XXAfjqgZm+U1h4+b 063U8XKQmcLoWrpPCMdy2Z+6ovVH5qzSb9LMH7K+eGkqFtolnDOlkhCwGMaBlXHb AdNyMClB31HAf45eJ+wEFMvje6uZyBJ6jLEJQUEa+uQ+vYyuZ1u8J6+mF/77mTx7 bm8ThpSDN5my8UaP6c6Yr66IrKgDZoUbW+8RfAv+XpyqsaiGiEHtuRBNYnOb4xID nmCalS6OAn8jKg6FRQTGyAW4xm0UeBkrQ5Ue4gXYYWUbZyNQ== Received: from mail-dy1-f197.google.com (mail-dy1-f197.google.com [74.125.82.197]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4e03gp00pm-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Wed, 06 May 2026 10:04:46 +0000 (GMT) Received: by mail-dy1-f197.google.com with SMTP id 5a478bee46e88-2f3eb8f3419so7124580eec.1 for ; Wed, 06 May 2026 03:04:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1778061886; x=1778666686; darn=vger.kernel.org; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:from:to:cc:subject:date:message-id:reply-to; bh=e7RuSzzgTNaS5/AnxoznykMakHr9Zb06kIRc/K3tw04=; b=iOKKWNzYIFV8BHVGsvWbGGpkr4q5+XDixcDnCPwLhbDVBPtqGb5gHIqkkdsgaSraKi BDtC9f/7oTzHecuiQuYh08DgP9GKyZG7P2qYWEacidV1MZUMkA1SRCtWx4uEcQE0575s 0DIm+wP2jD7imHialYvOa7p17NWq8VbFLdSKAZemOM881TfIGajaF/Fb8PAE2lfkIAGu Rc81kkw3zbAfMX2vF+8gbN1qTX3fSeQhQbUQ7U092RvJrRpY9WPlmxBhnAlCMKjPEIWF nykEUqI1PBYb+wSxfYdBg6Wvi7U3UED2Snk4FOvI9fBZNpcsTBg+ycwcJA5smajmX25R GEQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1778061886; x=1778666686; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=e7RuSzzgTNaS5/AnxoznykMakHr9Zb06kIRc/K3tw04=; b=rzcwizNpVVnIJuN+pteg1uMqTfSoobbEVF2UBJJwrNniXtvAMvvcesBLgOWMtcqc18 JfqqZ6KP3Ly5sPIO6HNPcqBsEwB9sA4LaA/HWKeCR6P+EHP2PnpzFuWVdlXMZU1tcdJz krGC30ulGbVCpv/3tRfxP+gbnJPU66KpFdXCG0BX3TfUzTYwVvt5pFLZUkAEqeZ98gJy UDm5ibPa6GDHATTjjn+/EmZ6+Z8a/nuxoHocf9rj/oefQSwBLYQo0Fgexf31tLqaahwt IQk5y1X2WAdk5di3DIChlQIJbAqXSDKzK2usEpCygjP0GCawbCDw1jlSmQAbiEaW+7Xw Bkrw== X-Forwarded-Encrypted: i=1; AFNElJ851pHcxbZ00N2XxlCK4muT5vP0hgPB7JIARzNtVvaE+fVPKRcxxr+biea3t0wQMp7knM9L6cSDGgoDJ08=@vger.kernel.org X-Gm-Message-State: AOJu0YzkqBKYmRsXYn8wOXmBj2gqOJTdc/3gHPWIKBcaUpF48YPWKkxX m9ezfwZcPlm6FpfqFisE6fkGAuRd1xKY/4R32mWWdiCbPd1Bz24CGcrSNqpCzqhybksZjO6lLqo JINCw/cvQG4Dso7LknVIc0P96P98nJkNzMVjNG6uyyWn9IQDFQEN0sdAhV6wjonWhKu4= X-Gm-Gg: AeBDiet7t3vjXoLdV+4PxzcwaSWE259mma2QMczIKKhkoiBcgcqY64Tbn5mLDhPC4wB i1AKPzjYz0ayNO8ULaL4jAzk+cIeH5+OFyZPoIgttye59m7jKqbWnn7m4Wka2X6JSeRxrI9D/El c6wVaAuDz6qmyLBTgriSE2zCwxxaVU9yt8/To4qsgxUrvkh5Ek1sw2wDuM50o6+SONcqsOGXpyp KuXo43DIM49Nn+0NzMuL/GNIzA+2fCOxYl+0DJiEniSWYTy3WBG66Q15q+JbO3krrhhT1LKXzcP edB/FPCuJrwRQO4EeUDGtMHssaXrPOdqPG8Kkggs8LB/gwqMRIuUmmi5hw283vahwFnQt4FfglQ TApApfEjduAQzbmwUEAwop03jJ/yoGbAvWgH5fhEta5yQqINZN8g6xlIjuEj1q0Fsaj05/KSWwY Ddnp5d X-Received: by 2002:a05:7300:bc1a:b0:2f1:496c:94d1 with SMTP id 5a478bee46e88-2f54ac74aabmr1189488eec.21.1778061885479; Wed, 06 May 2026 03:04:45 -0700 (PDT) X-Received: by 2002:a05:7300:bc1a:b0:2f1:496c:94d1 with SMTP id 5a478bee46e88-2f54ac74aabmr1189468eec.21.1778061884749; Wed, 06 May 2026 03:04:44 -0700 (PDT) Received: from hu-penyan-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-2f56f891a56sm2928834eec.14.2026.05.06.03.04.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 06 May 2026 03:04:44 -0700 (PDT) From: Peng Yang Date: Wed, 06 May 2026 03:04:41 -0700 Subject: [PATCH v4] virtio_console: bound __send_to_port() spin loop to prevent watchdog bite Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260506-add_timeout_to___send_to_port-v4-1-8f3c7549b72a@oss.qualcomm.com> X-B4-Tracking: v=1; b=H4sIADgS+2kC/43OwU4DIRAG4FdpOEsDMxTXnnwPY8guDBbjLhXYj abZdy+0h3rQ1Mtk/uTPN3NimVKgzPabE0u0hBziVIN62DB76Kc34sHVzECAFgoE750zJYwU52J KNMZkmlzbjjEVLoWy9DhYD0qyahwT+fB18V9erznPwzvZ0tDWOIRcYvq+PLDI1vvvrUVyybVFc IiDVx6eY87bz7n/sHEct3WwdnKBn+jTPRQqig6QvNOEXfcHijd0J/Q9FCva9U4o7S06i7+g67q eASQWEz2NAQAA X-Change-ID: 20260420-add_timeout_to___send_to_port-104ce7bcf241 To: Amit Shah , Arnd Bergmann , Greg Kroah-Hartman Cc: kernel@quicinc.com, virtualization@lists.linux.dev, linux-kernel@vger.kernel.org, kernel@oss.qualcomm.com, Peng Yang X-Mailer: b4 0.16-dev-3bfbc X-Developer-Signature: v=1; a=ed25519-sha256; t=1778061883; l=6757; i=peng.yang@oss.qualcomm.com; s=20260420; h=from:subject:message-id; bh=qM0QHSS2lOwtZwClWM3tEyZnrTRS8RnRUKoF5Opy19A=; b=6SoRarHSQJzYKN5cjt0OJqNZ33hWoBK7QuCOau3jtI/vbo4tZ+v2Rd0fWyOV4JvgUWIU3txAR HwTvUbCq+74CJPduHGsQYHoCiO1zrl/13JZ9TOHwxn1GdYQ1uWv2fi3 X-Developer-Key: i=peng.yang@oss.qualcomm.com; a=ed25519; pk=fY34c9+z3TbzFLgw2yql3bT/tbmxDEuxiVPTYAbRSTY= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTA2MDA5NyBTYWx0ZWRfXxkrtDVxb2sjf /VKCZBpLfZ5G+kIUx56RR2HlNO4nbnojYyhhE9YByTrISLmyxsUHz4nwG2kmQZNcyOnIJKMPOBN /dTxfTZir9vUmN0ibueo4t+8zLjWiVTec3fcF2He+DQGXUdri7sSTFfBNJo623MApQaiad1X3uo naoltlGRgPy6sPI+kQ1QRd+FTOsCluhfY0wNurfvoZPu15KZ6luHQRd3OITYBlKPMtNlzyQw9/b snGOzAPUaMe4nmyppImw+U6BqcfFHWq/D1yptJuduASR4yRyQmqGC3n4hslMTxZg2dekYy2M6cI OhdR+/lwjyAoN1I12W7TORbc0dW8J0kDyll2fe7fFTbXAT/w0WFjz9slshiHUNurwaaUCptgFh2 omib+yWBL1kfSskfSb67zXsSJYyhnXdAv3bEg8ovNqM79rxgzsqSPRam0HkhZ0KnTgGUpVk4MW8 p/z45uivQJKrAA0cIdw== X-Proofpoint-ORIG-GUID: OHCP7nDJB3GMHb2foheEGHB43kjTqqh8 X-Proofpoint-GUID: OHCP7nDJB3GMHb2foheEGHB43kjTqqh8 X-Authority-Analysis: v=2.4 cv=W8wIkxWk c=1 sm=1 tr=0 ts=69fb123e cx=c_pps a=Uww141gWH0fZj/3QKPojxA==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=IkcTkHD0fZMA:10 a=NGcC8JguVDcA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=rJkE3RaqiGZ5pbrm-msn:22 a=bC-a23v3AAAA:8 a=EUspDBNiAAAA:8 a=VwQbUJbxAAAA:8 a=ag1SF4gXAAAA:8 a=UaD9Rcc6a6UQGHyLLyMA:9 a=QEXdDO2ut3YA:10 a=PxkB5W3o20Ba91AHUih5:22 a=FO4_E8m0qiDe52t0p3_H:22 a=Yupwre4RP9_Eg_Bd0iYG:22 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-05-05_03,2026-04-30_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 clxscore=1015 suspectscore=0 lowpriorityscore=0 adultscore=0 priorityscore=1501 bulkscore=0 impostorscore=0 phishscore=0 malwarescore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2604200000 definitions=main-2605060097 __send_to_port() acquires outvq_lock with IRQs disabled via spin_lock_irqsave(), then spins in virtqueue_get_buf() waiting for the host to consume the TX descriptor. When the host is slow to respond (e.g. under heavy load from concurrent virtio_mem plug operations during secondary VM boot), the spin never exits. The watchdog bark ISR fires on another CPU and tries to printk(), which calls hvc_console_print() -> put_chars() -> __send_to_port(), attempting to acquire outvq_lock. With outvq_lock already held and IRQs disabled, all CPUs stall and the watchdog cannot be pet, triggering a bite. Add a 200ms deadline using ktime_get_mono_fast_ns() to break out of the spin loop as a fallback. Since __send_to_port() may now return before the host has consumed the TX descriptor, put_chars() is changed to allocate a struct port_buffer (GFP_ATOMIC) as the virtqueue token instead of a raw kmemdup() pointer, so that reclaim_consumed_buffers() can safely call free_buf() on it regardless of whether a timeout occurred. put_chars() frees the buffer only when virtqueue_add_outbuf() fails and the token was never submitted. Signed-off-by: Peng Yang --- Changes in v4: - Rewrite commit message to be more concise and focused. - Link to v3: https://patch.msgid.link/20260506-add_timeout_to___send_to_po= rt-v3-1-8ad046fc3dc3@oss.qualcomm.com Changes in v3: - Fix token leak in __send_to_port(): capture virtqueue_get_buf() return value and call free_buf() after the spin loop exits normally. - Link to v2: https://patch.msgid.link/20260429-add_timeout_to___send_to_po= rt-v2-1-3d23efd6e388@oss.qualcomm.com Changes in v2: - Rework put_chars() to allocate full struct port_buffer (GFP_ATOMIC) so free_buf() can safely reclaim the token on timeout. - Transfer buffer ownership to virtqueue on success; free immediately on virtqueue_add_outbuf() failure. - Link to v1: https://patch.msgid.link/20260420-add_timeout_to___send_to_po= rt-v1-1-6c32d33bf4f2@oss.qualcomm.com To: Amit Shah To: Arnd Bergmann To: Greg Kroah-Hartman Cc: kernel@oss.qualcomm.com Cc: virtualization@lists.linux.dev Cc: linux-kernel@vger.kernel.org --- drivers/char/virtio_console.c | 75 +++++++++++++++++++++++++++++++++++----= ---- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 9a33217c68d9..12674a667fec 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "../tty/hvc/hvc_console.h" =20 #define is_rproc_enabled IS_ENABLED(CONFIG_REMOTEPROC) @@ -601,6 +602,8 @@ static ssize_t __send_to_port(struct port *port, struct= scatterlist *sg, int err; unsigned long flags; unsigned int len; + void *token; + u64 deadline; =20 out_vq =3D port->out_vq; =20 @@ -632,10 +635,20 @@ static ssize_t __send_to_port(struct port *port, stru= ct scatterlist *sg, * buffer and relax the spinning requirement. The downside is * we need to kmalloc a GFP_ATOMIC buffer each time the * console driver writes something out. + * + * To avoid spinning forever if the host stops processing the + * TX virtqueue (e.g. during VM shutdown), a 200ms deadline is + * used to break out of the loop as a fallback. */ - while (!virtqueue_get_buf(out_vq, &len) - && !virtqueue_is_broken(out_vq)) + deadline =3D ktime_get_mono_fast_ns() + 200ULL * NSEC_PER_MSEC; + while (!(token =3D virtqueue_get_buf(out_vq, &len)) && + !virtqueue_is_broken(out_vq)) { + if (ktime_get_mono_fast_ns() >=3D deadline) + break; cpu_relax(); + } + if (token) + free_buf(token, false); done: spin_unlock_irqrestore(&port->outvq_lock, flags); =20 @@ -1097,31 +1110,65 @@ static const struct file_operations port_fops =3D { }; =20 /* - * The put_chars() callback is pretty straightforward. + * The put_chars() callback writes characters to the virtio console port. + * + * We allocate a struct port_buffer (with GFP_ATOMIC) to wrap the data so + * that reclaim_consumed_buffers() can safely call free_buf() on the token + * returned by virtqueue_get_buf(), even if __send_to_port() timed out + * before observing the used-ring update. * - * We turn the characters into a scatter-gather list, add it to the - * output queue and then kick the Host. Then we sit here waiting for - * it to finish: inefficient in theory, but in practice - * implementations will do it immediately. + * On success, ownership of the buffer is transferred to the virtqueue as + * the descriptor token; it will be reclaimed by reclaim_consumed_buffers(= ). + * On failure (virtqueue_add_outbuf() error), the buffer was never submitt= ed + * and must be freed explicitly here. */ static ssize_t put_chars(u32 vtermno, const u8 *buf, size_t count) { struct port *port; struct scatterlist sg[1]; - void *data; - int ret; + struct port_buffer *pbuf; + ssize_t ret; + + if (!count) + return 0; =20 port =3D find_port_by_vtermno(vtermno); if (!port) return -EPIPE; =20 - data =3D kmemdup(buf, count, GFP_ATOMIC); - if (!data) + pbuf =3D kmalloc(struct_size(pbuf, sg, 0), GFP_ATOMIC); + if (!pbuf) + return -ENOMEM; + + pbuf->buf =3D kmalloc(count, GFP_ATOMIC); + if (!pbuf->buf) { + kfree(pbuf); return -ENOMEM; + } + pbuf->dev =3D NULL; + pbuf->sgpages =3D 0; + pbuf->len =3D count; + pbuf->offset =3D 0; + pbuf->size =3D count; + memcpy(pbuf->buf, buf, count); =20 - sg_init_one(sg, data, count); - ret =3D __send_to_port(port, sg, 1, count, data, false); - kfree(data); + sg_init_one(sg, pbuf->buf, count); + ret =3D __send_to_port(port, sg, 1, count, pbuf, false); + + /* + * If virtqueue_add_outbuf() failed inside __send_to_port() (ret <=3D 0), + * the token was never submitted to the virtqueue, so reclaim_consumed_ + * buffers() will never see it. Free pbuf explicitly in that case. + * + * On success (ret > 0), __send_to_port() may have already freed pbuf + * via free_buf() if virtqueue_get_buf() returned the token before the + * deadline. If the spin loop timed out instead, pbuf is still in the + * virtqueue and will be reclaimed and freed by + * reclaim_consumed_buffers() -> free_buf() on the next call. Either + * way, do NOT free pbuf here. + */ + if (ret <=3D 0) + free_buf(pbuf, false); return ret; } =20 --- base-commit: 97e797263a5e963da3d1e66e743fd518567dfe37 change-id: 20260420-add_timeout_to___send_to_port-104ce7bcf241 Best regards, -- =20 Peng Yang