Live Patching
 help / color / mirror / Atom feed
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

  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