Linux Kernel Selftest development
 help / color / mirror / Atom feed
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 01/11] klp-build: Fix dependent patches in a series
Date: Fri, 16 Oct 2026 17:24:31 -0700	[thread overview]
Message-ID: <20261017002441.716615-2-song@kernel.org> (raw)
In-Reply-To: <20261017002441.716615-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 early with "no changes
detected" instead of building the patched kernel for nothing.

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 | 93 +++++++++++++++++++++----------------
 1 file changed, 54 insertions(+), 39 deletions(-)

diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build
index b52a8489d9f6..6cdc36e97c21 100755
--- a/scripts/livepatch/klp-build
+++ b/scripts/livepatch/klp-build
@@ -467,60 +467,75 @@ 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, with
+# refreshed hunk headers.  The patches may depend on each other, so they can't
+# be refreshed 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
-# affect the __LINE__ macro for otherwise unchanged functions further down the
-# file, and update $PATCHES to point to the fixed patches.
+# Combine the patches into a single patch, 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 patch.
 fix_patches() {
-	local idx
-	local i
+	local tmp_patch="$TMP_DIR/tmp.patch"
+	local new_patch="$TMP_DIR/fixed.patch"
 
 	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
-
-		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"
+	"$FIX_PATCH_LINES" "$tmp_patch" | recountdiff > "$new_patch"
+	PATCHES=("$new_patch")
 
-		PATCHES[i]="$new_patch"
-
-		rm -f "$tmp_patch"
-		idx=$(printf "%04d" $(( 10#$idx + 1 )))
-	done
+	rm -f "$tmp_patch"
 }
 
 clean_kernel() {
-- 
2.53.0-Meta


  reply	other threads:[~2026-10-17  0:24 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-17  0:24 [PATCH 00/11] klp-build: Fix dependent patches, add selftests Song Liu
2026-10-17  0:24 ` Song Liu [this message]
2026-10-17  0:24 ` [PATCH 02/11] klp-build: Add --patch-only option Song Liu
2026-10-17  0:24 ` [PATCH 03/11] selftests/livepatch: Add tests for klp-build's patch handling Song Liu
2026-10-17  0:24 ` [PATCH 04/11] selftests/livepatch: Test klp-build with dependent patches Song Liu
2026-10-17  0:24 ` [PATCH 05/11] selftests/livepatch: Test klp-build with patches to different functions Song Liu
2026-10-17  0:24 ` [PATCH 06/11] selftests/livepatch: Test klp-build with patches which cancel out Song Liu
2026-10-17  0:24 ` [PATCH 07/11] selftests/livepatch: Test klp-build with created and deleted files Song Liu
2026-10-17  0:24 ` [PATCH 08/11] selftests/livepatch: Test where klp-build adds #line directives Song Liu
2026-10-17  0:24 ` [PATCH 09/11] selftests/livepatch: Test klp-build's rejection of unsupported files Song Liu
2026-10-17  0:24 ` [PATCH 10/11] selftests/livepatch: Test klp-build with patches which don't apply Song Liu
2026-10-17  0:24 ` [PATCH 11/11] selftests/livepatch: Test klp-build with patches which need offset or 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=20261017002441.716615-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