From nobody Mon Sep 28 13:59:28 2026 Received: from mail-pg1-f198.google.com (mail-pg1-f198.google.com [209.85.215.198]) (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 3FCF4346A0B for ; Thu, 20 Aug 2026 19:19:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.198 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787253547; cv=none; b=lH/0oGOc48P6QuP5lUxQa8pcEOSJpvoWVQuZEVZenUmnV71Q6wYCJPCIMvByIxkz6TmcOk8c4jO0oz6Ymys4JMgn4MGVNG+eXhEdhF2LskY2WxnEsY+jtE9I+GfAx1XQz/bx78rtvKW8xch24KCHDUBkJpvukti4pcpDz1/qxxw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787253547; c=relaxed/simple; bh=JeIQ5YzQA7ox6ArI9duNTXrPTlTiy0pz+FRKTCuyWjQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=GGKb5n2OCKd8TnyXWd7YVlML4y5NnZXJAU5fC4WbEM0iLjSs7OY1MO12G7pXpMotSyHfBqpF7j4gj6fhkMgI8B+mEuh70i7z953QNRZ1Giyu6QdpQs4paN9osMRli6YYnYVCwREAgxrKoquEZNZZpvQ7nxi31P+Index5Ie518E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--skhawaja.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=J1M4q4Eo; arc=none smtp.client-ip=209.85.215.198 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--skhawaja.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="J1M4q4Eo" Received: by mail-pg1-f198.google.com with SMTP id 41be03b00d2f7-cc11b5dd54dso484439a12.3 for ; Thu, 20 Aug 2026 12:19:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1787253545; x=1787858345; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=fQ+SSW2xYaWYPCjZNKHlYzGG7Cn/26PBkUG+IbsFEFI=; b=J1M4q4EoELU3DxE4KHQZDTYjEKUf84IambCi1wqHsz+1wvtfciUEfmyP/t/YJoeuF4 v12bDnagvnuc79gtAUI5kwFPyhgKx/2XdWhMQqQAyFPgmyfyt7SvgrDMOSdnGwzMqzkx OCs5Y80g7P3MMGyPHKzkWCoOSyTX04Vv6TtP2pmP4C0FxRM6RS3QswG4lTd8cIeJIYZR FJXnPO/298x60s/XTqM34K+EB8K4p3bVGrPEznBfKzVxUTqCjpEwr374IU2xqe6QQGoo xklSn2ZXBb0Zsn22b8LOPwYR/yCp0KJTp4XryMWid2Cr9ghXQGDyYwo9S4k329u8tnko 2MWw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787253545; x=1787858345; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=fQ+SSW2xYaWYPCjZNKHlYzGG7Cn/26PBkUG+IbsFEFI=; b=ics0Fowinx9RfZFdBp9tcf/ZS9Z4jV+wUvmSvP1zhOKLB7vdiWWeVNgCMyvh+k23oV j1hPsBpqpR02P3LO2rB84/VK8VddRyNhwHZc0ZaJbBvpQgPWY+3+0H0l9kotR3KvFytn diGwUEmdT8TMfjGog0rfrtu29Kkp+kzOvrA6D6Lw7FzvIQIkibpm51cuGSrKi7wFmBfK 9gtTQnd0CYLGVe018cqsDz/y5Fxx0yZ+lgsURqzE2ajI8KmyQ4k6CzFqKW7sPihmz6sm Fp8K9DoWZrtIX8IvEzDYGviJkULHWA/fzjGWASM+U3w5Rkky5WG+YCDyaOXXg/uiZOmM txcA== X-Forwarded-Encrypted: i=1; AHgh+RoPuRV9evXpjThgh+FL/X83315+YYwjdzkgx7gijOkWLaRfrIp2TdwbaWRroj66I2cR2qpQFmlSmbV1WqY=@vger.kernel.org X-Gm-Message-State: AOJu0Yzex4pxdMxQPNmN/KGHRnbLJPT8NiQ26qdnOkbje4KLpjzYj9XA uEtOAS0XiiAc4Mwh1A0NOmI4bWrh12yFm6OYkQjUNttdNUMDMUl8nMOV90yKZ7ot4DCTOtnJeyB gvQ/v4i2N+3Rhdw== X-Received: from pgsb12.prod.google.com ([2002:a65:67cc:0:b0:cc1:4df5:5acb]) (user=skhawaja job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:4516:b0:3b2:a809:ffe with SMTP id adf61e73a8af0-3cd300901e1mr1395552637.14.1787253545341; Thu, 20 Aug 2026 12:19:05 -0700 (PDT) Date: Thu, 20 Aug 2026 19:18:54 +0000 In-Reply-To: <20260820191854.1642931-1-skhawaja@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260820191854.1642931-1-skhawaja@google.com> X-Mailer: git-send-email 2.55.0.766.g2966f0265a-goog Message-ID: <20260820191854.1642931-2-skhawaja@google.com> Subject: [PATCH v3 1/1] liveupdate: luo_file: Add internal APIs for file preservation From: Samiullah Khawaja To: Pasha Tatashin , Mike Rapoport , Pratyush Yadav , Alexander Graf Cc: Pranjal Shrivastava , Samiullah Khawaja , David Matlack , tarunsahu@google.com, open list , "open list:KEXEC HANDOVER (KHO)" , "open list:KEXEC HANDOVER (KHO)" Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Pasha Tatashin Live update orchestrator file handlers depend on the preservation of other files. To make sure that the dependency is preserved, the file handlers needs to fetch the preservation token of the preserved dependency. Similarly during restore, a file handler wants to fetch the restored file of the dependency. Add APIs that allows fetching token of dependency during preservation, and fetching the restored file dependency during restore. Reviewed-by: Pranjal Shrivastava Signed-off-by: Pasha Tatashin Signed-off-by: Samiullah Khawaja --- include/linux/liveupdate.h | 22 +++++++++ kernel/liveupdate/luo_file.c | 84 ++++++++++++++++++++++++++++++++ kernel/liveupdate/luo_internal.h | 17 +++++++ 3 files changed, 123 insertions(+) diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h index 63ea5417de84..6051abc0612c 100644 --- a/include/linux/liveupdate.h +++ b/include/linux/liveupdate.h @@ -25,6 +25,7 @@ struct file; /** * struct liveupdate_file_op_args - Arguments for file operation callbacks. * @handler: The file handler being called. + * @session: The session this file belongs to. * @retrieve_status: The retrieve status for the 'can_finish / finish' * operation. A value of 0 means the retrieve has not b= een * attempted, a positive value means the retrieve was @@ -45,6 +46,7 @@ struct file; */ struct liveupdate_file_op_args { struct liveupdate_file_handler *handler; + struct liveupdate_session *session; int retrieve_status; struct file *file; u64 serialized_data; @@ -247,6 +249,14 @@ void liveupdate_flb_put_incoming(struct liveupdate_flb= *flb); int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp); void liveupdate_flb_put_outgoing(struct liveupdate_flb *flb); =20 +/* kernel can internally retrieve files */ +int liveupdate_get_file_incoming(struct liveupdate_session *s, u64 token, + struct file **filep); + +/* Get a token for an outgoing file, or -ENOENT if file is not preserved */ +int liveupdate_get_token_outgoing(struct liveupdate_session *s, + struct file *file, u64 *tokenp); + #else /* CONFIG_LIVEUPDATE */ =20 static inline bool liveupdate_enabled(void) @@ -299,5 +309,17 @@ static inline void liveupdate_flb_put_outgoing(struct = liveupdate_flb *flb) { } =20 +static inline int liveupdate_get_file_incoming(struct liveupdate_session *= s, + u64 token, struct file **filep) +{ + return -EOPNOTSUPP; +} + +static inline int liveupdate_get_token_outgoing(struct liveupdate_session = *s, + struct file *file, u64 *tokenp) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_LIVEUPDATE */ #endif /* _LINUX_LIVEUPDATE_H */ diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c index c39f96961a85..0a4994377c98 100644 --- a/kernel/liveupdate/luo_file.c +++ b/kernel/liveupdate/luo_file.c @@ -91,6 +91,21 @@ * again later. If the issue cannot be resolved, these resources will b= e held * by LUO until the next live update cycle, at which point they will be * discarded. + * + * Dependencies: + * + * Preserved files may have dependencies on other files that also need to = be + * preserved during a live update. A file handler can resolve these depend= encies + * by querying the token of the dependency. That token can then be seriali= zed + * and used to fetch the dependency during the retrieve() callback in the = next + * kernel. + * + * Some of these dependencies can be resolved late during File Handler fre= eze() + * callback, but some of these might need resolution during File Handler + * preserve() callback based on the constraints such as immutability and + * performance. This introduces an order of preservation. Note that the or= der of + * preservation of dependencies can be safely relaxed later, but it cannot= be + * enforced later. */ =20 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -284,6 +299,7 @@ int luo_preserve_file(struct luo_file_set *file_set, u6= 4 token, int fd) mutex_init(&luo_file->mutex); =20 args.handler =3D fh; + args.session =3D luo_session_from_file_set(file_set); args.file =3D file; err =3D fh->ops->preserve(&args); if (err) @@ -341,6 +357,7 @@ void luo_file_unpreserve_files(struct luo_file_set *fil= e_set) struct luo_file, list); =20 args.handler =3D luo_file->fh; + args.session =3D luo_session_from_file_set(file_set); args.file =3D luo_file->file; args.serialized_data =3D luo_file->serialized_data; args.private_data =3D luo_file->private_data; @@ -374,6 +391,7 @@ static int luo_file_freeze_one(struct luo_file_set *fil= e_set, struct liveupdate_file_op_args args =3D {0}; =20 args.handler =3D luo_file->fh; + args.session =3D luo_session_from_file_set(file_set); args.file =3D luo_file->file; args.serialized_data =3D luo_file->serialized_data; args.private_data =3D luo_file->private_data; @@ -395,6 +413,7 @@ static void luo_file_unfreeze_one(struct luo_file_set *= file_set, struct liveupdate_file_op_args args =3D {0}; =20 args.handler =3D luo_file->fh; + args.session =3D luo_session_from_file_set(file_set); args.file =3D luo_file->file; args.serialized_data =3D luo_file->serialized_data; args.private_data =3D luo_file->private_data; @@ -587,6 +606,7 @@ int luo_retrieve_file(struct luo_file_set *file_set, u6= 4 token, } =20 args.handler =3D luo_file->fh; + args.session =3D luo_session_from_file_set(file_set); args.serialized_data =3D luo_file->serialized_data; err =3D luo_file->fh->ops->retrieve(&args); if (err) { @@ -620,6 +640,7 @@ static int luo_file_can_finish_one(struct luo_file_set = *file_set, struct liveupdate_file_op_args args =3D {0}; =20 args.handler =3D luo_file->fh; + args.session =3D luo_session_from_file_set(file_set); args.file =3D luo_file->file; args.serialized_data =3D luo_file->serialized_data; args.retrieve_status =3D luo_file->retrieve_status; @@ -637,6 +658,7 @@ static void luo_file_finish_one(struct luo_file_set *fi= le_set, guard(mutex)(&luo_file->mutex); =20 args.handler =3D luo_file->fh; + args.session =3D luo_session_from_file_set(file_set); args.file =3D luo_file->file; args.serialized_data =3D luo_file->serialized_data; args.retrieve_status =3D luo_file->retrieve_status; @@ -926,3 +948,65 @@ void liveupdate_unregister_file_handler(struct liveupd= ate_file_handler *fh) luo_flb_unregister_all(fh); list_del(&ACCESS_PRIVATE(fh, list)); } + +/** + * liveupdate_get_token_outgoing - Get the token for a preserved file. + * @s: The outgoing liveupdate session. + * @file: The file object to search for. + * @tokenp: Output parameter for the found token. + * + * Searches the list of preserved files in an outgoing session for a match= ing + * file object. If found, the corresponding user-provided token is returne= d. + * + * This function is intended for in-kernel callers that need to correlate a + * file with its liveupdate token. + * + * Context: It must be called with session mutex acquired. + * Return: 0 on success, -ENOENT if the file is not preserved in this sess= ion. + */ +int liveupdate_get_token_outgoing(struct liveupdate_session *s, + struct file *file, u64 *tokenp) +{ + struct luo_file_set *file_set =3D luo_file_set_from_session_locked(s); + struct luo_file *luo_file; + int err =3D -ENOENT; + + list_for_each_entry(luo_file, &file_set->files_list, list) { + if (luo_file->file =3D=3D file) { + if (tokenp) + *tokenp =3D luo_file->token; + err =3D 0; + break; + } + } + + return err; +} +EXPORT_SYMBOL_GPL(liveupdate_get_token_outgoing); + +/** + * liveupdate_get_file_incoming - Retrieves a preserved file for in-kernel= use. + * @s: The incoming liveupdate session (restored from the previous ke= rnel). + * @token: The unique token identifying the file to retrieve. + * @filep: On success, this will be populated with a pointer to the retri= eved + * 'struct file'. + * + * Provides a kernel-internal API for other subsystems to retrieve their + * preserved files after a live update. This function is a simple wrapper + * around luo_retrieve_file(), allowing callers to find a file by its toke= n. + * + * The caller receives a new reference to the file and must call fput() wh= en it + * is no longer needed. The file's lifetime is managed by LUO and any user= space + * file descriptors. + * + * Context: It must be called with session mutex acquired of a restored se= ssion. + * Return: 0 on success. Returns -ENOENT if no file with the matching toke= n is + * found, or any other negative errno on failure. + */ +int liveupdate_get_file_incoming(struct liveupdate_session *s, u64 token, + struct file **filep) +{ + return luo_retrieve_file(luo_file_set_from_session_locked(s), + token, filep); +} +EXPORT_SYMBOL_GPL(liveupdate_get_file_incoming); diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_inter= nal.h index 64879ffe7378..dac6644bfb18 100644 --- a/kernel/liveupdate/luo_internal.h +++ b/kernel/liveupdate/luo_internal.h @@ -77,6 +77,23 @@ struct luo_session { =20 extern struct rw_semaphore luo_register_rwlock; =20 +static inline struct liveupdate_session *luo_session_from_file_set(struct = luo_file_set *file_set) +{ + struct luo_session *session; + + session =3D container_of(file_set, struct luo_session, file_set); + + return (struct liveupdate_session *)session; +} + +static inline struct luo_file_set *luo_file_set_from_session_locked(struct= liveupdate_session *s) +{ + struct luo_session *session =3D (struct luo_session *)s; + + lockdep_assert_held(&session->mutex); + return &session->file_set; +} + int luo_session_create(const char *name, struct file **filep); int luo_session_retrieve(const char *name, struct file **filep); void __init luo_session_setup_outgoing(u64 *sessions_pa); --=20 2.55.0.766.g2966f0265a-goog