From: Jeff Mahoney <jeffm@suse.com>
Subject: kernel: add product-identifying information to kernel build
References: FATE#325281
Patch-mainline: Never, SUSE-specific

Our kernels may be offered using the same base kernel version across
several product streams.  We have tags in our git repository to map
specific versions to a release, but that requires having easy access
to the repository and taking the multiple steps to resolve the release
information.

This patch makes the product release easier to discover by both SUSE
support staff and third-party developers.

This adds a new <linux/suse_version.h> header that defines several
values that can be used to programatically discover what kernel
version is being used:

* SUSE_PRODUCT_FAMILY     The "family" of product, e.g. SLE or Leap
* SUSE_PRODUCT_NAME       The full product name, which may consist of
                          several whitespace-separated words
* SUSE_PRODUCT_SHORTNAME  The abbreviated product name where it makes
			  sense, e.g. SLE15-SP1.
* SUSE_VERSION            Numeric major number of release
* SUSE_PATCHLEVEL         The minor numer or service pack level of the
			  release
* SUSE_AUXRELEASE	  Currently unused
* SUSE_PRODUCT_CODE       An encoded product code that is the result of
                          combining the family, version, patchlevel, and
			  aux release
* SUSE_PRODUCT		  Macro to use to generate the code

It also adds a new "suserelease" module tag that contains the
shortname and also prints the shortname after the kernel version during
system faults.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 Makefile                      |   11 +++++
 init/Kconfig.suse             |   72 ++++++++++++++++++++++++++++++++++++-
 kernel/printk/printk.c        |    5 +-
 scripts/gen-suse_version_h.sh |   81 ++++++++++++++++++++++++++++++++++++++++++
 scripts/mod/modpost.c         |   10 +++++
 5 files changed, 175 insertions(+), 4 deletions(-)

--- a/Makefile
+++ b/Makefile
@@ -1035,6 +1035,15 @@ endef
 include/config/kernel.release: include/config/auto.conf FORCE
 	$(call filechk,kernel.release)
 
+suse_version_h := include/generated/uapi/linux/suse_version.h
+
+define filechk_suse_version
+	$(CONFIG_SHELL) $(srctree)/scripts/gen-suse_version_h.sh
+endef
+
+$(suse_version_h): include/config/auto.conf FORCE
+	$(call filechk,suse_version)
+
 
 # Things we need to do before we recursively start building the kernel
 # or the modules are listed in "prepare".
@@ -1064,7 +1073,7 @@ endif
 prepare2: prepare3 prepare-compiler-check outputmakefile asm-generic
 
 prepare1: prepare2 $(version_h) include/generated/utsrelease.h \
-                   include/config/auto.conf
+                   include/config/auto.conf $(suse_version_h)
 	$(cmd_crmodverdir)
 
 archprepare: archheaders archscripts prepare1 scripts_basic
--- a/init/Kconfig.suse
+++ b/init/Kconfig.suse
@@ -1,9 +1,78 @@
 config SUSE_KERNEL
 	def_bool y
 
+menu "SUSE Release Details"
+	depends on SUSE_KERNEL
+
+choice
+	prompt "SUSE Product Family"
+	default SUSE_PRODUCT_SLE
+	help
+	  This option defines the SUSE product family that owns this
+	  kernel release.
+
+config SUSE_PRODUCT_SLE
+	bool "SUSE Linux Enteprise"
+
+config SUSE_PRODUCT_OPENSUSE_LEAP
+	bool "openSUSE Leap"
+
+config SUSE_PRODUCT_OPENSUSE_TUMBLEWEED
+	bool "openSUSE Tumbleweed"
+endchoice
+
+config SUSE_PRODUCT_CODE
+	int
+	range 1 3
+	default 1 if SUSE_PRODUCT_SLE
+	default 2 if SUSE_PRODUCT_OPENSUSE_LEAP
+	default 3 if SUSE_PRODUCT_OPENSUSE_TUMBLEWEED
+
+if SUSE_PRODUCT_SLE
+config SUSE_VERSION
+	int "Release Version"
+	range 0 255
+	default 255
+
+config SUSE_PATCHLEVEL
+	int "Service Pack Version"
+	range 0 255
+	default 255
+endif
+
+if SUSE_PRODUCT_OPENSUSE_LEAP
+config SUSE_VERSION
+	int "Release Major Version"
+	range 0 255
+	default 255
+
+config SUSE_PATCHLEVEL
+	int "Release Minor Version"
+	range 0 255
+	default 255
+endif
+
+# Tumbleweed doesn't currently use version information, but we should
+# still have the values defined even if zeroed out.
+if SUSE_PRODUCT_OPENSUSE_TUMBLEWEED
+config SUSE_VERSION
+	int
+	range 0 255
+	default 0
+
+config SUSE_PATCHLEVEL
+	int
+	range 0 255
+	default 0
+endif
+
+config SUSE_AUXRELEASE
+	int
+	range 0 255
+	default 0
+
 config SUSE_KERNEL_SUPPORTED
 	bool "Enable enterprise support facility"
-	depends on SUSE_KERNEL
 	help
 	  This feature enables the handling of the "supported" module flag.
 	  This flag can be used to report unsupported module loads or even
@@ -18,3 +87,4 @@ config SUSE_KERNEL_SUPPORTED
 	  If you aren't building a kernel for an enterprise distribution,
 	  say n.
 
+endmenu
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -48,6 +48,7 @@
 #include <linux/sched/clock.h>
 #include <linux/sched/debug.h>
 #include <linux/sched/task_stack.h>
+#include <linux/suse_version.h>
 
 #include <linux/uaccess.h>
 #include <asm/sections.h>
