From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp3.mymangomail.com (unknown [209.141.44.239]) (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 A13BE317177 for ; Fri, 20 Mar 2026 18:00:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.141.44.239 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774029656; cv=none; b=igqkZhnv9m8wnqIRcDejTExhJ5TRdWUB3KqTEm1/pC4FiJdbhPYoS0OgYKDM2k0bem3D/CfE8kzug/IwjcATR8WD0I88ZDDQYixS0XwZovm9OVJIZ8A0C4N4PSeVWaezL3z7kQrm9/K5n3afhunbL1+khbRnhYtszDm58tbeKlU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1774029656; c=relaxed/simple; bh=QWzd64L8DpR90a0dwQiBIkOjZTFKBpBjyJYEA80DZcA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gn4TEpxhVGrudU2zIk9irM/ehuA5Sma16FoFRJYMScXn3fVse2YBsiJHACpp+irq34lfzDcy8vjtyC9T43andYLxcVomwH9Q2EmG0osBEE36lVKpIXt6mv7nHFACsctYUvHyChTTtRuxJNst2N5bzaeiv5W+YU06fhjz+v/UYwM= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=gerlicz.space; spf=pass smtp.mailfrom=gerlicz.space; dkim=pass (1024-bit key) header.d=gerlicz.space header.i=@gerlicz.space header.b=CVlr5fcb; arc=none smtp.client-ip=209.141.44.239 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=gerlicz.space Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gerlicz.space Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=gerlicz.space header.i=@gerlicz.space header.b="CVlr5fcb" Received: from [127.0.1.1] (localhost [127.0.0.1]) by hillsboro.smtp.mymangomail.com (Mango Mail) with ESMTP id CA6965D9CF; Fri, 20 Mar 2026 12:40:49 -0400 (EDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gerlicz.space; s=mango-1; t=1774024849; bh=QWzd64L8DpR90a0dwQiBIkOjZTFKBpBjyJYEA80DZcA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=CVlr5fcb4wlv/TtO3vW3AC/Jm6ICTm/eyKjhDPV/8VMUuIjXTpJsD0mdi8g71aYpf 0JIxHH9sE2RXzitN6IGUmCNVCy2ZwMms3/ZFHO0kL/QzBc2i/kETtbp69tnH8JJtOg 7T4KVWl6vtg2ax/fKQpnQizf1s2t4Gah5V5DMuq4= X-Mango-Origin: 1 X-Mango-Origin: 1 X-Mango-Origin: 1 X-Mango-Origin: 1 X-Mango-Origin: 1 X-Mango-Origin: 1 X-Mango-Origin: 1 X-Mango-Origin: 1 X-Mango-Origin: 1 Received: from authenticated-user (smtp.mymangomail.com [205.185.121.143]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by hillsboro.smtp.mymangomail.com (Mango Mail) with ESMTPSA id 92A775D9B1; Fri, 20 Mar 2026 12:39:37 -0400 (EDT) From: Oskar Gerlicz Kowalczuk To: Pasha Tatashin , Mike Rapoport , Baoquan He Cc: Pratyush Yadav , Andrew Morton , linux-kernel@vger.kernel.org, kexec@lists.infradead.org, linux-mm@kvack.org, Oskar Gerlicz Kowalczuk Subject: [PATCH 2/5] kexec: abort liveupdate handover on kernel_kexec() unwind Date: Fri, 20 Mar 2026 17:37:17 +0100 Message-ID: <20260320163720.100456-2-oskar@gerlicz.space> In-Reply-To: <20260320163720.100456-1-oskar@gerlicz.space> References: <20260320163720.100456-1-oskar@gerlicz.space> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Once outgoing sessions are blocked during reboot, every failure path after liveupdate_reboot() must release that state again. Today kernel_kexec() sets liveupdate_prepared only after liveupdate_reboot() returns successfully, so a partial failure inside liveupdate_reboot() skips the abort path entirely. The kho_finalize() failure path also leaves the LUO session state frozen. This is dangerous because a failed kexec attempt can leave userspace with outgoing sessions stuck in reboot state, blocking release and preserve paths until the next reboot. Export a liveupdate_reboot_abort() helper, call it from the kho_finalize() error path, and mark liveupdate as prepared before entering liveupdate_reboot(). That makes every failed handover attempt unwind the session state and wake blocked waiters. Signed-off-by: Oskar Gerlicz Kowalczuk --- include/linux/liveupdate.h | 5 +++++ kernel/kexec_core.c | 4 ++++ kernel/liveupdate/luo_core.c | 11 ++++++++++- kernel/liveupdate/luo_internal.h | 1 + kernel/liveupdate/luo_session.c | 23 +++++++++++++++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h index dd11fdc76a5f..d93b043a0421 100644 --- a/include/linux/liveupdate.h +++ b/include/linux/liveupdate.h @@ -226,6 +226,7 @@ bool liveupdate_enabled(void); /* Called during kexec to tell LUO that entered into reboot */ int liveupdate_reboot(void); +void liveupdate_reboot_abort(void); int liveupdate_register_file_handler(struct liveupdate_file_handler *fh); int liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh); @@ -250,6 +251,10 @@ static inline int liveupdate_reboot(void) return 0; } +static inline void liveupdate_reboot_abort(void) +{ +} + static inline int liveupdate_register_file_handler(struct liveupdate_file_handler *fh) { return -EOPNOTSUPP; diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index 2fea396d29b9..492c17f7e96f 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -1139,6 +1139,7 @@ bool kexec_load_permitted(int kexec_image_type) int kernel_kexec(void) { int error = 0; + bool liveupdate_prepared = false; if (!kexec_trylock()) return -EBUSY; @@ -1147,6 +1148,7 @@ int kernel_kexec(void) goto Unlock; } + liveupdate_prepared = true; error = liveupdate_reboot(); if (error) goto Unlock; @@ -1231,6 +1233,8 @@ int kernel_kexec(void) #endif Unlock: + if (error && liveupdate_prepared) + liveupdate_reboot_abort(); kexec_unlock(); return error; } diff --git a/kernel/liveupdate/luo_core.c b/kernel/liveupdate/luo_core.c index dda7bb57d421..95a0b81ce60d 100644 --- a/kernel/liveupdate/luo_core.c +++ b/kernel/liveupdate/luo_core.c @@ -233,8 +233,9 @@ int liveupdate_reboot(void) err = kho_finalize(); if (err) { pr_err("kho_finalize failed %d\n", err); + liveupdate_reboot_abort(); /* - * kho_finalize() may return libfdt errors, to aboid passing to + * kho_finalize() may return libfdt errors, to avoid passing to * userspace unknown errors, change this to EAGAIN. */ err = -EAGAIN; @@ -243,6 +244,14 @@ int liveupdate_reboot(void) return err; } +void liveupdate_reboot_abort(void) +{ + if (!liveupdate_enabled()) + return; + + luo_session_abort_reboot(); +} + /** * liveupdate_enabled - Check if the live update feature is enabled. * diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h index 8083d8739b09..ad09ea756156 100644 --- a/kernel/liveupdate/luo_internal.h +++ b/kernel/liveupdate/luo_internal.h @@ -82,6 +82,7 @@ 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); int luo_session_serialize(void); +void luo_session_abort_reboot(void); int luo_session_deserialize(void); bool luo_session_quiesce(void); void luo_session_resume(void); diff --git a/kernel/liveupdate/luo_session.c b/kernel/liveupdate/luo_session.c index ee5ea2a8ed3f..39215e5eda7a 100644 --- a/kernel/liveupdate/luo_session.c +++ b/kernel/liveupdate/luo_session.c @@ -649,6 +649,29 @@ int luo_session_serialize(void) return err; } +void luo_session_abort_reboot(void) +{ + struct luo_session_header *sh = &luo_session_global.outgoing; + struct luo_session *session; + int i = 0; + + guard(rwsem_write)(&sh->rwsem); + if (!READ_ONCE(sh->rebooting)) + return; + + list_for_each_entry(session, &sh->list, list) { + if (i >= sh->header_ser->count) + break; + + luo_session_unfreeze_one(session, &sh->ser[i]); + memset(&sh->ser[i], 0, sizeof(sh->ser[i])); + i++; + } + + sh->header_ser->count = 0; + luo_session_reboot_done(sh); +} + /** * luo_session_quiesce - Ensure no active sessions exist and lock session lists. * -- 2.53.0