From: Song Liu <song@kernel.org>
To: live-patching@vger.kernel.org, linux-kselftest@vger.kernel.org
Cc: jpoimboe@kernel.org, jikos@kernel.org, mbenes@suse.cz,
pmladek@suse.com, joe.lawrence@redhat.com, shuah@kernel.org,
linux-kernel@vger.kernel.org, Song Liu <song@kernel.org>
Subject: [PATCH v2 01/12] klp-build: Fix dependent patches in a series
Date: Wed, 28 Oct 2026 14:45:23 -0700 [thread overview]
Message-ID: <20261028214534.1919398-2-song@kernel.org> (raw)
In-Reply-To: <20261028214534.1919398-1-song@kernel.org>
fix_patches() refreshes each patch on its own against the original
source: it applies the patch, copies the patched files, and reverts it.
If a later patch in the series depends on an earlier one, it doesn't
apply to the original source, and klp-build fails even though
validate_patches(), which applies the patches in order, accepted the
series:
$ ./scripts/livepatch/klp-build 0001-dummy.patch 0002-Revert-dummy.patch
Validating patch(es)
Building original kernel
Copying original object files
Fixing patch(es)
Reversed (or previously applied) patch detected! Assume -R? [n]
Apply anyway? [n]
1 out of 1 hunk ignored
error: klp-build: .../klp-tmp/tmp.patch did not apply
Refreshing each patch on top of the previous ones wouldn't work either.
fix-patch-lines adds #line directives to each fixed patch, so the next
patch's context wouldn't match. The #line numbers in later patches
would also refer to the intermediate source rather than the original
source, which defeats the purpose of preserving __LINE__.
Instead, apply all the patches in order and diff the result against the
original source to get a single combined patch, then run fix-patch-lines
on that. If the patches have no net effect, fail with "no changes
detected" instead of building the patched kernel for nothing.
The combined patch gets its own variable, $COMBINED_PATCH, instead of
replacing the patches in $PATCHES, and fix_patches() becomes
process_patches(), as it no longer fixes the patches it is given. The
intermediate patch without #line directives is left in klp-tmp for
debugging. get_patch_files() is now the only user of
get_patch_input_files() and get_patch_output_files(), so fold them into
it.
Fixes: 24ebfcd65a87 ("livepatch/klp-build: Introduce klp-build script for generating livepatch modules")
Assisted-by: Claude:claude-opus-5
Signed-off-by: Song Liu <song@kernel.org>
---
scripts/livepatch/klp-build | 121 +++++++++++++++++-------------------
1 file changed, 57 insertions(+), 64 deletions(-)
diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index b52a8489d9f6..a0bfc40093f9 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -47,6 +47,7 @@ KMOD_DIR="$TMP_DIR/5-kmod"
STASH_DIR="$TMP_DIR/stash"
TIMESTAMP="$TMP_DIR/timestamp"
PATCH_TMP_DIR="$TMP_DIR/tmp"
+COMBINED_PATCH="$TMP_DIR/combined.patch"
KLP_DIFF_LOG="$DIFF_DIR/diff.log"
@@ -328,33 +329,16 @@ set_kernelversion() {
sed -i "2i echo $kernelrelease; exit 0" scripts/setlocalversion
}
-get_patch_input_files() {
- local patch="$1"
-
- grep0 -E '^--- ' "$patch" \
- | grep0 -v -e '/dev/null' -e '1969-12-31' -e '1970-01-01' \
- | gawk '{print $2}' \
- | sed 's|^[^/]*/||' \
- | sort -u
-}
-
-get_patch_output_files() {
+get_patch_files() {
local patch="$1"
- grep0 -E '^\+\+\+ ' "$patch" \
+ grep0 -E '^(---|\+\+\+) ' "$patch" \
| grep0 -v -e '/dev/null' -e '1969-12-31' -e '1970-01-01' \
| gawk '{print $2}' \
| sed 's|^[^/]*/||' \
| sort -u
}
-get_patch_files() {
- local patch="$1"
-
- { get_patch_input_files "$patch"; get_patch_output_files "$patch"; } \
- | sort -u
-}
-
check_unsupported_patches() {
local patch
@@ -467,60 +451,69 @@ do_init() {
set_kernelversion
}
-# Refresh the patch hunk headers, specifically the line numbers and counts.
-refresh_patch() {
- local patch="$1"
+# Combine the patches into a single patch against the original source. The
+# patches may depend on each other, so they can't be diffed individually.
+combine_patches() {
+ local outfile="$1"
local tmpdir="$PATCH_TMP_DIR"
- local input_files=()
- local output_files=()
+ local files=()
+ local patch
+ local file
rm -rf "$tmpdir"
- mkdir -p "$tmpdir/a"
- mkdir -p "$tmpdir/b"
+ mkdir -p "$tmpdir"
- # Get all source files affected by the patch
- get_patch_input_files "$patch" | mapfile -t input_files
- get_patch_output_files "$patch" | mapfile -t output_files
+ # Get all source files affected by the patches
+ for patch in "${PATCHES[@]}"; do
+ get_patch_files "$patch"
+ done | sort -u | mapfile -t files
- # Copy orig source files to 'a'
- echo "${input_files[@]}" | xargs cp --parents --target-directory="$tmpdir/a"
+ # Copy orig source files to $tmpdir
+ for file in "${files[@]}"; do
+ if [[ -e "$file" ]]; then
+ cp --parents "$file" "$tmpdir"
+ fi
+ done
- # Copy patched source files to 'b'
- apply_patch "$patch" "--silent"
- echo "${output_files[@]}" | xargs cp --parents --target-directory="$tmpdir/b"
- revert_patch "$patch"
+ # Diff the orig source files against the patched ones in place to make a
+ # clean patch. Use /dev/null for created and deleted files.
+ : > "$outfile"
+ apply_patches "--silent"
+ for file in "${files[@]}"; do
+ local old="$tmpdir/$file"
+ local new="$file"
+ local old_label="a/$file"
+ local new_label="b/$file"
+ local status=0
+
+ if [[ ! -e "$old" ]]; then
+ old=/dev/null
+ old_label=/dev/null
+ fi
+ if [[ ! -e "$new" ]]; then
+ new=/dev/null
+ new_label=/dev/null
+ fi
- # Diff 'a' and 'b' to make a clean patch
- ( cd "$tmpdir" && diff -Nupr a b > "$patch" ) || true
+ diff -up --label "$old_label" --label "$new_label" "$old" "$new" \
+ >> "$outfile" || status=$?
+ if (( status > 1 )); then
+ die "diff failed for $file"
+ fi
+ done
+ revert_patches
}
-# Copy the patches to a temporary directory, fix their lines so as not to
+# Combine the patches into $COMBINED_PATCH, and fix its lines so as not to
# affect the __LINE__ macro for otherwise unchanged functions further down the
-# file, and update $PATCHES to point to the fixed patches.
-fix_patches() {
- local idx
- local i
-
- rm -f "$TMP_DIR"/*.patch
-
- idx=0001
- for i in "${!PATCHES[@]}"; do
- local old_patch="${PATCHES[$i]}"
- local tmp_patch="$TMP_DIR/tmp.patch"
- local patch="${PATCHES[$i]}"
- local new_patch
+# file.
+process_patches() {
+ local tmp_patch="$TMP_DIR/tmp.patch"
- new_patch="$TMP_DIR/$idx-fixed-$(basename "$patch")"
+ combine_patches "$tmp_patch"
+ [[ ! -s "$tmp_patch" ]] && die "no changes detected"
- cp -f "$old_patch" "$tmp_patch"
- refresh_patch "$tmp_patch"
- "$FIX_PATCH_LINES" "$tmp_patch" | recountdiff > "$new_patch"
-
- PATCHES[i]="$new_patch"
-
- rm -f "$tmp_patch"
- idx=$(printf "%04d" $(( 10#$idx + 1 )))
- done
+ "$FIX_PATCH_LINES" "$tmp_patch" | recountdiff > "$COMBINED_PATCH"
}
clean_kernel() {
@@ -909,9 +902,9 @@ if (( SHORT_CIRCUIT <= 1 )); then
fi
if (( SHORT_CIRCUIT <= 2 )); then
- status "Fixing patch(es)"
- fix_patches
- apply_patches "--silent"
+ status "Processing patch(es)"
+ process_patches
+ apply_patch "$COMBINED_PATCH" "--silent"
status "Building patched kernel"
build_kernel "patched"
revert_patches
--
2.53.0-Meta
next prev parent reply other threads:[~2026-10-28 21:45 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 21:45 [PATCH v2 00/12] klp-build: Fix dependent patches, add selftests Song Liu
2026-10-28 21:45 ` Song Liu [this message]
2026-10-28 21:45 ` [PATCH v2 02/12] klp-build: Process the patches before building the original kernel Song Liu
2026-10-28 21:45 ` [PATCH v2 03/12] klp-build: Move patch processing to klp-prepare-patch Song Liu
2026-10-28 21:45 ` [PATCH v2 04/12] selftests/livepatch: Add tests for klp-prepare-patch Song Liu
2026-10-28 21:45 ` [PATCH v2 05/12] selftests/livepatch: Test klp-prepare-patch with dependent patches Song Liu
2026-10-28 21:45 ` [PATCH v2 06/12] selftests/livepatch: Test klp-prepare-patch with independent patches Song Liu
2026-10-28 21:45 ` [PATCH v2 07/12] selftests/livepatch: Test klp-prepare-patch with patches which cancel out Song Liu
2026-10-28 21:45 ` [PATCH v2 08/12] selftests/livepatch: Test klp-prepare-patch with created and deleted files Song Liu
2026-10-28 21:45 ` [PATCH v2 09/12] selftests/livepatch: Test where klp-prepare-patch adds #line directives Song Liu
2026-10-28 21:45 ` [PATCH v2 10/12] selftests/livepatch: Test klp-prepare-patch with unsupported files Song Liu
2026-10-28 21:45 ` [PATCH v2 11/12] selftests/livepatch: Test klp-prepare-patch with patches which don't apply Song Liu
2026-10-28 21:45 ` [PATCH v2 12/12] selftests/livepatch: Test klp-prepare-patch with offset and fuzz Song Liu
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=20261028214534.1919398-2-song@kernel.org \
--to=song@kernel.org \
--cc=jikos@kernel.org \
--cc=joe.lawrence@redhat.com \
--cc=jpoimboe@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=live-patching@vger.kernel.org \
--cc=mbenes@suse.cz \
--cc=pmladek@suse.com \
--cc=shuah@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