| From 12cf516b74e67e2140d943a4ce61390d0a917dde Mon Sep 17 00:00:00 2001 |
| From: David Rientjes <rientjes@google.com> |
| Date: Thu, 30 Jan 2020 22:14:48 -0800 |
| Subject: [PATCH] mm, thp: fix defrag setting if newline is not used |
| |
| commit f42f25526502d851d0e3ca1e46297da8aafce8a7 upstream. |
| |
| If thp defrag setting "defer" is used and a newline is *not* used when |
| writing to the sysfs file, this is interpreted as the "defer+madvise" |
| option. |
| |
| This is because we do prefix matching and if five characters are written |
| without a newline, the current code ends up comparing to the first five |
| bytes of the "defer+madvise" option and using that instead. |
| |
| Use the more appropriate sysfs_streq() that handles the trailing newline |
| for us. Since this doubles as a nice cleanup, do it in enabled_store() |
| as well. |
| |
| The current implementation relies on prefix matching: the number of |
| bytes compared is either the number of bytes written or the length of |
| the option being compared. With a newline, "defer\n" does not match |
| "defer+"madvise"; without a newline, however, "defer" is considered to |
| match "defer+madvise" (prefix matching is only comparing the first five |
| bytes). End result is that writing "defer" is broken unless it has an |
| additional trailing character. |
| |
| This means that writing "madv" in the past would match and set |
| "madvise". With strict checking, that no longer is the case but it is |
| unlikely anybody is currently doing this. |
| |
| Link: http://lkml.kernel.org/r/alpine.DEB.2.21.2001171411020.56385@chino.kir.corp.google.com |
| Fixes: 21440d7eb904 ("mm, thp: add new defer+madvise defrag option") |
| Signed-off-by: David Rientjes <rientjes@google.com> |
| Suggested-by: Andrew Morton <akpm@linux-foundation.org> |
| Acked-by: Vlastimil Babka <vbabka@suse.cz> |
| Cc: Mel Gorman <mgorman@techsingularity.net> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/mm/huge_memory.c b/mm/huge_memory.c |
| index aae6027dc82d..6597095d54c0 100644 |
| --- a/mm/huge_memory.c |
| +++ b/mm/huge_memory.c |
| @@ -172,16 +172,13 @@ static ssize_t enabled_store(struct kobject *kobj, |
| { |
| ssize_t ret = count; |
| |
| - if (!memcmp("always", buf, |
| - min(sizeof("always")-1, count))) { |
| + if (sysfs_streq(buf, "always")) { |
| clear_bit(TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG, &transparent_hugepage_flags); |
| set_bit(TRANSPARENT_HUGEPAGE_FLAG, &transparent_hugepage_flags); |
| - } else if (!memcmp("madvise", buf, |
| - min(sizeof("madvise")-1, count))) { |
| + } else if (sysfs_streq(buf, "madvise")) { |
| clear_bit(TRANSPARENT_HUGEPAGE_FLAG, &transparent_hugepage_flags); |
| set_bit(TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG, &transparent_hugepage_flags); |
| - } else if (!memcmp("never", buf, |
| - min(sizeof("never")-1, count))) { |
| + } else if (sysfs_streq(buf, "never")) { |
| clear_bit(TRANSPARENT_HUGEPAGE_FLAG, &transparent_hugepage_flags); |
| clear_bit(TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG, &transparent_hugepage_flags); |
| } else |
| @@ -245,32 +242,27 @@ static ssize_t defrag_store(struct kobject *kobj, |
| struct kobj_attribute *attr, |
| const char *buf, size_t count) |
| { |
| - if (!memcmp("always", buf, |
| - min(sizeof("always")-1, count))) { |
| + if (sysfs_streq(buf, "always")) { |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags); |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, &transparent_hugepage_flags); |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, &transparent_hugepage_flags); |
| set_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags); |
| - } else if (!memcmp("defer+madvise", buf, |
| - min(sizeof("defer+madvise")-1, count))) { |
| + } else if (sysfs_streq(buf, "defer+madvise")) { |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags); |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags); |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, &transparent_hugepage_flags); |
| set_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, &transparent_hugepage_flags); |
| - } else if (!memcmp("defer", buf, |
| - min(sizeof("defer")-1, count))) { |
| + } else if (sysfs_streq(buf, "defer")) { |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags); |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, &transparent_hugepage_flags); |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, &transparent_hugepage_flags); |
| set_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags); |
| - } else if (!memcmp("madvise", buf, |
| - min(sizeof("madvise")-1, count))) { |
| + } else if (sysfs_streq(buf, "madvise")) { |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags); |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags); |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, &transparent_hugepage_flags); |
| set_bit(TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, &transparent_hugepage_flags); |
| - } else if (!memcmp("never", buf, |
| - min(sizeof("never")-1, count))) { |
| + } else if (sysfs_streq(buf, "never")) { |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, &transparent_hugepage_flags); |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, &transparent_hugepage_flags); |
| clear_bit(TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_OR_MADV_FLAG, &transparent_hugepage_flags); |
| -- |
| 2.7.4 |
| |