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

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.

mkubecek: after 5.17-rc1 mainline commit 129ab0d2d9f3 ("kbuild: do not
quote string values in include/config/auto.conf"), we cannot include
include/config/auto.conf in scripts/gen-suse_version_h.sh any more, extract
the config values from it manually.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
---
 Makefile                      |   12 ++++-
 init/Kconfig.suse             |   86 ++++++++++++++++++++++++++++++++++++
 lib/dump_stack.c              |    5 +-
 scripts/gen-suse_version_h.sh |  100 ++++++++++++++++++++++++++++++++++++++++++
 scripts/mod/modpost.c         |   10 ++++
 5 files changed, 210 insertions(+), 3 deletions(-)
 create mode 100644 scripts/gen-suse_version_h.sh

--- a/Makefile
+++ b/Makefile
@@ -1173,6 +1173,15 @@ export extmod_prefix = $(if $(KBUILD_EXT
 export MODORDER := $(extmod_prefix)modules.order
 export MODULES_NSDEPS := $(extmod_prefix)modules.nsdeps
 
+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)
+
 ifeq ($(KBUILD_EXTMOD),)
 
 build-dir	:= .
@@ -1268,7 +1277,8 @@ PHONY += prepare archprepare
 
 archprepare: outputmakefile archheaders archscripts scripts include/config/kernel.release \
 	asm-generic $(version_h) $(autoksyms_h) include/generated/utsrelease.h \
-	include/generated/compile.h include/generated/autoconf.h remove-stale-files
+	include/generated/compile.h include/generated/autoconf.h remove-stale-files \
+	$(suse_version_h)
 
 prepare0: archprepare
 	$(Q)$(MAKE) $(build)=scripts/mod
--- a/init/Kconfig.suse
+++ b/init/Kconfig.suse
@@ -1,6 +1,91 @@
 config SUSE_KERNEL
 	def_bool y
 
+menu "SUSE Release Details"
+choice SUSE_PRODUCT_CODE
+	prompt "SUSE Product Family"
+	default SUSE_PRODUCT_SLE
+	depends on SUSE_KERNEL
+	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"
+
+config SUSE_PRODUCT_ALP
+	bool "SUSE Adaptable Linux Platform"
+endchoice
+
+config SUSE_PRODUCT_CODE
+	int
+	range 1 4
+	default 1 if SUSE_PRODUCT_SLE
+	default 2 if SUSE_PRODUCT_OPENSUSE_LEAP
+	default 3 if SUSE_PRODUCT_OPENSUSE_TUMBLEWEED
+	default 4 if SUSE_PRODUCT_ALP
+
+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
+
+if SUSE_PRODUCT_ALP
+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
+
+config SUSE_AUXRELEASE
+	int
+	range 0 255
+	default 0
+
 config SUSE_KERNEL_SUPPORTED
 	bool "Enable enterprise support facility"
 	depends on SUSE_KERNEL
@@ -18,3 +103,4 @@ config SUSE_KERNEL_SUPPORTED
 	  If you aren't building a kernel for an enterprise distribution,
 	  say n.
 
+endmenu
--- a/lib/dump_stack.c
+++ b/lib/dump_stack.c
@@ -14,6 +14,7 @@
 #include <linux/kexec.h>
 #include <linux/utsname.h>
 #include <linux/stop_machine.h>
+#include <linux/suse_version.h>
 
 static char dump_stack_arch_desc_str[128];
 
@@ -54,13 +55,13 @@ 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 %.*s" BUILD_ID_FMT "\n",
+	printk("%sCPU: %d PID: %d Comm: %.20s %s%s %s %.*s %s" BUILD_ID_FMT "\n",
 	       log_lvl, raw_smp_processor_id(), current->pid, current->comm,
 	       kexec_crash_loaded() ? "Kdump: loaded " : "",
 	       print_tainted(),
 	       init_utsname()->release,
 	       (int)strcspn(init_utsname()->version, " "),
-	       init_utsname()->version, BUILD_ID_VAL);
+	       init_utsname()->version, SUSE_PRODUCT_SHORTNAME, BUILD_ID_VAL);
 
 	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,100 @@
+#!/bin/bash
+
+function get_config() {
+	local line
+
+	line=$(grep "^${1}=" include/config/auto.conf)
+	if [ -z "$line" ]; then
+		return
+	fi
+	echo "${line#*=}"
+}
+
+if [ ! -e include/config/auto.conf ]; then
+        echo "Error: auto.conf not generated - run 'make prepare' to create it" >&2
+	exit 1
+fi
+
+VERSION=$(get_config CONFIG_SUSE_VERSION)
+PATCHLEVEL=$(get_config CONFIG_SUSE_PATCHLEVEL)
+AUXRELEASE=$(get_config CONFIG_SUSE_AUXRELEASE)
+PRODUCT_CODE=$(get_config CONFIG_SUSE_PRODUCT_CODE)
+
+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 "$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"
+		;;
+	4)
+		SUSE_PRODUCT_NAME="SUSE Adaptable Linux Platform ${VERSION}.${PATCHLEVEL}"
+		SUSE_PRODUCT_SHORTNAME="ALP-${VERSION}.${PATCHLEVEL}"
+		SUSE_PRODUCT_FAMILY="ALP"
+		;;
+	*)
+		echo "Unknown SUSE_PRODUCT_CODE=${PRODUCT_CODE}" >&2
+		exit 1
+		;;
+esac
+
+SUSE_PRODUCT_CODE=$(( (${PRODUCT_CODE} << 24) + \
+		      (${VERSION} << 16) + (${PATCHLEVEL} << 8) + \
+		       ${AUXRELEASE} ))
+
+cat <<END
+#ifndef _SUSE_VERSION_H
+#define _SUSE_VERSION_H
+
+#define SUSE_PRODUCT_CODE_SLE				1
+#define SUSE_PRODUCT_CODE_OPENSUSE_LEAP			2
+#define SUSE_PRODUCT_CODE_OPENSUSE_TUMBLEWEED		3
+#define SUSE_PRODUCT_CODE_ALP				4
+
+#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
@@ -24,6 +24,7 @@
 #include "modpost.h"
 #include "../../include/generated/autoconf.h"
 #include "../../include/linux/license.h"
+#include "../../include/generated/uapi/linux/suse_version.h"
 
 /* Are we using CONFIG_MODVERSIONS? */
 static bool modversions;
@@ -2268,6 +2269,14 @@ static void write_buf(struct buffer *b,
 	}
 }
 
+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;
@@ -2334,6 +2343,7 @@ static void write_mod_c_file(struct modu
 	add_depends(&buf, mod);
 	add_moddevtable(&buf, mod);
 	add_srcversion(&buf, mod);
+	add_suserelease(&buf, mod);
 
 	ret = snprintf(fname, sizeof(fname), "%s.mod.c", mod->name);
 	if (ret >= sizeof(fname)) {
