summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLee Schermerhorn <lee.schermerhorn@hp.com>2008-04-28 02:13:23 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-28 08:58:24 -0700
commit095f1fc4ebf36c64fddf9b6db29b1ab5517378e6 (patch)
tree39aae9d5b05d8501d1794e92c6115331c0a40848
parent2291990ab36b4b2d8a81b1f92e7a046e51632a60 (diff)
mempolicy: rework shmem mpol parsing and display
mm/shmem.c currently contains functions to parse and display memory policy strings for the tmpfs 'mpol' mount option. Move this to mm/mempolicy.c with the rest of the mempolicy support. With subsequent patches, we'll be able to remove knowledge of the details [mode, flags, policy, ...] completely from shmem.c 1) replace shmem_parse_mpol() in mm/shmem.c with mpol_parse_str() in mm/mempolicy.c. Rework to use the policy_types[] array [used by mpol_to_str()] to look up mode by name. 2) use mpol_to_str() to format policy for shmem_show_mpol(). mpol_to_str() expects a pointer to a struct mempolicy, so temporarily construct one. This will be replaced with a reference to a struct mempolicy in the tmpfs superblock in a subsequent patch. NOTE 1: I changed mpol_to_str() to use a colon ':' rather than an equal sign '=' as the nodemask delimiter to match mpol_parse_str() and the tmpfs/shmem mpol mount option formatting that now uses mpol_to_str(). This is a user visible change to numa_maps, but then the addition of the mode flags already changed the display. It makes sense to me to have the mounts and numa_maps display the policy in the same format. However, if anyone objects strongly, I can pass the desired nodemask delimeter as an arg to mpol_to_str(). Note 2: Like show_numa_map(), I don't check the return code from mpol_to_str(). I do use a longer buffer than the one provided by show_numa_map(), which seems to have sufficed so far. Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com> Cc: Christoph Lameter <clameter@sgi.com> Cc: David Rientjes <rientjes@google.com> Cc: Mel Gorman <mel@csn.ul.ie> Cc: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/mempolicy.h21
-rw-r--r--mm/mempolicy.c104
-rw-r--r--mm/shmem.c118
3 files changed, 136 insertions, 107 deletions
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index b0fab9e8065..dcc17378c95 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -214,6 +214,13 @@ static inline void check_highest_zone(enum zone_type k)
int do_migrate_pages(struct mm_struct *mm,
const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags);
+
+#ifdef CONFIG_TMPFS
+extern int mpol_parse_str(char *str, unsigned short *mode,
+ unsigned short *mode_flags, nodemask_t *policy_nodes);
+
+extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol);
+#endif
#else
struct mempolicy {};
@@ -313,6 +320,20 @@ static inline int do_migrate_pages(struct mm_struct *mm,
static inline void check_highest_zone(int k)
{
}
+
+#ifdef CONFIG_TMPFS
+static inline int mpol_parse_str(char *value, unsigned short *policy,
+ unsigned short flags, nodemask_t *policy_nodes)
+{
+ return 1;
+}
+
+static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
+{
+ return 0;
+}
+#endif
+
#endif /* CONFIG_NUMA */
#endif /* __KERNEL__ */
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 3c8ee31572e..155bb284dbf 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -88,6 +88,7 @@
#include <linux/rmap.h>
#include <linux/security.h>
#include <linux/syscalls.h>
+#include <linux/ctype.h>
#include <asm/tlbflush.h>
#include <asm/uaccess.h>
@@ -1945,6 +1946,10 @@ void numa_default_policy(void)
}
/*
+ * Parse and format mempolicy from/to strings
+ */
+
+/*
* "local" is pseudo-policy: MPOL_PREFERRED with MPOL_F_LOCAL flag
* Used only for mpol_to_str()
*/
@@ -1952,12 +1957,107 @@ void numa_default_policy(void)
static const char * const policy_types[] =
{ "default", "prefer", "bind", "interleave", "local" };
+
+#ifdef CONFIG_TMPFS
+/**
+ * mpol_parse_str - parse string to mempolicy
+ * @str: string containing mempolicy to parse
+ * @mode: pointer to returned policy mode
+ * @mode_flags: pointer to returned flags
+ * @policy_nodes: pointer to returned nodemask
+ *
+ * Format of input:
+ * <mode>[=<flags>][:<nodelist>]
+ *
+ * Currently only used for tmpfs/shmem mount options
+ */
+int mpol_parse_str(char *str, unsigned short *mode, unsigned short *mode_flags,
+ nodemask_t *policy_nodes)
+{
+ char *nodelist = strchr(str, ':');
+ char *flags = strchr(str, '=');
+ int i;
+ int err = 1;
+
+ if (nodelist) {
+ /* NUL-terminate mode or flags string */
+ *nodelist++ = '\0';
+ if (nodelist_parse(nodelist, *policy_nodes))
+ goto out;
+ if (!nodes_subset(*policy_nodes, node_states[N_HIGH_MEMORY]))
+ goto out;
+ }
+ if (flags)
+ *flags++ = '\0'; /* terminate mode string */
+
+ for (i = 0; i < MPOL_MAX; i++) {
+ if (!strcmp(str, policy_types[i])) {
+ *mode = i;
+ break;
+ }
+ }
+ if (i == MPOL_MAX)
+ goto out;
+
+ switch (*mode) {
+ case MPOL_DEFAULT:
+ /* Don't allow a nodelist nor flags */
+ if (!nodelist && !flags)
+ err = 0;
+ break;
+ case MPOL_PREFERRED:
+ /* Insist on a nodelist of one node only */
+ if (nodelist) {
+ char *rest = nodelist;
+ while (isdigit(*rest))
+ rest++;
+ if (!*rest)
+ err = 0;
+ }
+ break;
+ case MPOL_BIND:
+ /* Insist on a nodelist */
+ if (nodelist)
+ err = 0;
+ break;
+ case MPOL_INTERLEAVE:
+ /*
+ * Default to online nodes with memory if no nodelist
+ */
+ if (!nodelist)
+ *policy_nodes = node_states[N_HIGH_MEMORY];
+ err = 0;
+ }
+
+ *mode_flags = 0;
+ if (flags) {
+ /*
+ * Currently, we only support two mutually exclusive
+ * mode flags.
+ */
+ if (!strcmp(flags, "static"))
+ *mode_flags |= MPOL_F_STATIC_NODES;
+ else if (!strcmp(flags, "relative"))
+ *mode_flags |= MPOL_F_RELATIVE_NODES;
+ else
+ err = 1;
+ }
+out:
+ /* Restore string for error message */
+ if (nodelist)
+ *--nodelist = ':';
+ if (flags)
+ *--flags = '=';
+ return err;
+}
+#endif /* CONFIG_TMPFS */
+
/*
* Convert a mempolicy into a string.
* Returns the number of characters in buffer (if positive)
* or an error (negative)
*/
-static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
+int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
{
char *p = buffer;
int l;
@@ -2022,7 +2122,7 @@ static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
if (!nodes_empty(nodes)) {
if (buffer + maxlen < p + 2)
return -ENOSPC;
- *p++ = '=';
+ *p++ = ':';
p += nodelist_scnprintf(p, buffer + maxlen - p, nodes);
}
return p - buffer;
diff --git a/mm/shmem.c b/mm/shmem.c
index 0b591c669b2..3c620dc1013 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1079,108 +1079,22 @@ redirty:
#ifdef CONFIG_NUMA
#ifdef CONFIG_TMPFS
-static int shmem_parse_mpol(char *value, unsigned short *policy,
- unsigned short *mode_flags, nodemask_t *policy_nodes)
-{
- char *nodelist = strchr(value, ':');
- char *flags = strchr(value, '=');
- int err = 1;
-
- if (nodelist) {
- /* NUL-terminate policy string */
- *nodelist++ = '\0';
- if (nodelist_parse(nodelist, *policy_nodes))
- goto out;
- if (!nodes_subset(*policy_nodes, node_states[N_HIGH_MEMORY]))
- goto out;
- }
- if (flags)
- *flags++ = '\0';
- if (!strcmp(value, "default")) {
- *policy = MPOL_DEFAULT;
- /* Don't allow a nodelist */
- if (!nodelist)
- err = 0;
- } else if (!strcmp(value, "prefer")) {
- *policy = MPOL_PREFERRED;
- /* Insist on a nodelist of one node only */
- if (nodelist) {
- char *rest = nodelist;
- while (isdigit(*rest))
- rest++;
- if (!*rest)
- err = 0;
- }
- } else if (!strcmp(value, "bind")) {
- *policy = MPOL_BIND;
- /* Insist on a nodelist */
- if (nodelist)
- err = 0;
- } else if (!strcmp(value, "interleave")) {
- *policy = MPOL_INTERLEAVE;
- /*
- * Default to online nodes with memory if no nodelist
- */
- if (!nodelist)
- *policy_nodes = node_states[N_HIGH_MEMORY];
- err = 0;
- }
-
- *mode_flags = 0;
- if (flags) {
- /*
- * Currently, we only support two mutually exclusive
- * mode flags.
- */
- if (!strcmp(flags, "static"))
- *mode_flags |= MPOL_F_STATIC_NODES;
- else if (!strcmp(flags, "relative"))
- *mode_flags |= MPOL_F_RELATIVE_NODES;
- else
- err = 1; /* unrecognized flag */
- }
-out:
- /* Restore string for error message */
- if (nodelist)
- *--nodelist = ':';
- if (flags)
- *--flags = '=';
- return err;
-}
-
-static void shmem_show_mpol(struct seq_file *seq, unsigned short policy,
+static void shmem_show_mpol(struct seq_file *seq, unsigned short mode,
unsigned short flags, const nodemask_t policy_nodes)
{
- char *policy_string;
-
- switch (policy) {
- case MPOL_PREFERRED:
- policy_string = "prefer";
- break;
- case MPOL_BIND:
- policy_string = "bind";
- break;
- case MPOL_INTERLEAVE:
- policy_string = "interleave";
- break;
- default:
- /* MPOL_DEFAULT */
- return;
- }
+ struct mempolicy temp;
+ char buffer[64];
- seq_printf(seq, ",mpol=%s", policy_string);
+ if (mode == MPOL_DEFAULT)
+ return; /* show nothing */
- if (policy != MPOL_INTERLEAVE ||
- !nodes_equal(policy_nodes, node_states[N_HIGH_MEMORY])) {
- char buffer[64];
- int len;
+ temp.mode = mode;
+ temp.flags = flags;
+ temp.v.nodes = policy_nodes;
- len = nodelist_scnprintf(buffer, sizeof(buffer), policy_nodes);
- if (len < sizeof(buffer))
- seq_printf(seq, ":%s", buffer);
- else
- seq_printf(seq, ":?");
- }
+ mpol_to_str(buffer, sizeof(buffer), &temp);
+
+ seq_printf(seq, ",mpol=%s", buffer);
}
#endif /* CONFIG_TMPFS */
@@ -1221,12 +1135,6 @@ static struct page *shmem_alloc_page(gfp_t gfp,
}
#else /* !CONFIG_NUMA */
#ifdef CONFIG_TMPFS
-static inline int shmem_parse_mpol(char *value, unsigned short *policy,
- unsigned short *mode_flags, nodemask_t *policy_nodes)
-{
- return 1;
-}
-
static inline void shmem_show_mpol(struct seq_file *seq, unsigned short policy,
unsigned short flags, const nodemask_t policy_nodes)
{
@@ -2231,8 +2139,8 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
if (*rest)
goto bad_val;
} else if (!strcmp(this_char,"mpol")) {
- if (shmem_parse_mpol(value, &sbinfo->policy,
- &sbinfo->flags, &sbinfo->policy_nodes))
+ if (mpol_parse_str(value, &sbinfo->policy,
+ &sbinfo->flags, &sbinfo->policy_nodes))
goto bad_val;
} else {
printk(KERN_ERR "tmpfs: Bad mount option %s\n",