module patching support for kpatch-build

This commit adds support for module patching with kpatch-build.
It introduces a new option, -t/--targets, that allows the user to
specify kernel make targets that are impacted by the patch.  These
targets will be examined by kpatch-build for changes.

While this approach requires the user to provide more information to
kpatch-build about what exactly has changed, it is better that
rebuilding the entire source tree (make vmlinux && make modules) which
would dramatically increase the runtime and disk space requirements of
using kpatch-build.

Future improvements could include a script that will independently
generate the targets list file.

Signed-off-by: Seth Jennings <sjenning@redhat.com>
This commit is contained in:
Seth Jennings 2014-06-04 16:42:45 -05:00
parent d026f9d866
commit d166fb4379

View File

@ -90,9 +90,10 @@ usage() {
echo " -c, --config Specify kernel config file" >&2
echo " -v, --vmlinux Specify original vmlinux" >&2
echo " -d, --debug Keep scratch files in /tmp" >&2
echo " -t, --targets File containing the list of kernel make targets to examine" >&2
}
options=$(getopt -o hr:s:c:v:d -l "help,sourcerpm:,sourcedir:,config:,vmlinux:,debug" -- "$@") || die "getopt failed"
options=$(getopt -o hr:s:c:v:t:d -l "help,sourcerpm:,sourcedir:,config:,vmlinux:,targets:,debug" -- "$@") || die "getopt failed"
eval set -- "$options"
@ -130,6 +131,11 @@ while [[ $# -gt 0 ]]; do
DEBUG=1
set -o xtrace
;;
-t|--targets)
TARGETSFILE=$(readlink -f "$2")
shift
[[ ! -f "$TARGETSFILE" ]] && die "targets file $TARGETSFILE not found"
;;
--)
if [[ -z "$2" ]]; then
echo "ERROR: no patch file specified" >&2
@ -144,6 +150,12 @@ while [[ $# -gt 0 ]]; do
shift
done
if [[ -z $TARGETSFILE ]]; then
TARGETS="vmlinux"
else
TARGETS="$(cat $TARGETSFILE)"
fi
SRCDIR="$CACHEDIR/src"
OBJDIR="$CACHEDIR/obj"
OBJDIR2="$CACHEDIR/obj2"
@ -249,20 +261,34 @@ fi
echo "Testing patch file"
cd "$SRCDIR" || die
patch -N -p1 --dry-run < "$PATCHFILE" || die "source patch file failed to apply"
cp "$PATCHFILE" "$APPLIEDPATCHFILE" || die
echo "Building original kernel"
make mrproper >> "$LOGFILE" 2>&1 || die
make "-j$CPUS" vmlinux "O=$OBJDIR" >> "$LOGFILE" 2>&1 || die
cp -LR "$DATADIR/patch" "$TEMPDIR" || die
for TARGET in $TARGETS # START target loop
do
TARGETNAME=$(basename $TARGET)
TEMPDIR="$TEMPDIR/$TARGETNAME"
mkdir -p "$TEMPDIR"
make "O=$OBJDIR" clean >> "$LOGFILE" 2>&1 || die
echo "Building patched kernel"
echo "Building original $TARGETNAME"
make mrproper >> "$LOGFILE" 2>&1 || die
make "-j$CPUS" $TARGET "O=$OBJDIR" >> "$LOGFILE" 2>&1 || die
echo "Building patched $TARGETNAME"
cp "$PATCHFILE" "$APPLIEDPATCHFILE" || die
patch -N -p1 < "$APPLIEDPATCHFILE" >> "$LOGFILE" 2>&1 || die
make "-j$CPUS" vmlinux "O=$OBJDIR" 2>&1 | tee -a "$TEMPDIR/patched_build.log" >> "$LOGFILE"
make "-j$CPUS" $TARGET "O=$OBJDIR" 2>&1 | tee -a "$TEMPDIR/patched_build.log" >> "$LOGFILE"
[[ "${PIPESTATUS[0]}" -eq 0 ]] || die
echo "Detecting changed objects"
grep CC "$TEMPDIR/patched_build.log" | grep -v -e init/version.o -e scripts/mod/devicetable-offsets.s -e scripts/mod/file2alias.o | awk '{print $2}' > "$TEMPDIR/changed_objs"
grep CC "$TEMPDIR/patched_build.log" | grep -v -e init/version.o -e scripts/mod/devicetable-offsets.s -e scripts/mod/file2alias.o > "$TEMPDIR/tmp"
while read FILE; do
if [[ $TARGET = "vmlinux" ]]; then
echo $FILE | awk '{print $2}' >> "$TEMPDIR/changed_objs"
else
echo $FILE | awk '{print $3}' >> "$TEMPDIR/changed_objs"
fi
done < "$TEMPDIR/tmp"
[[ ! -s "$TEMPDIR/changed_objs" ]] && die "no changed objects were detected"
grep -q asm-offsets.s $TEMPDIR/changed_objs && die "a struct definition change was detected"
@ -294,18 +320,30 @@ cd "$TEMPDIR/orig"
FILES="$(find * -type f)"
cd "$TEMPDIR"
mkdir output
if [[ $TARGET = "vmlinux" ]]; then
KOBJFILE=$VMLINUX
else
KOBJFILE="/lib/modules/$ARCHVERSION/kernel/$TARGET"
[[ -e "$KOBJFILE" ]] || die "module not found at $KOBJFILE. Ensure kernel package is installed."
fi
for i in $FILES; do
mkdir -p "output/$(dirname $i)"
"$TOOLSDIR"/create-diff-object "orig/$i" "patched/$i" "$VMLINUX" "output/$i" 2>&1 |tee -a "$LOGFILE"
"$TOOLSDIR"/create-diff-object "orig/$i" "patched/$i" "$KOBJFILE" "output/$i" 2>&1 |tee -a "$LOGFILE"
[[ "${PIPESTATUS[0]}" -eq 0 ]] || die
done
cd output
ld -r -o $TEMPDIR/output.o $FILES >> "$LOGFILE" 2>&1 || die
TEMPDIR=$(dirname $TEMPDIR)
cd "$SRCDIR"
done # END target loop
echo "Building patch module: kpatch-$PATCHNAME.ko"
cp "$OBJDIR/.config" "$SRCDIR"
cd "$SRCDIR"
make prepare >> "$LOGFILE" 2>&1 || die
cd "$TEMPDIR/output"
ld -r -o ../patch/output.o $FILES >> "$LOGFILE" 2>&1 || die
cd "$TEMPDIR"
ld -r -o patch/output.o $(ls */output.o) >> "$LOGFILE" 2>&1 || die
cd "$TEMPDIR/patch"
KPATCH_BUILD="$SRCDIR" KPATCH_NAME="$PATCHNAME" KBUILD_EXTRA_SYMBOLS="$SYMVERSFILE" make "O=$OBJDIR" >> "$LOGFILE" 2>&1 || die
$STRIPCMD "kpatch-$PATCHNAME.ko" >> "$LOGFILE" 2>&1 || die