From d6eb800c34353b03eb24ddaf302d74dab1c3aec9 Mon Sep 17 00:00:00 2001
From: Ludwig Nussel <ludwig.nussel@suse.de>
Date: Thu, 17 Jun 2021 13:31:32 +0200
Subject: [PATCH] UsrMerge the kernel

- Move files in /boot to modules dir

  The file names in /boot are included as %ghost links. The %post script
  creates symlinks for the kernel, sysctl.conf and System.map in
  /boot for compatibility. Some tools require adjustments before we
  can drop those links. If boot is a separate partition, a copy is
  used instead of a link.

  The logic for /boot/vmlinuz and /boot/initrd doesn't change with
  this patch.

- Use /usr/lib/modules as module dir when usermerge is active in the
  target distro.
---
 rpm/kernel-binary.spec.in   | 75 +++++++++++++++++++++++++++----------
 rpm/kernel-obs-qa.spec.in   |  2 +-
 rpm/kernel-source.rpmlintrc |  6 +--
 rpm/kernel-subpackage-build | 30 +++++++++------
 rpm/kernel-subpackage-spec  | 11 ++++++
 rpm/post.sh                 | 19 +++++++++-
 rpm/postun.sh               |  4 +-
 rpm/split-modules           | 10 +++--
 8 files changed, 116 insertions(+), 41 deletions(-)

diff --git a/rpm/kernel-binary.spec.in b/rpm/kernel-binary.spec.in
index 9d7434a179fe..65a5c64ebe41 100644
--- a/rpm/kernel-binary.spec.in
+++ b/rpm/kernel-binary.spec.in
@@ -68,6 +68,13 @@
 %define install_vdso 0
 %endif
 
+%if %{undefined usrmerged} && 0%{?suse_version} >= 1550
+%define usrmerged 1
+%endif
+
+%define modules_dir %{?usrmerged:/usr}/lib/modules/%kernelrelease-%build_flavor
+
+
 Name:           kernel-@FLAVOR@
 Summary:        @SUMMARY@
 License:        GPL-2.0
@@ -465,6 +472,11 @@ done
 
 %install
 
+%if 0%{?usrmerged}
+mkdir -p %{buildroot}/usr/lib
+ln -s usr/lib %{buildroot}/lib
+%endif
+
 # get rid of /usr/lib/rpm/brp-strip-debug
 # strip removes too much from the vmlinux ELF binary
 export NO_BRP_STRIP_DEBUG=true
@@ -557,10 +569,10 @@ add_vmlinux()
 # sign the modules, firmware and possibly the kernel in the buildservice
 BRP_PESIGN_FILES=""
 %if "%CONFIG_EFI_STUB" == "y"
-BRP_PESIGN_FILES="/boot/$image-%kernelrelease-%build_flavor"
+BRP_PESIGN_FILES="%modules_dir/$image"
 %endif
 %ifarch s390x ppc64 ppc64le
-BRP_PESIGN_FILES="/boot/$image-%kernelrelease-%build_flavor"
+BRP_PESIGN_FILES="%modules_dir/$image"
 %endif
 %if "%CONFIG_MODULE_SIG" == "y"
 BRP_PESIGN_FILES="$BRP_PESIGN_FILES *.ko"
@@ -623,6 +635,7 @@ for sub in '' '-extra' \
             -e "s:@RPM_TARGET_CPU@:%_target_cpu:g" \
 	    -e "s:@CPU_ARCH_FLAVOR@:%cpu_arch_flavor:g" \
             -e "s:@SRCVARIANT@:%variant:g" \
+            -e "s:@MODULESDIR@:%modules_dir:g" \
             %_sourcedir/$script.sh > %my_builddir/$script$sub.sh
         if test "$base_package" -eq 1 -a "${#certs[@]}" -gt 0; then
             case "$script" in
@@ -829,6 +842,9 @@ if [ %CONFIG_MODULES = y ]; then
 fi
 
 rm -rf %{buildroot}/lib/firmware
