[PATCH -mm 2/2] mm: page_idle: split 32bit page_idle's flag from the common flags

Yafang Shao
2022-12-17T10:59:01Z

After we split page_owner's flag from the common page_ext flags, now
only 32bit page_idle is using the commt flags. Then we can define a flag
for 32bit page_idle only.
After this patch, the size of struct page_ext will be 0, so it won't
take extra memory overhead for the page_ext which don't use this flag.

Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
---
include/linux/page_ext.h | 12 +-----------
include/linux/page_idle.h | 39 +++++++++++++++++++++++++++++++++------
mm/page_ext.c | 10 ----------
mm/page_idle.c | 12 ++++++++++++
4 files changed, 46 insertions(+), 27 deletions(-)

diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h
index c8ca4954145c..6515d2a62f34 100644
--- a/include/linux/page_ext.h
+++ b/include/linux/page_ext.h
@@ -15,14 +15,6 @@ struct page_ext_operations {
};

#ifdef CONFIG_PAGE_EXTENSION
-
-#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT)
-enum page_ext_flags {
- PAGE_EXT_YOUNG,
- PAGE_EXT_IDLE,
-};
-#endif
-
/*
* Page Extension can be considered as an extended mem_map.
* A page_ext page is associated with every page descriptor. The
@@ -30,9 +22,7 @@ enum page_ext_flags {
* All page_ext are allocated at boot or memory hotplug event,
* then the page_ext for pfn always exists.
*/
-struct page_ext {
- unsigned long flags;
-};
+struct page_ext {};

extern bool early_page_ext;
extern unsigned long page_ext_size;
diff --git a/include/linux/page_idle.h b/include/linux/page_idle.h
index 5cb7bd2078ec..4d1311fdae1d 100644
--- a/include/linux/page_idle.h
+++ b/include/linux/page_idle.h
@@ -9,6 +9,21 @@
#ifdef CONFIG_PAGE_IDLE_FLAG

#ifndef CONFIG_64BIT
+enum page_idle_flags {
+ PAGE_EXT_YOUNG,
+ PAGE_EXT_IDLE,
+};
+
+struct page_idle {
+ unsigned long flags;
+};
+
+extern struct page_ext_operations page_idle_ops;
+static inline struct page_idle *get_page_idle(struct page_ext *page_ext)
+{
+ return (void *)page_ext + page_idle_ops.offset;
+}
+
/*
* If there is not enough space to store Idle and Young bits in page flags, use
* page ext flags instead.
@@ -16,12 +31,14 @@
static inline bool folio_test_young(struct folio *folio)
{
struct page_ext *page_ext = page_ext_get(&folio->page);
+ struct page_idle *pi;
bool page_young;

if (unlikely(!page_ext))
return false;

- page_young = test_bit(PAGE_EXT_YOUNG, &page_ext->flags);
+ pi = get_page_idle(page_ext);
+ page_young = test_bit(PAGE_EXT_YOUNG, &pi->flags);
page_ext_put(page_ext);

return page_young;
@@ -30,23 +47,27 @@ static inline bool folio_test_young(struct folio *folio)
static inline void folio_set_young(struct folio *folio)
{
struct page_ext *page_ext = page_ext_get(&folio->page);
+ struct page_idle *pi;

if (unlikely(!page_ext))
return;

- set_bit(PAGE_EXT_YOUNG, &page_ext->flags);
+ pi = get_page_idle(page_ext);
+ set_bit(PAGE_EXT_YOUNG, &pi->flags);
page_ext_put(page_ext);
}

static inline bool folio_test_clear_young(struct folio *folio)
{
struct page_ext *page_ext = page_ext_get(&folio->page);
+ struct page_idle *pi;
bool page_young;

if (unlikely(!page_ext))
return false;

- page_young = test_and_clear_bit(PAGE_EXT_YOUNG, &page_ext->flags);
+ pi = get_page_idle(page_ext);
+ page_young = test_and_clear_bit(PAGE_EXT_YOUNG, &pi->flags);
page_ext_put(page_ext);

return page_young;
@@ -55,12 +76,14 @@ static inline bool folio_test_clear_young(struct folio *folio)
static inline bool folio_test_idle(struct folio *folio)
{
struct page_ext *page_ext = page_ext_get(&folio->page);
+ struct page_idle *pi;
bool page_idle;

if (unlikely(!page_ext))
return false;

- page_idle = test_bit(PAGE_EXT_IDLE, &page_ext->flags);
+ pi = get_page_idle(page_ext);
+ page_idle = test_bit(PAGE_EXT_IDLE, &pi->flags);
page_ext_put(page_ext);

return page_idle;
@@ -69,22 +92,26 @@ static inline bool folio_test_idle(struct folio *folio)
static inline void folio_set_idle(struct folio *folio)
{
struct page_ext *page_ext = page_ext_get(&folio->page);
+ struct page_idle *pi;

if (unlikely(!page_ext))
return;

- set_bit(PAGE_EXT_IDLE, &page_ext->flags);
+ pi = get_page_idle(page_ext);
+ set_bit(PAGE_EXT_IDLE, &pi->flags);
page_ext_put(page_ext);
}

static inline void folio_clear_idle(struct folio *folio)
{
struct page_ext *page_ext = page_ext_get(&folio->page);
+ struct page_idle *pi;

if (unlikely(!page_ext))
return;

- clear_bit(PAGE_EXT_IDLE, &page_ext->flags);
+ pi = get_page_idle(page_ext);
+ clear_bit(PAGE_EXT_IDLE, &pi->flags);
page_ext_put(page_ext);
}
#endif /* !CONFIG_64BIT */
diff --git a/mm/page_ext.c b/mm/page_ext.c
index 4ee522fd381c..b3459bf08b78 100644
--- a/mm/page_ext.c
+++ b/mm/page_ext.c
@@ -64,16 +64,6 @@
#define PAGE_EXT_INVALID (0x1)
#endif

-#if defined(CONFIG_PAGE_IDLE_FLAG) && !defined(CONFIG_64BIT)
-static bool need_page_idle(void)
-{
- return true;
-}
-static struct page_ext_operations page_idle_ops __initdata = {
- .need = need_page_idle,
-};
-#endif
-
static struct page_ext_operations *page_ext_ops[] __initdata = {
#ifdef CONFIG_PAGE_OWNER
&page_owner_ops,
diff --git a/mm/page_idle.c b/mm/page_idle.c
index bc08332a609c..ea1b08a541b3 100644
--- a/mm/page_idle.c
+++ b/mm/page_idle.c
@@ -18,6 +18,18 @@
#define BITMAP_CHUNK_SIZE sizeof(u64)
#define BITMAP_CHUNK_BITS (BITMAP_CHUNK_SIZE * BITS_PER_BYTE)

+#ifndef CONFIG_64BIT
+static bool need_page_idle(void)
+{
+ return true;
+}
+
+struct page_ext_operations page_idle_ops __initdata = {
+ .size = sizeof(struct page_idle),
+ .need = need_page_idle,
+};
+#endif
+
/*
* Idle page tracking only considers user memory pages, for other types of
* pages the idle flag is always unset and an attempt to set it is silently
--
2.30.1 (Apple Git-130)