From nobody Sun Feb 8 01:52:07 2026 Received: from sender4-pp-f112.zoho.com (sender4-pp-f112.zoho.com [136.143.188.112]) (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 BF62231BC95 for ; Fri, 30 Jan 2026 14:52:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.112 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769784726; cv=pass; b=YpuAGtk4tXz+grA1zgFr5edwQMcPRCSFmTYMsj8e7Pb1d/BHVDOnDeknJaoIt1yt08w2+qmMsFbJCH0phbwwMAjsFSYljdKllvLb0jsHbjI2DHx5V7xSW/1sY1a+fcylfJVXclJ+WO3yqcAWjyxscy1J6cWi0yDmKJ85J3AxOVA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769784726; c=relaxed/simple; bh=G3cVWgppnU3vtnRghKGnQe00FA3N59jD//FdPtFoDrc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=B+pVAfDLyGGll/DELjdVHgPQI3w1WgFmXDUM+Vkh3fBNYWRlVF3IpixMwIJ1pNFBwSEQmA8KVLCF4ysyFF0utxNd+lKD/jfXPeCMqRsWatqAl68/ViFBWcrrfCnFvPPQmkgslgsMf3OodW8/d6h4pzFZ6WX3Y+EGhUA6qfovICA= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linux.beauty; spf=pass smtp.mailfrom=linux.beauty; dkim=pass (1024-bit key) header.d=linux.beauty header.i=me@linux.beauty header.b=KwVXalqP; arc=pass smtp.client-ip=136.143.188.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linux.beauty Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.beauty Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.beauty header.i=me@linux.beauty header.b="KwVXalqP" ARC-Seal: i=1; a=rsa-sha256; t=1769784704; cv=none; d=zohomail.com; s=zohoarc; b=ixrk4YN/BNj96DVXlh7TlQpAdw/V8EHGk0zRYG+vgiroBAujzSMQ2/COjDDUwq1AyQyP1ESnxu974V0WjM7SYxx6k+bToxubcoUvOPbrx1L20AFRS+sv66ZFTnWur3PgiJCA4XIdz2/oYl9X73fTlgO4QoL+Cr511p7p/IrEBtw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1769784704; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To; bh=0sigC7NiTxNLAax7/+B9OkXqoq3ARjs97hBD6xuCTuA=; b=m/sX8x/SCeT5gsu1KTBzuzTu6R0XibY+BMzo5hyZ8yaVvGaVZqpczBZPptBv93nqkoMSWDs4RAB7lRlIzg2BipB65RN2FB3uri1U3FDU4Ir6iBud/XotdgwOl+oig5enBGmtiej/tFP0RlRMUf3Rm1uEs3kPsQ8i2p01HHWRsxk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=linux.beauty; spf=pass smtp.mailfrom=me@linux.beauty; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1769784704; s=zmail; d=linux.beauty; i=me@linux.beauty; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-ID:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Message-Id:Reply-To; bh=0sigC7NiTxNLAax7/+B9OkXqoq3ARjs97hBD6xuCTuA=; b=KwVXalqPC1Xuhzj70eoLsGzNiTwNQvrl0IQeVKBrH/wBSREcn5QjWxBSrt2Ua9Fm J9WT8ROb05WI9zMyV+XDrV3OV/NJ+J4wl8z92SkC9lEcqmJOF+pSj6id8mVT/nEqNa4 RiSZO8wqoCOuYpBttMG6FzShBr5v6t8cHLrzX8I0= Received: by mx.zohomail.com with SMTPS id 1769784701372338.8712380432893; Fri, 30 Jan 2026 06:51:41 -0800 (PST) From: Li Chen To: Pasha Tatashin , Mike Rapoport , Pratyush Yadav , linux-kernel@vger.kernel.org Cc: Li Chen Subject: [PATCH v1 1/3] liveupdate: track post-kexec restore window Date: Fri, 30 Jan 2026 22:51:17 +0800 Message-ID: <20260130145122.368748-2-me@linux.beauty> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260130145122.368748-1-me@linux.beauty> References: <20260130145122.368748-1-me@linux.beauty> 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 X-ZohoMailClient: External Content-Type: text/plain; charset="utf-8" A kexec-based live update introduces a window after the new kernel boots where userspace needs to retrieve and restore preserved sessions. Provide liveupdate_restore_in_progress() backed by a counter of incoming sessions left, and make session finishing idempotent to avoid double finish paths causing counter underflow. Signed-off-by: Li Chen --- include/linux/liveupdate.h | 11 +++++++++ kernel/liveupdate/luo_core.c | 2 ++ kernel/liveupdate/luo_internal.h | 4 ++++ kernel/liveupdate/luo_session.c | 41 +++++++++++++++++++++++++++++++- 4 files changed, 57 insertions(+), 1 deletion(-) diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h index ed81e7b31a9f..406a6e2dd4a1 100644 --- a/include/linux/liveupdate.h +++ b/include/linux/liveupdate.h @@ -217,6 +217,12 @@ struct liveupdate_flb { /* Return true if live update orchestrator is enabled */ bool liveupdate_enabled(void); =20 +/* + * Return true during a kexec-based live update boot while userspace is st= ill + * restoring preserved sessions/resources. + */ +bool liveupdate_restore_in_progress(void); + /* Called during kexec to tell LUO that entered into reboot */ int liveupdate_reboot(void); =20 @@ -238,6 +244,11 @@ static inline bool liveupdate_enabled(void) return false; } =20 +static inline bool liveupdate_restore_in_progress(void) +{ + return false; +} + static inline int liveupdate_reboot(void) { return 0; diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c index 7a9ef16b37d8..19c91843fbdb 100644 --- a/kernel/liveupdate/luo_core.c +++ b/kernel/liveupdate/luo_core.c @@ -128,6 +128,8 @@ static int __init luo_early_startup(void) if (err) return err; =20 + luo_session_restore_window_init(); + err =3D luo_flb_setup_incoming(luo_global.fdt_in); =20 return err; diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_inter= nal.h index 6115d6a4054d..8aa4c5b0101b 100644 --- a/kernel/liveupdate/luo_internal.h +++ b/kernel/liveupdate/luo_internal.h @@ -72,6 +72,8 @@ struct luo_file_set { * previous kernel) sessions. * @retrieved: A boolean flag indicating whether this session has been * retrieved by a consumer in the new kernel. + * @finished: A boolean flag indicating whether this session has been + * successfully finished in the new kernel. * @file_set: A set of files that belong to this session. * @mutex: protects fields in the luo_session. */ @@ -80,6 +82,7 @@ struct luo_session { struct luo_session_ser *ser; struct list_head list; bool retrieved; + bool finished; struct luo_file_set file_set; struct mutex mutex; }; @@ -88,6 +91,7 @@ int luo_session_create(const char *name, struct file **fi= lep); int luo_session_retrieve(const char *name, struct file **filep); int __init luo_session_setup_outgoing(void *fdt); int __init luo_session_setup_incoming(void *fdt); +void __init luo_session_restore_window_init(void); int luo_session_serialize(void); int luo_session_deserialize(void); bool luo_session_quiesce(void); diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_sessio= n.c index dbdbc3bd7929..e1d1ab795c40 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -50,6 +50,7 @@ =20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt =20 +#include #include #include #include @@ -117,6 +118,31 @@ static struct luo_session_global luo_session_global = =3D { }, }; =20 +static atomic_long_t liveupdate_incoming_sessions_left =3D ATOMIC_LONG_INI= T(0); + +bool liveupdate_restore_in_progress(void) +{ + return atomic_long_read(&liveupdate_incoming_sessions_left) > 0; +} + +void __init luo_session_restore_window_init(void) +{ + struct luo_session_header *sh =3D &luo_session_global.incoming; + u64 count; + + if (!sh->active) + return; + + count =3D sh->header_ser->count; + if (count > LUO_SESSION_MAX) { + pr_warn("incoming session count %llu exceeds max %lu\n", + count, LUO_SESSION_MAX); + count =3D LUO_SESSION_MAX; + } + + atomic_long_set(&liveupdate_incoming_sessions_left, (long)count); +} + static struct luo_session *luo_session_alloc(const char *name) { struct luo_session *session =3D kzalloc(sizeof(*session), GFP_KERNEL); @@ -182,8 +208,21 @@ static void luo_session_remove(struct luo_session_head= er *sh, =20 static int luo_session_finish_one(struct luo_session *session) { + int err; + guard(mutex)(&session->mutex); - return luo_file_finish(&session->file_set); + if (session->finished) + return 0; + + err =3D luo_file_finish(&session->file_set); + if (err) + return err; + + session->finished =3D true; + if (session->retrieved) + atomic_long_dec(&liveupdate_incoming_sessions_left); + + return 0; } =20 static void luo_session_unfreeze_one(struct luo_session *session, --=20 2.52.0 From nobody Sun Feb 8 01:52:07 2026 Received: from sender4-pp-g123.zoho.com (sender4-pp-g123.zoho.com [136.143.188.123]) (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 D496E31BC95 for ; Fri, 30 Jan 2026 14:52:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.123 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769784733; cv=pass; b=Im9lRH5zDp1q0TitZIC39HgRsZD3oQw1/bHglAoPmYBN5lsP5ICIdtJk+ivEMCP5v8RKsYMCEyu4oJqnu5/rolZMHwVbproG9t6vQTZCkdSfOlphUFIveXCY43yNmTfqtq9cKmuOFogQr24V4FdGNbS9zxs2QChy2PkDeEDjDvk= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769784733; c=relaxed/simple; bh=+w1Y00hggF0M/OMkwUROq7lyblyWhRDsAI2q5xhBeJs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aNGeOAPqA7LU9629KN1dgbGR3ogd31xo1tBcye+BDrAxnJIldU+WxhTMzIF3ZgPxDPLzEbCiqAYnIFfLnuraiI8OLyFVDugYW7RcZsMCo35uVRmLM8Ioq62Uqp3uktvF8kLifB4umjsSNKw6sWaUfys0hNyEsYRJKaUTO+NHLW0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linux.beauty; spf=pass smtp.mailfrom=linux.beauty; dkim=pass (1024-bit key) header.d=linux.beauty header.i=me@linux.beauty header.b=To5n8mYC; arc=pass smtp.client-ip=136.143.188.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linux.beauty Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.beauty Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.beauty header.i=me@linux.beauty header.b="To5n8mYC" ARC-Seal: i=1; a=rsa-sha256; t=1769784708; cv=none; d=zohomail.com; s=zohoarc; b=FVpEFdAwp3x4il4of3BzkzRjzu31+0VOXWeoMXO7BhdqaJpyvDURuiinhjIAztnI/sk52OmdGYNuzuOpdDFjS0qJz98Xyjao2ZDnG1TTNrjDLlmxeWilGBE4BsNe+Kr+Q5McmBV0bl1MsTQhLpSjocsd5aHH/xyZAdM/E30fA9A= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1769784708; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To; bh=Qr4dp1DPnegx3roUBm2SMQe7fX+ISr7dRpn3wVvsn3U=; b=j2Yeoi+hkW0u1AOe+9txksDDFzdc+T6X8IsyJMdw7x9o3EHa6bb4Wpl2/pYZBzGT7f3Iidds1iJMiZXB00vClmIgpxoiJ7c7Je/sUfsmsSY0iKETsS7hym/Lm/rY5pdzobPmwA+0GYREbjfMhwxG21InqXsiFBPDVodEOPahT5E= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=linux.beauty; spf=pass smtp.mailfrom=me@linux.beauty; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1769784708; s=zmail; d=linux.beauty; i=me@linux.beauty; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-ID:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Message-Id:Reply-To; bh=Qr4dp1DPnegx3roUBm2SMQe7fX+ISr7dRpn3wVvsn3U=; b=To5n8mYCO1EiKykFgxoV20S9snfIVTy/B0P0IUXBqvotv0FOvfZuHKyuRG5FYdiC SUbS5lV1BJK08NiK2j/b0NLoEVdE2wfkkEs6VY946lMQ3M4GlU2jN5LK37PJviOa0bM XxO729N3cvbqgiuQC292rw5R9y1nHMassXQLjVFw= Received: by mx.zohomail.com with SMTPS id 176978470596793.32935511186281; Fri, 30 Jan 2026 06:51:45 -0800 (PST) From: Li Chen To: Pasha Tatashin , Mike Rapoport , Pratyush Yadav , linux-kernel@vger.kernel.org Cc: Li Chen Subject: [PATCH v1 2/3] liveupdate: bound and control post-kexec restore window Date: Fri, 30 Jan 2026 22:51:18 +0800 Message-ID: <20260130145122.368748-3-me@linux.beauty> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260130145122.368748-1-me@linux.beauty> References: <20260130145122.368748-1-me@linux.beauty> 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 X-ZohoMailClient: External Content-Type: text/plain; charset="utf-8" The restore window can remain open indefinitely if userspace never finishes some incoming sessions. Bound the window with a hard timeout and add a RESTORE_DONE ioctl on /dev/liveupdate so an orchestrator can end it explicitly once restoration is complete. Signed-off-by: Li Chen --- include/linux/liveupdate.h | 4 +++ include/uapi/linux/liveupdate.h | 34 ++++++++++++++++++ kernel/liveupdate/luo_core.c | 15 ++++++++ kernel/liveupdate/luo_internal.h | 1 + kernel/liveupdate/luo_session.c | 59 ++++++++++++++++++++++++++------ 5 files changed, 103 insertions(+), 10 deletions(-) diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h index 406a6e2dd4a1..301d3e94516e 100644 --- a/include/linux/liveupdate.h +++ b/include/linux/liveupdate.h @@ -220,6 +220,10 @@ bool liveupdate_enabled(void); /* * Return true during a kexec-based live update boot while userspace is st= ill * restoring preserved sessions/resources. + * + * The restore window ends automatically once all incoming sessions have b= een + * retrieved and finished. Userspace can also terminate the window explici= tly + * (and early) via LIVEUPDATE_IOCTL_RESTORE_DONE. */ bool liveupdate_restore_in_progress(void); =20 diff --git a/include/uapi/linux/liveupdate.h b/include/uapi/linux/liveupdat= e.h index 30bc66ee9436..357137d9a78c 100644 --- a/include/uapi/linux/liveupdate.h +++ b/include/uapi/linux/liveupdate.h @@ -51,6 +51,7 @@ enum { LIVEUPDATE_CMD_BASE =3D 0x00, LIVEUPDATE_CMD_CREATE_SESSION =3D LIVEUPDATE_CMD_BASE, LIVEUPDATE_CMD_RETRIEVE_SESSION =3D 0x01, + LIVEUPDATE_CMD_RESTORE_DONE =3D 0x02, }; =20 /* ioctl commands for session file descriptors */ @@ -118,6 +119,39 @@ struct liveupdate_ioctl_retrieve_session { #define LIVEUPDATE_IOCTL_RETRIEVE_SESSION \ _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_RETRIEVE_SESSION) =20 +/** + * struct liveupdate_ioctl_restore_done - ioctl(LIVEUPDATE_IOCTL_RESTORE_D= ONE) + * @size: Input; sizeof(struct liveupdate_ioctl_restore_done) + * @reserved: Input; Must be zero. Reserved for future use. + * + * Marks the completion of the post-kexec restore window. + * + * After a live update (kexec), userspace needs time to restore preserved + * sessions/resources. Some kernel subsystems may apply temporary compatib= ility + * behavior during this window. Userspace should call this ioctl once it h= as + * completed restoration and wants normal kernel behavior to resume, even = if + * some incoming sessions are left unused. + * + * This ioctl updates global state and is not tied to a specific live upda= te + * session file descriptor. A typical userspace agent calls it once per li= ve + * update, after it has restored the required state. + * + * Note that the restore window may also end automatically once all incomi= ng + * sessions have been retrieved and finished (or their session file + * descriptors have been closed). This ioctl is intended for cases where an + * agent intentionally does not retrieve all incoming sessions or does not= want + * to wait for them to be finished/closed. + * + * Return: 0 on success, negative error code on failure. + */ +struct liveupdate_ioctl_restore_done { + __u32 size; + __u32 reserved; +}; + +#define LIVEUPDATE_IOCTL_RESTORE_DONE \ + _IO(LIVEUPDATE_IOCTL_TYPE, LIVEUPDATE_CMD_RESTORE_DONE) + /* Session specific IOCTLs */ =20 /** diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c index 19c91843fbdb..fb6a73c08979 100644 --- a/kernel/liveupdate/luo_core.c +++ b/kernel/liveupdate/luo_core.c @@ -340,6 +340,18 @@ static int luo_ioctl_retrieve_session(struct luo_ucmd = *ucmd) return err; } =20 +static int luo_ioctl_restore_done(struct luo_ucmd *ucmd) +{ + struct liveupdate_ioctl_restore_done *argp =3D ucmd->cmd; + + if (argp->reserved) + return -EINVAL; + + luo_session_restore_done(); + + return luo_ucmd_respond(ucmd, sizeof(*argp)); +} + static int luo_open(struct inode *inodep, struct file *filep) { struct luo_device_state *ldev =3D container_of(filep->private_data, @@ -371,6 +383,7 @@ static int luo_release(struct inode *inodep, struct fil= e *filep) union ucmd_buffer { struct liveupdate_ioctl_create_session create; struct liveupdate_ioctl_retrieve_session retrieve; + struct liveupdate_ioctl_restore_done restore_done; }; =20 struct luo_ioctl_op { @@ -395,6 +408,8 @@ static const struct luo_ioctl_op luo_ioctl_ops[] =3D { struct liveupdate_ioctl_create_session, name), IOCTL_OP(LIVEUPDATE_IOCTL_RETRIEVE_SESSION, luo_ioctl_retrieve_session, struct liveupdate_ioctl_retrieve_session, name), + IOCTL_OP(LIVEUPDATE_IOCTL_RESTORE_DONE, luo_ioctl_restore_done, + struct liveupdate_ioctl_restore_done, reserved), }; =20 static long luo_ioctl(struct file *filep, unsigned int cmd, unsigned long = arg) diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_inter= nal.h index 8aa4c5b0101b..03a5b27498be 100644 --- a/kernel/liveupdate/luo_internal.h +++ b/kernel/liveupdate/luo_internal.h @@ -96,6 +96,7 @@ int luo_session_serialize(void); int luo_session_deserialize(void); bool luo_session_quiesce(void); void luo_session_resume(void); +void luo_session_restore_done(void); =20 int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd); void luo_file_unpreserve_files(struct luo_file_set *file_set); diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_sessio= n.c index e1d1ab795c40..2c7dd3b12303 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,7 @@ #include #include #include +#include #include #include "luo_internal.h" =20 @@ -118,8 +120,28 @@ static struct luo_session_global luo_session_global = =3D { }, }; =20 +/* + * Count of incoming sessions that still keep the post-kexec restore window + * open. This is initialized from the serialized session header and decrem= ented + * when a retrieved session is finished (or closed). Userspace can also en= d the + * restore window explicitly via LIVEUPDATE_IOCTL_RESTORE_DONE. + */ static atomic_long_t liveupdate_incoming_sessions_left =3D ATOMIC_LONG_INI= T(0); =20 +#define LIVEUPDATE_RESTORE_WINDOW_TIMEOUT (15 * 60 * HZ) + +static void liveupdate_restore_window_timeout(struct work_struct *work) +{ + if (!liveupdate_restore_in_progress()) + return; + + pr_warn_once("liveupdate restore window timed out\n"); + atomic_long_set(&liveupdate_incoming_sessions_left, 0); +} + +static DECLARE_DELAYED_WORK(liveupdate_restore_window_timeout_work, + liveupdate_restore_window_timeout); + bool liveupdate_restore_in_progress(void) { return atomic_long_read(&liveupdate_incoming_sessions_left) > 0; @@ -141,6 +163,16 @@ void __init luo_session_restore_window_init(void) } =20 atomic_long_set(&liveupdate_incoming_sessions_left, (long)count); + + if (count > 0) + schedule_delayed_work(&liveupdate_restore_window_timeout_work, + LIVEUPDATE_RESTORE_WINDOW_TIMEOUT); +} + +void luo_session_restore_done(void) +{ + atomic_long_set(&liveupdate_incoming_sessions_left, 0); + cancel_delayed_work_sync(&liveupdate_restore_window_timeout_work); } =20 static struct luo_session *luo_session_alloc(const char *name) @@ -209,18 +241,26 @@ static void luo_session_remove(struct luo_session_hea= der *sh, static int luo_session_finish_one(struct luo_session *session) { int err; + bool cancel_timeout =3D false; =20 - guard(mutex)(&session->mutex); - if (session->finished) - return 0; + { + guard(mutex)(&session->mutex); + if (session->finished) + return 0; =20 - err =3D luo_file_finish(&session->file_set); - if (err) - return err; + err =3D luo_file_finish(&session->file_set); + if (err) + return err; =20 - session->finished =3D true; - if (session->retrieved) - atomic_long_dec(&liveupdate_incoming_sessions_left); + session->finished =3D true; + if (session->retrieved) { + if (atomic_long_dec_if_positive(&liveupdate_incoming_sessions_left) =3D= =3D 0) + cancel_timeout =3D true; + } + } + + if (cancel_timeout) + cancel_delayed_work_sync(&liveupdate_restore_window_timeout_work); =20 return 0; } @@ -545,7 +585,6 @@ int __init luo_session_setup_incoming(void *fdt_in) luo_session_global.incoming.header_ser =3D header_ser; luo_session_global.incoming.ser =3D (void *)(header_ser + 1); luo_session_global.incoming.active =3D true; - return 0; } =20 --=20 2.52.0 From nobody Sun Feb 8 01:52:07 2026 Received: from sender4-pp-g125.zoho.com (sender4-pp-g125.zoho.com [136.143.188.125]) (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 6C654303C9F; Fri, 30 Jan 2026 14:52:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=pass smtp.client-ip=136.143.188.125 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769784779; cv=pass; b=qRdfNU7yNV+r0t2fwSEQW0ruyQSzdA6uO53QhnNe/pku4RsvrPDTiC34y07buZuyBzqQXHZ4Ryy/aFqsS6C+PSqeWqUa6IWJ8apoF9zZXfB+X+SMlnIPGKQmzKFgmWszkatOX5cRcTN2kRuNhoMtgzHj2hfOjhNkN0bOWtxOBB4= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769784779; c=relaxed/simple; bh=41ZSw8e/e5f/AuqeCxVE2oTQbqIo+4zi3gJPu89fVgY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=P9ZxdAvRdAOcIkbMyJIBpZ5oeMQz96exSpkz+SurF6qrMpqpOcnenl3r8X9oZe07/Uf0jc3ogO9syz6jsupqZ12MCCfXQWWGR+oIJz3PsT00kHjhGmE0VFW8ENWtkrxaWb+8SOJYU/bZT9gvTmcO6iBdBChQwcmtsGo4WGD8eoc= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linux.beauty; spf=pass smtp.mailfrom=linux.beauty; dkim=pass (1024-bit key) header.d=linux.beauty header.i=me@linux.beauty header.b=SRBhcykL; arc=pass smtp.client-ip=136.143.188.125 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=linux.beauty Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.beauty Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.beauty header.i=me@linux.beauty header.b="SRBhcykL" ARC-Seal: i=1; a=rsa-sha256; t=1769784720; cv=none; d=zohomail.com; s=zohoarc; b=lo3kwHp0jF3jjdfnzFC/JNibTZag0oNVgjbwbRUQZLU9vCynlluDt44DHI2kLU7aVNn2LMh7TnN94TwBkKaU3UqSU+XmcuQDZba2jrZTjOuNi4SY0sj6tgGkLQNylcvvgESMgLANJKh/IasCWZ+NnVsRaP5ZY/YAErbEoGwPnlM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1769784720; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:Subject:To:To:Message-Id:Reply-To; bh=g30GeD5luz415Zspf8u9IYtmiaQwDaZdE/ttvlyNc/k=; b=m8nPvh9njtD+hMoXBjSVhUYU5p5o9BgUCLxxAC6IzOnqoOG1F6o8QGnC+6XWKBakORMHBDLFM7+qR7oKIJKR3o0oJmeQyx+Wyq6MRYRhIiOQiIa6a0WZzSX+7kPPAxtj5B7GScNyrINa1P/N+Gw0CBevsioKnqwCEYMOMXZ/4n0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass header.i=linux.beauty; spf=pass smtp.mailfrom=me@linux.beauty; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1769784720; s=zmail; d=linux.beauty; i=me@linux.beauty; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-ID:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Message-Id:Reply-To; bh=g30GeD5luz415Zspf8u9IYtmiaQwDaZdE/ttvlyNc/k=; b=SRBhcykLjLSun/HHplWgjobxH70QpCOxNnIB0DaWK5iZEO87zOwRxq54q8nyP2jx XoHxEUvMJqbdI9x8JxfKq6C7wU84zHuW/+iGhgbIyQRHralNG+Vndzb1oQNEUZGhII6 2eLU4e0KbIMr5dvuwlU2SX7498WOIsToXjII5Nu8= Received: by mx.zohomail.com with SMTPS id 176978471899844.65970746766061; Fri, 30 Jan 2026 06:51:58 -0800 (PST) From: Li Chen To: Jonathan Corbet , Pasha Tatashin , Mike Rapoport , Pratyush Yadav , Eric Dumazet , Neal Cardwell , Kuniyuki Iwashima , "David S. Miller" , David Ahern , Jakub Kicinski , Paolo Abeni , Simon Horman , Andrew Morton , "Borislav Petkov (AMD)" , Randy Dunlap , Pawan Gupta , Petr Mladek , Feng Tang , Kees Cook , Li RongQing , Arnd Bergmann , Askar Safin , Frank van der Linden , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org Cc: Li Chen Subject: [PATCH v1 3/3] liveupdate: suppress TCP RST during post-kexec restore window Date: Fri, 30 Jan 2026 22:51:19 +0800 Message-ID: <20260130145122.368748-4-me@linux.beauty> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260130145122.368748-1-me@linux.beauty> References: <20260130145122.368748-1-me@linux.beauty> 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 X-ZohoMailClient: External Content-Type: text/plain; charset="utf-8" During a kexec-based live update, userspace may restore established TCP connections after the new kernel has booted (e.g. via CRIU). Any packet arriving for a not-yet-restored socket will hit the no-socket path and trigger a TCP RST, causing the peer to immediately drop the connection. Add an optional cmdline knob, liveupdate_tcp_rst_suppress=3D, to drop such packets while liveupdate_restore_in_progress() is true. Only segments with ACK set and SYN clear are dropped, and the default behavior remains unchanged. Document the liveupdate_tcp_rst_suppress cmdline parameter. Signed-off-by: Li Chen --- Documentation/admin-guide/kernel-parameters.txt | 10 ++++++++++ include/linux/liveupdate.h | 11 +++++++++++ kernel/liveupdate/luo_core.c | 14 ++++++++++++++ kernel/liveupdate/luo_session.c | 1 + net/ipv4/tcp_ipv4.c | 5 +++++ net/ipv6/tcp_ipv6.c | 5 +++++ 6 files changed, 46 insertions(+) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentatio= n/admin-guide/kernel-parameters.txt index 3097e4266d76..b73347a0aefd 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -3442,6 +3442,16 @@ Kernel parameters If there are multiple matching configurations changing the same attribute, the last one is used. =20 + liveupdate_tcp_rst_suppress=3D [KNL,EARLY] + Format: + When enabled, drop packets for established connections + (ACK set, SYN clear) that would otherwise trigger a RST + in the LUO post-kexec restore window. + This is useful when userspace restores sockets after + kexec (e.g. via CRIU). + Requires liveupdate=3Don. + Default: off. + lockd.nlm_grace_period=3DP [NFS] Assign grace period. Format: =20 diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h index 301d3e94516e..6ca740ec19d4 100644 --- a/include/linux/liveupdate.h +++ b/include/linux/liveupdate.h @@ -227,6 +227,12 @@ bool liveupdate_enabled(void); */ bool liveupdate_restore_in_progress(void); =20 +/* + * Return true when TCP RST suppression is enabled for the post-kexec rest= ore + * window. + */ +bool liveupdate_tcp_rst_suppress_enabled(void); + /* Called during kexec to tell LUO that entered into reboot */ int liveupdate_reboot(void); =20 @@ -253,6 +259,11 @@ static inline bool liveupdate_restore_in_progress(void) return false; } =20 +static inline bool liveupdate_tcp_rst_suppress_enabled(void) +{ + return false; +} + static inline int liveupdate_reboot(void) { return 0; diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c index fb6a73c08979..0ed5c9ce1421 100644 --- a/kernel/liveupdate/luo_core.c +++ b/kernel/liveupdate/luo_core.c @@ -64,6 +64,7 @@ =20 static struct { bool enabled; + bool tcp_rst_suppress; void *fdt_out; void *fdt_in; u64 liveupdate_num; @@ -75,6 +76,13 @@ static int __init early_liveupdate_param(char *buf) } early_param("liveupdate", early_liveupdate_param); =20 +static int __init early_liveupdate_tcp_rst_suppress_param(char *buf) +{ + return kstrtobool(buf, &luo_global.tcp_rst_suppress); +} +early_param("liveupdate_tcp_rst_suppress", + early_liveupdate_tcp_rst_suppress_param); + static int __init luo_early_startup(void) { phys_addr_t fdt_phys; @@ -259,6 +267,12 @@ bool liveupdate_enabled(void) return luo_global.enabled; } =20 +bool liveupdate_tcp_rst_suppress_enabled(void) +{ + return liveupdate_enabled() && luo_global.tcp_rst_suppress; +} +EXPORT_SYMBOL_GPL(liveupdate_tcp_rst_suppress_enabled); + /** * DOC: LUO ioctl Interface * diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_sessio= n.c index 2c7dd3b12303..427ae74061ba 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -146,6 +146,7 @@ bool liveupdate_restore_in_progress(void) { return atomic_long_read(&liveupdate_incoming_sessions_left) > 0; } +EXPORT_SYMBOL_GPL(liveupdate_restore_in_progress); =20 void __init luo_session_restore_window_init(void) { diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f8a9596e8f4d..9a95f3dbf39a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -2349,6 +2350,10 @@ int tcp_v4_rcv(struct sk_buff *skb) bad_packet: __TCP_INC_STATS(net, TCP_MIB_INERRS); } else { + if (liveupdate_tcp_rst_suppress_enabled() && + liveupdate_restore_in_progress() && + th->ack && !th->syn) + goto discard_it; tcp_v4_send_reset(NULL, skb, sk_rst_convert_drop_reason(drop_reason)); } =20 diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 280fe5978559..c2e680eba041 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -40,6 +40,7 @@ #include #include #include +#include =20 #include #include @@ -1900,6 +1901,10 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buf= f *skb) bad_packet: __TCP_INC_STATS(net, TCP_MIB_INERRS); } else { + if (liveupdate_tcp_rst_suppress_enabled() && + liveupdate_restore_in_progress() && + th->ack && !th->syn) + goto discard_it; tcp_v6_send_reset(NULL, skb, sk_rst_convert_drop_reason(drop_reason)); } =20 --=20 2.52.0