+%if 0%{?usrmerged}
+rm %{buildroot}/lib
+%endif
 
 add_dirs_to_filelist() {
     sed -rn '
@@ -841,7 +857,7 @@ add_dirs_to_filelist() {
         # print all parents
         :a
             # skip directories owned by other packages
-            s:^%%dir (/boot|/etc|/lib/(modules|firmware)|/usr/src)/[^/]+$::
+            s:^%%dir (/boot|/etc|(/usr)?/lib/(modules|firmware)|/usr/src)/[^/]+$::
             s:/[^/]+$::p
         ta
     ' "$@" | sort -u
@@ -854,10 +870,19 @@ fi
 
 shopt -s nullglob dotglob
 > %my_builddir/kernel-devel.files
-for file in %buildroot/boot/symtypes* %buildroot/lib/modules/*/{build,source}; do
-	f=${file##%buildroot}
-	echo "$f"
-done | add_dirs_to_filelist >%my_builddir/kernel-devel.files
+{
+    echo "%modules_dir/build"
+    echo "%modules_dir/source"
+    cd %buildroot
+    for file in boot/symtypes*; do
+        l="${file##*/}"
+        l="%modules_dir/${l//-%kernelrelease-%build_flavor}"
+        mv "$file" "%{buildroot}$l"
+        ln -s "..$l" $file
+        echo "$l"
+        echo "%%ghost /$file"
+    done
+} | add_dirs_to_filelist >%my_builddir/kernel-devel.files
 ( cd %buildroot ; find .%obj_install_dir/%cpu_arch_flavor -type f ; ) | \
 sed -e 's/^[.]//' | grep -v -e '[.]ipa-clones$' -e '/Symbols[.]list$' -e '/ipa-clones[.]list$'| \
 add_dirs_to_filelist >> %my_builddir/kernel-devel.files
@@ -866,6 +891,8 @@ add_dirs_to_filelist >> %my_builddir/kernel-devel.files
     echo %ghost /boot/initrd$suffix
     cd %buildroot
     for f in boot/*; do
+        l="${f##*/}"
+        l="%modules_dir/${l//-%kernelrelease-%build_flavor}"
         if test -L "$f"; then
             echo "%%ghost /$f"
             continue
@@ -880,25 +907,35 @@ add_dirs_to_filelist >> %my_builddir/kernel-devel.files
         boot/vmlinux-*.%{compress_vmlinux})
             ;;
         boot/vmlinux-*)
-            if $ghost_vmlinux; then
-                echo "%%ghost /$f"
-                continue
-            fi
+            [ "$ghost_vmlinux" != 'true' ] || echo -n "%%ghost "
+            ;;
+        boot/vmlinuz-*)
+            echo -n "%%attr(0644, root, root) "
             ;;
         boot/symtypes*)
+            echo "%exclude $l"
             continue
             ;;
         esac
-        echo "%%attr(0644, root, root) /$f"
+        mv "$f" "./$l"
+        ln -s "..$l" $f
+        # the find in the CONFIG_MODULES condition below also finds the files
+        # but there's sort -u later, so this is ok
+        echo "$l"
+        echo "%%ghost /$f"
     done
 
     if [ %CONFIG_MODULES = y ]; then
-	find lib/modules/%kernelrelease-%build_flavor \
+	find %{?usrmerged:usr/}lib/modules/%kernelrelease-%build_flavor \
 	    -type d -o \
 	    \( -path '*/modules.*' ! -path '*/modules.order' \
 	     ! -path '*/modules.builtin' \
 	     ! -path '*/modules.builtin.modinfo' \) -printf '%%%%ghost /%%p\n' \
-	       -o -name '*.ko' -prune -o -type f -printf '/%%p\n'
+	       -o -name '*.ko' -prune \
+	       -o \( -type f \
+	        ! -path '*/symtypes*' \
+	        ! -path '*/vmlinu*' \
+	        \) -printf '/%%p\n'
 	cat %my_builddir/base-modules
     fi
     if test %CONFIG_MODULE_SIG = "y" -a -d etc/uefi/certs; then
