From 388c4e6cc6bf6dda73e4bfb16406685e380fdccc Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <nakayama.ts@ncos.nec.co.jp>
Date: Fri, 21 Jan 2011 15:00:33 +0900
Subject: [PATCH] get_kernel_config(): life-time of a particular command.

In this implementation, get_kernel_config() can work without
read_in_kernel_config(IKCFG_SETUP/IKCFG_FREE).

The ikconfig data is only available for the life-time of
a particular command.

Signed-off-by: Toshikazu Nakayama <nakayama.ts@ncos.nec.co.jp>
---
 crash-5.1.1/cmdline.c |    3 +
 crash-5.1.1/defs.h    |   14 +++++
 crash-5.1.1/kernel.c  |  135 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 152 insertions(+), 0 deletions(-)

diff --git a/crash-5.1.1/cmdline.c b/crash-5.1.1/cmdline.c
index 48d23b6..b1579df 100755
--- a/crash-5.1.1/cmdline.c
+++ b/crash-5.1.1/cmdline.c
@@ -1101,6 +1101,9 @@ restore_sanity(void)
 	clear_vma_cache();
 	clear_active_set();
 
+	if (kt->ikconfig_flags & IKCONFIG_LOADED)
+		read_in_kernel_config(IKCFG_FREE);
+
 	/*
 	 *  Call the cleanup() function of any extension.
 	 */
diff --git a/crash-5.1.1/defs.h b/crash-5.1.1/defs.h
index 520847c..88f3b53 100755
--- a/crash-5.1.1/defs.h
+++ b/crash-5.1.1/defs.h
@@ -577,6 +577,10 @@ struct kernel_table {                   /* kernel data */
 		ulong p2m_missing;
 	} pvops_xen;
 	int highest_irq;
