Commit e6ebf011 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
Loading
Loading
Loading
Loading
+2 −5
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf,
		 */
		ppage = pfn_to_online_page(pfn);

		if (!ppage || PageSlab(ppage) || page_has_type(ppage))
		if (!ppage)
			pcount = 0;
		else
			pcount = page_mapcount(ppage);
@@ -124,11 +124,8 @@ u64 stable_page_flags(struct page *page)

	/*
	 * 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;
	if (PageAnon(page))
		u |= 1 << KPF_ANON;
+5 −3
Original line number Diff line number Diff line
@@ -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
 * as part of that folio.
 *
 * The result is undefined for pages which cannot be mapped into userspace.
 * For example SLAB or special types of pages. See function page_has_type().
 * They use this field in struct page differently.
 * Will report 0 for pages which cannot be mapped into userspace, eg
 * slab, page tables and similar.
 */
static inline int page_mapcount(struct page *page)
{
	int mapcount = atomic_read(&page->_mapcount) + 1;

	/* Handle page_has_type() pages */
	if (mapcount < 0)
		mapcount = 0;
	if (unlikely(PageCompound(page)))
		mapcount += folio_entire_mapcount(page_folio(page));

+82 −62
Original line number Diff line number Diff line
@@ -190,7 +190,6 @@ enum pageflags {

	/* At least one page in this folio has the hwpoison flag set */
	PG_has_hwpoisoned = PG_error,
	PG_hugetlb = PG_active,
	PG_large_rmappable = PG_workingset, /* anon or file-backed */
};

@@ -458,30 +457,51 @@ static __always_inline int TestClearPage##uname(struct page *page) \
	TESTSETFLAG(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)				\
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; }

#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) {  }

#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) {  }

#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) {  }

#define TESTSETFLAG_FALSE(uname, lname)					\
static inline bool folio_test_set_##lname(struct folio *folio)		\
{ return 0; }								\
FOLIO_TEST_SET_FLAG_FALSE(lname)					\
static inline int TestSetPage##uname(struct page *page) { return 0; }

#define TESTCLEARFLAG_FALSE(uname, lname)				\
static inline bool folio_test_clear_##lname(struct folio *folio)	\
{ return 0; }								\
FOLIO_TEST_CLEAR_FLAG_FALSE(lname)					\
static inline int TestClearPage##uname(struct page *page) { return 0; }

#define PAGEFLAG_FALSE(uname, lname) TESTPAGEFLAG_FALSE(uname, lname)	\
@@ -855,29 +875,6 @@ TESTPAGEFLAG_FALSE(LargeRmappable, large_rmappable)

#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
/*
 * PageHuge() only returns true for hugetlbfs pages, but not for
@@ -933,34 +930,23 @@ PAGEFLAG_FALSE(HasHWPoisoned, has_hwpoisoned)
	TESTSCFLAG_FALSE(HasHWPoisoned, has_hwpoisoned)
#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),
 * 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
 * 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.
 */

#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 PG_buddy	0x00000080
#define PG_offline	0x00000100
#define PG_table	0x00000200
#define PG_guard	0x00000400
#define PG_hugetlb	0x00000800

#define PageType(page, flag)						\
	((page->page_type & (PAGE_TYPE_BASE | flag)) == PAGE_TYPE_BASE)
@@ -977,35 +963,38 @@ static inline int page_has_type(const struct page *page)
	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)				\
FOLIO_TYPE_OPS(lname, fname)						\
static __always_inline int Page##uname(const struct page *page)		\
{									\
	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)		\
{									\
	VM_BUG_ON_PAGE(!PageType(page, 0), page);			\
	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)	\
{									\
	VM_BUG_ON_PAGE(!Page##uname(page), page);			\
	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
@@ -1052,6 +1041,37 @@ PAGE_TYPE_OPS(Table, table, pgtable)
 */
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);

PAGEFLAG(Isolated, isolated, PF_ANY);
@@ -1118,7 +1138,7 @@ static __always_inline void __ClearPageAnonExclusive(struct page *page)
 */
#define PAGE_FLAGS_SECOND						\
	(0xffUL /* order */		| 1UL << PG_has_hwpoisoned |	\
	 1UL << PG_hugetlb		| 1UL << PG_large_rmappable)
	 1UL << PG_large_rmappable)

#define PAGE_FLAGS_PRIVATE				\
	(1UL << PG_private | 1UL << PG_private_2)
+1 −0
Original line number Diff line number Diff line
@@ -135,6 +135,7 @@ IF_HAVE_PG_ARCH_X(arch_3)
#define DEF_PAGETYPE_NAME(_name) { PG_##_name, __stringify(_name) }

#define __def_pagetype_names						\
	DEF_PAGETYPE_NAME(hugetlb),					\
	DEF_PAGETYPE_NAME(offline),					\
	DEF_PAGETYPE_NAME(guard),					\
	DEF_PAGETYPE_NAME(table),					\
+2 −3
Original line number Diff line number Diff line
@@ -205,11 +205,10 @@ static int __init crash_save_vmcoreinfo_init(void)
	VMCOREINFO_NUMBER(PG_head_mask);
#define PAGE_BUDDY_MAPCOUNT_VALUE	(~PG_buddy)
	VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE);
#ifdef CONFIG_HUGETLB_PAGE
	VMCOREINFO_NUMBER(PG_hugetlb);
#define PAGE_HUGETLB_MAPCOUNT_VALUE	(~PG_hugetlb)
	VMCOREINFO_NUMBER(PAGE_HUGETLB_MAPCOUNT_VALUE);
#define PAGE_OFFLINE_MAPCOUNT_VALUE	(~PG_offline)
	VMCOREINFO_NUMBER(PAGE_OFFLINE_MAPCOUNT_VALUE);
#endif

#ifdef CONFIG_KALLSYMS
	VMCOREINFO_SYMBOL(kallsyms_names);
Loading