--- extensions/cgget.c	2012-12-07 18:04:32.095275457 +0800
+++ ../crash/extensions/cgget.c	2012-12-28 15:35:03.816830712 +0800
@@ -369,11 +369,6 @@
 	BLKCG_POLICY_PROP,
 };
 
-//enum blkcg_plid {
-//	BLKCG_POLICY_THROTL = 0,        /* Id of throtl is 0 from version 3.5 */
-//	BLKCG_POLICY_PROP,
-//};
-
 /* blkio attributes owned by proportional weight policy */
 enum blkcg_file_name_prop {
 	BLKIO_PROP_weight = 1,
@@ -472,6 +467,9 @@
 static struct cgroup_subsys_table cgroup_subsys_table[CGROUP_SUBSYS_MAX];
 static int cgroup_subsys_num = 0;
 static int is_cgroup_supported = 0;
+static uint variable_flag = 0;
+static int var_num[CGROUP_SUBSYS_MAX] = {0};
+static char *variable_str[CGROUP_SUBSYS_MAX][30] = {{0}};
 
 static struct option long_options[] = {
 	{"help", no_argument, 0, 'h'},
@@ -576,12 +574,14 @@
 static ulong get_subsys_parent(ulong, int);
 static inline char *get_dentry_path(ulong, char *, int);
 static void format_path_str(const char *, char *);
+static void filter_str(char **, int *);
 static int make_cgroup_spec(struct cgroup_spec **, char **,
-			    char **, int, int);
+			    char **, int *, int*);
 static int make_all_cgroup_spec(struct cgroup_spec **, char **,
-				char **, int, int);
+				char **, int *, int *);
 static void cgroup_subsys_table_init();
-static int parse_cgroup_spec(struct cgroup_spec **, char *, int, int);
+static int parse_variable_spec(char *, char **, int *);
+static void print_specified_param(int);
 static void print_cgroup_list(char *, struct cgroup_spec **, int, int);
 static ulong retrieve_path(ulong, ulong, ulong *, const char *);
 static ulong get_css_addr(struct cgroup_spec *, int, ulong);
