[PATCH 1/4] x86: add cpus_scnprintf function v2

From: Mike Travis
Date: Fri Apr 04 2008 - 21:26:31 EST


* Add a new cpus_scnprintf() function and a sysctl flag to control
how cpumask sets are printed. The default is to use the current
cpumask_scnprintf(). If kernel.compat_cpus_printf is '0' (default 1),
then cpulist_scnprintf() is used. A nodes_scnprintf() function is
also provided for compatibilty.

Note that setting the kernel.compat_cpus_printf to '0' also makes the
syntax compatible with the setting and showing of cpuset parameters
such as cpu_exclusive and mem_exclusive.

This is introduced with a CONFIG_KERN_COMPAT_CPUSET_PRINTF flag which
currently is only defined for X86_64_SMP architecture.

* In addition, remove the cpumask_scnprintf_len() function.

This is all needed to accomodate large NR_CPUS count and the usage has
been added to Documentation/sysctl/kernel.txt.

Based on:
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+ x86/latest .../x86/linux-2.6-x86.git
+ sched-devel/latest .../mingo/linux-2.6-sched-devel.git

Signed-off-by: Mike Travis <travis@xxxxxxx>
---
v2:
Renamed cpuset_scnprintf() to cpus_scnprintf to avoid confusion with
"cpusets", and changed the other names to match.

Added a sentinel character ('+') for the cpulist type output so scripts
can be written to handle both cases.

Added a warning in the Documentation/sysctl/kernel.txt that changing this
option may break scripts and programs that rely on the current format.
Also provided example on how to process the output.
---
Documentation/sysctl/kernel.txt | 56 ++++++++++++++++++++++++++++++++++++++++
arch/x86/Kconfig | 4 ++
arch/x86/kernel/setup.c | 5 +++
include/linux/bitmap.h | 1
include/linux/cpumask.h | 35 ++++++++++++++++++++-----
include/linux/nodemask.h | 31 ++++++++++++++++++++++
kernel/sysctl.c | 11 +++++++
lib/bitmap.c | 16 -----------
8 files changed, 135 insertions(+), 24 deletions(-)

