mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
2291990ab3
commit
095f1fc4eb
|
@ -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,
|
||||||
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__ */
|
||||||
|
|
||||||
|
|
104
mm/mempolicy.c
104
mm/mempolicy.c
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
116
mm/shmem.c
116
mm/shmem.c
|
@ -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,
|
||||||
}
|
}
|
||||||
#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,8 +2139,8 @@ 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 {
|
||||||
printk(KERN_ERR "tmpfs: Bad mount option %s\n",
|
printk(KERN_ERR "tmpfs: Bad mount option %s\n",
|
||||||
|
|
Loading…
Reference in New Issue