@@ -602,15 +602,18 @@
 char *help_cgget[] = {
 	"cgget",		/* command name */
 	"display parameters of cgroup.",
-	"cgget [-g <controller>] [-a] <path> ...\n"
+	"[-a] [-r <name>] [-g <controller>] <path> ...\n"
 	"  or\n"
-	"  cgget -g <controller>:<path> ...",
+	"  cgget [-a] [-r <name>] -g <controller>:<path> ...",
 	"Displays the parameter(s) of input cgroup(s).\n"
 	"If no controller is specified, the values of "
 	"all possible variables are printed.\n"
 	"Either command line style is OK, but these can not be mixed.\n",
 	"-a, --all",
 	"print the variables for all controllers which consist in the given path.\n",
+	"-r <name>",
+	"defines parameter to display.",
+	"This option can be used multiple times.\n",
 	"-g <controller>",
 	"defines controllers whose values should be displayed.",
 	"This option can be used multiple times.\n",
@@ -620,8 +623,8 @@
 	"-h, --help",
 	"display this message.\n",
 	"EXAMPLES",
-	"display the controller 'cpu' in path '/'",
-	" crash>cgget -g cpu:/",
+	"1. display the controller 'cpu' in path '/'",
+	" crash> cgget -g cpu:/",
 	" /:",
 	" cpu.rt_period_us: 1000000",
 	" cpu.rt_runtime_us: 950000",
@@ -632,7 +635,24 @@
 	" cpu.cfs_quota_us: 0",
 	" cpu.shares: 1024",
 	" or",
-	" crash>cgget -g cpu /",
+	" crash> cgget -g cpu /",
+	" /:",
+	" cpu.rt_period_us: 1000000",
+	" cpu.rt_runtime_us: 950000",
+	" cpu.stat: nr_periods 0",
+	" \tnr_throttled 0",
+	" \tthrottled_time 0",
+	" cpu.cfs_period_us: 0",
+	" cpu.cfs_quota_us: 0",
+	" cpu.shares: 1024",
+	"2. display the parameter 'cpuset.mems' in path '/libvirt'",
+	" crash> cgget -r cpuset.mems /libvirt",
+	" /libvirt:",
+	" cpuset.mems: 0",
+	"3. display the controller 'cpu' and paramter 'cpuset.mems' at same time",
+	" crash> cgget -r cpuset.mems -g cpu /",
+	" /:",
+	" cpuset.mems: 0",
 	" /:",
 	" cpu.rt_period_us: 1000000",
 	" cpu.rt_runtime_us: 950000",
@@ -1564,7 +1584,7 @@
 	int val = 0;
 
 	if (is_root_mem_cgroup(subsys_addr)) {
-		if (symbol_value("vm_swappiness") == -1)
+		if (symbol_exists("vm_swappiness") == -1)
 			return;
 		readmem(symbol_value("vm_swappiness"), KVADDR, &val,
 			sizeof(int), "vm_swappiness", FAULT_ON_ERROR);
@@ -2535,36 +2555,42 @@
 {
 	int c;
 	int ret = 0;
-	int i = 0, j = 0, k = 0;
-	int dis_all_param = 0, group_flag = 0;
+	int idx, i = 0, j = 0, k = 0;
+	int dis_all_param = 0, group_flag = 0, var_flag = 0;
 	struct cgroup_spec *group_list[CGROUP_HIER_MAX] = {NULL};
-	char *subsys_str[CGROUP_HIER_MAX], *path[CGROUP_HIER_MAX];
-
+	char *subsys_str[CGROUP_HIER_MAX], *path[CGROUP_HIER_MAX],
+	     *gctrlptr, *pathptr;
 
 	if (!is_cgroup_supported) {
 		command_not_supported();
 		return;
 	}
-	while ((c = getopt_long(argcnt, args, "hg:a", 
+	while ((c = getopt_long(argcnt, args, "hg:r:a", 
 		long_options, NULL)) != EOF) {
 		switch(c)
 		{
 		case 'g':
 			if (strchr(optarg, ':') != NULL) {
 				group_flag |= MODE_COMBINE_PATH;
-				ret = parse_cgroup_spec(&group_list[i], optarg, i,
-							CGROUP_HIER_MAX);
-				if (ret != 0) {
+				gctrlptr = strtok(optarg, ":");
+				pathptr = strtok(NULL, ":");
+				if (gctrlptr == NULL || pathptr == NULL) {
 					argerrs++;
 					goto err;
 				}
-				i++;
+				subsys_str[j++] = strdup(gctrlptr);
+				path[k++] = strdup(pathptr);
 			} else {
 				group_flag |= MODE_SEPARATE_PATH;
-				subsys_str[j] = strdup(optarg);
-				j++;
+				subsys_str[j++] = strdup(optarg);
 			}
 			break;
+		case 'r':
+			var_flag = 1;
+			ret = parse_variable_spec(optarg, subsys_str, &j);
+			if (ret == -1)
+				goto err;
+			break;
 		case 'a':
 			dis_all_param = 1;
 			break;
@@ -2576,8 +2602,7 @@
 	}
 
 	if (((group_flag & MODE_COMBINE_PATH) && args[optind]) || 
-	    (!(group_flag & MODE_COMBINE_PATH) && !args[optind]) || 
-	    ((group_flag & MODE_COMBINE_PATH) && dis_all_param)) {
+	    (!(group_flag & MODE_COMBINE_PATH) && !args[optind])) {
 		argerrs++;
 		goto err;
 	}
@@ -2588,25 +2613,34 @@
 			argerrs++;
 			goto err;
 		}
-		path[k] = strdup(args[optind]);
-		k++;
-		optind++;
+		path[k++] = strdup(args[optind++]);
+	}
+
+	if (var_flag && (path[0] == NULL)) {
+		argerrs++;
+		goto err;
 	}
 
 	/* if only PATH is specified, treat it as -a is specified. */
-	if (!group_flag)
+	if (!group_flag && !var_flag)
 		dis_all_param = 1;
 
-	if (group_flag & MODE_SEPARATE_PATH)
-		i = make_cgroup_spec(group_list, subsys_str, path, j, k);
 	if (dis_all_param)
-		i = make_all_cgroup_spec(group_list, subsys_str, path, j, k);
+		i = make_all_cgroup_spec(group_list, subsys_str, path, &j, &k);
+	else
+		i = make_cgroup_spec(group_list, subsys_str, path, &j, &k);
 	if (i < 1)
 		goto err;
 
 	print_cgroup_list(args[0], group_list, i, dis_all_param);
 
 err:
+	for (idx = 0; idx < CGROUP_SUBSYS_MAX; idx++) {
+		while (--var_num[idx] >= 0)
+			free(variable_str[idx][var_num[idx]]);
+		var_num[idx] = 0;
+	}
+	variable_flag = 0;
 	while (--i >= 0)
 		free(group_list[i]);
 	while (--j >= 0)
@@ -2615,17 +2649,51 @@
 		free(path[k]);
 	if (argerrs)
 		cmd_usage(pc->curcmd, SYNOPSIS);
+}
 
+/* strip off the same string */
+static void
+filter_str(char *str[], int *str_num)
+{
+	char *work_str[CGROUP_HIER_MAX];
+	int i, j, k = 0;
+
+	/* Organize the filtered strings in the temp string array */
+	for (i = 0; i < *str_num; i++) {
+		for (j = i + 1; j < *str_num; j++) {
+			if (strcmp(str[i], str[j]) == 0)
+				break;
+		}
+		if (j == *str_num)
+			work_str[k++] = strdup(str[i]);
+		free(str[i]);
+	}
+	/* Assign the temp buffer to original string array */
+	for(i = 0; i < k; i++)
+		str[i] = work_str[i];
+	*str_num = k;
 }
 
 static int
 make_cgroup_spec(struct cgroup_spec **group_list, char *subsys_str[],
-			char *path[], int str_num, int path_num)
+			char *path[], int *str_num, int *path_num)
 {
 	int j, k, i = 0;
 
-	for (j = 0; j < str_num; j++) {
-		for (k = 0; k < path_num; k++) {
+	filter_str(subsys_str, str_num);
+	filter_str(path, path_num);
+	for (j = 0; j < CGROUP_SUBSYS_MAX; j++)
+		filter_str(variable_str[j], &var_num[j]);
+
+	for (j = 0; j < *str_num; j++) {
+		for (k = 0; k < *path_num; k++) {
+			while (group_list[i] != NULL)
+				i++;
+			if (i > CGROUP_HIER_MAX) {
+				fprintf(stderr, "Max allowed hierarchies %d"
+					" reached.\n", CGROUP_HIER_MAX);
+				return -1;
+			}
 			group_list[i] = calloc(1, sizeof(struct cgroup_spec));
 			if (!group_list[i]) {
 				fprintf(stderr, "calloc error.\n");
@@ -2644,12 +2712,12 @@
 
 static int
 make_all_cgroup_spec(struct cgroup_spec **group_list, char *subsys_str[],
-		     char *path[], int str_num, int path_num)
+		     char *path[], int *str_num, int *path_num)
 {
-	int i, j, k = 0;
+	int i, j, k;
 
 	for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-		for (j = 0; j < str_num; j++) {
+		for (j = 0; j < *str_num; j++) {
 			/* if matched string is found, it must be
 			 * specified by user, jump out. */
 			if (0 == strcmp(cgroup_subsys_table[i].subsys_str,
@@ -2658,12 +2726,12 @@
 		}
 		/* "j == str_num" means no matched string is found,
 		 * so add it to subsys_str. */
-		if (j == str_num &&
+		if (j == *str_num &&
 		    cgroup_subsys_table[i].subsys_str != NULL &&
 		    *cgroup_subsys_table[i].subsys_str != '\0' &&
 		    *cgroup_subsys_table[i].subsys_str != ' ') {
-			subsys_str[str_num] = strdup(cgroup_subsys_table[i].subsys_str);
-			str_num++;
+			subsys_str[*str_num] = strdup(cgroup_subsys_table[i].subsys_str);
+			(*str_num)++;
 		}
 	}
 
@@ -2714,34 +2782,81 @@
 }
 
 static int
-parse_cgroup_spec(struct cgroup_spec **group_list, char *optarg, int index, int capacity)
+parse_variable_spec(char *optarg, char **subsys_str, int *j)
 {
-	char *gctrlptr, *pathptr;
+	char *cg, *var;
+	int i;
 
-	if (!(index < capacity)) {
-		fprintf(stderr, "Max allowed hierarchies %d reached.\n", capacity);
+	cg = strtok(optarg, ".");
+	var = strtok(NULL, ".");
+	if (cg == NULL || var == NULL)
 		return -1;
+
+	for (i = 0; i < CGROUP_SUBSYS_MAX; i++) {
+		if (strcmp(subsys_name[i], cg) == 0) {
+			subsys_str[*j] = strdup(cg);
+			variable_str[i][var_num[i]] = strdup(var);
+			variable_flag |= NUM_TO_BIT(i);
+			(*j)++;
+			var_num[i]++;
+			break;
+		}
 	}
 
-	*group_list = calloc(1, sizeof(struct cgroup_spec));
-	if (!(*group_list)) {
-		fprintf(stderr, "calloc error.\n");
+	if (i == CGROUP_SUBSYS_MAX) {
+		fprintf(fp, "No subsys '%s' is found.\n", cg);
 		return -1;
 	}
-
-	gctrlptr = strtok(optarg, ":");
-	pathptr = strtok(NULL, ":");
-	if ( gctrlptr == NULL || pathptr == NULL)
-		goto failed;
-	strncpy((*group_list)->subsys_str, gctrlptr, strlen(gctrlptr));
-	strncpy((*group_list)->path, pathptr, strlen(pathptr));
-
 	return 0;
+}
 
-failed:
-	if (*group_list)
-		free(*group_list);
-	return -1;
+static void
+print_specified_param(int subsys_id)
+{
+	char *linebuf = NULL;
+	int i, flag = 0, found = 0;
+	size_t length;
+	int st_idx = strlen(subsys_name[subsys_id]);
+
+	/* reset the file discriptor */
+	rewind(fp);
+	while (-1 != getline(&linebuf, &length, fp)) {
+		/*
+		 * If flag == 1, this means the param was matched.
+		 * Since we don't know if the next line belongs to
+		 * this param or not, we check it. If YES, print
+		 * it, too.
+		 */
+		if (flag == 1) {
+			if (!strstr(linebuf, subsys_name[subsys_id])) {
+				fprintf(pc->saved_fp, "%s", linebuf);
+				continue;
+			}
+			flag = 0;
+		}
+		for (i = 0; i < var_num[subsys_id]; i++) {
+			/*
+			 * compare the param string after
+			 * name of subsys at beginning.
+			 */
+			if (variable_str[subsys_id][i] != NULL &&
+			    strstr(&linebuf[st_idx], variable_str[subsys_id][i])) {
+				found |= NUM_TO_BIT(i);
+				flag = 1;
+				fprintf(pc->saved_fp, "%s", linebuf);
+			}
+		}
+	}
+
+	for (i = 0; i < var_num[subsys_id]; i++) {
+		if (!test_bit(i, found))
+			fprintf(pc->saved_fp, "Can not find param '%s'.\n",
+				variable_str[subsys_id][i]);
+	}
+	if (linebuf) {
+		free(linebuf);
+		linebuf = NULL;
+	}
 }
 
 static ulong
@@ -2831,15 +2946,21 @@
 		return;
 
 	/* if only "/" or "." */
-	if ((0 == strcmp("/", str_in)) || (0 == strcmp(".", str_in))) {
+	if ((0 == strcmp("/", str_in)) || (0 == strcmp(".", str_in)))
 		strcpy(str_out, "/");
-		return;
-	}
+	else if ('.' == str_in[0] && '/' == str_in[1])
+		/* if "./" is specified at the beginning */
+		strcpy(str_out, &str_in[1]);
+	else if ('/' != str_in[0]) {
+		/* if no '/' is specified at the beginning */
+		str_out[0] = '/';
+		strcpy(&str_out[1], str_in);
+	} else
+		strcpy(str_out, str_in);
 
 	/* strip the '/' character at the last position */
-	strcpy(str_out, str_in);
-	if ('/' == str_out[len - 1])
-		str_out[len - 1] = '\0';
+	if ('/' == str_out[strlen(str_out) - 1])
+		str_out[strlen(str_out) - 1] = '\0';
 }
 
 static ulong
@@ -2961,6 +3082,10 @@
 
 	fprintf(fp, "%s:\n", group_list->path);
 
+	/* if some param is specified, first output all into a tmpfile. */
+	if (test_bit(cpuset_subsys_id, variable_flag))
+		open_tmpfile();
+
 	for (i = CS_CPU_EXCLUSIVE; i <= CS_CPUS; i++) {
 		if (cpuset_offset_table.cpuset_shed_relax_domain_level == -1 &&
 		    i == CS_SHED_RELAX_DOMAIN_LEVEL)
@@ -3031,6 +3156,12 @@
 			break;
 		}
 	}
+
+	/* second, output the needed param */
+	if (test_bit(cpuset_subsys_id, variable_flag)) {
+		print_specified_param(cpuset_subsys_id);
+		close_tmpfile();
+	}
 }
 
 static void
@@ -3043,6 +3174,10 @@
 
 	fprintf(fp, "%s:\n", group_list->path);
 
+	/* if some param is specified, first output all into a tmpfile. */
+	if (test_bit(cpu_cgroup_subsys_id, variable_flag))
+		open_tmpfile();
+
 	rt_bandwidth_addr = subsys_addr + tg_offset_table.tg_rt_bandwidth;
 	cfs_bandwidth_addr = subsys_addr + tg_offset_table.tg_cfs_bandwidth;
 
@@ -3101,6 +3236,12 @@
 			break;
 		}
 	}
+
+	/* second, output the needed param */
+	if (test_bit(cpu_cgroup_subsys_id, variable_flag)) {
+		print_specified_param(cpu_cgroup_subsys_id);
+		close_tmpfile();
+	}
 }
 
 static void
@@ -3112,6 +3253,9 @@
 
 	fprintf(fp, "%s:\n", group_list->path);
 
+	/* if some param is specified, first output all into a tmpfile. */
+	if (test_bit(cpuacct_subsys_id, variable_flag))
+		open_tmpfile();
 
 	for (i = CPUACCT_STAT; i < CPUACCT_NR_PARAMS; i++) {
 		if (cpuacct_offset_table.cpuacct_cpustat == -1 &&
@@ -3136,6 +3280,12 @@
 			break;
 		}
 	}
+
+	/* second, output the needed param */
+	if (test_bit(cpuacct_subsys_id, variable_flag)) {
+		print_specified_param(cpuacct_subsys_id);
+		close_tmpfile();
+	}
 }
 
 static void
@@ -3148,6 +3298,10 @@
 
 	fprintf(fp, "%s:\n", group_list->path);
 
+	/* if some param is specified, first output all into a tmpfile. */
+	if (test_bit(hugetlb_subsys_id, variable_flag))
+		open_tmpfile();
+
 	hugepage_addr = subsys_addr + hugetlb_offset_table.hugetlb_hugepage;
 
 	readmem(symbol_value("hstates") + MEMBER_OFFSET("hstate", "order"), KVADDR,
@@ -3169,6 +3323,12 @@
 				"limit"), NULL);
 	fprintf(fp, "%s.%s.limit_in_bytes: %lu\n",
 		group_list->subsys_str, buf, val);
+
+	/* second, output the needed param */
+	if (test_bit(hugetlb_subsys_id, variable_flag)) {
+		print_specified_param(hugetlb_subsys_id);
+		close_tmpfile();
+	}
 }
 
 static void
@@ -3182,6 +3342,10 @@
 
 	fprintf(fp, "%s:\n", group_list->path);
 
+	/* if some param is specified, first output all into a tmpfile. */
+	if (test_bit(mem_cgroup_subsys_id, variable_flag))
+		open_tmpfile();
+
 	/* check if do swap account */
 	if (symbol_exists("do_swap_account"))
 		readmem(symbol_value("do_swap_account"), KVADDR, &do_swap_account,
@@ -3337,6 +3501,12 @@
 			break;
 		}
 	}
+
+	/* second, output the needed param */
+	if (test_bit(mem_cgroup_subsys_id, variable_flag)) {
+		print_specified_param(mem_cgroup_subsys_id);
+		close_tmpfile();
+	}
 }
 
 static void
@@ -3346,6 +3516,10 @@
 
 	fprintf(fp, "%s:\n", group_list->path);
 
+	/* if some param is specified, first output all into a tmpfile. */
+	if (test_bit(devices_subsys_id, variable_flag))
+		open_tmpfile();
+
 	list_head = subsys_addr + devices_offset_table.devices_whitelist;
 	whitelist_addr = (ulong)list_next((void *)list_head, NULL,
 				MEMBER_OFFSET("dev_whitelist_item", "list"));
@@ -3360,6 +3534,12 @@
 					MEMBER_OFFSET("dev_whitelist_item", "list"));
 	} while (list_head != whitelist_addr +
 			MEMBER_OFFSET("dev_whitelist_item", "list"));
+
+	/* second, output the needed param */
+	if (test_bit(devices_subsys_id, variable_flag)) {
+		print_specified_param(devices_subsys_id);
+		close_tmpfile();
+	}
 }
 
 static void