+	int ikconfig_flags;
+#define IKCONFIG_AVAIL	0x1	/* kernel contains ikconfig data */
+#define IKCONFIG_LOADED	0x2	/* ikconfig data is currently loaded */
+	int ikconfig_ents;
 };
 
 /*
@@ -4053,6 +4057,16 @@ void read_in_kernel_config(int);
 
 #define IKCFG_INIT   (0)
 #define IKCFG_READ   (1)
+#define IKCFG_SETUP  (2)
+#define IKCFG_FREE   (3)
+
+int get_kernel_config(char *, char **);
+enum {
+	IKCONFIG_N,
+	IKCONFIG_Y,
+	IKCONFIG_M,
+	IKCONFIG_STR,
+};
 
 #define MAGIC_START  "IKCFG_ST"
 #define MAGIC_END    "IKCFG_ED"
diff --git a/crash-5.1.1/kernel.c b/crash-5.1.1/kernel.c
index a5fea0c..97b7236 100755
--- a/crash-5.1.1/kernel.c
+++ b/crash-5.1.1/kernel.c
@@ -4384,6 +4384,8 @@ dump_kernel_table(int verbose)
         fprintf(fp, "       NR_CPUS: %d (compiled-in to this version of %s)\n",
 		NR_CPUS, pc->program_name); 
 	fprintf(fp, "kernel_NR_CPUS: %d\n", kt->kernel_NR_CPUS);
+	fprintf(fp, "ikconfig_flags: %d\n", kt->ikconfig_flags);
+	fprintf(fp, " ikconfig_ents: %d\n", kt->ikconfig_ents);
 	if (kt->display_bh == display_bh_1)
         	fprintf(fp, "    display_bh: display_bh_1()\n");
 	else if (kt->display_bh == display_bh_2)
@@ -6849,7 +6851,112 @@ search_mapping_page(ulong mfn, ulong *index, ulong *startptr, ulong *endptr)
 	return found;
 }
 
+/*
+ * IKCONFIG management.
+ */
+#define IKCONFIG_MAX		5000
+static struct ikconfig_list {
+	char *name;
+	char *val;
+} *ikconfig_all;
+
+static void add_ikconfig_entry(char *line, struct ikconfig_list *ent)
+{
+	char *tokptr, *name, *val;
+
+	name = strtok_r(line, "=", &tokptr);
+	sscanf(name, "CONFIG_%s", name);
+	val = strtok_r(NULL, "", &tokptr);
+
+	ent->name = strdup(name);
+	ent->val = strdup(val);
+}
+
+static int setup_ikconfig(char *config)
+{
+	char *ent, *tokptr;
+
+	ikconfig_all = calloc(1, sizeof(struct ikconfig_list) * IKCONFIG_MAX);
+	if (!ikconfig_all) {
+		error(WARNING, "cannot calloc for ikconfig entries.\n");
+		return 0;
+	}
+
+	ent =  strtok_r(config, "\n", &tokptr);
+	while (ent) {
+		while (whitespace(*ent))
+			ent++;
+
+		if (ent[0] != '#') {
+			add_ikconfig_entry(ent,
+					 &ikconfig_all[kt->ikconfig_ents++]);
+			if (kt->ikconfig_ents == IKCONFIG_MAX) {
+				error(WARNING, "ikconfig overflow.\n");
+				return 1;
+			}
+		}
+		ent = strtok_r(NULL, "\n", &tokptr);
+	}
+	if (kt->ikconfig_ents == 0) {
+		free(ikconfig_all);
+		return 0;
+	}
+	ikconfig_all = realloc(ikconfig_all,
+			   sizeof(struct ikconfig_list) * kt->ikconfig_ents);
+
+	return 1;
+}
+
+static void free_ikconfig(void)
+{
+	int i;
+
+	for (i = 0; i < kt->ikconfig_ents; i++) {
+		free(ikconfig_all[i].name);
+		free(ikconfig_all[i].val);
+	}
+	free(ikconfig_all);
+}
+
+int get_kernel_config(char *conf_name, char **str)
+{
+	int i;
+	int ret = IKCONFIG_N;
+	char *name;
+
+	if (!(kt->ikconfig_flags & IKCONFIG_AVAIL)) {
+		error(WARNING, "CONFIG_IKCONFIG is not set\n");
+		return ret;
+	} else if (!(kt->ikconfig_flags & IKCONFIG_LOADED)) {
+		read_in_kernel_config(IKCFG_SETUP);
+		if (!kt->ikconfig_flags & IKCONFIG_LOADED)
+			error(WARNING,
+			      "Failed read_in_kernel_config(IKCFG_SETUP)\n");
+			return ret;
+	}
+
+	name = strdup(conf_name);
+	if (!strncmp(name, "CONFIG_", strlen("CONFIG_")))
+		sscanf(name, "CONFIG_%s", name);
+
+	for (i = 0; i < kt->ikconfig_ents; i++) {
+		if (STREQ(name, ikconfig_all[i].name)) {
+			if (str)
+				*str = ikconfig_all[i].val;
+			if (STREQ(ikconfig_all[i].val, "y"))
+				ret = IKCONFIG_Y;
+			else if (STREQ(ikconfig_all[i].val, "m"))
+				ret = IKCONFIG_M;
+			else
+				ret = IKCONFIG_STR;
 
+			break;
+		}
+	}
+	free(name);
+
+	return ret;
+}
 
 /*
  *  Read the relevant IKCONFIG (In Kernel Config) data if available.
@@ -6880,6 +6987,9 @@ read_in_kernel_config(int command)
 		if (command == IKCFG_READ)
 			error(FATAL, 
 			    "kernel_config_data does not exist in this kernel\n");
+		else if (command == IKCFG_SETUP || command == IKCFG_FREE)
+			error(WARNING, 
+			    "kernel_config_data does not exist in this kernel\n");
 		return;
 	}
 	
@@ -6979,6 +7089,31 @@ again:
 
 	pos = uncomp;
 
+	if (command == IKCFG_INIT)
+		kt->ikconfig_flags |= IKCONFIG_AVAIL;
+	else if (command == IKCFG_SETUP) {
+		if (!(kt->ikconfig_flags & IKCONFIG_LOADED)) {
+			if (setup_ikconfig(pos)) {
+				kt->ikconfig_flags |= IKCONFIG_LOADED;
+				if (CRASHDEBUG(1))
+					fprintf(fp,
+					"ikconfig: Setup %d valid configs.\n",
+						kt->ikconfig_ents);
+			} else
+				error(WARNING, "Failed setup_ikconfig()\n\n");
+		} else
+			error(WARNING, "Invalid IKCFG_SETUP\n");
+		goto out1;
+	} else if (command == IKCFG_FREE) {
+		if (kt->ikconfig_flags & IKCONFIG_LOADED) {
+			free_ikconfig();
+			kt->ikconfig_ents = 0;
+			kt->ikconfig_flags &= ~IKCONFIG_LOADED;
+		} else
+			error(WARNING, "Invalid IKCFG_FREE\n");
+		goto out1;
+	}
+
 	do {
 		ret = sscanf(pos, "%511[^\n]\n%n", line, &ii);
 		if (ret > 0) {
-- 
1.7.4.rc2.18.gb20e9