@@ -956,15 +993,15 @@ for f in %my_builddir/*-kmp-modules; do
 done
 
 if [ %CONFIG_MODULES = y ]; then
-  install -m 644 %_sourcedir/modules.fips %{buildroot}/lib/modules/%kernelrelease-%build_flavor/modules.fips
-  echo /lib/modules/%kernelrelease-%build_flavor/modules.fips >> %my_builddir/kernel-base.files
-  echo /lib/modules/%kernelrelease-%build_flavor/modules.fips >> %my_builddir/kernel-main.files
+  install -m 644 %_sourcedir/modules.fips %{buildroot}%modules_dir/modules.fips
+  echo %modules_dir/modules.fips >> %my_builddir/kernel-base.files
+  echo %modules_dir/modules.fips >> %my_builddir/kernel-main.files
 fi
 
 # Hardlink duplicate files automatically (from package fdupes): It doesn't save
 # much, but it keeps rpmlint from breaking the package build. Note that we skip
 # /usr/src/linux-obj intentionally, to not accidentally break timestamps there
-%fdupes $RPM_BUILD_ROOT/lib
+%fdupes %buildroot%modules_dir
 
 %preun -f preun.sh
 
@@ -1144,7 +1181,7 @@ static, unlike the %{patch_package}-<kernel-version>-flavor package names.
 %files %{livepatch}
 # rpmlint complains about empty packages, so lets own something
 %defattr(-, root, root)
-%dir /lib/modules/%kernelrelease-%build_flavor
+%dir %modules_dir
 %endif
 
 %if 0%{?klp_symbols} && "%livepatch" != ""
diff --git a/rpm/kernel-obs-qa.spec.in b/rpm/kernel-obs-qa.spec.in
index 251885dbef33..fa8234e8af62 100644
--- a/rpm/kernel-obs-qa.spec.in
+++ b/rpm/kernel-obs-qa.spec.in
@@ -60,7 +60,7 @@ projects and runs basic tests.
 # and called here.
 
 krel=$(uname -r)
-if test ! -d "/lib/modules/$krel/kernel"; then
+if test ! -d "/lib/modules/$krel/kernel" && test ! -d "/usr/lib/modules/$krel/kernel"; then
 	echo "Kernel package for $krel not installed; exiting"
 	exit 0
 fi
diff --git a/rpm/kernel-source.rpmlintrc b/rpm/kernel-source.rpmlintrc
index 5d4abc78cb23..748d9097df9e 100644
--- a/rpm/kernel-source.rpmlintrc
+++ b/rpm/kernel-source.rpmlintrc
@@ -1,10 +1,10 @@
 # These zero-length files are correct:
 addFilter("zero-length /usr/src/linux-.*-obj/.*/include/config.*h")
 # vdsos are special
-addFilter("shared-lib-without-dependency-information /lib/modules/[1-9].*/vdso/.*")
-addFilter("missing-PT_GNU_STACK-section /lib/modules/[1-9].*/vdso/.*")
+addFilter("shared-lib-without-dependency-information .*/lib/modules/[1-9].*/vdso/.*")
+addFilter("missing-PT_GNU_STACK-section .*/lib/modules/[1-9].*/vdso/.*")
 # This is a stale symlink until the kernel-source package is installed:
-addFilter("dangling-symlink /lib/modules/[1-9].*/source")
+addFilter("dangling-symlink .*/lib/modules/[1-9].*/source")
 # These hidden files are fine:
 addFilter("hidden-file-or-dir /usr/src/linux-.*-obj/.*/.config")
 addFilter("hidden-file-or-dir /usr/src/linux-.*-obj/.*/.kernel-binary.spec.buildenv")
diff --git a/rpm/kernel-subpackage-build b/rpm/kernel-subpackage-build
index 71df40c00906..6bc9b16a1ace 100644
--- a/rpm/kernel-subpackage-build
+++ b/rpm/kernel-subpackage-build
@@ -21,7 +21,8 @@ rpm -q --qf '%{POSTUN}' $kernel_package_name | sed -e "s/$kernel_nvrq/$package_n
 
 [ -z "$(rpm -q --triggers $kernel_package_name)" ] # not handled
 
-KREL=$(cat kernel.flist | grep ^/lib/modules | { sort -r ||: ;} | head -n 1 | sed -e s,^/lib/modules/,, -e 's,/.*,,')
+KREL=$(sed -rne '/^(\/usr)?\/lib\/modules\/([^/]+)$/{s,.*/,,;p;q}' < kernel.flist)
+grep -q /usr/lib/modules/ kernel.flist && USR=/usr
 
 $scriptdir/mergedep $KREL > modules.dep
 
@@ -29,9 +30,9 @@ $scriptdir/mergedep $KREL > modules.dep
 $scriptdir/moddep modules.dep request-modules modules
 
 $scriptdir/modflist kernel.flist modules modules.flist /lib/modules/$KREL/modules.builtin
-cat kernel.flist | grep -v ^/lib/modules >> modules.flist
-[ -d /lib/modules/$KREL/vdso ] && echo /lib/modules/$KREL/vdso >> modules.flist ||:
-echo /lib/modules/$KREL/modules.* | tr ' ' '\n' >> modules.flist
+grep -v ^$USR/lib/modules < kernel.flist >> modules.flist
+[ -d $USR/lib/modules/$KREL/vdso ] && echo $USR/lib/modules/$KREL/vdso >> modules.flist ||:
+echo $USR/lib/modules/$KREL/modules.* | tr ' ' '\n' >> modules.flist
 
 tar -C / -cf- -T modules.flist | tar -C $RPM_BUILD_ROOT -xvf-
 