@@ -3272,11 +3273,11 @@ void __init dump_stack_set_arch_desc(con
  */
 void dump_stack_print_info(const char *log_lvl)
 {
-	printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n",
+	printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s %s\n",
 	       log_lvl, raw_smp_processor_id(), current->pid, current->comm,
 	       print_tainted(), init_utsname()->release,
 	       (int)strcspn(init_utsname()->version, " "),
-	       init_utsname()->version);
+	       init_utsname()->version, SUSE_PRODUCT_SHORTNAME);
 
 	if (dump_stack_arch_desc_str[0] != '\0')
 		printk("%sHardware name: %s\n",
--- /dev/null
+++ b/scripts/gen-suse_version_h.sh
@@ -0,0 +1,81 @@
+#!/bin/bash
+
+if test -e include/config/auto.conf; then
+        . include/config/auto.conf
+else
+        echo "Error: auto.conf not generated - run 'make prepare' to create it" >&2
+	exit 1
+fi
+
+VERSION="${CONFIG_SUSE_VERSION}"
+PATCHLEVEL="${CONFIG_SUSE_PATCHLEVEL}"
+AUXRELEASE="${CONFIG_SUSE_AUXRELEASE}"
+
+if [ -z "$VERSION" -o -z "$PATCHLEVEL" -o -z "$AUXRELEASE" ]; then
+	# This would be a bug in the Kconfig
+	cat <<- END >&2
+	ERROR: Missing VERSION, PATCHLEVEL, or AUXRELEASE."
+	Please check init/Kconfig.suse for correctness.
+	END
+	exit 1
+fi
+
+if [ "$VERSION" = 255 -o "$PATCHLEVEL" = 255 ]; then
+	cat <<- END >&2
+
+	ERROR: This release needs to be properly configured.
+	Please add real values for SUSE_VERSION and SUSE_PATCHLEVEL.
+
+	END
+	exit 1
+fi
+
+
+case "$CONFIG_SUSE_PRODUCT_CODE" in
+	1)
+		if [ "${PATCHLEVEL}" = "0" ]; then
+			SP=""
+		else
+			SP="${PATCHLEVEL}"
+		fi
+		SUSE_PRODUCT_NAME="SUSE Linux Enterprise ${VERSION}${SP:+ SP}${SP}"
+		SUSE_PRODUCT_SHORTNAME="SLE${VERSION}${SP:+-SP}${SP}"
+		SUSE_PRODUCT_FAMILY="SLE"
+		;;
+	2)
+		SUSE_PRODUCT_NAME="openSUSE Leap ${VERSION}.${PATCHLEVEL}"
+		SUSE_PRODUCT_SHORTNAME="$SUSE_PRODUCT_NAME"
+		SUSE_PRODUCT_FAMILY="Leap"
+		;;
+	3)
+		SUSE_PRODUCT_NAME="openSUSE Tumbleweed"
+		SUSE_PRODUCT_SHORTNAME="$SUSE_PRODUCT_NAME"
+		SUSE_PRODUCT_FAMILY="Tumbleweed"
+		;;
+	*)
+		echo "Unknown SUSE_PRODUCT_CODE=${CONFIG_SUSE_PRODUCT_CODE}" >&2
+		exit 1
+		;;
+esac
+
+SUSE_PRODUCT_CODE=$(( (${CONFIG_SUSE_PRODUCT_CODE} << 24) + \
+		      (${VERSION} << 16) + (${PATCHLEVEL} << 8) + \
+		       ${AUXRELEASE} ))
+
+cat <<END
+#ifndef _SUSE_VERSION_H
+#define _SUSE_VERSION_H
+
+#define SUSE_PRODUCT_FAMILY     "${SUSE_PRODUCT_FAMILY}"
+#define SUSE_PRODUCT_NAME       "${SUSE_PRODUCT_NAME}"
+#define SUSE_PRODUCT_SHORTNAME  "${SUSE_PRODUCT_SHORTNAME}"
+#define SUSE_VERSION            ${VERSION}
+#define SUSE_PATCHLEVEL         ${PATCHLEVEL}
+#define SUSE_AUXRELEASE		${AUXRELEASE}
+#define SUSE_PRODUCT_CODE       ${SUSE_PRODUCT_CODE}
+#define SUSE_PRODUCT(product, version, patchlevel, auxrelease)		\\
+	(((product) << 24) + ((version) << 16) +			\\
+	 ((patchlevel) << 8) + (auxrelease))
+
+#endif /* _SUSE_VERSION_H */
+END
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -23,6 +23,7 @@
 #include "../../include/generated/autoconf.h"
 #include "../../include/linux/license.h"
 #include "../../include/linux/export.h"
+#include "../../include/generated/uapi/linux/suse_version.h"
 
 /* Are we using CONFIG_MODVERSIONS? */
 static int modversions = 0;
@@ -2373,6 +2374,14 @@ static void add_srcversion(struct buffer
 	}
 }
 
+static void add_suserelease(struct buffer *b, struct module *mod)
+{
+#ifdef SUSE_PRODUCT_SHORTNAME
+	buf_printf(b, "\n");
+	buf_printf(b, "MODULE_INFO(suserelease, \"%s\");\n",
+		   SUSE_PRODUCT_SHORTNAME);
+#endif
+}
 static void write_if_changed(struct buffer *b, const char *fname)
 {
 	char *tmp;
@@ -2632,6 +2641,7 @@ int main(int argc, char **argv)
 		add_depends(&buf, mod, modules);
 		add_moddevtable(&buf, mod);
 		add_srcversion(&buf, mod);
+		add_suserelease(&buf, mod);
 
 		sprintf(fname, "%s.mod.c", mod->name);
 		write_if_changed(&buf, fname);
