Message ID | 20191209174836.11063-3-david@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | mm: fix max_pfn not falling on section boundary | expand |
Hi David, I love your patch! Yet something to improve: [auto build test ERROR on linus/master] [also build test ERROR on linux/master v5.5-rc1 next-20191209] [cannot apply to mmotm/master] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982] url: https://github.com/0day-ci/linux/commits/David-Hildenbrand/mm-fix-max_pfn-not-falling-on-section-boundary/20191210-071011 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 6794862a16ef41f753abd75c03a152836e4c8028 config: um-x86_64_defconfig (attached as .config) compiler: gcc-7 (Debian 7.5.0-1) 7.5.0 reproduce: # save the attached .config to linux build tree make ARCH=um SUBARCH=x86_64 If you fix the issue, kindly add following tag Reported-by: kbuild test robot <lkp@intel.com> All error/warnings (new ones prefixed by >>): In file included from include/asm-generic/bug.h:19:0, from ./arch/um/include/generated/asm/bug.h:1, from include/linux/bug.h:5, from include/linux/mmdebug.h:5, from include/linux/mm.h:9, from include/linux/memblock.h:13, from fs/proc/page.c:2: fs/proc/page.c: In function 'kpagecount_read': >> fs/proc/page.c:32:55: error: 'PAGES_PER_SECTION' undeclared (first use in this function); did you mean 'USEC_PER_SEC'? const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^ include/linux/kernel.h:62:46: note: in definition of macro '__round_mask' #define __round_mask(x, y) ((__typeof__(x))((y)-1)) ^ >> fs/proc/page.c:32:37: note: in expansion of macro 'round_up' const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^~~~~~~~ fs/proc/page.c:32:55: note: each undeclared identifier is reported only once for each function it appears in const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^ include/linux/kernel.h:62:46: note: in definition of macro '__round_mask' #define __round_mask(x, y) ((__typeof__(x))((y)-1)) ^ >> fs/proc/page.c:32:37: note: in expansion of macro 'round_up' const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^~~~~~~~ fs/proc/page.c: In function 'kpageflags_read': fs/proc/page.c:212:55: error: 'PAGES_PER_SECTION' undeclared (first use in this function); did you mean 'USEC_PER_SEC'? const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^ include/linux/kernel.h:62:46: note: in definition of macro '__round_mask' #define __round_mask(x, y) ((__typeof__(x))((y)-1)) ^ fs/proc/page.c:212:37: note: in expansion of macro 'round_up' const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^~~~~~~~ vim +32 fs/proc/page.c > 2 #include <linux/memblock.h> 3 #include <linux/compiler.h> 4 #include <linux/fs.h> 5 #include <linux/init.h> 6 #include <linux/ksm.h> 7 #include <linux/mm.h> 8 #include <linux/mmzone.h> 9 #include <linux/huge_mm.h> 10 #include <linux/proc_fs.h> 11 #include <linux/seq_file.h> 12 #include <linux/hugetlb.h> 13 #include <linux/memcontrol.h> 14 #include <linux/mmu_notifier.h> 15 #include <linux/page_idle.h> 16 #include <linux/kernel-page-flags.h> 17 #include <linux/uaccess.h> 18 #include "internal.h" 19 20 #define KPMSIZE sizeof(u64) 21 #define KPMMASK (KPMSIZE - 1) 22 #define KPMBITS (KPMSIZE * BITS_PER_BYTE) 23 24 /* /proc/kpagecount - an array exposing page counts 25 * 26 * Each entry is a u64 representing the corresponding 27 * physical page count. 28 */ 29 static ssize_t kpagecount_read(struct file *file, char __user *buf, 30 size_t count, loff_t *ppos) 31 { > 32 const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); 33 u64 __user *out = (u64 __user *)buf; 34 struct page *ppage; 35 unsigned long src = *ppos; 36 unsigned long pfn; 37 ssize_t ret = 0; 38 u64 pcount; 39 40 pfn = src / KPMSIZE; 41 if (src & KPMMASK || count & KPMMASK) 42 return -EINVAL; 43 if (src >= max_dump_pfn * KPMSIZE) 44 return 0; 45 count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); 46 47 while (count > 0) { 48 /* 49 * TODO: ZONE_DEVICE support requires to identify 50 * memmaps that were actually initialized. 51 */ 52 ppage = pfn_to_online_page(pfn); 53 54 if (!ppage || PageSlab(ppage) || page_has_type(ppage)) 55 pcount = 0; 56 else 57 pcount = page_mapcount(ppage); 58 59 if (put_user(pcount, out)) { 60 ret = -EFAULT; 61 break; 62 } 63 64 pfn++; 65 out++; 66 count -= KPMSIZE; 67 68 cond_resched(); 69 } 70 71 *ppos += (char __user *)out - buf; 72 if (!ret) 73 ret = (char __user *)out - buf; 74 return ret; 75 } 76 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation
Hi David, I love your patch! Yet something to improve: [auto build test ERROR on linus/master] [also build test ERROR on linux/master v5.5-rc1 next-20191209] [cannot apply to mmotm/master] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system. BTW, we also suggest to use '--base' option to specify the base tree in git format-patch, please see https://stackoverflow.com/a/37406982] url: https://github.com/0day-ci/linux/commits/David-Hildenbrand/mm-fix-max_pfn-not-falling-on-section-boundary/20191210-071011 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 6794862a16ef41f753abd75c03a152836e4c8028 config: i386-defconfig (attached as .config) compiler: gcc-7 (Debian 7.5.0-1) 7.5.0 reproduce: # save the attached .config to linux build tree make ARCH=i386 If you fix the issue, kindly add following tag Reported-by: kbuild test robot <lkp@intel.com> All errors (new ones prefixed by >>): In file included from include/asm-generic/bug.h:19:0, from arch/x86/include/asm/bug.h:83, from include/linux/bug.h:5, from include/linux/mmdebug.h:5, from include/linux/mm.h:9, from include/linux/memblock.h:13, from fs/proc/page.c:2: fs/proc/page.c: In function 'kpagecount_read': >> fs/proc/page.c:32:55: error: 'PAGES_PER_SECTION' undeclared (first use in this function); did you mean 'PAGE_KERNEL_IO'? const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^ include/linux/kernel.h:62:46: note: in definition of macro '__round_mask' #define __round_mask(x, y) ((__typeof__(x))((y)-1)) ^ fs/proc/page.c:32:37: note: in expansion of macro 'round_up' const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^~~~~~~~ fs/proc/page.c:32:55: note: each undeclared identifier is reported only once for each function it appears in const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^ include/linux/kernel.h:62:46: note: in definition of macro '__round_mask' #define __round_mask(x, y) ((__typeof__(x))((y)-1)) ^ fs/proc/page.c:32:37: note: in expansion of macro 'round_up' const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^~~~~~~~ fs/proc/page.c: In function 'kpageflags_read': fs/proc/page.c:212:55: error: 'PAGES_PER_SECTION' undeclared (first use in this function); did you mean 'PAGE_KERNEL_IO'? const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^ include/linux/kernel.h:62:46: note: in definition of macro '__round_mask' #define __round_mask(x, y) ((__typeof__(x))((y)-1)) ^ fs/proc/page.c:212:37: note: in expansion of macro 'round_up' const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); ^~~~~~~~ vim +32 fs/proc/page.c > 2 #include <linux/memblock.h> 3 #include <linux/compiler.h> 4 #include <linux/fs.h> 5 #include <linux/init.h> 6 #include <linux/ksm.h> 7 #include <linux/mm.h> 8 #include <linux/mmzone.h> 9 #include <linux/huge_mm.h> 10 #include <linux/proc_fs.h> 11 #include <linux/seq_file.h> 12 #include <linux/hugetlb.h> 13 #include <linux/memcontrol.h> 14 #include <linux/mmu_notifier.h> 15 #include <linux/page_idle.h> 16 #include <linux/kernel-page-flags.h> 17 #include <linux/uaccess.h> 18 #include "internal.h" 19 20 #define KPMSIZE sizeof(u64) 21 #define KPMMASK (KPMSIZE - 1) 22 #define KPMBITS (KPMSIZE * BITS_PER_BYTE) 23 24 /* /proc/kpagecount - an array exposing page counts 25 * 26 * Each entry is a u64 representing the corresponding 27 * physical page count. 28 */ 29 static ssize_t kpagecount_read(struct file *file, char __user *buf, 30 size_t count, loff_t *ppos) 31 { > 32 const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); 33 u64 __user *out = (u64 __user *)buf; 34 struct page *ppage; 35 unsigned long src = *ppos; 36 unsigned long pfn; 37 ssize_t ret = 0; 38 u64 pcount; 39 40 pfn = src / KPMSIZE; 41 if (src & KPMMASK || count & KPMMASK) 42 return -EINVAL; 43 if (src >= max_dump_pfn * KPMSIZE) 44 return 0; 45 count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); 46 47 while (count > 0) { 48 /* 49 * TODO: ZONE_DEVICE support requires to identify 50 * memmaps that were actually initialized. 51 */ 52 ppage = pfn_to_online_page(pfn); 53 54 if (!ppage || PageSlab(ppage) || page_has_type(ppage)) 55 pcount = 0; 56 else 57 pcount = page_mapcount(ppage); 58 59 if (put_user(pcount, out)) { 60 ret = -EFAULT; 61 break; 62 } 63 64 pfn++; 65 out++; 66 count -= KPMSIZE; 67 68 cond_resched(); 69 } 70 71 *ppos += (char __user *)out - buf; 72 if (!ret) 73 ret = (char __user *)out - buf; 74 return ret; 75 } 76 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org Intel Corporation
On 10.12.19 02:04, kbuild test robot wrote: > Hi David, > > I love your patch! Yet something to improve: > > [auto build test ERROR on linus/master] > [also build test ERROR on linux/master v5.5-rc1 next-20191209] > [cannot apply to mmotm/master] > [if your patch is applied to the wrong git tree, please drop us a note to help > improve the system. BTW, we also suggest to use '--base' option to specify the > base tree in git format-patch, please see https://stackoverflow.com/a/37406982] > > url: https://github.com/0day-ci/linux/commits/David-Hildenbrand/mm-fix-max_pfn-not-falling-on-section-boundary/20191210-071011 > base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 6794862a16ef41f753abd75c03a152836e4c8028 > config: i386-defconfig (attached as .config) > compiler: gcc-7 (Debian 7.5.0-1) 7.5.0 > reproduce: > # save the attached .config to linux build tree > make ARCH=i386 > > If you fix the issue, kindly add following tag > Reported-by: kbuild test robot <lkp@intel.com> > > All errors (new ones prefixed by >>): > > In file included from include/asm-generic/bug.h:19:0, > from arch/x86/include/asm/bug.h:83, > from include/linux/bug.h:5, > from include/linux/mmdebug.h:5, > from include/linux/mm.h:9, > from include/linux/memblock.h:13, > from fs/proc/page.c:2: > fs/proc/page.c: In function 'kpagecount_read': >>> fs/proc/page.c:32:55: error: 'PAGES_PER_SECTION' undeclared (first use in this function); did you mean 'PAGE_KERNEL_IO'? > const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); > ^ > include/linux/kernel.h:62:46: note: in definition of macro '__round_mask' > #define __round_mask(x, y) ((__typeof__(x))((y)-1)) > ^ > fs/proc/page.c:32:37: note: in expansion of macro 'round_up' > const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); > ^~~~~~~~ > fs/proc/page.c:32:55: note: each undeclared identifier is reported only once for each function it appears in > const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); > ^ > include/linux/kernel.h:62:46: note: in definition of macro '__round_mask' > #define __round_mask(x, y) ((__typeof__(x))((y)-1)) > ^ > fs/proc/page.c:32:37: note: in expansion of macro 'round_up' > const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); > ^~~~~~~~ > fs/proc/page.c: In function 'kpageflags_read': > fs/proc/page.c:212:55: error: 'PAGES_PER_SECTION' undeclared (first use in this function); did you mean 'PAGE_KERNEL_IO'? > const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); > ^ > include/linux/kernel.h:62:46: note: in definition of macro '__round_mask' > #define __round_mask(x, y) ((__typeof__(x))((y)-1)) > ^ > fs/proc/page.c:212:37: note: in expansion of macro 'round_up' > const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); > ^~~~~~~~ > So PAGES_PER_SECTION only applies to CONFIG_SPARSEMEM. Some local function that messes with that should do the trick. Allows us to add a comment as well :) diff --git a/fs/proc/page.c b/fs/proc/page.c index e40dbfe1168e..2984df28ccea 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -21,6 +21,21 @@ #define KPMMASK (KPMSIZE - 1) #define KPMBITS (KPMSIZE * BITS_PER_BYTE) +static inline unsigned long get_max_dump_pfn(void) +{ +#ifdef CONFIG_SPARSEMEM + /* + * The memmap of early sections is completely populated and marked + * online even if max_pfn does not fall on a section boundary - + * pfn_to_online_page() will succeed on all pages. Allow inspecting + * these memmaps. + */ + return round_up(max_pfn, PAGES_PER_SECTION); +#else + return max_pfn; +#endif +} + /* /proc/kpagecount - an array exposing page counts * * Each entry is a u64 representing the corresponding @@ -29,6 +44,7 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + const unsigned long max_dump_pfn = get_max_dump_pfn(); u64 __user *out = (u64 __user *)buf; struct page *ppage; unsigned long src = *ppos; @@ -37,9 +53,11 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf, u64 pcount; pfn = src / KPMSIZE; - count = min_t(size_t, count, (max_pfn * KPMSIZE) - src); if (src & KPMMASK || count & KPMMASK) return -EINVAL; + if (src >= max_dump_pfn * KPMSIZE) + return 0; + count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); while (count > 0) { /* @@ -208,6 +226,7 @@ u64 stable_page_flags(struct page *page) static ssize_t kpageflags_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + const unsigned long max_dump_pfn = get_max_dump_pfn(); u64 __user *out = (u64 __user *)buf; struct page *ppage; unsigned long src = *ppos; @@ -215,9 +234,11 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf, ssize_t ret = 0; pfn = src / KPMSIZE; - count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); if (src & KPMMASK || count & KPMMASK) return -EINVAL; + if (src >= max_dump_pfn * KPMSIZE) + return 0; + count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); while (count > 0) { /* @@ -253,6 +274,7 @@ static const struct file_operations proc_kpageflags_operations = { static ssize_t kpagecgroup_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + const unsigned long max_dump_pfn = get_max_dump_pfn(); u64 __user *out = (u64 __user *)buf; struct page *ppage; unsigned long src = *ppos; @@ -261,9 +283,11 @@ static ssize_t kpagecgroup_read(struct file *file, char __user *buf, u64 ino; pfn = src / KPMSIZE; - count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); if (src & KPMMASK || count & KPMMASK) return -EINVAL; + if (src >= max_dump_pfn * KPMSIZE) + return 0; + count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); while (count > 0) { /*
diff --git a/fs/proc/page.c b/fs/proc/page.c index e40dbfe1168e..da01d3d9999a 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -29,6 +29,7 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); u64 __user *out = (u64 __user *)buf; struct page *ppage; unsigned long src = *ppos; @@ -37,9 +38,11 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf, u64 pcount; pfn = src / KPMSIZE; - count = min_t(size_t, count, (max_pfn * KPMSIZE) - src); if (src & KPMMASK || count & KPMMASK) return -EINVAL; + if (src >= max_dump_pfn * KPMSIZE) + return 0; + count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); while (count > 0) { /* @@ -208,6 +211,7 @@ u64 stable_page_flags(struct page *page) static ssize_t kpageflags_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); u64 __user *out = (u64 __user *)buf; struct page *ppage; unsigned long src = *ppos; @@ -215,9 +219,11 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf, ssize_t ret = 0; pfn = src / KPMSIZE; - count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); if (src & KPMMASK || count & KPMMASK) return -EINVAL; + if (src >= max_dump_pfn * KPMSIZE) + return 0; + count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); while (count > 0) { /* @@ -253,6 +259,7 @@ static const struct file_operations proc_kpageflags_operations = { static ssize_t kpagecgroup_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + const unsigned long max_dump_pfn = round_up(max_pfn, PAGES_PER_SECTION); u64 __user *out = (u64 __user *)buf; struct page *ppage; unsigned long src = *ppos; @@ -261,9 +268,11 @@ static ssize_t kpagecgroup_read(struct file *file, char __user *buf, u64 ino; pfn = src / KPMSIZE; - count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); if (src & KPMMASK || count & KPMMASK) return -EINVAL; + if (src >= max_dump_pfn * KPMSIZE) + return 0; + count = min_t(unsigned long, count, (max_dump_pfn * KPMSIZE) - src); while (count > 0) { /*
If max_pfn does not fall onto a section boundary, it is possible to inspect PFNs up to max_pfn, and PFNs above max_pfn, however, max_pfn itself can't be inspected. We can have a valid (and online) memmap at and above max_pfn if max_pfn is not aligned to a section boundary. The whole early section has a memmap and is marked online. Being able to inspect the state of these PFNs is valuable for debugging, especially because max_pfn can change on memory hotplug and expose these memmaps. Also, querying page flags via "./page-types -r -a 0x144001," (tools/vm/page-types.c) inside a x86-64 guest with 4160MB under QEMU results in an (almost) endless loop in user space, because the end is not detected properly when starting after max_pfn. Instead, let's allow to inspect all pages in the highest section and return 0 directly if we try to access pages above that section. While at it, check the count before adjusting it, to avoid masking user errors. Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Oscar Salvador <osalvador@suse.de> Cc: Michal Hocko <mhocko@kernel.org> Cc: Stephen Rothwell <sfr@canb.auug.org.au> Cc: linux-fsdevel@vger.kernel.org Signed-off-by: David Hildenbrand <david@redhat.com> --- fs/proc/page.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)