--- linux-2.6.x86.orig/Documentation/sysctl/kernel.txt
+++ linux-2.6.x86/Documentation/sysctl/kernel.txt
@@ -18,6 +18,7 @@ Currently, these files might (depending
show up in /proc/sys/kernel:
- acpi_video_flags
- acct
+- compat_cpus_printf
- core_pattern
- core_uses_pid
- ctrl-alt-del
@@ -85,6 +86,61 @@ valid for 30 seconds.

==============================================================

+compat_cpus_printf:
+
+compat_cpus_printf is used to alter the way cpumask_t cpu bits
+are printed. To maintain compatibility with the current output
+format, the default is '1'.
+
+** DO NOT CHANGE THIS ** if you run programs or scripts which may
+rely on the current format until you are certain they can handle the
+newer, more compact format. If you change the format, it will apply
+to all programs that access common /proc and /sys interfaces.
+
+The current format results in the following print when the number
+of cpus in a system is large. An example when NR_CPUS is 4096 and
+compat_cpus_printf is '1':
+
+ # cat /sys/devices/system/cpu/cpu92/cache/index2/shared_cpu_map
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,\
+ 00000000,00000000,00000000,00000000,00000000,33000000,00000000,00000000
+
+The same example when compat_cpus_printf = '0':
+
+ # echo 0 > /proc/sys/kernel/compat_cpus_printf
+ # cat /sys/devices/system/cpu/cpu3/cache/index0/shared_cpu_map
+ +88-89,92-93
+
+Note that when the "non-compatibile" (or "cpulist") format is specified,
+a preceeding '+' is output. This allows user scripts and programs that
+process the output to distinguish which format is present:
+
+ if (buf[0] == '+')
+ bitmask_parselist(&buf[1], ...);
+ else
+ bitmask_parsehex(buf, ...);
+
+See libbitmask(3) for details on parsing the output.
+
+In addition to conversion of cpumask_t cpu bits, nodemask_t bits are
+handled the same way.
+
+==============================================================
+
core_pattern:

core_pattern is used to specify a core dumpfile pattern name.
--- linux-2.6.x86.orig/arch/x86/Kconfig
+++ linux-2.6.x86/arch/x86/Kconfig
@@ -192,6 +192,10 @@ config X86_TRAMPOLINE
depends on X86_SMP || (X86_VOYAGER && SMP)
default y

+config KERN_COMPAT_CPUS_PRINTF
+ bool
+ default X86_64_SMP
+
config KTIME_SCALAR
def_bool X86_32
source "init/Kconfig"
--- linux-2.6.x86.orig/arch/x86/kernel/setup.c
+++ linux-2.6.x86/arch/x86/kernel/setup.c
@@ -25,6 +25,11 @@ static void __init setup_nr_cpu_ids(void
static inline void setup_nr_cpu_ids(void) { }
#endif

+#ifdef CONFIG_KERN_COMPAT_CPUS_PRINTF
+/* select cpus_scnprintf output */
+int compat_cpus_printf = 1;
+#endif
+
#if defined(CONFIG_HAVE_SETUP_PER_CPU_AREA) && defined(CONFIG_SMP)
/*
* Copy data used in early init routines from the initial arrays to the
--- linux-2.6.x86.orig/include/linux/bitmap.h
+++ linux-2.6.x86/include/linux/bitmap.h
@@ -108,7 +108,6 @@ extern int __bitmap_weight(const unsigne

extern int bitmap_scnprintf(char *buf, unsigned int len,
const unsigned long *src, int nbits);
-extern int bitmap_scnprintf_len(unsigned int len);
extern int __bitmap_parse(const char *buf, unsigned int buflen, int is_user,
unsigned long *dst, int nbits);
extern int bitmap_parse_user(const char __user *ubuf, unsigned int ulen,
--- linux-2.6.x86.orig/include/linux/cpumask.h
+++ linux-2.6.x86/include/linux/cpumask.h
@@ -14,6 +14,8 @@
* bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
* For details of cpu_remap(), see bitmap_bitremap in lib/bitmap.c
* For details of cpus_remap(), see bitmap_remap in lib/bitmap.c.
+ * For details of cpus_scnprintf(), see compat_cpus_printf in
+ * Documentation/sysctl/kernel.txt.
*
* The available cpumask operations are:
*
@@ -52,6 +54,9 @@
* int cpumask_parse_user(ubuf, ulen, mask) Parse ascii string as cpumask
* int cpulist_scnprintf(buf, len, mask) Format cpumask as list for printing
* int cpulist_parse(buf, map) Parse ascii string as cpulist
+ * int cpus_scnprintf(buf, len, mask) Format cpumask with either
+ * cpumask_scnprintf or cpulist_scnprintf
+ * based on the value of compat_cpus_printf
* int cpu_remap(oldbit, old, new) newbit = map(old, new)(oldbit)
* int cpus_remap(dst, src, old, new) *dst = map(old, new)(src)
*
@@ -285,13 +290,6 @@ static inline int __cpumask_scnprintf(ch
return bitmap_scnprintf(buf, len, srcp->bits, nbits);
}

-#define cpumask_scnprintf_len(len) \
- __cpumask_scnprintf_len((len))
-static inline int __cpumask_scnprintf_len(int len)
-{
- return bitmap_scnprintf_len(len);
-}
-
#define cpumask_parse_user(ubuf, ulen, dst) \
__cpumask_parse_user((ubuf), (ulen), &(dst), NR_CPUS)
static inline int __cpumask_parse_user(const char __user *buf, int len,
@@ -314,6 +312,29 @@ static inline int __cpulist_parse(const
return bitmap_parselist(buf, dstp->bits, nbits);
}

+#ifdef CONFIG_KERN_COMPAT_CPUS_PRINTF
+#define cpus_scnprintf(buf, len, src) __cpus_scnprintf((buf), (len), &(src))
+static inline int __cpus_scnprintf(char *buf, int len, const cpumask_t *srcp)
+{
+ extern int compat_cpus_printf;
+
+ if (compat_cpus_printf)
+ return __cpumask_scnprintf(buf, len, srcp, NR_CPUS);
+ else {
+ int n = 0;
+ if (len > 1) {
+ *buf++ = '+';
+ *buf = '\0';
+ n = __cpulist_scnprintf(buf, len-1, srcp, NR_CPUS);
+ n++;
+ }
+ return n;
+ }
+}
+#else
+#define cpus_scnprintf(buf, len, src) cpumask_scnprintf(buf, len, src)
+#endif
+
#define cpu_remap(oldbit, old, new) \
__cpu_remap((oldbit), &(old), &(new), NR_CPUS)
static inline int __cpu_remap(int oldbit,
--- linux-2.6.x86.orig/include/linux/nodemask.h
+++ linux-2.6.x86/include/linux/nodemask.h
@@ -14,6 +14,8 @@
* bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
* For details of node_remap(), see bitmap_bitremap in lib/bitmap.c.
* For details of nodes_remap(), see bitmap_remap in lib/bitmap.c.
+ * For details of nodes_scnprintf(), see compat_cpus_printf in
+ * Documentation/sysctl/kernel.txt.
*
* The available nodemask operations are:
*
@@ -54,6 +56,9 @@
* int nodemask_parse_user(ubuf, ulen, mask) Parse ascii string as nodemask
* int nodelist_scnprintf(buf, len, mask) Format nodemask as list for printing
* int nodelist_parse(buf, map) Parse ascii string as nodelist
+ * int nodes_scnprintf(buf, len, mask) Format nodemask with either
+ * nodemask_scnprintf or nodelist_scnprintf
+ * based on the value of compat_cpus_printf
* int node_remap(oldbit, old, new) newbit = map(old, new)(oldbit)
* int nodes_remap(dst, src, old, new) *dst = map(old, new)(dst)
*
@@ -310,6 +315,32 @@ static inline int __nodelist_parse(const
return bitmap_parselist(buf, dstp->bits, nbits);
}

+#ifdef CONFIG_KERN_COMPAT_CPUS_PRINTF
+#define nodes_scnprintf(buf, len, src) \
+ __nodes_scnprintf((buf), (len), &(src))
+static inline int __nodes_scnprintf(char *buf, int len, const nodemask_t *srcp)
+{
+ extern int compat_cpus_printf;
+
+ if (compat_cpus_printf)
+ return __nodemask_scnprintf(buf, len, srcp, MAX_NUMNODES);
+ else {
+ int n = 0;
+ if (len > 1) {
+ *buf++ = '+';
+ *buf = '\0';
+ n = __nodelist_scnprintf(buf, len-1, srcp,
+ MAX_NUMNODES);
+ n++;
+ }
+ return n;
+ }
+}
+#else
+#define nodes_scnprintf(buf, len, src) nodemask_scnprintf(buf, len, src)
+#endif
+
+
#define node_remap(oldbit, old, new) \
__node_remap((oldbit), &(old), &(new), MAX_NUMNODES)
static inline int __node_remap(int oldbit,
--- linux-2.6.x86.orig/kernel/sysctl.c
+++ linux-2.6.x86/kernel/sysctl.c
@@ -82,6 +82,7 @@ extern int compat_log;
extern int maps_protect;
extern int sysctl_stat_interval;
extern int latencytop_enabled;
+extern int compat_cpus_printf;

/* Constants used for minimum and maximum */
#if defined(CONFIG_DETECT_SOFTLOCKUP) || defined(CONFIG_HIGHMEM)
@@ -831,6 +832,16 @@ static struct ctl_table kern_table[] = {
.proc_handler = &proc_dointvec,
},
#endif
+#ifdef CONFIG_KERN_COMPAT_CPUS_PRINTF
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "compat_cpus_printf",
+ .data = &compat_cpus_printf,
+ .maxlen = sizeof (int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+#endif

/*
* NOTE: do not add new entries to this table unless you have read
--- linux-2.6.x86.orig/lib/bitmap.c
+++ linux-2.6.x86/lib/bitmap.c
@@ -316,22 +316,6 @@ int bitmap_scnprintf(char *buf, unsigned
EXPORT_SYMBOL(bitmap_scnprintf);

/**
- * bitmap_scnprintf_len - return buffer length needed to convert
- * bitmap to an ASCII hex string.
- * @len: number of bits to be converted
- */
-int bitmap_scnprintf_len(unsigned int len)
-{
- /* we need 9 chars per word for 32 bit words (8 hexdigits + sep/null) */
- int bitslen = ALIGN(len, CHUNKSZ);
- int wordlen = CHUNKSZ / 4;
- int buflen = (bitslen / wordlen) * (wordlen + 1) * sizeof(char);
-
- return buflen;
-}
-EXPORT_SYMBOL(bitmap_scnprintf_len);
-
-/**
* __bitmap_parse - convert an ASCII hex string into a bitmap.
* @buf: pointer to buffer containing string.
* @buflen: buffer size in bytes. If string is smaller than this

--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/