aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Rientjes <rientjes@google.com>2013-11-12 18:07:28 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-12 22:09:05 -0500
commit948927ee9e4f35f287e61a79c9f0e85ca2202c7d (patch)
tree611c78ab8b15b7ed1bb1e03791711bfb8f19edf5
parent40c3baa7c66f1352521378ee83509fb8f4c465de (diff)
mm, mempolicy: make mpol_to_str robust and always succeed
mpol_to_str() should not fail. Currently, it either fails because the string buffer is too small or because a string hasn't been defined for a mempolicy mode. If a new mempolicy mode is introduced and no string is defined for it, just warn and return "unknown". If the buffer is too small, just truncate the string and return, the same behavior as snprintf(). This also fixes a bug where there was no NULL-byte termination when doing *p++ = '=' and *p++ ':' and maxlen has been reached. Signed-off-by: David Rientjes <rientjes@google.com> Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Chen Gang <gang.chen@asianux.com> Cc: Rik van Riel <riel@redhat.com> Cc: Dave Jones <davej@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/proc/task_mmu.c14
-rw-r--r--include/linux/mempolicy.h5
-rw-r--r--mm/mempolicy.c52
3 files changed, 24 insertions, 47 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 390bdab01c3c..9f1369fe0afb 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -1387,8 +1387,8 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
1387 struct mm_struct *mm = vma->vm_mm; 1387 struct mm_struct *mm = vma->vm_mm;
1388 struct mm_walk walk = {}; 1388 struct mm_walk walk = {};
1389 struct mempolicy *pol; 1389 struct mempolicy *pol;
1390 int n; 1390 char buffer[64];
1391 char buffer[50]; 1391 int nid;
1392 1392
1393 if (!mm) 1393 if (!mm)
1394 return 0; 1394 return 0;
@@ -1404,10 +1404,8 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
1404 walk.mm = mm; 1404 walk.mm = mm;
1405 1405
1406 pol = get_vma_policy(task, vma, vma->vm_start); 1406 pol = get_vma_policy(task, vma, vma->vm_start);
1407 n = mpol_to_str(buffer, sizeof(buffer), pol); 1407 mpol_to_str(buffer, sizeof(buffer), pol);
1408 mpol_cond_put(pol); 1408 mpol_cond_put(pol);
1409 if (n < 0)
1410 return n;
1411 1409
1412 seq_printf(m, "%08lx %s", vma->vm_start, buffer); 1410 seq_printf(m, "%08lx %s", vma->vm_start, buffer);
1413 1411
@@ -1460,9 +1458,9 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
1460 if (md->writeback) 1458 if (md->writeback)
1461 seq_printf(m, " writeback=%lu", md->writeback); 1459 seq_printf(m, " writeback=%lu", md->writeback);
1462 1460
1463 for_each_node_state(n, N_MEMORY) 1461 for_each_node_state(nid, N_MEMORY)
1464 if (md->node[n]) 1462 if (md->node[nid])
1465 seq_printf(m, " N%d=%lu", n, md->node[n]); 1463 seq_printf(m, " N%d=%lu", nid, md->node[nid]);
1466out: 1464out:
1467 seq_putc(m, '\n'); 1465 seq_putc(m, '\n');
1468 1466
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index ea4d2495c646..9fe426b30a41 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -169,7 +169,7 @@ int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from,
169extern int mpol_parse_str(char *str, struct mempolicy **mpol); 169extern int mpol_parse_str(char *str, struct mempolicy **mpol);
170#endif 170#endif
171 171
172extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol); 172extern void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol);
173 173
174/* Check if a vma is migratable */ 174/* Check if a vma is migratable */
175static inline int vma_migratable(struct vm_area_struct *vma) 175static inline int vma_migratable(struct vm_area_struct *vma)
@@ -307,9 +307,8 @@ static inline int mpol_parse_str(char *str, struct mempolicy **mpol)
307} 307}
308#endif 308#endif
309 309
310static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) 310static inline void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
311{ 311{
312 return 0;
313} 312}
314 313
315static inline int mpol_misplaced(struct page *page, struct vm_area_struct *vma, 314static inline int mpol_misplaced(struct page *page, struct vm_area_struct *vma,
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 71cb253368cb..260b8213a873 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -2914,62 +2914,45 @@ out:
2914 * @maxlen: length of @buffer 2914 * @maxlen: length of @buffer
2915 * @pol: pointer to mempolicy to be formatted 2915 * @pol: pointer to mempolicy to be formatted
2916 * 2916 *
2917 * Convert a mempolicy into a string. 2917 * Convert @pol into a string. If @buffer is too short, truncate the string.
2918 * Returns the number of characters in buffer (if positive) 2918 * Recommend a @maxlen of at least 32 for the longest mode, "interleave", the
2919 * or an error (negative) 2919 * longest flag, "relative", and to display at least a few node ids.
2920 */ 2920 */
2921int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) 2921void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
2922{ 2922{
2923 char *p = buffer; 2923 char *p = buffer;
2924 int l; 2924 nodemask_t nodes = NODE_MASK_NONE;
2925 nodemask_t nodes; 2925 unsigned short mode = MPOL_DEFAULT;
2926 unsigned short mode; 2926 unsigned short flags = 0;
2927 unsigned short flags = pol ? pol->flags : 0;
2928
2929 /*
2930 * Sanity check: room for longest mode, flag and some nodes
2931 */
2932 VM_BUG_ON(maxlen < strlen("interleave") + strlen("relative") + 16);
2933 2927
2934 if (!pol || pol == &default_policy) 2928 if (pol && pol != &default_policy) {
2935 mode = MPOL_DEFAULT;
2936 else
2937 mode = pol->mode; 2929 mode = pol->mode;
2930 flags = pol->flags;
2931 }
2938 2932
2939 switch (mode) { 2933 switch (mode) {
2940 case MPOL_DEFAULT: 2934 case MPOL_DEFAULT:
2941 nodes_clear(nodes);
2942 break; 2935 break;
2943
2944 case MPOL_PREFERRED: 2936 case MPOL_PREFERRED:
2945 nodes_clear(nodes);
2946 if (flags & MPOL_F_LOCAL) 2937 if (flags & MPOL_F_LOCAL)
2947 mode = MPOL_LOCAL; 2938 mode = MPOL_LOCAL;
2948 else 2939 else
2949 node_set(pol->v.preferred_node, nodes); 2940 node_set(pol->v.preferred_node, nodes);
2950 break; 2941 break;
2951
2952 case MPOL_BIND: 2942 case MPOL_BIND:
2953 /* Fall through */
2954 case MPOL_INTERLEAVE: 2943 case MPOL_INTERLEAVE:
2955 nodes = pol->v.nodes; 2944 nodes = pol->v.nodes;
2956 break; 2945 break;
2957
2958 default: 2946 default:
2959 return -EINVAL; 2947 WARN_ON_ONCE(1);
2948 snprintf(p, maxlen, "unknown");
2949 return;
2960 } 2950 }
2961 2951
2962 l = strlen(policy_modes[mode]); 2952 p += snprintf(p, maxlen, policy_modes[mode]);
2963 if (buffer + maxlen < p + l + 1)
2964 return -ENOSPC;
2965
2966 strcpy(p, policy_modes[mode]);
2967 p += l;
2968 2953
2969 if (flags & MPOL_MODE_FLAGS) { 2954 if (flags & MPOL_MODE_FLAGS) {
2970 if (buffer + maxlen < p + 2) 2955 p += snprintf(p, buffer + maxlen - p, "=");
2971 return -ENOSPC;
2972 *p++ = '=';
2973 2956
2974 /* 2957 /*
2975 * Currently, the only defined flags are mutually exclusive 2958 * Currently, the only defined flags are mutually exclusive
@@ -2981,10 +2964,7 @@ int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
2981 } 2964 }
2982 2965
2983 if (!nodes_empty(nodes)) { 2966 if (!nodes_empty(nodes)) {
2984 if (buffer + maxlen < p + 2) 2967 p += snprintf(p, buffer + maxlen - p, ":");
2985 return -ENOSPC;
2986 *p++ = ':';
2987 p += nodelist_scnprintf(p, buffer + maxlen - p, nodes); 2968 p += nodelist_scnprintf(p, buffer + maxlen - p, nodes);
2988 } 2969 }
2989 return p - buffer;
2990} 2970}