@@ -44,18 +45,24 @@ exit 1
 fi
 
 echo "%defattr(-,root,root)" > subpackage.flist
-cat kernel.flist | grep -v ^/lib/modules >> subpackage.flist
-echo /lib/modules/$KREL >> subpackage.flist
+grep -v $USR/lib/modules < kernel.flist >> subpackage.flist
+echo $USR/lib/modules/$KREL >> subpackage.flist
 cat kernel-ghost.flist | sed -e 's/^/%ghost /' >> subpackage.flist
 
 cat kernel-ghost.flist | while read ghost ; do
 	case $ghost in
-		/boot/image-%build_flavor | /boot/vmlinux-%build_flavor | /boot/vmlinuz-%build_flavor | \
-		/boot/Image-%build_flavor | /boot/initrd-%build_flavor)
+		/boot/image-$KREL | /boot/vmlinux-$KREL | /boot/vmlinuz-$KREL | \
+		/boot/Image-$KREL | /boot/initrd-$KREL)
+			;;
+		/boot/System.map-$KREL | /boot/symtypes-$KREL* | /boot/symvers-$KREL*)
 			;;
 		/boot/vmlinux | /boot/vmlinuz | /boot/zImage | /boot/Image | /boot/image | /boot/initrd)
 			;;
-		/boot/vmlinux-$KREL)
+		/boot/.*$KREL.hmac )
+			;;
+		/boot/config-$KREL | /boot/sysctl.conf-$KREL)
+			;;
+		/boot/vmlinux-$KREL*)
 			[ -f /boot/vmlinux-$KREL.gz ] && touch vmlinux-$KREL
 			;;
 		/boot/initrd-$KREL | /boot/initrd-$KREL-kdump)
@@ -66,13 +73,14 @@ cat kernel-ghost.flist | while read ghost ; do
 			      bs=1024 seek=2047 count=1
 			chmod 0600 $RPM_BUILD_ROOT$ghost
 			;;
-		/lib/modules/$KREL/modules.*)
+		$USR/lib/modules/$KREL/modules.*)
 			[ -f $RPM_BUILD_ROOT$ghost ]
 			;;
+		$USR/lib/modules/$KREL/vmlinux)
+			;;
 		*)
 			echo Missing file "$ghost" not handled.
 			exit 1;
 			;;
 	esac
 done
-
diff --git a/rpm/kernel-subpackage-spec b/rpm/kernel-subpackage-spec
index 3f2bea62aa43..cbf649fc38c5 100644
--- a/rpm/kernel-subpackage-spec
+++ b/rpm/kernel-subpackage-spec
@@ -1,6 +1,10 @@
 %define rpm_kver %(rpm -q --qf '%%{VERSION}' %kernel_package_name)
 %define rpm_krel %(rpm -q --qf '%%{RELEASE}' %kernel_package_name)
 
+%if %{undefined usrmerged} && 0%{?suse_version} >= 1550
+%define usrmerged 1
+%endif
+
 # Force bzip2 instead of lzma compression to
 # 1) allow install on older dist versions, and
 # 2) decrease build times (bsc#962356)
@@ -79,10 +83,17 @@ There is no reason to install this package.
 %build
 
 %install
+%if 0%{?usrmerged}
+ln -s usr/lib %{buildroot}/lib
+%endif
 
 echo "%{?modules}" | tr ', ' '\n\n' > request-modules
 %scriptdir/kernel-subpackage-build %kernel_package_name %rpm_kver-%rpm_krel %package_name-%version-%release
 
+%if 0%{?usrmerged}
+rm %{buildroot}/lib
+%endif
+
 %preun -f preun.sh
 
 %postun -f postun.sh
