From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pf1-f201.google.com (mail-pf1-f201.google.com [209.85.210.201]) (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 98A2A3E8662 for ; Mon, 27 Apr 2026 17:56:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777312600; cv=none; b=khV+C1n0F20zqje1aHBA16o7kBK/Ys2/aWkUckeNpnoxISO2iI1d1FbO3u67PNJZQRwpFa4EEHjj4zvpXSRZ1N0hj1eckq2E+f1lbQ4t9vKj6jJm39cQPnOpqPSTFR2opw8+CL/KvIikMyF+qLpAhhiqxG3XGGLZmEI4DmeS0vA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777312600; c=relaxed/simple; bh=x4IOU98o+rjmFYQTmP04oUgS1EoRHQ+c8IqZoCnpH7c=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=IICFjffVxKjx0eEB3KgHCBi0NPHhLBEVoOD2s1ZXB4Y7k27tB9RWxzrOQaeoXCElMIeoBK3pcXLvtMTc7vaOyoFM/oeoko5Qb+n6Z8Erxrh57tkE4viDgkSKcF8yGGW22XwUyKiygMnR5MXBaNXZm64rD8l5qCIXRcphqFFmI+w= 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=GyI3KJBh; arc=none smtp.client-ip=209.85.210.201 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="GyI3KJBh" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-82f71437218so6941623b3a.2 for ; Mon, 27 Apr 2026 10:56:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1777312597; x=1777917397; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=mmUApxay/7DEPGb/4OIg6VDc6PfvE6l8vIcH5zw5p8M=; b=GyI3KJBhXPRg4dWEGzV9AjICwsqT+r9d6UMPdx7889K67rZxOkmAJScHmr9PM3CC0v NwUVcuSslHfaeasuiDB87PJaU3TnLOA3dxOQU+XGYDtv7uZKLhMJebNZNP4ERfFQiJJE oxkIHPbWTyg0GW1j1685nxG4AyKCICv3AZm0mz60yJUo0oPbJnnu4jpt3FjOmfIYgKls A9BnVtvpBL/Di71RdOu7FwQvB1JgFJSVEx1Me8JqB8u+D6Pe3xxgiz7RF+s3fZHdwhSB LWjcGDfxRvKZG6AT7qdbnR5wZJv6sUnz+lb9mF3TKvmRn4+Ev7JSNnr+PFLHQ7+A33ka +Blw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777312597; x=1777917397; h=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; bh=mmUApxay/7DEPGb/4OIg6VDc6PfvE6l8vIcH5zw5p8M=; b=asyeC303LT2lXwSxodSkqIM8FZj1BfV2Xhd2rHusTzV7hp4xlYQMbE6eCMxqdXjnAU xXZwVEhl9DyJHC8KqRa2QMaX04jm5rl3OV3APrnvBP8/SXSFt7CwPAdg5FDAV6kNFsm7 jfpHW6FgM3QC/VYtpFvqhxxBomS3ygUNH5eiBWbwBrnr4AGKsnVvCchJCWSAqlpL2qfP V5mn/HMYZAIe6YAS+HA7NpVL33MRDUA8ygYxbdNg4qmFsmev0NAIeF13vASbupnxVekL J36AaqhCcznWXgMkNgtE7UxR36/l5+mQrkgEf4KqTaPy2puwSPojpFOlyoqjDV4r5+cU Cckw== X-Forwarded-Encrypted: i=1; AFNElJ+RfoAqjX4At5d/eBLVTe+gB+5NlfsUwUpLzIbvhiXfSVkFtiN5VpIL51sXr4xnowb/7IBWX6MKd2eYlrA=@vger.kernel.org X-Gm-Message-State: AOJu0YykCo/XSepd5Vv8ft0XEk3ZywS46VvsDlOCpwS1uXDxovJqux48 obwFv1pvGm0vf8eQDRIQ3jwhG+3nzWpK5P1LQjH7Qeakm4ayUkfSa7E79J+ouvWwKrEyncr7jCk hnFrOOj9/K53BTg== X-Received: from pghu17.prod.google.com ([2002:a63:ef11:0:b0:c74:321:201a]) (user=skhawaja job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:6a1b:b0:398:6ea8:21d2 with SMTP id adf61e73a8af0-3a398c940d5mr486685637.19.1777312596794; Mon, 27 Apr 2026 10:56:36 -0700 (PDT) Date: Mon, 27 Apr 2026 17:56:18 +0000 In-Reply-To: <20260427175633.1978233-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: <20260427175633.1978233-1-skhawaja@google.com> X-Mailer: git-send-email 2.54.0.545.g6539524ca2-goog Message-ID: <20260427175633.1978233-2-skhawaja@google.com> Subject: [PATCH v2 01/16] liveupdate: luo_file: Add internal APIs for file preservation From: Samiullah Khawaja To: David Woodhouse , Lu Baolu , Joerg Roedel , Will Deacon , Jason Gunthorpe Cc: Pasha Tatashin , Samiullah Khawaja , Robin Murphy , Kevin Tian , Alex Williamson , Shuah Khan , iommu@lists.linux.dev, linux-kernel@vger.kernel.org, kvm@vger.kernel.org, Saeed Mahameed , Adithya Jayachandran , Parav Pandit , Leon Romanovsky , William Tu , Pratyush Yadav , David Matlack , Andrew Morton , Chris Li , Pranjal Shrivastava , Vipin Sharma , YiFei Zhu Content-Type: text/plain; charset="UTF-8" From: Pasha Tatashin The core liveupdate mechanism allows userspace to preserve file descriptors. However, kernel subsystems often manage struct file objects directly and need to participate in the preservation process programmatically without relying solely on userspace interaction. Signed-off-by: Pasha Tatashin Signed-off-by: Samiullah Khawaja --- include/linux/liveupdate.h | 21 ++++++++++ kernel/liveupdate/luo_file.c | 69 ++++++++++++++++++++++++++++++++ kernel/liveupdate/luo_internal.h | 17 ++++++++ 3 files changed, 107 insertions(+) diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h index 88722e5caf02..261f61998fce 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 been * 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; @@ -243,6 +245,13 @@ int liveupdate_flb_get_incoming(struct liveupdate_flb *flb, void **objp); void liveupdate_flb_put_incoming(struct liveupdate_flb *flb); int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, void **objp); +/* 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 */ @@ -292,5 +301,17 @@ static inline int liveupdate_flb_get_outgoing(struct liveupdate_flb *flb, return -EOPNOTSUPP; } +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 a0a419085e28..0aa0b4e5339f 100644 --- a/kernel/liveupdate/luo_file.c +++ b/kernel/liveupdate/luo_file.c @@ -323,6 +323,7 @@ int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd) mutex_init(&luo_file->mutex); args.handler = fh; + args.session = luo_session_from_file_set(file_set); args.file = file; err = fh->ops->preserve(&args); if (err) @@ -380,6 +381,7 @@ void luo_file_unpreserve_files(struct luo_file_set *file_set) struct luo_file, list); args.handler = luo_file->fh; + args.session = luo_session_from_file_set(file_set); args.file = luo_file->file; args.serialized_data = luo_file->serialized_data; args.private_data = luo_file->private_data; @@ -411,6 +413,7 @@ static int luo_file_freeze_one(struct luo_file_set *file_set, struct liveupdate_file_op_args args = {0}; args.handler = luo_file->fh; + args.session = luo_session_from_file_set(file_set); args.file = luo_file->file; args.serialized_data = luo_file->serialized_data; args.private_data = luo_file->private_data; @@ -432,6 +435,7 @@ static void luo_file_unfreeze_one(struct luo_file_set *file_set, struct liveupdate_file_op_args args = {0}; args.handler = luo_file->fh; + args.session = luo_session_from_file_set(file_set); args.file = luo_file->file; args.serialized_data = luo_file->serialized_data; args.private_data = luo_file->private_data; @@ -621,6 +625,7 @@ int luo_retrieve_file(struct luo_file_set *file_set, u64 token, } args.handler = luo_file->fh; + args.session = luo_session_from_file_set(file_set); args.serialized_data = luo_file->serialized_data; err = luo_file->fh->ops->retrieve(&args); if (err) { @@ -654,6 +659,7 @@ static int luo_file_can_finish_one(struct luo_file_set *file_set, struct liveupdate_file_op_args args = {0}; args.handler = luo_file->fh; + args.session = luo_session_from_file_set(file_set); args.file = luo_file->file; args.serialized_data = luo_file->serialized_data; args.retrieve_status = luo_file->retrieve_status; @@ -671,6 +677,7 @@ static void luo_file_finish_one(struct luo_file_set *file_set, guard(mutex)(&luo_file->mutex); args.handler = luo_file->fh; + args.session = luo_session_from_file_set(file_set); args.file = luo_file->file; args.serialized_data = luo_file->serialized_data; args.retrieve_status = luo_file->retrieve_status; @@ -924,3 +931,65 @@ void liveupdate_unregister_file_handler(struct liveupdate_file_handler *fh) luo_flb_unregister_all(fh); list_del(&ACCESS_PRIVATE(fh, list)); } +EXPORT_SYMBOL_GPL(liveupdate_unregister_file_handler); + +/** + * 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 matching + * file object. If found, the corresponding user-provided token is returned. + * + * 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 session. + */ +int liveupdate_get_token_outgoing(struct liveupdate_session *s, + struct file *file, u64 *tokenp) +{ + struct luo_file_set *file_set = luo_file_set_from_session_locked(s); + struct luo_file *luo_file; + int err = -ENOENT; + + list_for_each_entry(luo_file, &file_set->files_list, list) { + if (luo_file->file == file) { + if (tokenp) + *tokenp = luo_file->token; + err = 0; + break; + } + } + + return err; +} + +/** + * liveupdate_get_file_incoming - Retrieves a preserved file for in-kernel use. + * @s: The incoming liveupdate session (restored from the previous kernel). + * @token: The unique token identifying the file to retrieve. + * @filep: On success, this will be populated with a pointer to the retrieved + * '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 token. + * + * The caller receives a new reference to the file and must call fput() when it + * is no longer needed. The file's lifetime is managed by LUO and any userspace + * file descriptors. If the caller needs to hold a reference to the file beyond + * the immediate scope, it must call get_file() itself. + * + * Context: It must be called with session mutex acquired of a restored session. + * Return: 0 on success. Returns -ENOENT if no file with the matching token 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); +} diff --git a/kernel/liveupdate/luo_internal.h b/kernel/liveupdate/luo_internal.h index 875844d7a41d..08b198802e7f 100644 --- a/kernel/liveupdate/luo_internal.h +++ b/kernel/liveupdate/luo_internal.h @@ -79,6 +79,23 @@ struct luo_session { extern struct rw_semaphore luo_register_rwlock; +static inline struct liveupdate_session *luo_session_from_file_set(struct luo_file_set *file_set) +{ + struct luo_session *session; + + session = 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 = (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); int __init luo_session_setup_outgoing(void *fdt); -- 2.54.0.545.g6539524ca2-goog