From f7b31a132860be246627c281fda1aecea12f9afc 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 whole crash.

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

The ikconfig data is available for the life-time while crash running.

Signed-off-by: Toshikazu Nakayama <nakayama.ts@ncos.nec.co.jp>
---
 crash-5.1.1/defs.h   |   10 +++
 crash-5.1.1/kernel.c |  198 ++++++++++++++++++++++++++++++++++----------------
 2 files changed, 144 insertions(+), 64 deletions(-)

diff --git a/crash-5.1.1/defs.h b/crash-5.1.1/defs.h
index 520847c..28c474e 100755
--- a/crash-5.1.1/defs.h
+++ b/crash-5.1.1/defs.h
@@ -577,6 +577,8 @@ struct kernel_table {                   /* kernel data */
 		ulong p2m_missing;
 	} pvops_xen;
 	int highest_irq;
+	int ikconfig_load;
+	int ikconfig_ents;
 };
 
 /*
@@ -4054,6 +4056,14 @@ void read_in_kernel_config(int);
 #define IKCFG_INIT   (0)
 #define IKCFG_READ   (1)
 
+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"
 #define MAGIC_SIZE   (sizeof(MAGIC_START) - 1)
diff --git a/crash-5.1.1/kernel.c b/crash-5.1.1/kernel.c
index a5fea0c..078f202 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_load: %d\n", kt->ikconfig_load);
+	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,99 @@ 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) {
+		if (CRASHDEBUG(8))
+			fprintf(fp, "%s\n", 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;
+			}
+		} else if (strstr(ent, "CONFIG_DEBUG_BUGVERBOSE") &&
+			   strstr(ent, "not set"))
+				kt->flags |= BUGVERBOSE_OFF;
+		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;
+}
+
+int get_kernel_config(char *conf_name, char **str)
+{
+	int i;
+	int ret = IKCONFIG_N;
+	char *name;
+
+	if (!kt->ikconfig_load) {
+		error(WARNING, "CONFIG_IKCONFIG is not set\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.
@@ -6869,7 +6963,7 @@ read_in_kernel_config(int command)
 	struct syment *sp;
 	int ii, jj, ret, end, found=0;
 	unsigned long size, bufsz;
-	char *pos, *ln, *buf, *head, *tail, *val, *uncomp;
+	char *pos, *buf, *head, *tail, *val, *uncomp;
 	char line[512];
 	z_stream stream;
 
@@ -6979,75 +7073,51 @@ again:
 
 	pos = uncomp;
 
+	if (command == IKCFG_INIT) {
+		if (!kt->ikconfig_load) {
+			kt->ikconfig_load = setup_ikconfig(pos);
+			if (CRASHDEBUG(1))
+				fprintf(fp,
+					"ikconfig: Setup %d valid configs.\n",
+					kt->ikconfig_ents);
+		}
+		if (!kt->ikconfig_load)
+			/* any trouble? */
+			goto out1;
+		/* init kernel table's ikconfig stuff. */
+		for (jj = 0; ikconfig[jj]; jj++) {
+			if (get_kernel_config(ikconfig[jj], &val) != IKCONFIG_N) {
+				if (STREQ(ikconfig[jj], "CONFIG_NR_CPUS")) {
+					kt->kernel_NR_CPUS = atoi(val);
+					if (CRASHDEBUG(1)) 
+						error(INFO, 
+						    "CONFIG_NR_CPUS: %d\n",
+							kt->kernel_NR_CPUS);
+
+				} else if (STREQ(ikconfig[jj], "CONFIG_PGTABLE_4")) {
+					machdep->flags |= VM_4_LEVEL;
+					if (CRASHDEBUG(1))
+						error(INFO, "CONFIG_PGTABLE_4\n");
+
+				} else if (STREQ(ikconfig[jj], "CONFIG_HZ")) {
+					machdep->hz = atoi(val);
+					if (CRASHDEBUG(1))
+						error(INFO, 
+						    "CONFIG_HZ: %d\n",
+							machdep->hz);
+				}
+			}
+		}
+		goto out1;
+	}
+
 	do {
 		ret = sscanf(pos, "%511[^\n]\n%n", line, &ii);
 		if (ret > 0) {
-			if ((command == IKCFG_READ) || CRASHDEBUG(8))
+			if (command == IKCFG_READ)
 				fprintf(fp, "%s\n", line);
 
 			pos += ii;
-
-			ln = line;
-				
-			/* skip leading whitespace */
-			while (whitespace(*ln))
-				ln++;
-
-			/* skip comments -- except when looking for "not set" */
-			if (*ln == '#') {
-				if (strstr(ln, "CONFIG_DEBUG_BUGVERBOSE") &&
-				    strstr(ln, "not set"))
-					kt->flags |= BUGVERBOSE_OFF;
-				continue;
-			}
-
-			/* Find '=' */
-			if ((head = strchr(ln, '=')) != NULL) {
-				*head = '\0';
-				val = head + 1;
-
-				head--;
-
-				/* skip trailing whitespace */
-				while (whitespace(*head)) {
-					*head = '\0';
-					head--;
-				}
-
-				/* skip whitespace */
-				while (whitespace(*val))
-					val++;
-
-			} else /* Bad line, skip it */
-				continue;
-
-			if (command != IKCFG_INIT)
-				continue;
-
-			for (jj = 0; ikconfig[jj]; jj++) {
-				 if (STREQ(ln, ikconfig[jj])) {
-
-					if (STREQ(ln, "CONFIG_NR_CPUS")) {
-						kt->kernel_NR_CPUS = atoi(val);
-						if (CRASHDEBUG(1)) 
-							error(INFO, 
-							    "CONFIG_NR_CPUS: %d\n",
-								kt->kernel_NR_CPUS);
-
-					} else if (STREQ(ln, "CONFIG_PGTABLE_4")) {
-						machdep->flags |= VM_4_LEVEL;
-						if (CRASHDEBUG(1))
-							error(INFO, "CONFIG_PGTABLE_4\n");
-
-					} else if (STREQ(ln, "CONFIG_HZ")) {
-						machdep->hz = atoi(val);
-						if (CRASHDEBUG(1))
-							error(INFO, 
-							    "CONFIG_HZ: %d\n",
-								machdep->hz);
-					}
-				}
-			}
 		}
 	} while (ret > 0);
 
-- 
1.7.4.rc2.18.gb20e9