@@ -3373,6 +3553,11 @@
 		return;
 
 	fprintf(fp, "%s:\n", group_list->path);
+
+	/* if some param is specified, first output all into a tmpfile. */
+	if (test_bit(freezer_subsys_id, variable_flag))
+		open_tmpfile();
+
 	readmem(subsys_addr + freezer_offset_table.freezer_state , KVADDR,
 		&state, sizeof(enum freezer_state), "freezer_state",
 		FAULT_ON_ERROR);
@@ -3390,6 +3575,12 @@
 		return;
 	}
 	fprintf(fp, "%s\n", buf);
+
+	/* second, output the needed param */
+	if (test_bit(freezer_subsys_id, variable_flag)) {
+		print_specified_param(freezer_subsys_id);
+		close_tmpfile();
+	}
 }
 
 static void
@@ -3399,10 +3590,20 @@
 
 	fprintf(fp, "%s:\n", group_list->path);
 
+	/* if some param is specified, first output all into a tmpfile. */
+	if (test_bit(net_cls_subsys_id, variable_flag))
+		open_tmpfile();
+
 	readmem(subsys_addr + cls_offset_table.cls_classid , KVADDR,
 		&classid, sizeof(uint32_t), "cls_classid",
 		FAULT_ON_ERROR);
 	fprintf(fp, "%s.classid: %d\n", group_list->subsys_str, classid);
