From: Josh Poimboeuf <jpoimboe@kernel.org>
To: Yafang Shao <laoar.shao@gmail.com>
Cc: jikos@kernel.org, mbenes@suse.cz, pmladek@suse.com,
joe.lawrence@redhat.com, song@kernel.org,
live-patching@vger.kernel.org
Subject: Re: [PATCH v7 for-next 3/8] livepatch: Implement replace set for scoped atomic replace
Date: Thu, 27 Aug 2026 17:26:14 -0700 [thread overview]
Message-ID: <apDO-a2n9UlrO_FA@jpoimboe> (raw)
In-Reply-To: <20260825114641.80452-4-laoar.shao@gmail.com>
On Tue, Aug 25, 2026 at 07:46:36PM +0800, Yafang Shao wrote:
> The current bool replace flag is too coarse: it is either all or
> nothing. A livepatch with .replace=true replaces ALL existing
> livepatches, which is safe but inflexible. There is no way to have
> multiple independent livepatch sets coexist on the same system.
>
> Replace it with a more flexible model using two new fields in
> struct klp_patch:
>
> - provides: an unsigned int id identifying the patch replace set.
> By default (provides=0), any livepatch replaces any other livepatch.
>
> - obsoletes: an optional array of unsigned int ids specifying
> additional provides ids to be replaced. This allows a new patch
> to explicitly obsolete patches from different replace sets.
>
> A new livepatch atomically replaces any existing livepatch whose
> provides id matches either:
> 1. The new patch provides id (same replace set), or
> 2. Any id in the new patch obsoletes list
>
> The klp-build script is updated with -p/--provides and -r/--obsoletes
> options. The obsoletes list automatically includes the provides id
> and deduplicates entries. Input validation rejects malformed values
> at build time.
>
> Two helper functions are introduced:
> - klp_patch_replaceable(): checks if an new patch will replace the old
> patch
Should be klp_patch_replaces()?
> - klp_has_function_conflict(): rejects loading a livepatch that would
> modify a function already patched by a livepatch with a different
> provides id.
I'm not sure the commit log really needs to list some functions it adds,
that's already evident in the patch.
> diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
> index ba9e3988c07c..854ed6230b96 100644
> --- a/include/linux/livepatch.h
> +++ b/include/linux/livepatch.h
> @@ -123,7 +123,8 @@ struct klp_state {
> * @mod: reference to the live patch module
> * @objs: object entries for kernel objects to be patched
> * @states: system states that can get modified
> - * @replace: replace all actively used patches
> + * @provides: only one active livepatch per id
> + * @obsoletes: replace given livepatch id(s)
> * @list: list node for global list of actively used patches
> * @kobj: kobject for sysfs resources
> * @obj_list: dynamic list of the object entries
> @@ -137,7 +138,9 @@ struct klp_patch {
> struct module *mod;
> struct klp_object *objs;
> struct klp_state *states;
> - bool replace;
> + unsigned int provides;
> + unsigned int *obsoletes;
> + unsigned int nr_obsoletes;
nr_obsoletes is missing from the kernel-doc above.
> @@ -72,15 +71,76 @@ static int __init livepatch_mod_init(void)
>
> /* TODO patch->states */
>
> -#ifdef KLP_NO_REPLACE
> - patch->replace = false;
> +#ifdef KLP_PROVIDES
> + patch->provides = KLP_PROVIDES;
> #else
> - patch->replace = true;
> + patch->provides = 0;
> +#endif
'patch' is already zeroed, so the #else isn't needed.
> +#ifdef KLP_OBSOLETES
> + /*
> + * Parse KLP_OBSOLETES string (format: "1,2,3") and convert to
> + * unsigned int array for patch->obsoletes.
> + *
> + * Note: The provides ID is not included here; the kernel will
> + * replace livepatch with the same provides ID.
> + */
> + {
> + unsigned int *obs_array;
> + unsigned int count = 1;
> + char *obsoletes_str;
> + char *token, *str;
> + int i = 0;
> +
> + for (str = (char *)KLP_OBSOLETES; *str; str++) {
> + if (*str == ',')
> + count++;
> + }
> +
> + obsoletes_str = kstrdup(KLP_OBSOLETES, GFP_KERNEL);
> + if (!obsoletes_str) {
> + ret = -ENOMEM;
> + goto err_free_objs;
> + }
> +
> + obs_array = kmalloc_array(count, sizeof(unsigned int), GFP_KERNEL);
> + if (!obs_array) {
> + kfree(obsoletes_str);
> + ret = -ENOMEM;
> + goto err_free_objs;
> + }
> +
> + str = obsoletes_str;
> + while ((token = strsep(&str, ",")) != NULL) {
> + unsigned int val;
> +
> + ret = kstrtouint(token, 10, &val);
> + if (ret) {
> + kfree(obsoletes_str);
> + kfree(obs_array);
> + goto err_free_objs;
> + }
> + obs_array[i++] = val;
> + }
> +
> + patch->obsoletes = obs_array;
> + patch->nr_obsoletes = i;
> +
> + if (i > 0)
> + pr_info("obsoletes patch ids: %s\n", KLP_OBSOLETES);
> +
> + kfree(obsoletes_str);
> + }
Can we do something simpler like this?
#ifdef KLP_OBSOLETES
static unsigned int klp_obsoletes[] = { KLP_OBSOLETES };
#endif
And in livepatch_mod_init():
#ifdef KLP_PROVIDES
patch->provides = KLP_PROVIDES;
#endif
#ifdef KLP_OBSOLETES
patch->obsoletes = klp_obsoletes;
patch->nr_obsoletes = ARRAY_SIZE(klp_obsoletes);
#endif
> +++ b/scripts/livepatch/klp-build
> @@ -21,7 +21,8 @@ shopt -s lastpipe
>
> unset DEBUG_CLONE DIFF_CHECKSUM SKIP_CLEANUP VERBOSE XTRACE
>
> -REPLACE=1
> +PROVIDES=0
> +OBSOLETES=""
> SHORT_CIRCUIT=0
> JOBS="$(getconf _NPROCESSORS_ONLN)"
> shopt -o xtrace | grep -q 'on' && XTRACE=1
> @@ -132,7 +133,8 @@ Options:
> -f, --show-first-changed Show address of first changed instruction
> -j, --jobs=<jobs> Build jobs to run simultaneously [default: $JOBS]
> -o, --output=<file.ko> Output file [default: livepatch-<patch-name>.ko]
> - --no-replace Disable livepatch atomic replace
> + -p, --provides=<id> Set the provides id for this livepatch
> + -r, --obsoletes=<ids> Set the obsoletes ids array (e.g., "0,1,2")
> -v, --verbose Pass V=1 to kernel/module builds
>
> Advanced Options:
> @@ -147,7 +149,6 @@ Advanced Options:
>
> EOF
> }
> -
> usage() {
Unnecessary whitespace change
> @@ -235,6 +254,37 @@ process_args() {
> exit 1
> fi
>
> + # Remove duplicates from obsoletes (if specified)
> + # Note: provides ID is not added here; the kernel will replace
> + # livepatch with the same provides ID.
> + if [[ -n "$OBSOLETES" ]]; then
> + local obsoletes_clean="${OBSOLETES//[ ]/}"
> + local IFS=','
> + local -a obs_array=()
> + local obs_id
> + local already_exists
> +
> + for obs_id in $obsoletes_clean; do
> + if [[ -n "$obs_id" ]]; then
> + already_exists=0
> + for existing in "${obs_array[@]}"; do
> + if [[ "$existing" -eq "$obs_id" ]]; then
> + already_exists=1
> + break
> + fi
> + done
> +
> + if [[ "$already_exists" -eq 0 ]]; then
> + obs_array+=("$obs_id")
> + fi
> + fi
> + done
> +
> + local IFS=','
> + OBSOLETES="${obs_array[*]}"
> + unset IFS
> + fi
> +
What's the point of this? Do we expect duplicates, and if so, wouldn't
it be the kernel's job to handle that?
--
Josh
next prev parent reply other threads:[~2026-08-28 0:26 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-25 11:46 [PATCH v7 for-next 0/8] livepatch: Introduce replace set support Yafang Shao
2026-08-25 11:46 ` [PATCH v7 for-next 1/8] livepatch: Make klp_find_func() non static Yafang Shao
2026-09-08 14:24 ` Miroslav Benes
2026-08-25 11:46 ` [PATCH v7 for-next 2/8] livepatch: Call klp_init_patch_early() earlier Yafang Shao
2026-08-25 12:06 ` sashiko-bot
2026-08-25 12:11 ` Yafang Shao
2026-08-27 23:57 ` Josh Poimboeuf
2026-08-28 2:24 ` Yafang Shao
2026-09-08 14:24 ` Miroslav Benes
2026-08-25 11:46 ` [PATCH v7 for-next 3/8] livepatch: Implement replace set for scoped atomic replace Yafang Shao
2026-08-25 11:59 ` sashiko-bot
2026-08-25 12:10 ` Yafang Shao
2026-08-28 0:26 ` Josh Poimboeuf [this message]
2026-08-28 3:03 ` Yafang Shao
2026-08-28 3:39 ` Josh Poimboeuf
2026-08-28 5:42 ` Yafang Shao
2026-09-02 7:31 ` Replace rules: was: " Petr Mladek
2026-09-02 9:40 ` Yafang Shao
2026-09-02 11:50 ` Yafang Shao
2026-09-03 10:01 ` Petr Mladek
2026-09-06 2:58 ` Yafang Shao
2026-09-03 9:27 ` Petr Mladek
2026-09-03 21:18 ` Song Liu
2026-09-06 8:34 ` Yafang Shao
2026-09-09 12:32 ` Miroslav Benes
2026-09-09 18:45 ` Song Liu
2026-09-10 8:31 ` Miroslav Benes
2026-09-10 9:17 ` Yafang Shao
2026-09-10 21:59 ` Song Liu
2026-09-02 7:34 ` documentation: " Petr Mladek
2026-09-02 9:50 ` Yafang Shao
2026-09-03 7:30 ` Petr Mladek
2026-09-02 7:37 ` code cleanup: " Petr Mladek
2026-09-02 9:52 ` Yafang Shao
2026-08-25 11:46 ` [PATCH v7 for-next 4/8] livepatch: Deprecate stack_order Yafang Shao
2026-08-28 0:29 ` Josh Poimboeuf
2026-08-28 3:14 ` Yafang Shao
2026-09-02 12:01 ` Petr Mladek
2026-09-02 12:20 ` Yafang Shao
2026-08-25 11:46 ` [PATCH v7 for-next 5/8] selftests/livepatch: Adapt atomic replace tests to provides/obsoletes Yafang Shao
2026-08-28 0:31 ` Josh Poimboeuf
2026-08-28 3:56 ` Yafang Shao
2026-09-02 13:45 ` Petr Mladek
2026-09-03 3:23 ` Yafang Shao
2026-08-25 11:46 ` [PATCH v7 for-next 6/8] selftests/livepatch: Add provides/obsoletes test scenarios Yafang Shao
2026-09-02 15:15 ` Petr Mladek
2026-09-03 5:43 ` Yafang Shao
2026-08-25 11:46 ` [PATCH v7 for-next 7/8] selftests/livepatch: Add test for state ID conflict across provides Yafang Shao
2026-09-02 15:25 ` Petr Mladek
2026-09-03 5:44 ` Yafang Shao
2026-08-25 11:46 ` [PATCH v7 for-next 8/8] selftests/livepatch: Add test for function " Yafang Shao
2026-09-02 15:51 ` Petr Mladek
2026-09-03 5:48 ` Yafang Shao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=apDO-a2n9UlrO_FA@jpoimboe \
--to=jpoimboe@kernel.org \
--cc=jikos@kernel.org \
--cc=joe.lawrence@redhat.com \
--cc=laoar.shao@gmail.com \
--cc=live-patching@vger.kernel.org \
--cc=mbenes@suse.cz \
--cc=pmladek@suse.com \
--cc=song@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox