All of lore.kernel.org
 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 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


  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.