Commit e6ebf011 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mm-hotfixes-stable-2024-04-26-13-30' of...

Merge tag 'mm-hotfixes-stable-2024-04-26-13-30' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull misc fixes from Andrew Morton:
 "11 hotfixes. 8 are cc:stable and the remaining 3 (nice ratio!) address
  post-6.8 issues or aren't considered suitable for backporting.

  All except one of these are for MM. I see no particular theme - it's
  singletons all over"

* tag 'mm-hotfixes-stable-2024-04-26-13-30' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
  mm/hugetlb: fix DEBUG_LOCKS_WARN_ON(1) when dissolve_free_hugetlb_folio()
  selftests: mm: protection_keys: save/restore nr_hugepages value from launch script
  stackdepot: respect __GFP_NOLOCKDEP allocation flag
  hugetlb: check for anon_vma prior to folio allocation
  mm: zswap: fix shrinker NULL crash with cgroup_disable=memory
  mm: turn folio_test_hugetlb into a PageType
  mm: support page_mapcount() on page_has_type() pages
  mm: create FOLIO_FLAG_FALSE and FOLIO_TYPE_OPS macros
  mm/hugetlb: fix missing hugetlb_lock for resv uncharge
  selftests: mm: fix unused and uninitialized variable warning
  selftests/harness: remove use of LINE_MAX
