Commit 948927ee9e4f35f287e61a79c9f0e85ca2202c7d

Authored by David Rientjes
Committed by Linus Torvalds
1 parent 40c3baa7c6

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>

Showing 3 changed files with 24 additions and 47 deletions Side-by-side Diff

... ... @@ -1387,8 +1387,8 @@
1387 1387 struct mm_struct *mm = vma->vm_mm;
1388 1388 struct mm_walk walk = {};
1389 1389 struct mempolicy *pol;
1390   - int n;
1391   - char buffer[50];
  1390 + char buffer[64];
  1391 + int nid;
1392 1392  
1393 1393 if (!mm)
1394 1394 return 0;
1395 1395  
... ... @@ -1404,10 +1404,8 @@
1404 1404 walk.mm = mm;
1405 1405  
1406 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 1408 mpol_cond_put(pol);
1409   - if (n < 0)
1410   - return n;
1411 1409  
1412 1410 seq_printf(m, "%08lx %s", vma->vm_start, buffer);
1413 1411  
... ... @@ -1460,9 +1458,9 @@
1460 1458 if (md->writeback)
1461 1459 seq_printf(m, " writeback=%lu", md->writeback);
1462 1460  
1463   - for_each_node_state(n, N_MEMORY)
1464   - if (md->node[n])
1465   - seq_printf(m, " N%d=%lu", n, md->node[n]);
  1461 + for_each_node_state(nid, N_MEMORY)
  1462 + if (md->node[nid])
  1463 + seq_printf(m, " N%d=%lu", nid, md->node[nid]);
1466 1464 out:
1467 1465 seq_putc(m, '\n');
1468 1466  
include/linux/mempolicy.h
... ... @@ -169,7 +169,7 @@
169 169 extern int mpol_parse_str(char *str, struct mempolicy **mpol);
170 170 #endif
171 171  
172   -extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol);
  172 +extern void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol);
173 173  
174 174 /* Check if a vma is migratable */
175 175 static inline int vma_migratable(struct vm_area_struct *vma)
176 176  
... ... @@ -307,9 +307,8 @@
307 307 }
308 308 #endif
309 309  
310   -static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
  310 +static inline void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
311 311 {
312   - return 0;
313 312 }
314 313  
315 314 static inline int mpol_misplaced(struct page *page, struct vm_area_struct *vma,
... ... @@ -2914,62 +2914,45 @@
2914 2914 * @maxlen: length of @buffer
2915 2915 * @pol: pointer to mempolicy to be formatted
2916 2916 *
2917   - * Convert a mempolicy into a string.
2918   - * Returns the number of characters in buffer (if positive)
2919   - * or an error (negative)
  2917 + * Convert @pol into a string. If @buffer is too short, truncate the string.
  2918 + * Recommend a @maxlen of at least 32 for the longest mode, "interleave", the
  2919 + * longest flag, "relative", and to display at least a few node ids.
2920 2920 */
2921   -int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
  2921 +void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
2922 2922 {
2923 2923 char *p = buffer;
2924   - int l;
2925   - nodemask_t nodes;
2926   - unsigned short mode;
2927   - unsigned short flags = pol ? pol->flags : 0;
  2924 + nodemask_t nodes = NODE_MASK_NONE;
  2925 + unsigned short mode = MPOL_DEFAULT;
  2926 + unsigned short flags = 0;
2928 2927  
2929   - /*
2930   - * Sanity check: room for longest mode, flag and some nodes
2931   - */
2932   - VM_BUG_ON(maxlen < strlen("interleave") + strlen("relative") + 16);
2933   -
2934   - if (!pol || pol == &default_policy)
2935   - mode = MPOL_DEFAULT;
2936   - else
  2928 + if (pol && pol != &default_policy) {
2937 2929 mode = pol->mode;
  2930 + flags = pol->flags;
  2931 + }
2938 2932  
2939 2933 switch (mode) {
2940 2934 case MPOL_DEFAULT:
2941   - nodes_clear(nodes);
2942 2935 break;
2943   -
2944 2936 case MPOL_PREFERRED:
2945   - nodes_clear(nodes);
2946 2937 if (flags & MPOL_F_LOCAL)
2947 2938 mode = MPOL_LOCAL;
2948 2939 else
2949 2940 node_set(pol->v.preferred_node, nodes);
2950 2941 break;
2951   -
2952 2942 case MPOL_BIND:
2953   - /* Fall through */
2954 2943 case MPOL_INTERLEAVE:
2955 2944 nodes = pol->v.nodes;
2956 2945 break;
2957   -
2958 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]);
2963   - if (buffer + maxlen < p + l + 1)
2964   - return -ENOSPC;
  2952 + p += snprintf(p, maxlen, policy_modes[mode]);
2965 2953  
2966   - strcpy(p, policy_modes[mode]);
2967   - p += l;
2968   -
2969 2954 if (flags & MPOL_MODE_FLAGS) {
2970   - if (buffer + maxlen < p + 2)
2971   - return -ENOSPC;
2972   - *p++ = '=';
  2955 + p += snprintf(p, buffer + maxlen - p, "=");
2973 2956  
2974 2957 /*
2975 2958 * Currently, the only defined flags are mutually exclusive
2976 2959  
... ... @@ -2981,11 +2964,8 @@
2981 2964 }
2982 2965  
2983 2966 if (!nodes_empty(nodes)) {
2984   - if (buffer + maxlen < p + 2)
2985   - return -ENOSPC;
2986   - *p++ = ':';
  2967 + p += snprintf(p, buffer + maxlen - p, ":");
2987 2968 p += nodelist_scnprintf(p, buffer + maxlen - p, nodes);
2988 2969 }
2989   - return p - buffer;
2990 2970 }