Commit 095f1fc4 authored by Lee Schermerhorn's avatar Lee Schermerhorn Committed by Linus Torvalds

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: default avatarLee 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 2291990a
...@@ -214,6 +214,13 @@ static inline void check_highest_zone(enum zone_type k) ...@@ -214,6 +214,13 @@ static inline void check_highest_zone(enum zone_type k)
int do_migrate_pages(struct mm_struct *mm, int do_migrate_pages(struct mm_struct *mm,
const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags); 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 #else
struct mempolicy {}; struct mempolicy {};
...@@ -313,6 +320,20 @@ static inline int do_migrate_pages(struct mm_struct *mm, ...@@ -313,6 +320,20 @@ static inline int do_migrate_pages(struct mm_struct *mm,
static inline void check_highest_zone(int k) 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 /* CONFIG_NUMA */
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -88,6 +88,7 @@ ...@@ -88,6 +88,7 @@
#include <linux/rmap.h> #include <linux/rmap.h>
#include <linux/security.h> #include <linux/security.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/ctype.h>
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -1944,6 +1945,10 @@ void numa_default_policy(void) ...@@ -1944,6 +1945,10 @@ void numa_default_policy(void)
do_set_mempolicy(MPOL_DEFAULT, 0, NULL); do_set_mempolicy(MPOL_DEFAULT, 0, NULL);
} }
/*
* Parse and format mempolicy from/to strings
*/
/* /*
* "local" is pseudo-policy: MPOL_PREFERRED with MPOL_F_LOCAL flag * "local" is pseudo-policy: MPOL_PREFERRED with MPOL_F_LOCAL flag
* Used only for mpol_to_str() * Used only for mpol_to_str()
...@@ -1952,12 +1957,107 @@ void numa_default_policy(void) ...@@ -1952,12 +1957,107 @@ void numa_default_policy(void)
static const char * const policy_types[] = static const char * const policy_types[] =
{ "default", "prefer", "bind", "interleave", "local" }; { "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. * Convert a mempolicy into a string.
* Returns the number of characters in buffer (if positive) * Returns the number of characters in buffer (if positive)
* or an error (negative) * 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; char *p = buffer;
int l; int l;
...@@ -2022,7 +2122,7 @@ static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) ...@@ -2022,7 +2122,7 @@ static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
if (!nodes_empty(nodes)) { if (!nodes_empty(nodes)) {
if (buffer + maxlen < p + 2) if (buffer + maxlen < p + 2)
return -ENOSPC; return -ENOSPC;
*p++ = '='; *p++ = ':';
p += nodelist_scnprintf(p, buffer + maxlen - p, nodes); p += nodelist_scnprintf(p, buffer + maxlen - p, nodes);
} }
return p - buffer; return p - buffer;
......
...@@ -1079,108 +1079,22 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) ...@@ -1079,108 +1079,22 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
#ifdef CONFIG_TMPFS #ifdef CONFIG_TMPFS
static int shmem_parse_mpol(char *value, unsigned short *policy, static void shmem_show_mpol(struct seq_file *seq, unsigned short mode,
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,
unsigned short flags, const nodemask_t policy_nodes) unsigned short flags, const nodemask_t policy_nodes)
{ {
char *policy_string; struct mempolicy temp;
char buffer[64];
switch (policy) { if (mode == MPOL_DEFAULT)
case MPOL_PREFERRED: return; /* show nothing */
policy_string = "prefer";
break;
case MPOL_BIND:
policy_string = "bind";
break;
case MPOL_INTERLEAVE:
policy_string = "interleave";
break;
default:
/* MPOL_DEFAULT */
return;
}
seq_printf(seq, ",mpol=%s", policy_string); temp.mode = mode;
temp.flags = flags;
temp.v.nodes = policy_nodes;
if (policy != MPOL_INTERLEAVE || mpol_to_str(buffer, sizeof(buffer), &temp);
!nodes_equal(policy_nodes, node_states[N_HIGH_MEMORY])) {
char buffer[64];
int len;
len = nodelist_scnprintf(buffer, sizeof(buffer), policy_nodes); seq_printf(seq, ",mpol=%s", buffer);
if (len < sizeof(buffer))
seq_printf(seq, ":%s", buffer);
else
seq_printf(seq, ":?");
}
} }
#endif /* CONFIG_TMPFS */ #endif /* CONFIG_TMPFS */
...@@ -1221,12 +1135,6 @@ static struct page *shmem_alloc_page(gfp_t gfp, ...@@ -1221,12 +1135,6 @@ static struct page *shmem_alloc_page(gfp_t gfp,
} }
#else /* !CONFIG_NUMA */ #else /* !CONFIG_NUMA */
#ifdef CONFIG_TMPFS #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, static inline void shmem_show_mpol(struct seq_file *seq, unsigned short policy,
unsigned short flags, const nodemask_t policy_nodes) unsigned short flags, const nodemask_t policy_nodes)
{ {
...@@ -2231,7 +2139,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, ...@@ -2231,7 +2139,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
if (*rest) if (*rest)
goto bad_val; goto bad_val;
} else if (!strcmp(this_char,"mpol")) { } else if (!strcmp(this_char,"mpol")) {
if (shmem_parse_mpol(value, &sbinfo->policy, if (mpol_parse_str(value, &sbinfo->policy,
&sbinfo->flags, &sbinfo->policy_nodes)) &sbinfo->flags, &sbinfo->policy_nodes))
goto bad_val; goto bad_val;
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment