Message ID | 20240321142448.1645400-8-willy@infradead.org (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | Various significant MM patches | expand |
On 2024/3/21 22:24, Matthew Wilcox (Oracle) wrote: > Reclaim the Slab page flag by using a spare bit in PageType. We are > perennially short of page flags for various purposes, and now that > the original SLAB allocator has been retired, SLUB does not use the > mapcount/page_type field. This lets us remove a number of special cases > for ignoring mapcount on Slab pages. > > Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> > --- > include/linux/page-flags.h | 21 +++++++++++++++++---- > include/trace/events/mmflags.h | 2 +- > mm/memory-failure.c | 9 --------- > mm/slab.h | 2 +- > 4 files changed, 19 insertions(+), 15 deletions(-) > > diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h > index 94eb8a11a321..73e0b17c7728 100644 > --- a/include/linux/page-flags.h > +++ b/include/linux/page-flags.h > @@ -109,7 +109,6 @@ enum pageflags { > PG_active, > PG_workingset, > PG_error, > - PG_slab, > PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/ > PG_arch_1, > PG_reserved, > @@ -524,7 +523,6 @@ PAGEFLAG(Active, active, PF_HEAD) __CLEARPAGEFLAG(Active, active, PF_HEAD) > TESTCLEARFLAG(Active, active, PF_HEAD) > PAGEFLAG(Workingset, workingset, PF_HEAD) > TESTCLEARFLAG(Workingset, workingset, PF_HEAD) > -__PAGEFLAG(Slab, slab, PF_NO_TAIL) > PAGEFLAG(Checked, checked, PF_NO_COMPOUND) /* Used by some filesystems */ > > /* Xen */ > @@ -931,7 +929,7 @@ PAGEFLAG_FALSE(HasHWPoisoned, has_hwpoisoned) > #endif > > /* > - * For pages that are never mapped to userspace (and aren't PageSlab), > + * For pages that are never mapped to userspace, > * page_type may be used. Because it is initialised to -1, we invert the > * sense of the bit, so __SetPageFoo *clears* the bit used for PageFoo, and > * __ClearPageFoo *sets* the bit used for PageFoo. We reserve a few high and > @@ -947,6 +945,7 @@ PAGEFLAG_FALSE(HasHWPoisoned, has_hwpoisoned) > #define PG_table 0x00000200 > #define PG_guard 0x00000400 > #define PG_hugetlb 0x00000800 > +#define PG_slab 0x00001000 > > #define PageType(page, flag) \ > ((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE) > @@ -1041,6 +1040,20 @@ PAGE_TYPE_OPS(Table, table, pgtable) > */ > PAGE_TYPE_OPS(Guard, guard, guard) > > +FOLIO_TYPE_OPS(slab, slab) > + > +/** > + * PageSlab - Determine if the page belongs to the slab allocator > + * @page: The page to test. > + * > + * Context: Any context. > + * Return: True for slab pages, false for any other kind of page. > + */ > +static inline bool PageSlab(const struct page *page) > +{ > + return folio_test_slab(page_folio(page)); > +} > + > #ifdef CONFIG_HUGETLB_PAGE > FOLIO_TYPE_OPS(hugetlb, hugetlb) > #else > @@ -1121,7 +1134,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page) > (1UL << PG_lru | 1UL << PG_locked | \ > 1UL << PG_private | 1UL << PG_private_2 | \ > 1UL << PG_writeback | 1UL << PG_reserved | \ > - 1UL << PG_slab | 1UL << PG_active | \ > + 1UL << PG_active | \ > 1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK) > > /* > diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h > index d55e53ac91bd..e46d6e82765e 100644 > --- a/include/trace/events/mmflags.h > +++ b/include/trace/events/mmflags.h > @@ -107,7 +107,6 @@ > DEF_PAGEFLAG_NAME(lru), \ > DEF_PAGEFLAG_NAME(active), \ > DEF_PAGEFLAG_NAME(workingset), \ > - DEF_PAGEFLAG_NAME(slab), \ > DEF_PAGEFLAG_NAME(owner_priv_1), \ > DEF_PAGEFLAG_NAME(arch_1), \ > DEF_PAGEFLAG_NAME(reserved), \ > @@ -135,6 +134,7 @@ IF_HAVE_PG_ARCH_X(arch_3) > #define DEF_PAGETYPE_NAME(_name) { PG_##_name, __stringify(_name) } > > #define __def_pagetype_names \ > + DEF_PAGETYPE_NAME(slab), \ > DEF_PAGETYPE_NAME(hugetlb), \ > DEF_PAGETYPE_NAME(offline), \ > DEF_PAGETYPE_NAME(guard), \ > diff --git a/mm/memory-failure.c b/mm/memory-failure.c > index 9349948f1abf..1cb41ba7870c 100644 > --- a/mm/memory-failure.c > +++ b/mm/memory-failure.c > @@ -1239,7 +1239,6 @@ static int me_huge_page(struct page_state *ps, struct page *p) > #define mlock (1UL << PG_mlocked) > #define lru (1UL << PG_lru) > #define head (1UL << PG_head) > -#define slab (1UL << PG_slab) > #define reserved (1UL << PG_reserved) > > static struct page_state error_states[] = { > @@ -1249,13 +1248,6 @@ static struct page_state error_states[] = { > * PG_buddy pages only make a small fraction of all free pages. > */ > > - /* > - * Could in theory check if slab page is free or if we can drop > - * currently unused objects without touching them. But just > - * treat it as standard kernel for now. > - */ > - { slab, slab, MF_MSG_SLAB, me_kernel }, Will it be better to leave the above slab case here to catch possible unhandled obscure races with slab? Though it looks like slab page shouldn't reach here. Thanks.
On 3/22/24 10:20, Miaohe Lin wrote: > On 2024/3/21 22:24, Matthew Wilcox (Oracle) wrote: >> Reclaim the Slab page flag by using a spare bit in PageType. We are >> perennially short of page flags for various purposes, and now that >> the original SLAB allocator has been retired, SLUB does not use the >> mapcount/page_type field. This lets us remove a number of special cases >> for ignoring mapcount on Slab pages. >> >> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Acked-by: Vlastimil Babka <vbabka@suse.cz> >> --- >> include/linux/page-flags.h | 21 +++++++++++++++++---- >> include/trace/events/mmflags.h | 2 +- >> mm/memory-failure.c | 9 --------- >> mm/slab.h | 2 +- >> 4 files changed, 19 insertions(+), 15 deletions(-) >> >> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h >> index 94eb8a11a321..73e0b17c7728 100644 >> --- a/include/linux/page-flags.h >> +++ b/include/linux/page-flags.h >> @@ -109,7 +109,6 @@ enum pageflags { >> PG_active, >> PG_workingset, >> PG_error, >> - PG_slab, >> PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/ >> PG_arch_1, >> PG_reserved, >> @@ -524,7 +523,6 @@ PAGEFLAG(Active, active, PF_HEAD) __CLEARPAGEFLAG(Active, active, PF_HEAD) >> TESTCLEARFLAG(Active, active, PF_HEAD) >> PAGEFLAG(Workingset, workingset, PF_HEAD) >> TESTCLEARFLAG(Workingset, workingset, PF_HEAD) >> -__PAGEFLAG(Slab, slab, PF_NO_TAIL) >> PAGEFLAG(Checked, checked, PF_NO_COMPOUND) /* Used by some filesystems */ >> >> /* Xen */ >> @@ -931,7 +929,7 @@ PAGEFLAG_FALSE(HasHWPoisoned, has_hwpoisoned) >> #endif >> >> /* >> - * For pages that are never mapped to userspace (and aren't PageSlab), >> + * For pages that are never mapped to userspace, >> * page_type may be used. Because it is initialised to -1, we invert the >> * sense of the bit, so __SetPageFoo *clears* the bit used for PageFoo, and >> * __ClearPageFoo *sets* the bit used for PageFoo. We reserve a few high and >> @@ -947,6 +945,7 @@ PAGEFLAG_FALSE(HasHWPoisoned, has_hwpoisoned) >> #define PG_table 0x00000200 >> #define PG_guard 0x00000400 >> #define PG_hugetlb 0x00000800 >> +#define PG_slab 0x00001000 >> >> #define PageType(page, flag) \ >> ((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE) >> @@ -1041,6 +1040,20 @@ PAGE_TYPE_OPS(Table, table, pgtable) >> */ >> PAGE_TYPE_OPS(Guard, guard, guard) >> >> +FOLIO_TYPE_OPS(slab, slab) >> + >> +/** >> + * PageSlab - Determine if the page belongs to the slab allocator >> + * @page: The page to test. >> + * >> + * Context: Any context. >> + * Return: True for slab pages, false for any other kind of page. >> + */ >> +static inline bool PageSlab(const struct page *page) >> +{ >> + return folio_test_slab(page_folio(page)); >> +} >> + >> #ifdef CONFIG_HUGETLB_PAGE >> FOLIO_TYPE_OPS(hugetlb, hugetlb) >> #else >> @@ -1121,7 +1134,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page) >> (1UL << PG_lru | 1UL << PG_locked | \ >> 1UL << PG_private | 1UL << PG_private_2 | \ >> 1UL << PG_writeback | 1UL << PG_reserved | \ >> - 1UL << PG_slab | 1UL << PG_active | \ >> + 1UL << PG_active | \ >> 1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK) >> >> /* >> diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h >> index d55e53ac91bd..e46d6e82765e 100644 >> --- a/include/trace/events/mmflags.h >> +++ b/include/trace/events/mmflags.h >> @@ -107,7 +107,6 @@ >> DEF_PAGEFLAG_NAME(lru), \ >> DEF_PAGEFLAG_NAME(active), \ >> DEF_PAGEFLAG_NAME(workingset), \ >> - DEF_PAGEFLAG_NAME(slab), \ >> DEF_PAGEFLAG_NAME(owner_priv_1), \ >> DEF_PAGEFLAG_NAME(arch_1), \ >> DEF_PAGEFLAG_NAME(reserved), \ >> @@ -135,6 +134,7 @@ IF_HAVE_PG_ARCH_X(arch_3) >> #define DEF_PAGETYPE_NAME(_name) { PG_##_name, __stringify(_name) } >> >> #define __def_pagetype_names \ >> + DEF_PAGETYPE_NAME(slab), \ >> DEF_PAGETYPE_NAME(hugetlb), \ >> DEF_PAGETYPE_NAME(offline), \ >> DEF_PAGETYPE_NAME(guard), \ >> diff --git a/mm/memory-failure.c b/mm/memory-failure.c >> index 9349948f1abf..1cb41ba7870c 100644 >> --- a/mm/memory-failure.c >> +++ b/mm/memory-failure.c >> @@ -1239,7 +1239,6 @@ static int me_huge_page(struct page_state *ps, struct page *p) >> #define mlock (1UL << PG_mlocked) >> #define lru (1UL << PG_lru) >> #define head (1UL << PG_head) >> -#define slab (1UL << PG_slab) >> #define reserved (1UL << PG_reserved) >> >> static struct page_state error_states[] = { >> @@ -1249,13 +1248,6 @@ static struct page_state error_states[] = { >> * PG_buddy pages only make a small fraction of all free pages. >> */ >> >> - /* >> - * Could in theory check if slab page is free or if we can drop >> - * currently unused objects without touching them. But just >> - * treat it as standard kernel for now. >> - */ >> - { slab, slab, MF_MSG_SLAB, me_kernel }, > > Will it be better to leave the above slab case here to catch possible unhandled obscure races with > slab? Though it looks like slab page shouldn't reach here. The code would need to handle page types as it's no longer a page flag. I guess that's your decision? If it's not necessary, then I guess MF_MSG_SLAB itself could be also removed with a buch of more code referencing it. > Thanks. >
On 21.03.24 15:24, Matthew Wilcox (Oracle) wrote: > Reclaim the Slab page flag by using a spare bit in PageType. We are > perennially short of page flags for various purposes, and now that > the original SLAB allocator has been retired, SLUB does not use the > mapcount/page_type field. This lets us remove a number of special cases > for ignoring mapcount on Slab pages. > > Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> > --- Acked-by: David Hildenbrand <david@redhat.com>
On Thu, Mar 21, 2024 at 02:24:45PM +0000, Matthew Wilcox (Oracle) wrote: > Reclaim the Slab page flag by using a spare bit in PageType. We are > perennially short of page flags for various purposes, and now that > the original SLAB allocator has been retired, SLUB does not use the > mapcount/page_type field. This lets us remove a number of special cases > for ignoring mapcount on Slab pages. Update vmcoreinfo: diff --git a/kernel/vmcore_info.c b/kernel/vmcore_info.c index 23c125c2e243..1d5eadd9dd61 100644 --- a/kernel/vmcore_info.c +++ b/kernel/vmcore_info.c @@ -198,7 +198,8 @@ static int __init crash_save_vmcoreinfo_init(void) VMCOREINFO_NUMBER(PG_private); VMCOREINFO_NUMBER(PG_swapcache); VMCOREINFO_NUMBER(PG_swapbacked); - VMCOREINFO_NUMBER(PG_slab); +#define PAGE_SLAB_MAPCOUNT_VALUE (~PG_slab) + VMCOREINFO_NUMBER(PAGE_SLAB_MAPCOUNT_VALUE); #ifdef CONFIG_MEMORY_FAILURE VMCOREINFO_NUMBER(PG_hwpoison); #endif
Hello, kernel test robot noticed "UBSAN:shift-out-of-bounds_in_fs/proc/page.c" on: commit: 30e5296811312a13938b83956a55839ac1e3aa40 ("[PATCH 7/9] mm: Free up PG_slab") url: https://github.com/intel-lab-lkp/linux/commits/Matthew-Wilcox-Oracle/mm-Always-initialise-folio-_deferred_list/20240321-222800 base: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git 23956900041d968f9ad0f30db6dede4daccd7aa9 patch link: https://lore.kernel.org/all/20240321142448.1645400-8-willy@infradead.org/ patch subject: [PATCH 7/9] mm: Free up PG_slab in testcase: ltp version: ltp-x86_64-14c1f76-1_20240323 with following parameters: disk: 1HDD fs: ext4 test: fs-00 compiler: gcc-12 test machine: 4 threads 1 sockets Intel(R) Core(TM) i3-3220 CPU @ 3.30GHz (Ivy Bridge) with 8G memory (please refer to attached dmesg/kmsg for entire log/backtrace) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <oliver.sang@intel.com> | Closes: https://lore.kernel.org/oe-lkp/202403312344.c0d273ab-oliver.sang@intel.com kern :warn : [ 528.627387] ------------[ cut here ]------------ kern :err : [ 528.627589] UBSAN: shift-out-of-bounds in fs/proc/page.c:107:18 kern :err : [ 528.627884] shift exponent 4096 is too large for 64-bit type 'long long unsigned int' kern :warn : [ 528.628200] CPU: 0 PID: 4703 Comm: proc01 Tainted: G S 6.8.0-11774-g30e529681131 #1 kern :warn : [ 528.628446] Hardware name: Hewlett-Packard p6-1451cx/2ADA, BIOS 8.15 02/05/2013 kern :warn : [ 528.628659] Call Trace: kern :warn : [ 528.628814] <TASK> kern :warn : [ 528.628960] dump_stack_lvl (lib/dump_stack.c:117 (discriminator 1)) kern :warn : [ 528.629134] __ubsan_handle_shift_out_of_bounds (lib/ubsan.c:218 lib/ubsan.c:454) kern :warn : [ 528.629360] stable_page_flags.part.0.cold (include/linux/page-flags.h:284 fs/proc/page.c:184) kern :warn : [ 528.629506] kpageflags_read (fs/proc/page.c:238 fs/proc/page.c:250) kern :warn : [ 528.629623] vfs_read (fs/read_write.c:474) kern :warn : [ 528.629737] ? do_sys_openat2 (fs/open.c:1415) kern :warn : [ 528.629898] ? kmem_cache_free (mm/slub.c:4280 mm/slub.c:4344) kern :warn : [ 528.630063] ? __pfx_vfs_read (fs/read_write.c:457) kern :warn : [ 528.630225] ? do_sys_openat2 (fs/open.c:1415) kern :warn : [ 528.630388] ? __pfx_do_sys_openat2 (fs/open.c:1392) kern :warn : [ 528.630552] ? __do_sys_newfstatat (fs/stat.c:464) kern :warn : [ 528.630717] ? __fget_light (include/linux/atomic/atomic-arch-fallback.h:479 include/linux/atomic/atomic-instrumented.h:50 fs/file.c:1145) kern :warn : [ 528.630888] ksys_read (fs/read_write.c:619) kern :warn : [ 528.631051] ? __pfx_ksys_read (fs/read_write.c:609) kern :warn : [ 528.631216] ? kmem_cache_free (mm/slub.c:4280 mm/slub.c:4344) kern :warn : [ 528.631415] do_syscall_64 (arch/x86/entry/common.c:52 arch/x86/entry/common.c:83) kern :warn : [ 528.631555] entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:129) kern :warn : [ 528.631756] RIP: 0033:0x7f90bf2ba19d kern :warn : [ 528.631913] Code: 31 c0 e9 c6 fe ff ff 50 48 8d 3d 66 54 0a 00 e8 49 ff 01 00 66 0f 1f 84 00 00 00 00 00 80 3d 41 24 0e 00 00 74 17 31 c0 0f 05 <48> 3d 00 f0 ff ff 77 5b c3 66 2e 0f 1f 84 00 00 00 00 00 48 83 ec All code ======== 0: 31 c0 xor %eax,%eax 2: e9 c6 fe ff ff jmpq 0xfffffffffffffecd 7: 50 push %rax 8: 48 8d 3d 66 54 0a 00 lea 0xa5466(%rip),%rdi # 0xa5475 f: e8 49 ff 01 00 callq 0x1ff5d 14: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 1b: 00 00 1d: 80 3d 41 24 0e 00 00 cmpb $0x0,0xe2441(%rip) # 0xe2465 24: 74 17 je 0x3d 26: 31 c0 xor %eax,%eax 28: 0f 05 syscall 2a:* 48 3d 00 f0 ff ff cmp $0xfffffffffffff000,%rax <-- trapping instruction 30: 77 5b ja 0x8d 32: c3 retq 33: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 3a: 00 00 00 3d: 48 rex.W 3e: 83 .byte 0x83 3f: ec in (%dx),%al Code starting with the faulting instruction =========================================== 0: 48 3d 00 f0 ff ff cmp $0xfffffffffffff000,%rax 6: 77 5b ja 0x63 8: c3 retq 9: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 10: 00 00 00 13: 48 rex.W 14: 83 .byte 0x83 15: ec in (%dx),%al kern :warn : [ 528.632309] RSP: 002b:00007ffe2eb3c008 EFLAGS: 00000246 ORIG_RAX: 0000000000000000 kern :warn : [ 528.632540] RAX: ffffffffffffffda RBX: 00007ffe2eb3d1b0 RCX: 00007f90bf2ba19d kern :warn : [ 528.632757] RDX: 0000000000000400 RSI: 000055e284e68c40 RDI: 0000000000000005 kern :warn : [ 528.632960] RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000073 kern :warn : [ 528.633156] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000005 kern :warn : [ 528.633399] R13: 000055e284e68c40 R14: 000055e2a975f8cb R15: 00007ffe2eb3d1b0 kern :warn : [ 528.633645] </TASK> kern :warn : [ 528.633813] ---[ end trace ]--- The kernel config and materials to reproduce are available at: https://download.01.org/0day-ci/archive/20240331/202403312344.c0d273ab-oliver.sang@intel.com
On 2024/3/22 18:41, Vlastimil Babka wrote: > On 3/22/24 10:20, Miaohe Lin wrote: >> On 2024/3/21 22:24, Matthew Wilcox (Oracle) wrote: >>> Reclaim the Slab page flag by using a spare bit in PageType. We are >>> perennially short of page flags for various purposes, and now that >>> the original SLAB allocator has been retired, SLUB does not use the >>> mapcount/page_type field. This lets us remove a number of special cases >>> for ignoring mapcount on Slab pages. >>> >>> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> > > Acked-by: Vlastimil Babka <vbabka@suse.cz> > >>> --- >>> include/linux/page-flags.h | 21 +++++++++++++++++---- >>> include/trace/events/mmflags.h | 2 +- >>> mm/memory-failure.c | 9 --------- >>> mm/slab.h | 2 +- >>> 4 files changed, 19 insertions(+), 15 deletions(-) >>> >>> diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h >>> index 94eb8a11a321..73e0b17c7728 100644 >>> --- a/include/linux/page-flags.h >>> +++ b/include/linux/page-flags.h >>> @@ -109,7 +109,6 @@ enum pageflags { >>> PG_active, >>> PG_workingset, >>> PG_error, >>> - PG_slab, >>> PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/ >>> PG_arch_1, >>> PG_reserved, >>> @@ -524,7 +523,6 @@ PAGEFLAG(Active, active, PF_HEAD) __CLEARPAGEFLAG(Active, active, PF_HEAD) >>> TESTCLEARFLAG(Active, active, PF_HEAD) >>> PAGEFLAG(Workingset, workingset, PF_HEAD) >>> TESTCLEARFLAG(Workingset, workingset, PF_HEAD) >>> -__PAGEFLAG(Slab, slab, PF_NO_TAIL) >>> PAGEFLAG(Checked, checked, PF_NO_COMPOUND) /* Used by some filesystems */ >>> >>> /* Xen */ >>> @@ -931,7 +929,7 @@ PAGEFLAG_FALSE(HasHWPoisoned, has_hwpoisoned) >>> #endif >>> >>> /* >>> - * For pages that are never mapped to userspace (and aren't PageSlab), >>> + * For pages that are never mapped to userspace, >>> * page_type may be used. Because it is initialised to -1, we invert the >>> * sense of the bit, so __SetPageFoo *clears* the bit used for PageFoo, and >>> * __ClearPageFoo *sets* the bit used for PageFoo. We reserve a few high and >>> @@ -947,6 +945,7 @@ PAGEFLAG_FALSE(HasHWPoisoned, has_hwpoisoned) >>> #define PG_table 0x00000200 >>> #define PG_guard 0x00000400 >>> #define PG_hugetlb 0x00000800 >>> +#define PG_slab 0x00001000 >>> >>> #define PageType(page, flag) \ >>> ((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE) >>> @@ -1041,6 +1040,20 @@ PAGE_TYPE_OPS(Table, table, pgtable) >>> */ >>> PAGE_TYPE_OPS(Guard, guard, guard) >>> >>> +FOLIO_TYPE_OPS(slab, slab) >>> + >>> +/** >>> + * PageSlab - Determine if the page belongs to the slab allocator >>> + * @page: The page to test. >>> + * >>> + * Context: Any context. >>> + * Return: True for slab pages, false for any other kind of page. >>> + */ >>> +static inline bool PageSlab(const struct page *page) >>> +{ >>> + return folio_test_slab(page_folio(page)); >>> +} >>> + >>> #ifdef CONFIG_HUGETLB_PAGE >>> FOLIO_TYPE_OPS(hugetlb, hugetlb) >>> #else >>> @@ -1121,7 +1134,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page) >>> (1UL << PG_lru | 1UL << PG_locked | \ >>> 1UL << PG_private | 1UL << PG_private_2 | \ >>> 1UL << PG_writeback | 1UL << PG_reserved | \ >>> - 1UL << PG_slab | 1UL << PG_active | \ >>> + 1UL << PG_active | \ >>> 1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK) >>> >>> /* >>> diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h >>> index d55e53ac91bd..e46d6e82765e 100644 >>> --- a/include/trace/events/mmflags.h >>> +++ b/include/trace/events/mmflags.h >>> @@ -107,7 +107,6 @@ >>> DEF_PAGEFLAG_NAME(lru), \ >>> DEF_PAGEFLAG_NAME(active), \ >>> DEF_PAGEFLAG_NAME(workingset), \ >>> - DEF_PAGEFLAG_NAME(slab), \ >>> DEF_PAGEFLAG_NAME(owner_priv_1), \ >>> DEF_PAGEFLAG_NAME(arch_1), \ >>> DEF_PAGEFLAG_NAME(reserved), \ >>> @@ -135,6 +134,7 @@ IF_HAVE_PG_ARCH_X(arch_3) >>> #define DEF_PAGETYPE_NAME(_name) { PG_##_name, __stringify(_name) } >>> >>> #define __def_pagetype_names \ >>> + DEF_PAGETYPE_NAME(slab), \ >>> DEF_PAGETYPE_NAME(hugetlb), \ >>> DEF_PAGETYPE_NAME(offline), \ >>> DEF_PAGETYPE_NAME(guard), \ >>> diff --git a/mm/memory-failure.c b/mm/memory-failure.c >>> index 9349948f1abf..1cb41ba7870c 100644 >>> --- a/mm/memory-failure.c >>> +++ b/mm/memory-failure.c >>> @@ -1239,7 +1239,6 @@ static int me_huge_page(struct page_state *ps, struct page *p) >>> #define mlock (1UL << PG_mlocked) >>> #define lru (1UL << PG_lru) >>> #define head (1UL << PG_head) >>> -#define slab (1UL << PG_slab) >>> #define reserved (1UL << PG_reserved) >>> >>> static struct page_state error_states[] = { >>> @@ -1249,13 +1248,6 @@ static struct page_state error_states[] = { >>> * PG_buddy pages only make a small fraction of all free pages. >>> */ >>> >>> - /* >>> - * Could in theory check if slab page is free or if we can drop >>> - * currently unused objects without touching them. But just >>> - * treat it as standard kernel for now. >>> - */ >>> - { slab, slab, MF_MSG_SLAB, me_kernel }, >> >> Will it be better to leave the above slab case here to catch possible unhandled obscure races with >> slab? Though it looks like slab page shouldn't reach here. > Sorry for late, I was on hard off-the-job training last week. > The code would need to handle page types as it's no longer a page flag. I > guess that's your decision? If it's not necessary, then I guess MF_MSG_SLAB > itself could be also removed with a buch of more code referencing it. It might be overkill to add codes to handle page types just for slab. We're only intended to handle Huge pages, LRU pages and free budy pages anyway. As code changes, I suspect MF_MSG_SLAB and MF_MSG_KERNEL are obsolete now. But it might be better to leave them alone. There might be some unhandled obscure races and some buggy kernel code might lead to something unexpected, e.g. slab pages with LRU flags? Thanks. > >> Thanks. >> > > . >
On Sun, Mar 31, 2024 at 11:11:10PM +0800, kernel test robot wrote: > kernel test robot noticed "UBSAN:shift-out-of-bounds_in_fs/proc/page.c" on: > > commit: 30e5296811312a13938b83956a55839ac1e3aa40 ("[PATCH 7/9] mm: Free up PG_slab") Quite right. Spotted another one while I was at it. Not able to test right now, but this should do the trick: diff --git a/fs/proc/page.c b/fs/proc/page.c index 5bc82828c6aa..55b01535eb22 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -175,6 +175,8 @@ u64 stable_page_flags(const struct page *page) u |= 1 << KPF_OFFLINE; if (PageTable(page)) u |= 1 << KPF_PGTABLE; + if (folio_test_slab(folio)) + u |= 1 << KPF_SLAB; #if defined(CONFIG_PAGE_IDLE_FLAG) && defined(CONFIG_64BIT) u |= kpf_copy_bit(k, KPF_IDLE, PG_idle); @@ -184,7 +186,6 @@ u64 stable_page_flags(const struct page *page) #endif u |= kpf_copy_bit(k, KPF_LOCKED, PG_locked); - u |= kpf_copy_bit(k, KPF_SLAB, PG_slab); u |= kpf_copy_bit(k, KPF_ERROR, PG_error); u |= kpf_copy_bit(k, KPF_DIRTY, PG_dirty); u |= kpf_copy_bit(k, KPF_UPTODATE, PG_uptodate); diff --git a/tools/cgroup/memcg_slabinfo.py b/tools/cgroup/memcg_slabinfo.py index 1d3a90d93fe2..270c28a0d098 100644 --- a/tools/cgroup/memcg_slabinfo.py +++ b/tools/cgroup/memcg_slabinfo.py @@ -146,12 +146,11 @@ def detect_kernel_config(): def for_each_slab(prog): - PGSlab = 1 << prog.constant('PG_slab') - PGHead = 1 << prog.constant('PG_head') + PGSlab = ~prog.constant('PG_slab') for page in for_each_page(prog): try: - if page.flags.value_() & PGSlab: + if page.page_type.value_() == PGSlab: yield cast('struct slab *', page) except FaultError: pass
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 94eb8a11a321..73e0b17c7728 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -109,7 +109,6 @@ enum pageflags { PG_active, PG_workingset, PG_error, - PG_slab, PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/ PG_arch_1, PG_reserved, @@ -524,7 +523,6 @@ PAGEFLAG(Active, active, PF_HEAD) __CLEARPAGEFLAG(Active, active, PF_HEAD) TESTCLEARFLAG(Active, active, PF_HEAD) PAGEFLAG(Workingset, workingset, PF_HEAD) TESTCLEARFLAG(Workingset, workingset, PF_HEAD) -__PAGEFLAG(Slab, slab, PF_NO_TAIL) PAGEFLAG(Checked, checked, PF_NO_COMPOUND) /* Used by some filesystems */ /* Xen */ @@ -931,7 +929,7 @@ PAGEFLAG_FALSE(HasHWPoisoned, has_hwpoisoned) #endif /* - * For pages that are never mapped to userspace (and aren't PageSlab), + * For pages that are never mapped to userspace, * page_type may be used. Because it is initialised to -1, we invert the * sense of the bit, so __SetPageFoo *clears* the bit used for PageFoo, and * __ClearPageFoo *sets* the bit used for PageFoo. We reserve a few high and @@ -947,6 +945,7 @@ PAGEFLAG_FALSE(HasHWPoisoned, has_hwpoisoned) #define PG_table 0x00000200 #define PG_guard 0x00000400 #define PG_hugetlb 0x00000800 +#define PG_slab 0x00001000 #define PageType(page, flag) \ ((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE) @@ -1041,6 +1040,20 @@ PAGE_TYPE_OPS(Table, table, pgtable) */ PAGE_TYPE_OPS(Guard, guard, guard) +FOLIO_TYPE_OPS(slab, slab) + +/** + * PageSlab - Determine if the page belongs to the slab allocator + * @page: The page to test. + * + * Context: Any context. + * Return: True for slab pages, false for any other kind of page. + */ +static inline bool PageSlab(const struct page *page) +{ + return folio_test_slab(page_folio(page)); +} + #ifdef CONFIG_HUGETLB_PAGE FOLIO_TYPE_OPS(hugetlb, hugetlb) #else @@ -1121,7 +1134,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page) (1UL << PG_lru | 1UL << PG_locked | \ 1UL << PG_private | 1UL << PG_private_2 | \ 1UL << PG_writeback | 1UL << PG_reserved | \ - 1UL << PG_slab | 1UL << PG_active | \ + 1UL << PG_active | \ 1UL << PG_unevictable | __PG_MLOCKED | LRU_GEN_MASK) /* diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h index d55e53ac91bd..e46d6e82765e 100644 --- a/include/trace/events/mmflags.h +++ b/include/trace/events/mmflags.h @@ -107,7 +107,6 @@ DEF_PAGEFLAG_NAME(lru), \ DEF_PAGEFLAG_NAME(active), \ DEF_PAGEFLAG_NAME(workingset), \ - DEF_PAGEFLAG_NAME(slab), \ DEF_PAGEFLAG_NAME(owner_priv_1), \ DEF_PAGEFLAG_NAME(arch_1), \ DEF_PAGEFLAG_NAME(reserved), \ @@ -135,6 +134,7 @@ IF_HAVE_PG_ARCH_X(arch_3) #define DEF_PAGETYPE_NAME(_name) { PG_##_name, __stringify(_name) } #define __def_pagetype_names \ + DEF_PAGETYPE_NAME(slab), \ DEF_PAGETYPE_NAME(hugetlb), \ DEF_PAGETYPE_NAME(offline), \ DEF_PAGETYPE_NAME(guard), \ diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 9349948f1abf..1cb41ba7870c 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1239,7 +1239,6 @@ static int me_huge_page(struct page_state *ps, struct page *p) #define mlock (1UL << PG_mlocked) #define lru (1UL << PG_lru) #define head (1UL << PG_head) -#define slab (1UL << PG_slab) #define reserved (1UL << PG_reserved) static struct page_state error_states[] = { @@ -1249,13 +1248,6 @@ static struct page_state error_states[] = { * PG_buddy pages only make a small fraction of all free pages. */ - /* - * Could in theory check if slab page is free or if we can drop - * currently unused objects without touching them. But just - * treat it as standard kernel for now. - */ - { slab, slab, MF_MSG_SLAB, me_kernel }, - { head, head, MF_MSG_HUGE, me_huge_page }, { sc|dirty, sc|dirty, MF_MSG_DIRTY_SWAPCACHE, me_swapcache_dirty }, @@ -1282,7 +1274,6 @@ static struct page_state error_states[] = { #undef mlock #undef lru #undef head -#undef slab #undef reserved static void update_per_node_mf_stats(unsigned long pfn, diff --git a/mm/slab.h b/mm/slab.h index d2bc9b191222..457b15da2a6b 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -84,8 +84,8 @@ struct slab { }; struct rcu_head rcu_head; }; - unsigned int __unused; + unsigned int __page_type; atomic_t __page_refcount; #ifdef CONFIG_MEMCG unsigned long memcg_data;
Reclaim the Slab page flag by using a spare bit in PageType. We are perennially short of page flags for various purposes, and now that the original SLAB allocator has been retired, SLUB does not use the mapcount/page_type field. This lets us remove a number of special cases for ignoring mapcount on Slab pages. Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> --- include/linux/page-flags.h | 21 +++++++++++++++++---- include/trace/events/mmflags.h | 2 +- mm/memory-failure.c | 9 --------- mm/slab.h | 2 +- 4 files changed, 19 insertions(+), 15 deletions(-)