+
+	/* second, output the needed param */
+	if (test_bit(net_cls_subsys_id, variable_flag)) {
+		print_specified_param(net_cls_subsys_id);
+		close_tmpfile();
+	}
 }
 
 static void
@@ -3412,10 +3613,20 @@
 
 	fprintf(fp, "%s:\n", group_list->path);
 
+	/* if some param is specified, first output all into a tmpfile. */
+	if (test_bit(net_prio_subsys_id, variable_flag))
+		open_tmpfile();
+
 	readmem(subsys_addr + netprio_offset_table.netprio_prioidx , KVADDR,
 		&prioidx, sizeof(uint32_t), "netprio_prioidx",
 		FAULT_ON_ERROR);
 	fprintf(fp, "%s.prioidx: %d\n", group_list->subsys_str, prioidx);
+
+	/* second, output the needed param */
+	if (test_bit(net_prio_subsys_id, variable_flag)) {
+		print_specified_param(net_prio_subsys_id);
+		close_tmpfile();
+	}
 }
 
 static void
@@ -3425,6 +3636,10 @@
 
 	fprintf(fp, "%s:\n", group_list->path);
 
+	/* if some param is specified, first output all into a tmpfile. */
+	if (test_bit(blkio_subsys_id, variable_flag))
+		open_tmpfile();
+
 	if (STRUCT_EXISTS("blkcg")) {
 		for (plid = BLKCG_POLICY_THROTL; plid <= BLKCG_POLICY_PROP; plid++) {
 			if (plid == BLKCG_POLICY_PROP)
@@ -3465,6 +3680,12 @@
 	}
 	/* there should be nothing to be displayed for reset_stats */
 	fprintf(fp, "%s.reset_stats: \n", group_list->subsys_str);
+
+	/* second, output the needed param */
+	if (test_bit(blkio_subsys_id, variable_flag)) {
+		print_specified_param(blkio_subsys_id);
+		close_tmpfile();
+	}
 }
 
 static void
