diff options
author | Lee Schermerhorn <lee.schermerhorn@hp.com> | 2008-04-28 05:13:23 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-28 11:58:24 -0400 |
commit | 095f1fc4ebf36c64fddf9b6db29b1ab5517378e6 (patch) | |
tree | 39aae9d5b05d8501d1794e92c6115331c0a40848 | |
parent | 2291990ab36b4b2d8a81b1f92e7a046e51632a60 (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.h | 21 | ||||
-rw-r--r-- | mm/mempolicy.c | 104 | ||||
-rw-r--r-- | mm/shmem.c | 118 |
3 files changed, 136 insertions, 107 deletions
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index b0fab9e80655..dcc17378c952 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) | |||
214 | int do_migrate_pages(struct mm_struct *mm, | 214 | int do_migrate_pages(struct mm_struct *mm, |
215 | const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags); | 215 | const nodemask_t *from_nodes, const nodemask_t *to_nodes, int flags); |
216 | 216 | ||
217 | |||
218 | #ifdef CONFIG_TMPFS | ||
219 | extern int mpol_parse_str(char *str, unsigned short *mode, | ||
220 | unsigned short *mode_flags, nodemask_t *policy_nodes); | ||
221 | |||
222 | extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol); | ||
223 | #endif | ||
217 | #else | 224 | #else |
218 | 225 | ||
219 | struct mempolicy {}; | 226 | struct mempolicy {}; |
@@ -313,6 +320,20 @@ static inline int do_migrate_pages(struct mm_struct *mm, | |||
313 | static inline void check_highest_zone(int k) | 320 | static inline void check_highest_zone(int k) |
314 | { | 321 | { |
315 | } | 322 | } |
323 | |||
324 | #ifdef CONFIG_TMPFS | ||
325 | static inline int mpol_parse_str(char *value, unsigned short *policy, | ||
326 | unsigned short flags, nodemask_t *policy_nodes) | ||
327 | { | ||
328 | return 1; | ||
329 | } | ||
330 | |||
331 | static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) | ||
332 | { | ||
333 | return 0; | ||
334 | } | ||
335 | #endif | ||
336 | |||
316 | #endif /* CONFIG_NUMA */ | 337 | #endif /* CONFIG_NUMA */ |
317 | #endif /* __KERNEL__ */ | 338 | #endif /* __KERNEL__ */ |
318 | 339 | ||
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 3c8ee31572ec..155bb284dbf1 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -88,6 +88,7 @@ | |||
88 | #include <linux/rmap.h> | 88 | #include <linux/rmap.h> |
89 | #include <linux/security.h> | 89 | #include <linux/security.h> |
90 | #include <linux/syscalls.h> | 90 | #include <linux/syscalls.h> |
91 | #include <linux/ctype.h> | ||
91 | 92 | ||
92 | #include <asm/tlbflush.h> | 93 | #include <asm/tlbflush.h> |
93 | #include <asm/uaccess.h> | 94 | #include <asm/uaccess.h> |
@@ -1945,6 +1946,10 @@ void numa_default_policy(void) | |||
1945 | } | 1946 | } |
1946 | 1947 | ||
1947 | /* | 1948 | /* |
1949 | * Parse and format mempolicy from/to strings | ||
1950 | */ | ||
1951 | |||
1952 | /* | ||
1948 | * "local" is pseudo-policy: MPOL_PREFERRED with MPOL_F_LOCAL flag | 1953 | * "local" is pseudo-policy: MPOL_PREFERRED with MPOL_F_LOCAL flag |
1949 | * Used only for mpol_to_str() | 1954 | * Used only for mpol_to_str() |
1950 | */ | 1955 | */ |
@@ -1952,12 +1957,107 @@ void numa_default_policy(void) | |||
1952 | static const char * const policy_types[] = | 1957 | static const char * const policy_types[] = |
1953 | { "default", "prefer", "bind", "interleave", "local" }; | 1958 | { "default", "prefer", "bind", "interleave", "local" }; |
1954 | 1959 | ||
1960 | |||
1961 | #ifdef CONFIG_TMPFS | ||
1962 | /** | ||
1963 | * mpol_parse_str - parse string to mempolicy | ||
1964 | * @str: string containing mempolicy to parse | ||
1965 | * @mode: pointer to returned policy mode | ||
1966 | * @mode_flags: pointer to returned flags | ||
1967 | * @policy_nodes: pointer to returned nodemask | ||
1968 | * | ||
1969 | * Format of input: | ||
1970 | * <mode>[=<flags>][:<nodelist>] | ||
1971 | * | ||
1972 | * Currently only used for tmpfs/shmem mount options | ||
1973 | */ | ||
1974 | int mpol_parse_str(char *str, unsigned short *mode, unsigned short *mode_flags, | ||
1975 | nodemask_t *policy_nodes) | ||
1976 | { | ||
1977 | char *nodelist = strchr(str, ':'); | ||
1978 | char *flags = strchr(str, '='); | ||
1979 | int i; | ||
1980 | int err = 1; | ||
1981 | |||
1982 | if (nodelist) { | ||
1983 | /* NUL-terminate mode or flags string */ | ||
1984 | *nodelist++ = '\0'; | ||
1985 | if (nodelist_parse(nodelist, *policy_nodes)) | ||
1986 | goto out; | ||
1987 | if (!nodes_subset(*policy_nodes, node_states[N_HIGH_MEMORY])) | ||
1988 | goto out; | ||
1989 | } | ||
1990 | if (flags) | ||
1991 | *flags++ = '\0'; /* terminate mode string */ | ||
1992 | |||
1993 | for (i = 0; i < MPOL_MAX; i++) { | ||
1994 | if (!strcmp(str, policy_types[i])) { | ||
1995 | *mode = i; | ||
1996 | break; | ||
1997 | } | ||
1998 | } | ||
1999 | if (i == MPOL_MAX) | ||
2000 | goto out; | ||
2001 | |||
2002 | switch (*mode) { | ||
2003 | case MPOL_DEFAULT: | ||
2004 | /* Don't allow a nodelist nor flags */ | ||
2005 | if (!nodelist && !flags) | ||
2006 | err = 0; | ||
2007 | break; | ||
2008 | case MPOL_PREFERRED: | ||
2009 | /* Insist on a nodelist of one node only */ | ||
2010 | if (nodelist) { | ||
2011 | char *rest = nodelist; | ||
2012 | while (isdigit(*rest)) | ||
2013 | rest++; | ||
2014 | if (!*rest) | ||
2015 | err = 0; | ||
2016 | } | ||
2017 | break; | ||
2018 | case MPOL_BIND: | ||
2019 | /* Insist on a nodelist */ | ||
2020 | if (nodelist) | ||
2021 | err = 0; | ||
2022 | break; | ||
2023 | case MPOL_INTERLEAVE: | ||
2024 | /* | ||
2025 | * Default to online nodes with memory if no nodelist | ||
2026 | */ | ||
2027 | if (!nodelist) | ||
2028 | *policy_nodes = node_states[N_HIGH_MEMORY]; | ||
2029 | err = 0; | ||
2030 | } | ||
2031 | |||
2032 | *mode_flags = 0; | ||
2033 | if (flags) { | ||
2034 | /* | ||
2035 | * Currently, we only support two mutually exclusive | ||
2036 | * mode flags. | ||
2037 | */ | ||
2038 | if (!strcmp(flags, "static")) | ||
2039 | *mode_flags |= MPOL_F_STATIC_NODES; | ||
2040 | else if (!strcmp(flags, "relative")) | ||
2041 | *mode_flags |= MPOL_F_RELATIVE_NODES; | ||
2042 | else | ||
2043 | err = 1; | ||
2044 | } | ||
2045 | out: | ||
2046 | /* Restore string for error message */ | ||
2047 | if (nodelist) | ||
2048 | *--nodelist = ':'; | ||
2049 | if (flags) | ||
2050 | *--flags = '='; | ||
2051 | return err; | ||
2052 | } | ||
2053 | #endif /* CONFIG_TMPFS */ | ||
2054 | |||
1955 | /* | 2055 | /* |
1956 | * Convert a mempolicy into a string. | 2056 | * Convert a mempolicy into a string. |
1957 | * Returns the number of characters in buffer (if positive) | 2057 | * Returns the number of characters in buffer (if positive) |
1958 | * or an error (negative) | 2058 | * or an error (negative) |
1959 | */ | 2059 | */ |
1960 | static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) | 2060 | int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) |
1961 | { | 2061 | { |
1962 | char *p = buffer; | 2062 | char *p = buffer; |
1963 | int l; | 2063 | int l; |
@@ -2022,7 +2122,7 @@ static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) | |||
2022 | if (!nodes_empty(nodes)) { | 2122 | if (!nodes_empty(nodes)) { |
2023 | if (buffer + maxlen < p + 2) | 2123 | if (buffer + maxlen < p + 2) |
2024 | return -ENOSPC; | 2124 | return -ENOSPC; |
2025 | *p++ = '='; | 2125 | *p++ = ':'; |
2026 | p += nodelist_scnprintf(p, buffer + maxlen - p, nodes); | 2126 | p += nodelist_scnprintf(p, buffer + maxlen - p, nodes); |
2027 | } | 2127 | } |
2028 | return p - buffer; | 2128 | return p - buffer; |
diff --git a/mm/shmem.c b/mm/shmem.c index 0b591c669b2d..3c620dc10135 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -1079,108 +1079,22 @@ redirty: | |||
1079 | 1079 | ||
1080 | #ifdef CONFIG_NUMA | 1080 | #ifdef CONFIG_NUMA |
1081 | #ifdef CONFIG_TMPFS | 1081 | #ifdef CONFIG_TMPFS |
1082 | static int shmem_parse_mpol(char *value, unsigned short *policy, | 1082 | static void shmem_show_mpol(struct seq_file *seq, unsigned short mode, |
1083 | unsigned short *mode_flags, nodemask_t *policy_nodes) | ||
1084 | { | ||
1085 | char *nodelist = strchr(value, ':'); | ||
1086 | char *flags = strchr(value, '='); | ||
1087 | int err = 1; | ||
1088 | |||
1089 | if (nodelist) { | ||
1090 | /* NUL-terminate policy string */ | ||
1091 | *nodelist++ = '\0'; | ||
1092 | if (nodelist_parse(nodelist, *policy_nodes)) | ||
1093 | goto out; | ||
1094 | if (!nodes_subset(*policy_nodes, node_states[N_HIGH_MEMORY])) | ||
1095 | goto out; | ||
1096 | } | ||
1097 | if (flags) | ||
1098 | *flags++ = '\0'; | ||
1099 | if (!strcmp(value, "default")) { | ||
1100 | *policy = MPOL_DEFAULT; | ||
1101 | /* Don't allow a nodelist */ | ||
1102 | if (!nodelist) | ||
1103 | err = 0; | ||
1104 | } else if (!strcmp(value, "prefer")) { | ||
1105 | *policy = MPOL_PREFERRED; | ||
1106 | /* Insist on a nodelist of one node only */ | ||
1107 | if (nodelist) { | ||
1108 | char *rest = nodelist; | ||
1109 | while (isdigit(*rest)) | ||
1110 | rest++; | ||
1111 | if (!*rest) | ||
1112 | err = 0; | ||
1113 | } | ||
1114 | } else if (!strcmp(value, "bind")) { | ||
1115 | *policy = MPOL_BIND; | ||
1116 | /* Insist on a nodelist */ | ||
1117 | if (nodelist) | ||
1118 | err = 0; | ||
1119 | } else if (!strcmp(value, "interleave")) { | ||
1120 | *policy = MPOL_INTERLEAVE; | ||
1121 | /* | ||
1122 | * Default to online nodes with memory if no nodelist | ||
1123 | */ | ||
1124 | if (!nodelist) | ||
1125 | *policy_nodes = node_states[N_HIGH_MEMORY]; | ||
1126 | err = 0; | ||
1127 | } | ||
1128 | |||
1129 | *mode_flags = 0; | ||
1130 | if (flags) { | ||
1131 | /* | ||
1132 | * Currently, we only support two mutually exclusive | ||
1133 | * mode flags. | ||
1134 | */ | ||
1135 | if (!strcmp(flags, "static")) | ||
1136 | *mode_flags |= MPOL_F_STATIC_NODES; | ||
1137 | else if (!strcmp(flags, "relative")) | ||
1138 | *mode_flags |= MPOL_F_RELATIVE_NODES; | ||
1139 | else | ||
1140 | err = 1; /* unrecognized flag */ | ||
1141 | } | ||
1142 | out: | ||
1143 | /* Restore string for error message */ | ||
1144 | if (nodelist) | ||
1145 | *--nodelist = ':'; | ||
1146 | if (flags) | ||
1147 | *--flags = '='; | ||
1148 | return err; | ||
1149 | } | ||
1150 | |||
1151 | static void shmem_show_mpol(struct seq_file *seq, unsigned short policy, | ||
1152 | unsigned short flags, const nodemask_t policy_nodes) | 1083 | unsigned short flags, const nodemask_t policy_nodes) |
1153 | { | 1084 | { |
1154 | char *policy_string; | 1085 | struct mempolicy temp; |
1155 | 1086 | char buffer[64]; | |
1156 | switch (policy) { | ||
1157 | case MPOL_PREFERRED: | ||
1158 | policy_string = "prefer"; | ||
1159 | break; | ||
1160 | case MPOL_BIND: | ||
1161 | policy_string = "bind"; | ||
1162 | break; | ||
1163 | case MPOL_INTERLEAVE: | ||
1164 | policy_string = "interleave"; | ||
1165 | break; | ||
1166 | default: | ||
1167 | /* MPOL_DEFAULT */ | ||
1168 | return; | ||
1169 | } | ||
1170 | 1087 | ||
1171 | seq_printf(seq, ",mpol=%s", policy_string); | 1088 | if (mode == MPOL_DEFAULT) |
1089 | return; /* show nothing */ | ||
1172 | 1090 | ||
1173 | if (policy != MPOL_INTERLEAVE || | 1091 | temp.mode = mode; |
1174 | !nodes_equal(policy_nodes, node_states[N_HIGH_MEMORY])) { | 1092 | temp.flags = flags; |
1175 | char buffer[64]; | 1093 | temp.v.nodes = policy_nodes; |
1176 | int len; | ||
1177 | 1094 | ||
1178 | len = nodelist_scnprintf(buffer, sizeof(buffer), policy_nodes); | 1095 | mpol_to_str(buffer, sizeof(buffer), &temp); |
1179 | if (len < sizeof(buffer)) | 1096 | |
1180 | seq_printf(seq, ":%s", buffer); | 1097 | seq_printf(seq, ",mpol=%s", buffer); |
1181 | else | ||
1182 | seq_printf(seq, ":?"); | ||
1183 | } | ||
1184 | } | 1098 | } |
1185 | #endif /* CONFIG_TMPFS */ | 1099 | #endif /* CONFIG_TMPFS */ |
1186 | 1100 | ||
@@ -1221,12 +1135,6 @@ static struct page *shmem_alloc_page(gfp_t gfp, | |||
1221 | } | 1135 | } |
1222 | #else /* !CONFIG_NUMA */ | 1136 | #else /* !CONFIG_NUMA */ |
1223 | #ifdef CONFIG_TMPFS | 1137 | #ifdef CONFIG_TMPFS |
1224 | static inline int shmem_parse_mpol(char *value, unsigned short *policy, | ||
1225 | unsigned short *mode_flags, nodemask_t *policy_nodes) | ||
1226 | { | ||
1227 | return 1; | ||
1228 | } | ||
1229 | |||
1230 | static inline void shmem_show_mpol(struct seq_file *seq, unsigned short policy, | 1138 | static inline void shmem_show_mpol(struct seq_file *seq, unsigned short policy, |
1231 | unsigned short flags, const nodemask_t policy_nodes) | 1139 | unsigned short flags, const nodemask_t policy_nodes) |
1232 | { | 1140 | { |
@@ -2231,8 +2139,8 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, | |||
2231 | if (*rest) | 2139 | if (*rest) |
2232 | goto bad_val; | 2140 | goto bad_val; |
2233 | } else if (!strcmp(this_char,"mpol")) { | 2141 | } else if (!strcmp(this_char,"mpol")) { |
2234 | if (shmem_parse_mpol(value, &sbinfo->policy, | 2142 | if (mpol_parse_str(value, &sbinfo->policy, |
2235 | &sbinfo->flags, &sbinfo->policy_nodes)) | 2143 | &sbinfo->flags, &sbinfo->policy_nodes)) |
2236 | goto bad_val; | 2144 | goto bad_val; |
2237 | } else { | 2145 | } else { |
2238 | printk(KERN_ERR "tmpfs: Bad mount option %s\n", | 2146 | printk(KERN_ERR "tmpfs: Bad mount option %s\n", |