diff --git a/rpm/post.sh b/rpm/post.sh
index 052ae5a6fdd2..3443305860e4 100644
--- a/rpm/post.sh
+++ b/rpm/post.sh
@@ -10,6 +10,23 @@ for x in /boot/@IMAGE@ /boot/initrd; do
     rm -f $x$suffix
     ln -s ${x##*/}-@KERNELRELEASE@-@FLAVOR@ $x$suffix
 done
+# compat stuff for /boot.
+# if /boot is not a speparate partition we can just link the kernel
+# there to save space. Otherwise copy.
+if mountpoint -q /boot; then
+    copy_or_link="cp -a"
+else
+    copy_or_link="ln -sf"
+fi
+# XXX: need to fix suse-module-tools for sysctl.conf and System.map
+for x in @IMAGE@ sysctl.conf System.map; do
+  if [ ! -e /boot/$x-@KERNELRELEASE@-@FLAVOR@ ]; then
+      $copy_or_link ..@MODULESDIR@/$x /boot/$x-@KERNELRELEASE@-@FLAVOR@
+      if [ -e @MODULESDIR@/.$x.hmac ]; then
+        $copy_or_link ..@MODULESDIR@/.$x.hmac /boot/.$x-@KERNELRELEASE@-@FLAVOR@.hmac
+      fi
+  fi
+done
 
 # Add symlinks of compatible modules to /lib/modules/$krel/weak-updates/,
 # run depmod and mkinitrd
@@ -56,7 +73,7 @@ if [ -f /etc/fstab -a ! -e /.buildenv ] ; then
     if [ @FLAVOR@ = rt ]; then
 	    default=force-default
     fi
-    if [ -e /boot/$initrd -o ! -e /lib/modules/@KERNELRELEASE@-@FLAVOR@ ] && \
+    if [ -e /boot/$initrd -o ! -e @MODULESDIR@ ] && \
        run_bootloader ; then
        [ -e /boot/$initrd ] || initrd=
 	if [ -x /usr/lib/bootloader/bootloader_entry ]; then
diff --git a/rpm/postun.sh b/rpm/postun.sh
index d5165044abc4..25cc463135e5 100644
--- a/rpm/postun.sh
+++ b/rpm/postun.sh
@@ -6,7 +6,7 @@ rm -f /boot/do_purge_kernels
 wm2=/usr/lib/module-init-tools/weak-modules2
 nvr=@SUBPACKAGE@-@RPM_VERSION_RELEASE@
 
-if [ -e /boot/System.map-@KERNELRELEASE@-@FLAVOR@ ]; then
+if [ -e @MODULESDIR@/System.map ]; then
     # the same package was reinstalled or just rebuilt, otherwise the files
     # would have been deleted by now
     # do not remove anything in this case (bnc#533766)
@@ -21,7 +21,7 @@ if [ @BASE_PACKAGE@ = 0 ]; then
     rm -f /var/run/rpm-$nvr-modules
     exit 0
 fi
-# Remove symlinks from /lib/modules/$krel/weak-updates/.
+# Remove symlinks from /usr/lib/modules/$krel/weak-updates/.
 if [ -x $wm2 ]; then
     /bin/bash -${-/e/} $wm2 --remove-kernel @KERNELRELEASE@-@FLAVOR@
 fi
diff --git a/rpm/split-modules b/rpm/split-modules
index 4f27fecff94a..58505fe1bb52 100755
--- a/rpm/split-modules
+++ b/rpm/split-modules
@@ -77,7 +77,7 @@ while read mod path; do
 	no)
 		;;
 	"")
-		echo "warning: ${path#/lib/modules/*/kernel/} not listed in supported.conf" >&2
+		echo "warning: $mod not listed in supported.conf" >&2
 		;;
 	*)
 		echo "error: invalid support flag for $mod: $support" >&2
@@ -119,11 +119,13 @@ join -j 1 -o 2.2 "$tmp/base" "$tmp/all" >"$opt_out/base-modules"
 
 # base firmware
 kver=$(make $MAKE_ARGS -s -C "$opt_builddir" kernelrelease)
-if test -d "$opt_dir/lib/firmware/$kver"; then
+fw_dir=/lib/firmware/$kver
+test -d $opt_dir/usr$fw_dir && fw_dir=/usr$fw_dir
+if test -d "$opt_dir$fw_dir"; then
 	join <(/sbin/modinfo -F firmware \
 		$(sed "s:^:$opt_dir:" "$opt_out/base-modules") | sort) \
-	     <(find "$opt_dir/lib/firmware/$kver" -type f -printf '%P\n' | sort)
-fi | sed "s:^:/lib/firmware/$kver/:" >"$opt_out/base-firmware"
+	     <(find "$opt_dir$fw_dir" -type f -printf '%P\n' | sort)
+fi | sed "s:^:$fw_dir:" >"$opt_out/base-firmware"
 
 # kmps
 for f in "$opt_builddir"/Module.*-kmp; do
-- 
2.26.2