parents 4630932a 52ccdde1
...@@ -67,7 +67,7 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf, ...@@ -67,7 +67,7 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf,
*/ */
ppage = pfn_to_online_page(pfn); ppage = pfn_to_online_page(pfn);
if (!ppage || PageSlab(ppage) || page_has_type(ppage)) if (!ppage)
pcount = 0; pcount = 0;
else else
pcount = page_mapcount(ppage); pcount = page_mapcount(ppage);
...@@ -124,11 +124,8 @@ u64 stable_page_flags(struct page *page) ...@@ -124,11 +124,8 @@ u64 stable_page_flags(struct page *page)
/* /*
* pseudo flags for the well known (anonymous) memory mapped pages * pseudo flags for the well known (anonymous) memory mapped pages
*
* Note that page->_mapcount is overloaded in SLAB, so the
* simple test in page_mapped() is not enough.
*/ */
if (!PageSlab(page) && page_mapped(page)) if (page_mapped(page))
u |= 1 << KPF_MMAP; u |= 1 << KPF_MMAP;
if (PageAnon(page)) if (PageAnon(page))
u |= 1 << KPF_ANON; u |= 1 << KPF_ANON;
......
...@@ -1223,14 +1223,16 @@ static inline void page_mapcount_reset(struct page *page) ...@@ -1223,14 +1223,16 @@ static inline void page_mapcount_reset(struct page *page)
* a large folio, it includes the number of times this page is mapped * a large folio, it includes the number of times this page is mapped
* as part of that folio. * as part of that folio.
* *
* The result is undefined for pages which cannot be mapped into userspace. * Will report 0 for pages which cannot be mapped into userspace, eg
* For example SLAB or special types of pages. See function page_has_type(). * slab, page tables and similar.
* They use this field in struct page differently.
*/ */
static inline int page_mapcount(struct page *page) static inline int page_mapcount(struct page *page)
{ {
int mapcount = atomic_read(&page->_mapcount) + 1; int mapcount = atomic_read(&page->_mapcount) + 1;
/* Handle page_has_type() pages */
if (mapcount < 0)
mapcount = 0;
if (unlikely(PageCompound(page))) if (unlikely(PageCompound(page)))
mapcount += folio_entire_mapcount(page_folio(page)); mapcount += folio_entire_mapcount(page_folio(page));
......
...@@ -190,7 +190,6 @@ enum pageflags { ...@@ -190,7 +190,6 @@ enum pageflags {
/* At least one page in this folio has the hwpoison flag set */ /* At least one page in this folio has the hwpoison flag set */
PG_has_hwpoisoned = PG_error, PG_has_hwpoisoned = PG_error,
PG_hugetlb = PG_active,
PG_large_rmappable = PG_workingset, /* anon or file-backed */ PG_large_rmappable = PG_workingset, /* anon or file-backed */
}; };
...@@ -458,30 +457,51 @@ static __always_inline int TestClearPage##uname(struct page *page) \ ...@@ -458,30 +457,51 @@ static __always_inline int TestClearPage##uname(struct page *page) \
TESTSETFLAG(uname, lname, policy) \ TESTSETFLAG(uname, lname, policy) \
TESTCLEARFLAG(uname, lname, policy) TESTCLEARFLAG(uname, lname, policy)
#define FOLIO_TEST_FLAG_FALSE(name) \
static inline bool folio_test_##name(const struct folio *folio) \
{ return false; }
#define FOLIO_SET_FLAG_NOOP(name) \
static inline void folio_set_##name(struct folio *folio) { }
#define FOLIO_CLEAR_FLAG_NOOP(name) \
static inline void folio_clear_##name(struct folio *folio) { }
#define __FOLIO_SET_FLAG_NOOP(name) \
static inline void __folio_set_##name(struct folio *folio) { }
#define __FOLIO_CLEAR_FLAG_NOOP(name) \
static inline void __folio_clear_##name(struct folio *folio) { }
#define FOLIO_TEST_SET_FLAG_FALSE(name) \
static inline bool folio_test_set_##name(struct folio *folio) \
{ return false; }
#define FOLIO_TEST_CLEAR_FLAG_FALSE(name) \
static inline bool folio_test_clear_##name(struct folio *folio) \
{ return false; }
#define FOLIO_FLAG_FALSE(name) \
FOLIO_TEST_FLAG_FALSE(name) \
FOLIO_SET_FLAG_NOOP(name) \
FOLIO_CLEAR_FLAG_NOOP(name)
#define TESTPAGEFLAG_FALSE(uname, lname) \ #define TESTPAGEFLAG_FALSE(uname, lname) \
static inline bool folio_test_##lname(const struct folio *folio) { return false; } \ FOLIO_TEST_FLAG_FALSE(lname) \
static inline int Page##uname(const struct page *page) { return 0; } static inline int Page##uname(const struct page *page) { return 0; }
#define SETPAGEFLAG_NOOP(uname, lname) \ #define SETPAGEFLAG_NOOP(uname, lname) \
static inline void folio_set_##lname(struct folio *folio) { } \ FOLIO_SET_FLAG_NOOP(lname) \
static inline void SetPage##uname(struct page *page) { } static inline void SetPage##uname(struct page *page) { }
#define CLEARPAGEFLAG_NOOP(uname, lname) \ #define CLEARPAGEFLAG_NOOP(uname, lname) \
static inline void folio_clear_##lname(struct folio *folio) { } \ FOLIO_CLEAR_FLAG_NOOP(lname) \
static inline void ClearPage##uname(struct page *page) { } static inline void ClearPage##uname(struct page *page) { }
#define __CLEARPAGEFLAG_NOOP(uname, lname) \ #define __CLEARPAGEFLAG_NOOP(uname, lname) \
static inline void __folio_clear_##lname(struct folio *folio) { } \ __FOLIO_CLEAR_FLAG_NOOP(lname) \
static inline void __ClearPage##uname(struct page *page) { } static inline void __ClearPage##uname(struct page *page) { }
#define TESTSETFLAG_FALSE(uname, lname) \ #define TESTSETFLAG_FALSE(uname, lname) \
static inline bool folio_test_set_##lname(struct folio *folio) \ FOLIO_TEST_SET_FLAG_FALSE(lname) \
{ return 0; } \
static inline int TestSetPage##uname(struct page *page) { return 0; } static inline int TestSetPage##uname(struct page *page) { return 0; }
#define TESTCLEARFLAG_FALSE(uname, lname) \ #define TESTCLEARFLAG_FALSE(uname, lname) \
static inline bool folio_test_clear_##lname(struct folio *folio) \ FOLIO_TEST_CLEAR_FLAG_FALSE(lname) \
{ return 0; } \
static inline int TestClearPage##uname(struct page *page) { return 0; } static inline int TestClearPage##uname(struct page *page) { return 0; }
#define PAGEFLAG_FALSE(uname, lname) TESTPAGEFLAG_FALSE(uname, lname) \ #define PAGEFLAG_FALSE(uname, lname) TESTPAGEFLAG_FALSE(uname, lname) \
...@@ -855,29 +875,6 @@ TESTPAGEFLAG_FALSE(LargeRmappable, large_rmappable) ...@@ -855,29 +875,6 @@ TESTPAGEFLAG_FALSE(LargeRmappable, large_rmappable)
#define PG_head_mask ((1UL << PG_head)) #define PG_head_mask ((1UL << PG_head))
#ifdef CONFIG_HUGETLB_PAGE
int PageHuge(const struct page *page);
SETPAGEFLAG(HugeTLB, hugetlb, PF_SECOND)
CLEARPAGEFLAG(HugeTLB, hugetlb, PF_SECOND)
/**
* folio_test_hugetlb - Determine if the folio belongs to hugetlbfs
* @folio: The folio to test.
*
* Context: Any context. Caller should have a reference on the folio to
* prevent it from being turned into a tail page.
* Return: True for hugetlbfs folios, false for anon folios or folios
* belonging to other filesystems.
*/
static inline bool folio_test_hugetlb(const struct folio *folio)
{
return folio_test_large(folio) &&
test_bit(PG_hugetlb, const_folio_flags(folio, 1));
}
#else
TESTPAGEFLAG_FALSE(Huge, hugetlb)
#endif
#ifdef CONFIG_TRANSPARENT_HUGEPAGE #ifdef CONFIG_TRANSPARENT_HUGEPAGE
/* /*
* PageHuge() only returns true for hugetlbfs pages, but not for * PageHuge() only returns true for hugetlbfs pages, but not for
...@@ -933,34 +930,23 @@ PAGEFLAG_FALSE(HasHWPoisoned, has_hwpoisoned) ...@@ -933,34 +930,23 @@ PAGEFLAG_FALSE(HasHWPoisoned, has_hwpoisoned)
TESTSCFLAG_FALSE(HasHWPoisoned, has_hwpoisoned) TESTSCFLAG_FALSE(HasHWPoisoned, has_hwpoisoned)
#endif #endif
/*
* Check if a page is currently marked HWPoisoned. Note that this check is
* best effort only and inherently racy: there is no way to synchronize with
* failing hardware.
*/
static inline bool is_page_hwpoison(struct page *page)
{
if (PageHWPoison(page))
return true;
return PageHuge(page) && PageHWPoison(compound_head(page));
}
/* /*
* For pages that are never mapped to userspace (and aren't PageSlab), * For pages that are never mapped to userspace (and aren't PageSlab),
* page_type may be used. Because it is initialised to -1, we invert the * 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 * 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 * __ClearPageFoo *sets* the bit used for PageFoo. We reserve a few high and
* low bits so that an underflow or overflow of page_mapcount() won't be * low bits so that an underflow or overflow of _mapcount won't be
* mistaken for a page type value. * mistaken for a page type value.
*/ */
#define PAGE_TYPE_BASE 0xf0000000 #define PAGE_TYPE_BASE 0xf0000000
/* Reserve 0x0000007f to catch underflows of page_mapcount */ /* Reserve 0x0000007f to catch underflows of _mapcount */
#define PAGE_MAPCOUNT_RESERVE -128 #define PAGE_MAPCOUNT_RESERVE -128
#define PG_buddy 0x00000080 #define PG_buddy 0x00000080
#define PG_offline 0x00000100 #define PG_offline 0x00000100
#define PG_table 0x00000200 #define PG_table 0x00000200
#define PG_guard 0x00000400 #define PG_guard 0x00000400
#define PG_hugetlb 0x00000800
#define PageType(page, flag) \ #define PageType(page, flag) \
((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE) ((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE)
...@@ -977,35 +963,38 @@ static inline int page_has_type(const struct page *page) ...@@ -977,35 +963,38 @@ static inline int page_has_type(const struct page *page)
return page_type_has_type(page->page_type); return page_type_has_type(page->page_type);
} }
#define FOLIO_TYPE_OPS(lname, fname) \
static __always_inline bool folio_test_##fname(const struct folio *folio)\
{ \
return folio_test_type(folio, PG_##lname); \
} \
static __always_inline void __folio_set_##fname(struct folio *folio) \
{ \
VM_BUG_ON_FOLIO(!folio_test_type(folio, 0), folio); \
folio->page.page_type &= ~PG_##lname; \
} \
static __always_inline void __folio_clear_##fname(struct folio *folio) \
{ \
VM_BUG_ON_FOLIO(!folio_test_##fname(folio), folio); \
folio->page.page_type |= PG_##lname; \
}
#define PAGE_TYPE_OPS(uname, lname, fname) \ #define PAGE_TYPE_OPS(uname, lname, fname) \
FOLIO_TYPE_OPS(lname, fname) \
static __always_inline int Page##uname(const struct page *page) \ static __always_inline int Page##uname(const struct page *page) \
{ \ { \
return PageType(page, PG_##lname); \ return PageType(page, PG_##lname); \
} \ } \
static __always_inline int folio_test_##fname(const struct folio *folio)\
{ \
return folio_test_type(folio, PG_##lname); \
} \
static __always_inline void __SetPage##uname(struct page *page) \ static __always_inline void __SetPage##uname(struct page *page) \
{ \ { \
VM_BUG_ON_PAGE(!PageType(page, 0), page); \ VM_BUG_ON_PAGE(!PageType(page, 0), page); \
page->page_type &= ~PG_##lname; \ page->page_type &= ~PG_##lname; \
} \ } \
static __always_inline void __folio_set_##fname(struct folio *folio) \
{ \
VM_BUG_ON_FOLIO(!folio_test_type(folio, 0), folio); \
folio->page.page_type &= ~PG_##lname; \
} \
static __always_inline void __ClearPage##uname(struct page *page) \ static __always_inline void __ClearPage##uname(struct page *page) \
{ \ { \
VM_BUG_ON_PAGE(!Page##uname(page), page); \ VM_BUG_ON_PAGE(!Page##uname(page), page); \
page->page_type |= PG_##lname; \ page->page_type |= PG_##lname; \
} \ }
static __always_inline void __folio_clear_##fname(struct folio *folio) \
{ \
VM_BUG_ON_FOLIO(!folio_test_##fname(folio), folio); \
folio->page.page_type |= PG_##lname; \
} \
/* /*
* PageBuddy() indicates that the page is free and in the buddy system * PageBuddy() indicates that the page is free and in the buddy system
...@@ -1052,6 +1041,37 @@ PAGE_TYPE_OPS(Table, table, pgtable) ...@@ -1052,6 +1041,37 @@ PAGE_TYPE_OPS(Table, table, pgtable)
*/ */
PAGE_TYPE_OPS(Guard, guard, guard) PAGE_TYPE_OPS(Guard, guard, guard)
#ifdef CONFIG_HUGETLB_PAGE
FOLIO_TYPE_OPS(hugetlb, hugetlb)
#else
FOLIO_TEST_FLAG_FALSE(hugetlb)
#endif
/**
* PageHuge - Determine if the page belongs to hugetlbfs
* @page: The page to test.
*
* Context: Any context.
* Return: True for hugetlbfs pages, false for anon pages or pages
* belonging to other filesystems.
*/
static inline bool PageHuge(const struct page *page)
{
return folio_test_hugetlb(page_folio(page));
}
/*
* Check if a page is currently marked HWPoisoned. Note that this check is
* best effort only and inherently racy: there is no way to synchronize with
* failing hardware.
*/
static inline bool is_page_hwpoison(struct page *page)
{
if (PageHWPoison(page))
return true;
return PageHuge(page) && PageHWPoison(compound_head(page));
}
extern bool is_free_buddy_page(struct page *page); extern bool is_free_buddy_page(struct page *page);
PAGEFLAG(Isolated, isolated, PF_ANY); PAGEFLAG(Isolated, isolated, PF_ANY);
...@@ -1118,7 +1138,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page) ...@@ -1118,7 +1138,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page)
*/ */
#define PAGE_FLAGS_SECOND \ #define PAGE_FLAGS_SECOND \
(0xffUL /* order */ | 1UL << PG_has_hwpoisoned | \ (0xffUL /* order */ | 1UL << PG_has_hwpoisoned | \
1UL << PG_hugetlb | 1UL << PG_large_rmappable) 1UL << PG_large_rmappable)
#define PAGE_FLAGS_PRIVATE \ #define PAGE_FLAGS_PRIVATE \
(1UL << PG_private | 1UL << PG_private_2) (1UL << PG_private | 1UL << PG_private_2)
......
...@@ -135,6 +135,7 @@ IF_HAVE_PG_ARCH_X(arch_3) ...@@ -135,6 +135,7 @@ IF_HAVE_PG_ARCH_X(arch_3)
#define DEF_PAGETYPE_NAME(_name) { PG_##_name, __stringify(_name) } #define DEF_PAGETYPE_NAME(_name) { PG_##_name, __stringify(_name) }
#define __def_pagetype_names \ #define __def_pagetype_names \
DEF_PAGETYPE_NAME(hugetlb), \
DEF_PAGETYPE_NAME(offline), \ DEF_PAGETYPE_NAME(offline), \
DEF_PAGETYPE_NAME(guard), \ DEF_PAGETYPE_NAME(guard), \
DEF_PAGETYPE_NAME(table), \ DEF_PAGETYPE_NAME(table), \
......
...@@ -205,11 +205,10 @@ static int __init crash_save_vmcoreinfo_init(void) ...@@ -205,11 +205,10 @@ static int __init crash_save_vmcoreinfo_init(void)
VMCOREINFO_NUMBER(PG_head_mask); VMCOREINFO_NUMBER(PG_head_mask);
#define PAGE_BUDDY_MAPCOUNT_VALUE (~PG_buddy) #define PAGE_BUDDY_MAPCOUNT_VALUE (~PG_buddy)
VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE); VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE);
#ifdef CONFIG_HUGETLB_PAGE #define PAGE_HUGETLB_MAPCOUNT_VALUE (~PG_hugetlb)
VMCOREINFO_NUMBER(PG_hugetlb); VMCOREINFO_NUMBER(PAGE_HUGETLB_MAPCOUNT_VALUE);
#define PAGE_OFFLINE_MAPCOUNT_VALUE (~PG_offline) #define PAGE_OFFLINE_MAPCOUNT_VALUE (~PG_offline)
VMCOREINFO_NUMBER(PAGE_OFFLINE_MAPCOUNT_VALUE); VMCOREINFO_NUMBER(PAGE_OFFLINE_MAPCOUNT_VALUE);
#endif
#ifdef CONFIG_KALLSYMS #ifdef CONFIG_KALLSYMS
VMCOREINFO_SYMBOL(kallsyms_names); VMCOREINFO_SYMBOL(kallsyms_names);
......
...@@ -627,10 +627,10 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries, ...@@ -627,10 +627,10 @@ depot_stack_handle_t stack_depot_save_flags(unsigned long *entries,
/* /*
* Zero out zone modifiers, as we don't have specific zone * Zero out zone modifiers, as we don't have specific zone
* requirements. Keep the flags related to allocation in atomic * requirements. Keep the flags related to allocation in atomic
* contexts and I/O. * contexts, I/O, nolockdep.
*/ */
alloc_flags &= ~GFP_ZONEMASK; alloc_flags &= ~GFP_ZONEMASK;
alloc_flags &= (GFP_ATOMIC | GFP_KERNEL); alloc_flags &= (GFP_ATOMIC | GFP_KERNEL | __GFP_NOLOCKDEP);
alloc_flags |= __GFP_NOWARN; alloc_flags |= __GFP_NOWARN;
page = alloc_pages(alloc_flags, DEPOT_POOL_ORDER); page = alloc_pages(alloc_flags, DEPOT_POOL_ORDER);
if (page) if (page)
......
...@@ -1624,7 +1624,7 @@ static inline void __clear_hugetlb_destructor(struct hstate *h, ...@@ -1624,7 +1624,7 @@ static inline void __clear_hugetlb_destructor(struct hstate *h,
{ {
lockdep_assert_held(&hugetlb_lock); lockdep_assert_held(&hugetlb_lock);
folio_clear_hugetlb(folio); __folio_clear_hugetlb(folio);
} }
/* /*
...@@ -1711,7 +1711,7 @@ static void add_hugetlb_folio(struct hstate *h, struct folio *folio, ...@@ -1711,7 +1711,7 @@ static void add_hugetlb_folio(struct hstate *h, struct folio *folio,
h->surplus_huge_pages_node[nid]++; h->surplus_huge_pages_node[nid]++;
} }
folio_set_hugetlb(folio); __folio_set_hugetlb(folio);
folio_change_private(folio, NULL); folio_change_private(folio, NULL);
/* /*
* We have to set hugetlb_vmemmap_optimized again as above * We have to set hugetlb_vmemmap_optimized again as above
...@@ -1781,7 +1781,7 @@ static void __update_and_free_hugetlb_folio(struct hstate *h, ...@@ -1781,7 +1781,7 @@ static void __update_and_free_hugetlb_folio(struct hstate *h,
* If vmemmap pages were allocated above, then we need to clear the * If vmemmap pages were allocated above, then we need to clear the
* hugetlb destructor under the hugetlb lock. * hugetlb destructor under the hugetlb lock.
*/ */
if (clear_dtor) { if (folio_test_hugetlb(folio)) {
spin_lock_irq(&hugetlb_lock); spin_lock_irq(&hugetlb_lock);
__clear_hugetlb_destructor(h, folio); __clear_hugetlb_destructor(h, folio);
spin_unlock_irq(&hugetlb_lock); spin_unlock_irq(&hugetlb_lock);
...@@ -2049,7 +2049,7 @@ static void __prep_account_new_huge_page(struct hstate *h, int nid) ...@@ -2049,7 +2049,7 @@ static void __prep_account_new_huge_page(struct hstate *h, int nid)
static void init_new_hugetlb_folio(struct hstate *h, struct folio *folio) static void init_new_hugetlb_folio(struct hstate *h, struct folio *folio)
{ {
folio_set_hugetlb(folio); __folio_set_hugetlb(folio);
INIT_LIST_HEAD(&folio->lru); INIT_LIST_HEAD(&folio->lru);
hugetlb_set_folio_subpool(folio, NULL); hugetlb_set_folio_subpool(folio, NULL);
set_hugetlb_cgroup(folio, NULL); set_hugetlb_cgroup(folio, NULL);
...@@ -2159,22 +2159,6 @@ static bool prep_compound_gigantic_folio_for_demote(struct folio *folio, ...@@ -2159,22 +2159,6 @@ static bool prep_compound_gigantic_folio_for_demote(struct folio *folio,
return __prep_compound_gigantic_folio(folio, order, true); return __prep_compound_gigantic_folio(folio, order, true);
} }
/*
* PageHuge() only returns true for hugetlbfs pages, but not for normal or
* transparent huge pages. See the PageTransHuge() documentation for more
* details.
*/
int PageHuge(const struct page *page)
{
const struct folio *folio;
if (!PageCompound(page))
return 0;
folio = page_folio(page);
return folio_test_hugetlb(folio);
}
EXPORT_SYMBOL_GPL(PageHuge);
/* /*
* Find and lock address space (mapping) in write mode. * Find and lock address space (mapping) in write mode.
* *
...@@ -3268,9 +3252,12 @@ struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma, ...@@ -3268,9 +3252,12 @@ struct folio *alloc_hugetlb_folio(struct vm_area_struct *vma,
rsv_adjust = hugepage_subpool_put_pages(spool, 1); rsv_adjust = hugepage_subpool_put_pages(spool, 1);
hugetlb_acct_memory(h, -rsv_adjust); hugetlb_acct_memory(h, -rsv_adjust);
if (deferred_reserve) if (deferred_reserve) {
spin_lock_irq(&hugetlb_lock);
hugetlb_cgroup_uncharge_folio_rsvd(hstate_index(h), hugetlb_cgroup_uncharge_folio_rsvd(hstate_index(h),
pages_per_huge_page(h), folio); pages_per_huge_page(h), folio);
spin_unlock_irq(&hugetlb_lock);
}
} }
if (!memcg_charge_ret) if (!memcg_charge_ret)
...@@ -6274,6 +6261,12 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm, ...@@ -6274,6 +6261,12 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,
VM_UFFD_MISSING); VM_UFFD_MISSING);
} }
if (!(vma->vm_flags & VM_MAYSHARE)) {
ret = vmf_anon_prepare(vmf);
if (unlikely(ret))
goto out;
}
folio = alloc_hugetlb_folio(vma, haddr, 0); folio = alloc_hugetlb_folio(vma, haddr, 0);
if (IS_ERR(folio)) { if (IS_ERR(folio)) {
/* /*
...@@ -6310,15 +6303,12 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm, ...@@ -6310,15 +6303,12 @@ static vm_fault_t hugetlb_no_page(struct mm_struct *mm,
*/ */
restore_reserve_on_error(h, vma, haddr, folio); restore_reserve_on_error(h, vma, haddr, folio);
folio_put(folio); folio_put(folio);
ret = VM_FAULT_SIGBUS;
goto out; goto out;
} }
new_pagecache_folio = true; new_pagecache_folio = true;
} else { } else {
folio_lock(folio); folio_lock(folio);
ret = vmf_anon_prepare(vmf);
if (unlikely(ret))
goto backout_unlocked;
anon_rmap = 1; anon_rmap = 1;
} }
} else { } else {
......
...@@ -1331,15 +1331,22 @@ static unsigned long zswap_shrinker_count(struct shrinker *shrinker, ...@@ -1331,15 +1331,22 @@ static unsigned long zswap_shrinker_count(struct shrinker *shrinker,
if (!gfp_has_io_fs(sc->gfp_mask)) if (!gfp_has_io_fs(sc->gfp_mask))
return 0; return 0;
#ifdef CONFIG_MEMCG_KMEM /*
mem_cgroup_flush_stats(memcg); * For memcg, use the cgroup-wide ZSWAP stats since we don't
nr_backing = memcg_page_state(memcg, MEMCG_ZSWAP_B) >> PAGE_SHIFT; * have them per-node and thus per-lruvec. Careful if memcg is
nr_stored = memcg_page_state(memcg, MEMCG_ZSWAPPED); * runtime-disabled: we can get sc->memcg == NULL, which is ok
#else * for the lruvec, but not for memcg_page_state().
/* use pool stats instead of memcg stats */ *
nr_backing = zswap_pool_total_size >> PAGE_SHIFT; * Without memcg, use the zswap pool-wide metrics.
nr_stored = atomic_read(&zswap_nr_stored); */
#endif if (!mem_cgroup_disabled()) {
mem_cgroup_flush_stats(memcg);
nr_backing = memcg_page_state(memcg, MEMCG_ZSWAP_B) >> PAGE_SHIFT;
nr_stored = memcg_page_state(memcg, MEMCG_ZSWAPPED);
} else {
nr_backing = zswap_pool_total_size >> PAGE_SHIFT;
nr_stored = atomic_read(&zswap_nr_stored);
}
if (!nr_stored) if (!nr_stored)
return 0; return 0;
......
...@@ -56,7 +56,6 @@ ...@@ -56,7 +56,6 @@
#include <asm/types.h> #include <asm/types.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <limits.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
...@@ -1159,7 +1158,7 @@ void __run_test(struct __fixture_metadata *f, ...@@ -1159,7 +1158,7 @@ void __run_test(struct __fixture_metadata *f,
struct __test_metadata *t) struct __test_metadata *t)
{ {
struct __test_xfail *xfail; struct __test_xfail *xfail;
char test_name[LINE_MAX]; char *test_name;
const char *diagnostic; const char *diagnostic;
/* reset test struct */ /* reset test struct */
...@@ -1167,8 +1166,12 @@ void __run_test(struct __fixture_metadata *f, ...@@ -1167,8 +1166,12 @@ void __run_test(struct __fixture_metadata *f,
t->trigger = 0; t->trigger = 0;
memset(t->results->reason, 0, sizeof(t->results->reason)); memset(t->results->reason, 0, sizeof(t->results->reason));
snprintf(test_name, sizeof(test_name), "%s%s%s.%s", if (asprintf(&test_name, "%s%s%s.%s", f->name,
f->name, variant->name[0] ? "." : "", variant->name, t->name); variant->name[0] ? "." : "", variant->name, t->name) == -1) {
ksft_print_msg("ERROR ALLOCATING MEMORY\n");
t->exit_code = KSFT_FAIL;
_exit(t->exit_code);
}
ksft_print_msg(" RUN %s ...\n", test_name); ksft_print_msg(" RUN %s ...\n", test_name);
...@@ -1206,6 +1209,7 @@ void __run_test(struct __fixture_metadata *f, ...@@ -1206,6 +1209,7 @@ void __run_test(struct __fixture_metadata *f,
ksft_test_result_code(t->exit_code, test_name, ksft_test_result_code(t->exit_code, test_name,
diagnostic ? "%s" : NULL, diagnostic); diagnostic ? "%s" : NULL, diagnostic);
free(test_name);
} }
static int test_harness_run(int argc, char **argv) static int test_harness_run(int argc, char **argv)
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/prctl.h> #include <linux/prctl.h>
#define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/auxv.h> #include <sys/auxv.h>
......
...@@ -54,7 +54,6 @@ int test_nr; ...@@ -54,7 +54,6 @@ int test_nr;
u64 shadow_pkey_reg; u64 shadow_pkey_reg;
int dprint_in_signal; int dprint_in_signal;
char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE]; char dprint_in_signal_buffer[DPRINT_IN_SIGNAL_BUF_SIZE];
char buf[256];
void cat_into_file(char *str, char *file) void cat_into_file(char *str, char *file)
{ {
...@@ -1745,42 +1744,6 @@ void pkey_setup_shadow(void) ...@@ -1745,42 +1744,6 @@ void pkey_setup_shadow(void)
shadow_pkey_reg = __read_pkey_reg(); shadow_pkey_reg = __read_pkey_reg();
} }
pid_t parent_pid;
void restore_settings_atexit(void)
{
if (parent_pid == getpid())
cat_into_file(buf, "/proc/sys/vm/nr_hugepages");
}
void save_settings(void)
{
int fd;
int err;
if (geteuid())
return;
fd = open("/proc/sys/vm/nr_hugepages", O_RDONLY);
if (fd < 0) {
fprintf(stderr, "error opening\n");
perror("error: ");
exit(__LINE__);
}
/* -1 to guarantee leaving the trailing \0 */
err = read(fd, buf, sizeof(buf)-1);
if (err < 0) {
fprintf(stderr, "error reading\n");
perror("error: ");
exit(__LINE__);
}
parent_pid = getpid();
atexit(restore_settings_atexit);
close(fd);
}
int main(void) int main(void)
{ {
int nr_iterations = 22; int nr_iterations = 22;
...@@ -1788,7 +1751,6 @@ int main(void) ...@@ -1788,7 +1751,6 @@ int main(void)
srand((unsigned int)time(NULL)); srand((unsigned int)time(NULL));
save_settings();
setup_handlers(); setup_handlers();
printf("has pkeys: %d\n", pkeys_supported); printf("has pkeys: %d\n", pkeys_supported);
......
...@@ -385,6 +385,7 @@ CATEGORY="ksm_numa" run_test ./ksm_tests -N -m 0 ...@@ -385,6 +385,7 @@ CATEGORY="ksm_numa" run_test ./ksm_tests -N -m 0
CATEGORY="ksm" run_test ./ksm_functional_tests CATEGORY="ksm" run_test ./ksm_functional_tests
# protection_keys tests # protection_keys tests
nr_hugepgs=$(cat /proc/sys/vm/nr_hugepages)
if [ -x ./protection_keys_32 ] if [ -x ./protection_keys_32 ]
then then
CATEGORY="pkey" run_test ./protection_keys_32 CATEGORY="pkey" run_test ./protection_keys_32
...@@ -394,6 +395,7 @@ if [ -x ./protection_keys_64 ] ...@@ -394,6 +395,7 @@ if [ -x ./protection_keys_64 ]
then then
CATEGORY="pkey" run_test ./protection_keys_64 CATEGORY="pkey" run_test ./protection_keys_64
fi fi
echo "$nr_hugepgs" > /proc/sys/vm/nr_hugepages
if [ -x ./soft-dirty ] if [ -x ./soft-dirty ]
then then
......
...@@ -300,7 +300,7 @@ int create_pagecache_thp_and_fd(const char *testfile, size_t fd_size, int *fd, ...@@ -300,7 +300,7 @@ int create_pagecache_thp_and_fd(const char *testfile, size_t fd_size, int *fd,
char **addr) char **addr)
{ {
size_t i; size_t i;
int dummy; int __attribute__((unused)) dummy = 0;
srand(time(NULL)); srand(time(NULL));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment