Skip to contentSkip to conversation

mm/zsmalloc: add zpdesc memory descriptor for zswap.zpool

PATCH In review [email protected] 6 participants 32 messages Sep 2, 2024 – Dec 4, 2024

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v7 cover mm/zsmalloc: add zpdesc memory descriptor for zswap.zpool

From: Alex Shi <[email protected]>

According to Metthew's plan, the page descriptor will be replace by a 8 bytes mem_desc on destination purpose.
https://lore.kernel.org/lkml/[email protected]/

This patchset abstracts the memory descriptor used in zsmalloc by zswap/zram. The descriptor still overlays the struct page; nothing has changed in that regard. What this patchset accomplishes is the use of folios in to save some code size, and the introduction of a new concept, zpdesc. This patchset is just an initial step; it does not bias the potential changes to kmem_alloc or larger zspage modifications.

To name the struct zpdesc instead of zsdesc, since there are still 3 zpools under zswap: zbud, z3fold, zsmalloc for now(z3fold maybe removed soon), and we could easyly extend it to other zswap.zpool in needs.

For all zswap.zpools, they are all using single page since often used under memory pressure. So the conversion via folio series helper is better than page's for compound_head check saving.

For now, all zpools are using some page struct members, like page.flags for PG_private/PG_locked. and list_head lru, page.mapping for page migration.

This patachset does not increase the descriptor size nor introduce any functional changes, and could save about 122Kbytes zsmalloc.o size.

Thanks a lot for comments and suggestion from Yosry, Yoo, Sergey, Willy and Vishal!

Thanks
Alex
---
v6->v7:
- rebase on akpm/mm-unstable on Aug 30

v5->v6:
- rebase on akpm/mm-unstable on Aug 4
- recover 2 helpers and update code comments according to Vishal's comments on patch 1 and 6.

v4->v5:
- rebase on akpm/mm-unstable on Aug 8 + Stephen Rothwell's build fix.
- add a helper and update code comments according to Sergey's comments
- fold patch 20/21, remove 3 helpers functions according to Vishal's comments

v3->v4:
- rebase on akpm/mm-unstable Jul 21
- fixed a build warning reported by LKP
- Add a comment update for struct page to zpdesc change

v2->v3:
- Fix LKP reported build issue
- Update the Usage of struct zpdesc fields.
- Rebase onto latest mm-unstable commit 2073cda629a4

v1->v2:
- Take Yosry and Yoo's suggestion to add more members in zpdesc,
- Rebase on latest mm-unstable commit 31334cf98dbd
Alex Shi (10):
mm/zsmalloc: add zpdesc memory descriptor for zswap.zpool mm/zsmalloc: use zpdesc in trylock_zspage()/lock_zspage() mm/zsmalloc: convert create_page_chain() and its users to use zpdesc mm/zsmalloc: rename reset_page to reset_zpdesc and use zpdesc in it mm/zsmalloc: convert SetZsPageMovable and remove unused funcs mm/zsmalloc: convert get/set_first_obj_offset() to take zpdesc mm/zsmalloc: introduce __zpdesc_clear_movable mm/zsmalloc: introduce __zpdesc_clear/set_zsmalloc() mm/zsmalloc: introduce zpdesc_clear_first() helper mm/zsmalloc: update comments for page->zpdesc changes

Hyeonggon Yoo (11):
mm/zsmalloc: convert __zs_map_object/__zs_unmap_object to use zpdesc mm/zsmalloc: add and use pfn/zpdesc seeking funcs mm/zsmalloc: convert obj_malloc() to use zpdesc mm/zsmalloc: convert obj_allocated() and related helpers to use zpdesc mm/zsmalloc: convert init_zspage() to use zpdesc mm/zsmalloc: convert obj_to_page() and zs_free() to use zpdesc mm/zsmalloc: add zpdesc_is_isolated()/zpdesc_zone() helper for
zs_page_migrate()
mm/zsmalloc: convert __free_zspage() to use zdsesc mm/zsmalloc: convert location_to_obj() to take zpdesc mm/zsmalloc: convert migrate_zspage() to use zpdesc mm/zsmalloc: convert get_zspage() to take zpdesc

 mm/zpdesc.h   | 147 +++++++++++++++
 mm/zsmalloc.c | 490 +++++++++++++++++++++++++++-----------------------
 2 files changed, 414 insertions(+), 223 deletions(-)
 create mode 100644 mm/zpdesc.h
Signature · 1 line
2.46.0
#1 lore raw

PATCH v7 1/21 mm/zsmalloc: add zpdesc memory descriptor for zswap.zpool

From: Alex Shi <[email protected]>

The 1st patch introduces new memory descriptor zpdesc and rename zspage.first_page to zspage.first_zpdesc, no functional change.

We removed PG_owner_priv_1 since it was moved to zspage after commit a41ec880aa7b ("zsmalloc: move huge compressed obj from page to zspage").

And keep the memcg_data member, since as Yosry pointed out:
"When the pages are freed, put_page() -> folio_put() -> __folio_put() will call mem_cgroup_uncharge(). The latter will call folio_memcg() (which reads folio->memcg_data) to figure out if uncharging needs to be done.

There are also other similar code paths that will check folio->memcg_data. It is currently expected to be present for all folios. So until we have custom code paths per-folio type for allocation/freeing/etc, we need to keep folio->memcg_data present and properly initialized."

---
 mm/zpdesc.h   | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++
 mm/zsmalloc.c |  9 ++++---
 2 files changed, 77 insertions(+), 4 deletions(-)
 create mode 100644 mm/zpdesc.h
mm/zpdesc.h new file +72 -0
new file mode 100644
index 000000000000..721ef8861131
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* zpdesc.h: zswap.zpool memory descriptor
+ *
+ * Written by Alex Shi <[email protected]>
+ *	      Hyeonggon Yoo <[email protected]>
+ */
+#ifndef __MM_ZPDESC_H__
+#define __MM_ZPDESC_H__
+
+/*
+ * struct zpdesc -	Memory descriptor for zpool memory, now is for zsmalloc
+ * @flags:		Page flags, PG_private: identifies the first component page
+ * @lru:		Indirectly used by page migration
+ * @mops:		Used by page migration
+ * @next:		Next zpdesc in a zspage in zsmalloc zpool
+ * @handle:		For huge zspage in zsmalloc zpool
+ * @zspage:		Points to the zspage this zpdesc is a part of
+ * @first_obj_offset:	First object offset in zsmalloc zpool
+ * @_refcount:		Indirectly use by page migration
+ * @memcg_data:		Memory Control Group data.
+ *
+ * This struct overlays struct page for now. Do not modify without a good
+ * understanding of the issues.
+ */
+struct zpdesc {
+	unsigned long flags;
+	struct list_head lru;
+	struct movable_operations *mops;
+	union {
+		/* Next zpdescs in a zspage in zsmalloc zpool */
+		struct zpdesc *next;
+		/* For huge zspage in zsmalloc zpool */
+		unsigned long handle;
+	};
+	struct zspage *zspage;
+	unsigned int first_obj_offset;
+	atomic_t _refcount;
+#ifdef CONFIG_MEMCG
+	unsigned long memcg_data;
+#endif
+};
+#define ZPDESC_MATCH(pg, zp) \
+	static_assert(offsetof(struct page, pg) == offsetof(struct zpdesc, zp))
+
+ZPDESC_MATCH(flags, flags);
+ZPDESC_MATCH(lru, lru);
+ZPDESC_MATCH(mapping, mops);
+ZPDESC_MATCH(index, next);
+ZPDESC_MATCH(index, handle);
+ZPDESC_MATCH(private, zspage);
+ZPDESC_MATCH(page_type, first_obj_offset);
+ZPDESC_MATCH(_refcount, _refcount);
+#ifdef CONFIG_MEMCG
+ZPDESC_MATCH(memcg_data, memcg_data);
+#endif
+#undef ZPDESC_MATCH
+static_assert(sizeof(struct zpdesc) <= sizeof(struct page));
+
+#define zpdesc_page(zp)			(_Generic((zp),			\
+	const struct zpdesc *:		(const struct page *)(zp),	\
+	struct zpdesc *:		(struct page *)(zp)))
+
+/* Using folio conversion to skip compound_head checking */
+#define zpdesc_folio(zp)		(_Generic((zp),			\
+	const struct zpdesc *:		(const struct folio *)(zp),	\
+	struct zpdesc *:		(struct folio *)(zp)))
+
+#define page_zpdesc(p)			(_Generic((p),			\
+	const struct page *:		(const struct zpdesc *)(p),	\
+	struct page *:			(struct zpdesc *)(p)))
+
+#endif
mm/zsmalloc.c +5 -4
index 73a3ec5b21ad..5d3e27083c72 100644
@@ -64,6 +64,7 @@
 #include <linux/pagemap.h>
 #include <linux/fs.h>
 #include <linux/local_lock.h>
+#include "zpdesc.h"
 
 #define ZSPAGE_MAGIC	0x58
 
@@ -251,7 +252,7 @@ struct zspage {
 	};
 	unsigned int inuse;
 	unsigned int freeobj;
-	struct page *first_page;
+	struct zpdesc *first_zpdesc;
 	struct list_head list; /* fullness list */
 	struct zs_pool *pool;
 	rwlock_t lock;
@@ -446,7 +447,7 @@ static inline void mod_zspage_inuse(struct zspage *zspage, int val)
 
 static inline struct page *get_first_page(struct zspage *zspage)
 {
-	struct page *first_page = zspage->first_page;
+	struct page *first_page = zpdesc_page(zspage->first_zpdesc);
 
 	VM_BUG_ON_PAGE(!is_first_page(first_page), first_page);
 	return first_page;
@@ -939,7 +940,7 @@ static void create_page_chain(struct size_class *class, struct zspage *zspage,
 		set_page_private(page, (unsigned long)zspage);
 		page->index = 0;
 		if (i == 0) {
-			zspage->first_page = page;
+			zspage->first_zpdesc = page_zpdesc(page);
 			SetPagePrivate(page);
 			if (unlikely(class->objs_per_zspage == 1 &&
 					class->pages_per_zspage == 1))
@@ -1315,7 +1316,7 @@ static unsigned long obj_malloc(struct zs_pool *pool,
 		link->handle = handle | OBJ_ALLOCATED_TAG;
 	else
 		/* record handle to page->index */
-		zspage->first_page->index = handle | OBJ_ALLOCATED_TAG;
+		zspage->first_zpdesc->handle = handle | OBJ_ALLOCATED_TAG;
 
 	kunmap_atomic(vaddr);
 	mod_zspage_inuse(zspage, 1);
Signature · 1 line
2.46.0
#2 lore raw
Quoted 5 lines · On Mon, Sep 02, 2024 at 03:21:12PM +0800, [email protected] wrote:

And keep the memcg_data member, since as Yosry pointed out:
"When the pages are freed, put_page() -> folio_put() -> __folio_put() will call mem_cgroup_uncharge(). The latter will call folio_memcg() (which reads folio->memcg_data) to figure out if uncharging needs to be done.

... why does that mean we need to keep memcg_data in this definition? If it's unused, it will stay unused.

Quoted 5 lines

There are also other similar code paths that will check folio->memcg_data. It is currently expected to be present for all folios. So until we have custom code paths per-folio type for allocation/freeing/etc, we need to keep folio->memcg_data present and properly initialized."

...

mm/zpdesc.h line 28

Quoted 4 lines
mm/zpdesc.h new file +4 -0
+struct zpdesc {
+	unsigned long flags;
+	struct list_head lru;
+	struct movable_operations *mops;

Hm. I'm not sure this is a wise definition. While yes, we know it will only point to the mops, we always set the bottom two bits to '10'. So I think it's safer to make this 'unsigned long mops' and force people to _not_ use it directly.

#3 lore raw

PATCH v7 2/21 mm/zsmalloc: use zpdesc in trylock_zspage()/lock_zspage()

In reply to [email protected]

From: Alex Shi <[email protected]>

To use zpdesc in trylock_zspage()/lock_zspage() funcs, we add couple of helpers:
zpdesc_lock()/zpdesc_unlock()/zpdesc_trylock()/zpdesc_wait_locked() and zpdesc_get()/zpdesc_put() for this purpose.

Here we use the folio series func in guts for 2 reasons, one zswap.zpool only get single page, and use folio could save some compound_head checking; two, folio_put could bypass devmap checking that we don't need.

BTW, thanks Intel LKP found a build warning on the patch.

---
 mm/zpdesc.h   | 30 ++++++++++++++++++++++++
 mm/zsmalloc.c | 64 ++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 73 insertions(+), 21 deletions(-)
mm/zpdesc.h +30 -0
index 721ef8861131..782b5ad67cda 100644
@@ -69,4 +69,34 @@ static_assert(sizeof(struct zpdesc) <= sizeof(struct page));
 	const struct page *:		(const struct zpdesc *)(p),	\
 	struct page *:			(struct zpdesc *)(p)))
 
+static inline void zpdesc_lock(struct zpdesc *zpdesc)
+{
+	folio_lock(zpdesc_folio(zpdesc));
+}
+
+static inline bool zpdesc_trylock(struct zpdesc *zpdesc)
+{
+	return folio_trylock(zpdesc_folio(zpdesc));
+}
+
+static inline void zpdesc_unlock(struct zpdesc *zpdesc)
+{
+	folio_unlock(zpdesc_folio(zpdesc));
+}
+
+static inline void zpdesc_wait_locked(struct zpdesc *zpdesc)
+{
+	folio_wait_locked(zpdesc_folio(zpdesc));
+}
+
+static inline void zpdesc_get(struct zpdesc *zpdesc)
+{
+	folio_get(zpdesc_folio(zpdesc));
+}
+
+static inline void zpdesc_put(struct zpdesc *zpdesc)
+{
+	folio_put(zpdesc_folio(zpdesc));
+}
+
 #endif
mm/zsmalloc.c +43 -21

119 lines not on this page · raw message

Signature · 1 line
2.46.0
#4 lore raw

PATCH v7 3/21 mm/zsmalloc: convert __zs_map_object/__zs_unmap_object to use zpdesc

In reply to [email protected]

From: Hyeonggon Yoo <[email protected]>

These two functions take pointer to an array of struct page. Introduce zpdesc_kmap_atomic() and make __zs_{map,unmap}_object() take pointer to an array of zpdesc instead of page.

Add silly type casting when calling them. Casting will be removed late.

---
 mm/zsmalloc.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)
mm/zsmalloc.c +13 -8
index 9806b1629880..1b49f74fd728 100644
@@ -243,6 +243,11 @@ struct zs_pool {
 	atomic_t compaction_in_progress;
 };
 
+static inline void *zpdesc_kmap_atomic(struct zpdesc *zpdesc)
+{
+	return kmap_atomic(zpdesc_page(zpdesc));
+}
+
 struct zspage {
 	struct {
 		unsigned int huge:HUGE_BITS;
@@ -1054,7 +1059,7 @@ static inline void __zs_cpu_down(struct mapping_area *area)
 }
 
 static void *__zs_map_object(struct mapping_area *area,
-			struct page *pages[2], int off, int size)
+			struct zpdesc *zpdescs[2], int off, int size)
 {
 	int sizes[2];
 	void *addr;
@@ -1071,10 +1076,10 @@ static void *__zs_map_object(struct mapping_area *area,
 	sizes[1] = size - sizes[0];
 
 	/* copy object to per-cpu buffer */
-	addr = kmap_atomic(pages[0]);
+	addr = zpdesc_kmap_atomic(zpdescs[0]);
 	memcpy(buf, addr + off, sizes[0]);
 	kunmap_atomic(addr);
-	addr = kmap_atomic(pages[1]);
+	addr = zpdesc_kmap_atomic(zpdescs[1]);
 	memcpy(buf + sizes[0], addr, sizes[1]);
 	kunmap_atomic(addr);
 out:
@@ -1082,7 +1087,7 @@ static void *__zs_map_object(struct mapping_area *area,
 }
 
 static void __zs_unmap_object(struct mapping_area *area,
-			struct page *pages[2], int off, int size)
+			struct zpdesc *zpdescs[2], int off, int size)
 {
 	int sizes[2];
 	void *addr;
@@ -1101,10 +1106,10 @@ static void __zs_unmap_object(struct mapping_area *area,
 	sizes[1] = size - sizes[0];
 
 	/* copy per-cpu buffer to object */
-	addr = kmap_atomic(pages[0]);
+	addr = zpdesc_kmap_atomic(zpdescs[0]);
 	memcpy(addr + off, buf, sizes[0]);
 	kunmap_atomic(addr);
-	addr = kmap_atomic(pages[1]);
+	addr = zpdesc_kmap_atomic(zpdescs[1]);
 	memcpy(addr, buf + sizes[0], sizes[1]);
 	kunmap_atomic(addr);
 
@@ -1245,7 +1250,7 @@ void *zs_map_object(struct zs_pool *pool, unsigned long handle,
 	pages[1] = get_next_page(page);
 	BUG_ON(!pages[1]);
 
-	ret = __zs_map_object(area, pages, off, class->size);
+	ret = __zs_map_object(area, (struct zpdesc **)pages, off, class->size);
 out:
 	if (likely(!ZsHugePage(zspage)))
 		ret += ZS_HANDLE_SIZE;
@@ -1280,7 +1285,7 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
 		pages[1] = get_next_page(page);
 		BUG_ON(!pages[1]);
 
-		__zs_unmap_object(area, pages, off, class->size);
+		__zs_unmap_object(area, (struct zpdesc **)pages, off, class->size);
 	}
 	local_unlock(&zs_map_area.lock);
 
Signature · 1 line
2.46.0
#5 lore raw

PATCH v7 4/21 mm/zsmalloc: add and use pfn/zpdesc seeking funcs

In reply to [email protected]

From: Hyeonggon Yoo <[email protected]>

Add pfn_zpdesc conversion, convert obj_to_location() to take zpdesc and also convert its users to use zpdesc.

---
 mm/zpdesc.h   |  9 +++++++
 mm/zsmalloc.c | 75 ++++++++++++++++++++++++++-------------------------
 2 files changed, 47 insertions(+), 37 deletions(-)
mm/zpdesc.h +9 -0
index 782b5ad67cda..11083a1c2464 100644
@@ -99,4 +99,13 @@ static inline void zpdesc_put(struct zpdesc *zpdesc)
 	folio_put(zpdesc_folio(zpdesc));
 }
 
+static inline unsigned long zpdesc_pfn(struct zpdesc *zpdesc)
+{
+	return page_to_pfn(zpdesc_page(zpdesc));
+}
+
+static inline struct zpdesc *pfn_zpdesc(unsigned long pfn)
+{
+	return page_zpdesc(pfn_to_page(pfn));
+}
 #endif
mm/zsmalloc.c +38 -37

189 lines not on this page · raw message

Signature · 1 line
2.46.0
#6 lore raw

PATCH v7 5/21 mm/zsmalloc: convert obj_malloc() to use zpdesc

In reply to [email protected]

From: Hyeonggon Yoo <[email protected]>

Use get_first_zpdesc/get_next_zpdesc to replace get_first_page/get_next_page. no functional change.

---
 mm/zsmalloc.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
mm/zsmalloc.c +8 -8
index a7e73c0de039..664fff88a7f0 100644
@@ -1315,12 +1315,12 @@ EXPORT_SYMBOL_GPL(zs_huge_class_size);
 static unsigned long obj_malloc(struct zs_pool *pool,
 				struct zspage *zspage, unsigned long handle)
 {
-	int i, nr_page, offset;
+	int i, nr_zpdesc, offset;
 	unsigned long obj;
 	struct link_free *link;
 	struct size_class *class;
 
-	struct page *m_page;
+	struct zpdesc *m_zpdesc;
 	unsigned long m_offset;
 	void *vaddr;
 
@@ -1328,14 +1328,14 @@ static unsigned long obj_malloc(struct zs_pool *pool,
 	obj = get_freeobj(zspage);
 
 	offset = obj * class->size;
-	nr_page = offset >> PAGE_SHIFT;
+	nr_zpdesc = offset >> PAGE_SHIFT;
 	m_offset = offset_in_page(offset);
-	m_page = get_first_page(zspage);
+	m_zpdesc = get_first_zpdesc(zspage);
 
-	for (i = 0; i < nr_page; i++)
-		m_page = get_next_page(m_page);
+	for (i = 0; i < nr_zpdesc; i++)
+		m_zpdesc = get_next_zpdesc(m_zpdesc);
 
-	vaddr = kmap_atomic(m_page);
+	vaddr = zpdesc_kmap_atomic(m_zpdesc);
 	link = (struct link_free *)vaddr + m_offset / sizeof(*link);
 	set_freeobj(zspage, link->next >> OBJ_TAG_BITS);
 	if (likely(!ZsHugePage(zspage)))
@@ -1348,7 +1348,7 @@ static unsigned long obj_malloc(struct zs_pool *pool,
 	kunmap_atomic(vaddr);
 	mod_zspage_inuse(zspage, 1);
 
-	obj = location_to_obj(m_page, obj);
+	obj = location_to_obj(zpdesc_page(m_zpdesc), obj);
 	record_obj(handle, obj);
 
 	return obj;
Signature · 1 line
2.46.0
#7 lore raw

PATCH v7 6/21 mm/zsmalloc: convert create_page_chain() and its users to use zpdesc

In reply to [email protected]

From: Alex Shi <[email protected]>

Introduce a few helper functions for conversion to convert create_page_chain() to use zpdesc, then use zpdesc in replace_sub_page() too.

---
 mm/zpdesc.h   |   6 +++
 mm/zsmalloc.c | 109 ++++++++++++++++++++++++++++++++------------------
 2 files changed, 76 insertions(+), 39 deletions(-)
mm/zpdesc.h +6 -0
index 11083a1c2464..3a65a7d494b7 100644
@@ -108,4 +108,10 @@ static inline struct zpdesc *pfn_zpdesc(unsigned long pfn)
 {
 	return page_zpdesc(pfn_to_page(pfn));
 }
+
+static inline void __zpdesc_set_movable(struct zpdesc *zpdesc,
+					const struct movable_operations *mops)
+{
+	__SetPageMovable(zpdesc_page(zpdesc), mops);
+}
 #endif
mm/zsmalloc.c +70 -39

176 lines not on this page · raw message

Signature · 1 line
2.46.0
#8 lore raw

PATCH v7 7/21 mm/zsmalloc: convert obj_allocated() and related helpers to use zpdesc

In reply to [email protected]

From: Hyeonggon Yoo <[email protected]>

Convert obj_allocated(), and related helpers to take zpdesc. Also make its callers to cast (struct page *) to (struct zpdesc *) when calling them. The users will be converted gradually as there are many.

---
 mm/zsmalloc.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
mm/zsmalloc.c +10 -10
index 6afc3e642e02..46d8be5cb4b7 100644
@@ -833,15 +833,15 @@ static unsigned long handle_to_obj(unsigned long handle)
 	return *(unsigned long *)handle;
 }
 
-static inline bool obj_allocated(struct page *page, void *obj,
+static inline bool obj_allocated(struct zpdesc *zpdesc, void *obj,
 				 unsigned long *phandle)
 {
 	unsigned long handle;
-	struct zspage *zspage = get_zspage(page);
+	struct zspage *zspage = get_zspage(zpdesc_page(zpdesc));
 
 	if (unlikely(ZsHugePage(zspage))) {
-		VM_BUG_ON_PAGE(!is_first_page(page), page);
-		handle = page->index;
+		VM_BUG_ON_PAGE(!is_first_zpdesc(zpdesc), zpdesc_page(zpdesc));
+		handle = zpdesc->handle;
 	} else
 		handle = *(unsigned long *)obj;
 
@@ -1590,18 +1590,18 @@ static void zs_object_copy(struct size_class *class, unsigned long dst,
  * return handle.
  */
 static unsigned long find_alloced_obj(struct size_class *class,
-				      struct page *page, int *obj_idx)
+				      struct zpdesc *zpdesc, int *obj_idx)
 {
 	unsigned int offset;
 	int index = *obj_idx;
 	unsigned long handle = 0;
-	void *addr = kmap_atomic(page);
+	void *addr = zpdesc_kmap_atomic(zpdesc);
 
-	offset = get_first_obj_offset(page);
+	offset = get_first_obj_offset(zpdesc_page(zpdesc));
 	offset += class->size * index;
 
 	while (offset < PAGE_SIZE) {
-		if (obj_allocated(page, addr + offset, &handle))
+		if (obj_allocated(zpdesc, addr + offset, &handle))
 			break;
 
 		offset += class->size;
@@ -1625,7 +1625,7 @@ static void migrate_zspage(struct zs_pool *pool, struct zspage *src_zspage,
 	struct size_class *class = pool->size_class[src_zspage->class];
 
 	while (1) {
-		handle = find_alloced_obj(class, s_page, &obj_idx);
+		handle = find_alloced_obj(class, page_zpdesc(s_page), &obj_idx);
 		if (!handle) {
 			s_page = get_next_page(s_page);
 			if (!s_page)
@@ -1858,7 +1858,7 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
 
 	for (addr = s_addr + offset; addr < s_addr + PAGE_SIZE;
 					addr += class->size) {
-		if (obj_allocated(page, addr, &handle)) {
+		if (obj_allocated(page_zpdesc(page), addr, &handle)) {
 
 			old_obj = handle_to_obj(handle);
 			obj_to_location(old_obj, &dummy, &obj_idx);
Signature · 1 line
2.46.0
#9 lore raw

PATCH v7 8/21 mm/zsmalloc: convert init_zspage() to use zpdesc

In reply to [email protected]

From: Hyeonggon Yoo <[email protected]>

Replace get_first/next_page func series and kmap_atomic to new helper, no functional change.

---
 mm/zsmalloc.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
mm/zsmalloc.c +8 -8
index 46d8be5cb4b7..01c5be6f4c96 100644
@@ -935,16 +935,16 @@ static void init_zspage(struct size_class *class, struct zspage *zspage)
 {
 	unsigned int freeobj = 1;
 	unsigned long off = 0;
-	struct page *page = get_first_page(zspage);
+	struct zpdesc *zpdesc = get_first_zpdesc(zspage);
 
-	while (page) {
-		struct page *next_page;
+	while (zpdesc) {
+		struct zpdesc *next_zpdesc;
 		struct link_free *link;
 		void *vaddr;
 
-		set_first_obj_offset(page, off);
+		set_first_obj_offset(zpdesc_page(zpdesc), off);
 
-		vaddr = kmap_atomic(page);
+		vaddr = zpdesc_kmap_atomic(zpdesc);
 		link = (struct link_free *)vaddr + off / sizeof(*link);
 
 		while ((off += class->size) < PAGE_SIZE) {
@@ -957,8 +957,8 @@ static void init_zspage(struct size_class *class, struct zspage *zspage)
 		 * page, which must point to the first object on the next
 		 * page (if present)
 		 */
-		next_page = get_next_page(page);
-		if (next_page) {
+		next_zpdesc = get_next_zpdesc(zpdesc);
+		if (next_zpdesc) {
 			link->next = freeobj++ << OBJ_TAG_BITS;
 		} else {
 			/*
@@ -968,7 +968,7 @@ static void init_zspage(struct size_class *class, struct zspage *zspage)
 			link->next = -1UL << OBJ_TAG_BITS;
 		}
 		kunmap_atomic(vaddr);
-		page = next_page;
+		zpdesc = next_zpdesc;
 		off %= PAGE_SIZE;
 	}
 
Signature · 1 line
2.46.0
#10 lore raw

PATCH v7 9/21 mm/zsmalloc: convert obj_to_page() and zs_free() to use zpdesc

In reply to [email protected]

From: Hyeonggon Yoo <[email protected]>

Rename obj_to_page() to obj_to_zpdesc() and also convert it and its user zs_free() to use zpdesc.

---
 mm/zsmalloc.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
mm/zsmalloc.c +5 -5
index 01c5be6f4c96..90d93cdc5df6 100644
@@ -808,9 +808,9 @@ static void obj_to_location(unsigned long obj, struct zpdesc **zpdesc,
 	*obj_idx = (obj & OBJ_INDEX_MASK);
 }
 
-static void obj_to_page(unsigned long obj, struct page **page)
+static void obj_to_zpdesc(unsigned long obj, struct zpdesc **zpdesc)
 {
-	*page = pfn_to_page(obj >> OBJ_INDEX_BITS);
+	*zpdesc = pfn_zpdesc(obj >> OBJ_INDEX_BITS);
 }
 
 /**
@@ -1483,7 +1483,7 @@ static void obj_free(int class_size, unsigned long obj)
 void zs_free(struct zs_pool *pool, unsigned long handle)
 {
 	struct zspage *zspage;
-	struct page *f_page;
+	struct zpdesc *f_zpdesc;
 	unsigned long obj;
 	struct size_class *class;
 	int fullness;
@@ -1497,8 +1497,8 @@ void zs_free(struct zs_pool *pool, unsigned long handle)
 	 */
 	read_lock(&pool->migrate_lock);
 	obj = handle_to_obj(handle);
-	obj_to_page(obj, &f_page);
-	zspage = get_zspage(f_page);
+	obj_to_zpdesc(obj, &f_zpdesc);
+	zspage = get_zspage(zpdesc_page(f_zpdesc));
 	class = zspage_class(pool, zspage);
 	spin_lock(&class->lock);
 	read_unlock(&pool->migrate_lock);
Signature · 1 line
2.46.0
#11 lore raw

PATCH v7 10/21 mm/zsmalloc: add zpdesc_is_isolated()/zpdesc_zone() helper for zs_page_migrate()

In reply to [email protected]

From: Hyeonggon Yoo <[email protected]>

To convert page to zpdesc in zs_page_migrate(), we added zpdesc_is_isolated()/zpdesc_zone() helpers. No functional change.

---
 mm/zpdesc.h   | 11 +++++++++++
 mm/zsmalloc.c | 30 ++++++++++++++++--------------
 2 files changed, 27 insertions(+), 14 deletions(-)
mm/zpdesc.h +11 -0
index 3a65a7d494b7..4b42d8517fcb 100644
@@ -114,4 +114,15 @@ static inline void __zpdesc_set_movable(struct zpdesc *zpdesc,
 {
 	__SetPageMovable(zpdesc_page(zpdesc), mops);
 }
+
+static inline bool zpdesc_is_isolated(struct zpdesc *zpdesc)
+{
+	return PageIsolated(zpdesc_page(zpdesc));
+}
+
+static inline struct zone *zpdesc_zone(struct zpdesc *zpdesc)
+{
+	return page_zone(zpdesc_page(zpdesc));
+}
+
 #endif
mm/zsmalloc.c +16 -14
index 90d93cdc5df6..caa4a7883ab8 100644
@@ -1817,19 +1817,21 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
 	struct size_class *class;
 	struct zspage *zspage;
 	struct zpdesc *dummy;
+	struct zpdesc *newzpdesc = page_zpdesc(newpage);
+	struct zpdesc *zpdesc = page_zpdesc(page);
 	void *s_addr, *d_addr, *addr;
 	unsigned int offset;
 	unsigned long handle;
 	unsigned long old_obj, new_obj;
 	unsigned int obj_idx;
 
-	VM_BUG_ON_PAGE(!PageIsolated(page), page);
+	VM_BUG_ON_PAGE(!zpdesc_is_isolated(zpdesc), zpdesc_page(zpdesc));
 
 	/* We're committed, tell the world that this is a Zsmalloc page. */
-	__SetPageZsmalloc(newpage);
+	__SetPageZsmalloc(zpdesc_page(newzpdesc));
 
 	/* The page is locked, so this pointer must remain valid */
-	zspage = get_zspage(page);
+	zspage = get_zspage(zpdesc_page(zpdesc));
 	pool = zspage->pool;
 
 	/*
@@ -1846,30 +1848,30 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
 	/* the migrate_write_lock protects zpage access via zs_map_object */
 	migrate_write_lock(zspage);
 
-	offset = get_first_obj_offset(page);
-	s_addr = kmap_atomic(page);
+	offset = get_first_obj_offset(zpdesc_page(zpdesc));
+	s_addr = zpdesc_kmap_atomic(zpdesc);
 
 	/*
 	 * Here, any user cannot access all objects in the zspage so let's move.
 	 */
-	d_addr = kmap_atomic(newpage);
+	d_addr = zpdesc_kmap_atomic(newzpdesc);
 	copy_page(d_addr, s_addr);
 	kunmap_atomic(d_addr);
 
 	for (addr = s_addr + offset; addr < s_addr + PAGE_SIZE;
 					addr += class->size) {
-		if (obj_allocated(page_zpdesc(page), addr, &handle)) {
+		if (obj_allocated(zpdesc, addr, &handle)) {
 
 			old_obj = handle_to_obj(handle);
 			obj_to_location(old_obj, &dummy, &obj_idx);
-			new_obj = (unsigned long)location_to_obj(newpage,
+			new_obj = (unsigned long)location_to_obj(zpdesc_page(newzpdesc),
 								obj_idx);
 			record_obj(handle, new_obj);
 		}
 	}
 	kunmap_atomic(s_addr);
 
-	replace_sub_page(class, zspage, page_zpdesc(newpage), page_zpdesc(page));
+	replace_sub_page(class, zspage, newzpdesc, zpdesc);
 	/*
 	 * Since we complete the data copy and set up new zspage structure,
 	 * it's okay to release migration_lock.
@@ -1878,14 +1880,14 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
 	spin_unlock(&class->lock);
 	migrate_write_unlock(zspage);
 
-	get_page(newpage);
-	if (page_zone(newpage) != page_zone(page)) {
-		dec_zone_page_state(page, NR_ZSPAGES);
-		inc_zone_page_state(newpage, NR_ZSPAGES);
+	zpdesc_get(newzpdesc);
+	if (zpdesc_zone(newzpdesc) != zpdesc_zone(zpdesc)) {
+		zpdesc_dec_zone_page_state(zpdesc);
+		zpdesc_inc_zone_page_state(newzpdesc);
 	}
 
 	reset_page(page);
-	put_page(page);
+	zpdesc_put(zpdesc);
 
 	return MIGRATEPAGE_SUCCESS;
 }
Signature · 1 line
2.46.0
#12 lore raw

PATCH v7 11/21 mm/zsmalloc: rename reset_page to reset_zpdesc and use zpdesc in it

In reply to [email protected]

From: Alex Shi <[email protected]>

zpdesc.zspage matches with page.private, zpdesc.next matches with page.index. They will be reset in reset_page() which is called prior to free base pages of a zspage.
Use zpdesc to replace page struct and rename it to reset_zpdesc(), few page helper still left since they are used too widely.

---
 mm/zsmalloc.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
mm/zsmalloc.c +7 -5
index caa4a7883ab8..b03bd7e07e98 100644
@@ -853,12 +853,14 @@ static inline bool obj_allocated(struct zpdesc *zpdesc, void *obj,
 	return true;
 }
 
-static void reset_page(struct page *page)
+static void reset_zpdesc(struct zpdesc *zpdesc)
 {
+	struct page *page = zpdesc_page(zpdesc);
+
 	__ClearPageMovable(page);
 	ClearPagePrivate(page);
-	set_page_private(page, 0);
-	page->index = 0;
+	zpdesc->zspage = NULL;
+	zpdesc->next = NULL;
 	__ClearPageZsmalloc(page);
 }
 
@@ -897,7 +899,7 @@ static void __free_zspage(struct zs_pool *pool, struct size_class *class,
 	do {
 		VM_BUG_ON_PAGE(!PageLocked(page), page);
 		next = get_next_page(page);
-		reset_page(page);
+		reset_zpdesc(page_zpdesc(page));
 		unlock_page(page);
 		dec_zone_page_state(page, NR_ZSPAGES);
 		put_page(page);
@@ -1886,7 +1888,7 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
 		zpdesc_inc_zone_page_state(newzpdesc);
 	}
 
-	reset_page(page);
+	reset_zpdesc(zpdesc);
 	zpdesc_put(zpdesc);
 
 	return MIGRATEPAGE_SUCCESS;
Signature · 1 line
2.46.0
#13 lore raw

PATCH v7 12/21 mm/zsmalloc: convert __free_zspage() to use zdsesc

In reply to [email protected]

From: Hyeonggon Yoo <[email protected]>

Introduce zpdesc_is_locked() and convert __free_zspage() to use zpdesc.

---
 mm/zpdesc.h   |  4 ++++
 mm/zsmalloc.c | 20 ++++++++++----------
 2 files changed, 14 insertions(+), 10 deletions(-)
mm/zpdesc.h +4 -0
index 4b42d8517fcb..a1834d36ccfc 100644
@@ -125,4 +125,8 @@ static inline struct zone *zpdesc_zone(struct zpdesc *zpdesc)
 	return page_zone(zpdesc_page(zpdesc));
 }
 
+static inline bool zpdesc_is_locked(struct zpdesc *zpdesc)
+{
+	return PageLocked(zpdesc_page(zpdesc));
+}
 #endif
mm/zsmalloc.c +10 -10
index b03bd7e07e98..5a8fd5fbc962 100644
@@ -888,23 +888,23 @@ static int trylock_zspage(struct zspage *zspage)
 static void __free_zspage(struct zs_pool *pool, struct size_class *class,
 				struct zspage *zspage)
 {
-	struct page *page, *next;
+	struct zpdesc *zpdesc, *next;
 
 	assert_spin_locked(&class->lock);
 
 	VM_BUG_ON(get_zspage_inuse(zspage));
 	VM_BUG_ON(zspage->fullness != ZS_INUSE_RATIO_0);
 
-	next = page = get_first_page(zspage);
+	next = zpdesc = get_first_zpdesc(zspage);
 	do {
-		VM_BUG_ON_PAGE(!PageLocked(page), page);
-		next = get_next_page(page);
-		reset_zpdesc(page_zpdesc(page));
-		unlock_page(page);
-		dec_zone_page_state(page, NR_ZSPAGES);
-		put_page(page);
-		page = next;
-	} while (page != NULL);
+		VM_BUG_ON_PAGE(!zpdesc_is_locked(zpdesc), zpdesc_page(zpdesc));
+		next = get_next_zpdesc(zpdesc);
+		reset_zpdesc(zpdesc);
+		zpdesc_unlock(zpdesc);
+		zpdesc_dec_zone_page_state(zpdesc);
+		zpdesc_put(zpdesc);
+		zpdesc = next;
+	} while (zpdesc != NULL);
 
 	cache_free_zspage(pool, zspage);
 
Signature · 1 line
2.46.0
#14 lore raw

PATCH v7 13/21 mm/zsmalloc: convert location_to_obj() to take zpdesc

In reply to [email protected]

From: Hyeonggon Yoo <[email protected]>

As all users of location_to_obj() now use zpdesc, convert location_to_obj() to take zpdesc.

---
 mm/zsmalloc.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)
mm/zsmalloc.c +6 -7
index 5a8fd5fbc962..f94c3a6653c7 100644
@@ -814,15 +814,15 @@ static void obj_to_zpdesc(unsigned long obj, struct zpdesc **zpdesc)
 }
 
 /**
- * location_to_obj - get obj value encoded from (<page>, <obj_idx>)
- * @page: page object resides in zspage
+ * location_to_obj - get obj value encoded from (<zpdesc>, <obj_idx>)
+ * @zpdesc: zpdesc object resides in zspage
  * @obj_idx: object index
  */
-static unsigned long location_to_obj(struct page *page, unsigned int obj_idx)
+static unsigned long location_to_obj(struct zpdesc *zpdesc, unsigned int obj_idx)
 {
 	unsigned long obj;
 
-	obj = page_to_pfn(page) << OBJ_INDEX_BITS;
+	obj = zpdesc_pfn(zpdesc) << OBJ_INDEX_BITS;
 	obj |= obj_idx & OBJ_INDEX_MASK;
 
 	return obj;
@@ -1379,7 +1379,7 @@ static unsigned long obj_malloc(struct zs_pool *pool,
 	kunmap_atomic(vaddr);
 	mod_zspage_inuse(zspage, 1);
 
-	obj = location_to_obj(zpdesc_page(m_zpdesc), obj);
+	obj = location_to_obj(m_zpdesc, obj);
 	record_obj(handle, obj);
 
 	return obj;
@@ -1866,8 +1866,7 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
 
 			old_obj = handle_to_obj(handle);
 			obj_to_location(old_obj, &dummy, &obj_idx);
-			new_obj = (unsigned long)location_to_obj(zpdesc_page(newzpdesc),
-								obj_idx);
+			new_obj = (unsigned long)location_to_obj(newzpdesc, obj_idx);
 			record_obj(handle, new_obj);
 		}
 	}
Signature · 1 line
2.46.0
#15 lore raw

PATCH v7 14/21 mm/zsmalloc: convert migrate_zspage() to use zpdesc

In reply to [email protected]

From: Hyeonggon Yoo <[email protected]>

Use get_first_zpdesc/get_next_zpdesc to replace get_first/next_page. No functional change.

---
 mm/zsmalloc.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
mm/zsmalloc.c +4 -4
index f94c3a6653c7..aeb8cab5767b 100644
@@ -1623,14 +1623,14 @@ static void migrate_zspage(struct zs_pool *pool, struct zspage *src_zspage,
 	unsigned long used_obj, free_obj;
 	unsigned long handle;
 	int obj_idx = 0;
-	struct page *s_page = get_first_page(src_zspage);
+	struct zpdesc *s_zpdesc = get_first_zpdesc(src_zspage);
 	struct size_class *class = pool->size_class[src_zspage->class];
 
 	while (1) {
-		handle = find_alloced_obj(class, page_zpdesc(s_page), &obj_idx);
+		handle = find_alloced_obj(class, s_zpdesc, &obj_idx);
 		if (!handle) {
-			s_page = get_next_page(s_page);
-			if (!s_page)
+			s_zpdesc = get_next_zpdesc(s_zpdesc);
+			if (!s_zpdesc)
 				break;
 			obj_idx = 0;
 			continue;
Signature · 1 line
2.46.0
#16 lore raw

PATCH v7 15/21 mm/zsmalloc: convert get_zspage() to take zpdesc

In reply to [email protected]

From: Hyeonggon Yoo <[email protected]>

Now that all users except get_next_page() (which will be removed in later patch) use zpdesc, convert get_zspage() to take zpdesc instead of page.

---
 mm/zsmalloc.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
mm/zsmalloc.c +10 -10
index aeb8cab5767b..d9251450ec60 100644
@@ -767,9 +767,9 @@ static int fix_fullness_group(struct size_class *class, struct zspage *zspage)
 	return newfg;
 }
 
-static struct zspage *get_zspage(struct page *page)
+static struct zspage *get_zspage(struct zpdesc *zpdesc)
 {
-	struct zspage *zspage = (struct zspage *)page_private(page);
+	struct zspage *zspage = zpdesc->zspage;
 
 	BUG_ON(zspage->magic != ZSPAGE_MAGIC);
 	return zspage;
@@ -777,7 +777,7 @@ static struct zspage *get_zspage(struct page *page)
 
 static struct page *get_next_page(struct page *page)
 {
-	struct zspage *zspage = get_zspage(page);
+	struct zspage *zspage = get_zspage(page_zpdesc(page));
 
 	if (unlikely(ZsHugePage(zspage)))
 		return NULL;
@@ -787,7 +787,7 @@ static struct page *get_next_page(struct page *page)
 
 static struct zpdesc *get_next_zpdesc(struct zpdesc *zpdesc)
 {
-	struct zspage *zspage = get_zspage(zpdesc_page(zpdesc));
+	struct zspage *zspage = get_zspage(zpdesc);
 
 	if (unlikely(ZsHugePage(zspage)))
 		return NULL;
@@ -837,7 +837,7 @@ static inline bool obj_allocated(struct zpdesc *zpdesc, void *obj,
 				 unsigned long *phandle)
 {
 	unsigned long handle;
-	struct zspage *zspage = get_zspage(zpdesc_page(zpdesc));
+	struct zspage *zspage = get_zspage(zpdesc);
 
 	if (unlikely(ZsHugePage(zspage))) {
 		VM_BUG_ON_PAGE(!is_first_zpdesc(zpdesc), zpdesc_page(zpdesc));
@@ -1252,7 +1252,7 @@ void *zs_map_object(struct zs_pool *pool, unsigned long handle,
 	read_lock(&pool->migrate_lock);
 	obj = handle_to_obj(handle);
 	obj_to_location(obj, &zpdesc, &obj_idx);
-	zspage = get_zspage(zpdesc_page(zpdesc));
+	zspage = get_zspage(zpdesc);
 
 	/*
 	 * migration cannot move any zpages in this zspage. Here, class->lock
@@ -1302,7 +1302,7 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
 
 	obj = handle_to_obj(handle);
 	obj_to_location(obj, &zpdesc, &obj_idx);
-	zspage = get_zspage(zpdesc_page(zpdesc));
+	zspage = get_zspage(zpdesc);
 	class = zspage_class(pool, zspage);
 	off = offset_in_page(class->size * obj_idx);
 
@@ -1466,7 +1466,7 @@ static void obj_free(int class_size, unsigned long obj)
 
 	obj_to_location(obj, &f_zpdesc, &f_objidx);
 	f_offset = offset_in_page(class_size * f_objidx);
-	zspage = get_zspage(zpdesc_page(f_zpdesc));
+	zspage = get_zspage(f_zpdesc);
 
 	vaddr = zpdesc_kmap_atomic(f_zpdesc);
 	link = (struct link_free *)(vaddr + f_offset);
@@ -1500,7 +1500,7 @@ void zs_free(struct zs_pool *pool, unsigned long handle)
 	read_lock(&pool->migrate_lock);
 	obj = handle_to_obj(handle);
 	obj_to_zpdesc(obj, &f_zpdesc);
-	zspage = get_zspage(zpdesc_page(f_zpdesc));
+	zspage = get_zspage(f_zpdesc);
 	class = zspage_class(pool, zspage);
 	spin_lock(&class->lock);
 	read_unlock(&pool->migrate_lock);
@@ -1833,7 +1833,7 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
 	__SetPageZsmalloc(zpdesc_page(newzpdesc));
 
 	/* The page is locked, so this pointer must remain valid */
-	zspage = get_zspage(zpdesc_page(zpdesc));
+	zspage = get_zspage(zpdesc);
 	pool = zspage->pool;
 
 	/*
Signature · 1 line
2.46.0
#17 lore raw

PATCH v7 16/21 mm/zsmalloc: convert SetZsPageMovable and remove unused funcs

In reply to [email protected]

From: Alex Shi <[email protected]>

Convert SetZsPageMovable() to use zpdesc, and then remove unused
funcs: get_next_page()/get_first_page()/is_first_page().

---
 mm/zsmalloc.c | 33 +++++----------------------------
 1 file changed, 5 insertions(+), 28 deletions(-)
mm/zsmalloc.c +5 -28
index d9251450ec60..3b98daa63ece 100644
@@ -462,11 +462,6 @@ static DEFINE_PER_CPU(struct mapping_area, zs_map_area) = {
 	.lock	= INIT_LOCAL_LOCK(lock),
 };
 
-static __maybe_unused int is_first_page(struct page *page)
-{
-	return PagePrivate(page);
-}
-
 static inline bool is_first_zpdesc(struct zpdesc *zpdesc)
 {
 	return PagePrivate(zpdesc_page(zpdesc));
@@ -483,14 +478,6 @@ static inline void mod_zspage_inuse(struct zspage *zspage, int val)
 	zspage->inuse += val;
 }
 
-static inline struct page *get_first_page(struct zspage *zspage)
-{
-	struct page *first_page = zpdesc_page(zspage->first_zpdesc);
-
-	VM_BUG_ON_PAGE(!is_first_page(first_page), first_page);
-	return first_page;
-}
-
 static struct zpdesc *get_first_zpdesc(struct zspage *zspage)
 {
 	struct zpdesc *first_zpdesc = zspage->first_zpdesc;
@@ -775,16 +762,6 @@ static struct zspage *get_zspage(struct zpdesc *zpdesc)
 	return zspage;
 }
 
-static struct page *get_next_page(struct page *page)
-{
-	struct zspage *zspage = get_zspage(page_zpdesc(page));
-
-	if (unlikely(ZsHugePage(zspage)))
-		return NULL;
-
-	return (struct page *)page->index;
-}
-
 static struct zpdesc *get_next_zpdesc(struct zpdesc *zpdesc)
 {
 	struct zspage *zspage = get_zspage(zpdesc);
@@ -1957,13 +1934,13 @@ static void init_deferred_free(struct zs_pool *pool)
 
 static void SetZsPageMovable(struct zs_pool *pool, struct zspage *zspage)
 {
-	struct page *page = get_first_page(zspage);
+	struct zpdesc *zpdesc = get_first_zpdesc(zspage);
 
 	do {
-		WARN_ON(!trylock_page(page));
-		__SetPageMovable(page, &zsmalloc_mops);
-		unlock_page(page);
-	} while ((page = get_next_page(page)) != NULL);
+		WARN_ON(!zpdesc_trylock(zpdesc));
+		__zpdesc_set_movable(zpdesc, &zsmalloc_mops);
+		zpdesc_unlock(zpdesc);
+	} while ((zpdesc = get_next_zpdesc(zpdesc)) != NULL);
 }
 #else
 static inline void zs_flush_migration(struct zs_pool *pool) { }
Signature · 1 line
2.46.0
#18 lore raw

PATCH v7 17/21 mm/zsmalloc: convert get/set_first_obj_offset() to take zpdesc

In reply to [email protected]

From: Alex Shi <[email protected]>

Now that all users of get/set_first_obj_offset() are converted to use zpdesc, convert them to take zpdesc.

---
 mm/zsmalloc.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)
mm/zsmalloc.c +14 -14
index 3b98daa63ece..839fe7eaca8a 100644
@@ -488,20 +488,20 @@ static struct zpdesc *get_first_zpdesc(struct zspage *zspage)
 
 #define FIRST_OBJ_PAGE_TYPE_MASK	0xffffff
 
-static inline unsigned int get_first_obj_offset(struct page *page)
+static inline unsigned int get_first_obj_offset(struct zpdesc *zpdesc)
 {
-	VM_WARN_ON_ONCE(!PageZsmalloc(page));
-	return page->page_type & FIRST_OBJ_PAGE_TYPE_MASK;
+	VM_WARN_ON_ONCE(!PageZsmalloc(zpdesc_page(zpdesc)));
+	return zpdesc->first_obj_offset & FIRST_OBJ_PAGE_TYPE_MASK;
 }
 
-static inline void set_first_obj_offset(struct page *page, unsigned int offset)
+static inline void set_first_obj_offset(struct zpdesc *zpdesc, unsigned int offset)
 {
-	/* With 24 bits available, we can support offsets into 16 MiB pages. */
-	BUILD_BUG_ON(PAGE_SIZE > SZ_16M);
-	VM_WARN_ON_ONCE(!PageZsmalloc(page));
+	/* With 16 bit available, we can support offsets into 64 KiB pages. */
+	BUILD_BUG_ON(PAGE_SIZE > SZ_64K);
+	VM_WARN_ON_ONCE(!PageZsmalloc(zpdesc_page(zpdesc)));
 	VM_WARN_ON_ONCE(offset & ~FIRST_OBJ_PAGE_TYPE_MASK);
-	page->page_type &= ~FIRST_OBJ_PAGE_TYPE_MASK;
-	page->page_type |= offset & FIRST_OBJ_PAGE_TYPE_MASK;
+	zpdesc->first_obj_offset &= ~FIRST_OBJ_PAGE_TYPE_MASK;
+	zpdesc->first_obj_offset |= offset & FIRST_OBJ_PAGE_TYPE_MASK;
 }
 
 static inline unsigned int get_freeobj(struct zspage *zspage)
@@ -921,7 +921,7 @@ static void init_zspage(struct size_class *class, struct zspage *zspage)
 		struct link_free *link;
 		void *vaddr;
 
-		set_first_obj_offset(zpdesc_page(zpdesc), off);
+		set_first_obj_offset(zpdesc, off);
 
 		vaddr = zpdesc_kmap_atomic(zpdesc);
 		link = (struct link_free *)vaddr + off / sizeof(*link);
@@ -1576,7 +1576,7 @@ static unsigned long find_alloced_obj(struct size_class *class,
 	unsigned long handle = 0;
 	void *addr = zpdesc_kmap_atomic(zpdesc);
 
-	offset = get_first_obj_offset(zpdesc_page(zpdesc));
+	offset = get_first_obj_offset(zpdesc);
 	offset += class->size * index;
 
 	while (offset < PAGE_SIZE) {
@@ -1771,8 +1771,8 @@ static void replace_sub_page(struct size_class *class, struct zspage *zspage,
 	} while ((zpdesc = get_next_zpdesc(zpdesc)) != NULL);
 
 	create_page_chain(class, zspage, zpdescs);
-	first_obj_offset = get_first_obj_offset(zpdesc_page(oldzpdesc));
-	set_first_obj_offset(zpdesc_page(newzpdesc), first_obj_offset);
+	first_obj_offset = get_first_obj_offset(oldzpdesc);
+	set_first_obj_offset(newzpdesc, first_obj_offset);
 	if (unlikely(ZsHugePage(zspage)))
 		newzpdesc->handle = oldzpdesc->handle;
 	__zpdesc_set_movable(newzpdesc, &zsmalloc_mops);
@@ -1827,7 +1827,7 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
 	/* the migrate_write_lock protects zpage access via zs_map_object */
 	migrate_write_lock(zspage);
 
-	offset = get_first_obj_offset(zpdesc_page(zpdesc));
+	offset = get_first_obj_offset(zpdesc);
 	s_addr = zpdesc_kmap_atomic(zpdesc);
 
 	/*
Signature · 1 line
2.46.0
#19 lore raw

PATCH v7 18/21 mm/zsmalloc: introduce __zpdesc_clear_movable

In reply to [email protected]

From: Alex Shi <[email protected]>

Add a helper __zpdesc_clear_movable() for __ClearPageMovable(), and use it in callers to make code clear.

---
 mm/zpdesc.h   | 5 +++++
 mm/zsmalloc.c | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)
mm/zpdesc.h +5 -0
index a1834d36ccfc..747a2d410a35 100644
@@ -115,6 +115,11 @@ static inline void __zpdesc_set_movable(struct zpdesc *zpdesc,
 	__SetPageMovable(zpdesc_page(zpdesc), mops);
 }
 
+static inline void __zpdesc_clear_movable(struct zpdesc *zpdesc)
+{
+	__ClearPageMovable(zpdesc_page(zpdesc));
+}
+
 static inline bool zpdesc_is_isolated(struct zpdesc *zpdesc)
 {
 	return PageIsolated(zpdesc_page(zpdesc));
mm/zsmalloc.c +1 -1
index 839fe7eaca8a..107973a2a36e 100644
@@ -834,7 +834,7 @@ static void reset_zpdesc(struct zpdesc *zpdesc)
 {
 	struct page *page = zpdesc_page(zpdesc);
 
-	__ClearPageMovable(page);
+	__zpdesc_clear_movable(zpdesc);
 	ClearPagePrivate(page);
 	zpdesc->zspage = NULL;
 	zpdesc->next = NULL;
Signature · 1 line
2.46.0
#20 lore raw

PATCH v7 19/21 mm/zsmalloc: introduce __zpdesc_clear/set_zsmalloc()

In reply to [email protected]

From: Alex Shi <[email protected]>

Add helper __zpdesc_clear_zsmalloc() for __ClearPageZsmalloc(), __zpdesc_set_zsmalloc() for __SetPageZsmalloc(), and use them in callers.

---
 mm/zpdesc.h   | 10 ++++++++++
 mm/zsmalloc.c |  8 ++++----
 2 files changed, 14 insertions(+), 4 deletions(-)
mm/zpdesc.h +10 -0
index 747a2d410a35..33f599081281 100644
@@ -120,6 +120,16 @@ static inline void __zpdesc_clear_movable(struct zpdesc *zpdesc)
 	__ClearPageMovable(zpdesc_page(zpdesc));
 }
 
+static inline void __zpdesc_set_zsmalloc(struct zpdesc *zpdesc)
+{
+	__SetPageZsmalloc(zpdesc_page(zpdesc));
+}
+
+static inline void __zpdesc_clear_zsmalloc(struct zpdesc *zpdesc)
+{
+	__ClearPageZsmalloc(zpdesc_page(zpdesc));
+}
+
 static inline bool zpdesc_is_isolated(struct zpdesc *zpdesc)
 {
 	return PageIsolated(zpdesc_page(zpdesc));
mm/zsmalloc.c +4 -4
index 107973a2a36e..411621f00a02 100644
@@ -838,7 +838,7 @@ static void reset_zpdesc(struct zpdesc *zpdesc)
 	ClearPagePrivate(page);
 	zpdesc->zspage = NULL;
 	zpdesc->next = NULL;
-	__ClearPageZsmalloc(page);
+	__zpdesc_clear_zsmalloc(zpdesc);
 }
 
 static int trylock_zspage(struct zspage *zspage)
@@ -1011,13 +1011,13 @@ static struct zspage *alloc_zspage(struct zs_pool *pool,
 		if (!zpdesc) {
 			while (--i >= 0) {
 				zpdesc_dec_zone_page_state(zpdescs[i]);
-				__ClearPageZsmalloc(zpdesc_page(zpdescs[i]));
+				__zpdesc_clear_zsmalloc(zpdescs[i]);
 				free_zpdesc(zpdescs[i]);
 			}
 			cache_free_zspage(pool, zspage);
 			return NULL;
 		}
-		__SetPageZsmalloc(zpdesc_page(zpdesc));
+		__zpdesc_set_zsmalloc(zpdesc);
 
 		zpdesc_inc_zone_page_state(zpdesc);
 		zpdescs[i] = zpdesc;
@@ -1807,7 +1807,7 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
 	VM_BUG_ON_PAGE(!zpdesc_is_isolated(zpdesc), zpdesc_page(zpdesc));
 
 	/* We're committed, tell the world that this is a Zsmalloc page. */
-	__SetPageZsmalloc(zpdesc_page(newzpdesc));
+	__zpdesc_set_zsmalloc(newzpdesc);
 
 	/* The page is locked, so this pointer must remain valid */
 	zspage = get_zspage(zpdesc);
Signature · 1 line
2.46.0
#21 lore raw

PATCH v7 20/21 mm/zsmalloc: introduce zpdesc_clear_first() helper

In reply to [email protected]

From: Alex Shi <[email protected]>

Like the zpdesc_set_first(), introduce zpdesc_clear_first() helper for ClearPagePrivate(), then clean up a 'struct page' usage in reset_zpdesc().

---
 mm/zsmalloc.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)
mm/zsmalloc.c +6 -3
index 411621f00a02..849f192d4937 100644
@@ -253,6 +253,11 @@ static inline void zpdesc_set_first(struct zpdesc *zpdesc)
 	SetPagePrivate(zpdesc_page(zpdesc));
 }
 
+static inline void zpdesc_clear_first(struct zpdesc *zpdesc)
+{
+	ClearPagePrivate(zpdesc_page(zpdesc));
+}
+
 static inline void zpdesc_inc_zone_page_state(struct zpdesc *zpdesc)
 {
 	inc_zone_page_state(zpdesc_page(zpdesc), NR_ZSPAGES);
@@ -832,10 +837,8 @@ static inline bool obj_allocated(struct zpdesc *zpdesc, void *obj,
 
 static void reset_zpdesc(struct zpdesc *zpdesc)
 {
-	struct page *page = zpdesc_page(zpdesc);
-
 	__zpdesc_clear_movable(zpdesc);
-	ClearPagePrivate(page);
+	zpdesc_clear_first(zpdesc);
 	zpdesc->zspage = NULL;
 	zpdesc->next = NULL;
 	__zpdesc_clear_zsmalloc(zpdesc);
Signature · 1 line
2.46.0
#22 lore raw

PATCH v7 21/21 mm/zsmalloc: update comments for page->zpdesc changes

In reply to [email protected]

From: Alex Shi <[email protected]>

After the page to zpdesc conversion, there still left few comments or function named with page not zpdesc, let's update the comments and rename function create_page_chain() as create_zpdesc_chain().

---
 mm/zsmalloc.c | 61 ++++++++++++++++++++++++++-------------------------
 1 file changed, 31 insertions(+), 30 deletions(-)
mm/zsmalloc.c +31 -30
index 849f192d4937..1e47cda05c83 100644
@@ -13,20 +13,19 @@
 
 /*
  * Following is how we use various fields and flags of underlying
- * struct page(s) to form a zspage.
+ * struct zpdesc(page) to form a zspage.
  *
- * Usage of struct page fields:
- *	page->private: points to zspage
- *	page->index: links together all component pages of a zspage
+ * Usage of struct zpdesc fields:
+ *	zpdesc->zspage: points to zspage
+ *	zpdesc->next: links together all component zpdescs of a zspage
  *		For the huge page, this is always 0, so we use this field
  *		to store handle.
- *	page->page_type: PGTY_zsmalloc, lower 24 bits locate the first object
- *		offset in a subpage of a zspage
- *
- * Usage of struct page flags:
- *	PG_private: identifies the first component page
- *	PG_owner_priv_1: identifies the huge component page
+ *	zpdesc->first_obj_offset: PGTY_zsmalloc, lower 24 bits locate the first
+ *		object offset in a subpage of a zspage
  *
+ * Usage of struct zpdesc(page) flags:
+ *	PG_private: identifies the first component zpdesc
+ *	PG_lock: lock all component zpdescs for a zspage free, serialize with
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -191,7 +190,10 @@ struct size_class {
 	 */
 	int size;
 	int objs_per_zspage;
-	/* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
+	/*
+	 * Number of PAGE_SIZE sized zpdescs/pages to combine to
+	 * form a 'zspage'
+	 */
 	int pages_per_zspage;
 
 	unsigned int index;
@@ -900,7 +902,7 @@ static void free_zspage(struct zs_pool *pool, struct size_class *class,
 
 	/*
 	 * Since zs_free couldn't be sleepable, this function cannot call
-	 * lock_page. The page locks trylock_zspage got will be released
+	 * lock_page. The zpdesc locks trylock_zspage got will be released
 	 * by __free_zspage.
 	 */
 	if (!trylock_zspage(zspage)) {
@@ -957,7 +959,7 @@ static void init_zspage(struct size_class *class, struct zspage *zspage)
 	set_freeobj(zspage, 0);
 }
 
-static void create_page_chain(struct size_class *class, struct zspage *zspage,
+static void create_zpdesc_chain(struct size_class *class, struct zspage *zspage,
 				struct zpdesc *zpdescs[])
 {
 	int i;
@@ -966,9 +968,9 @@ static void create_page_chain(struct size_class *class, struct zspage *zspage,
 	int nr_zpdescs = class->pages_per_zspage;
 
 	/*
-	 * Allocate individual pages and link them together as:
-	 * 1. all pages are linked together using zpdesc->next
-	 * 2. each sub-page point to zspage using zpdesc->zspage
+	 * Allocate individual zpdescs and link them together as:
+	 * 1. all zpdescs are linked together using zpdesc->next
+	 * 2. each sub-zpdesc point to zspage using zpdesc->zspage
 	 *
 	 * we set PG_private to identify the first zpdesc (i.e. no other zpdesc
 	 * has this flag set).
@@ -1026,7 +1028,7 @@ static struct zspage *alloc_zspage(struct zs_pool *pool,
 		zpdescs[i] = zpdesc;
 	}
 
-	create_page_chain(class, zspage, zpdescs);
+	create_zpdesc_chain(class, zspage, zpdescs);
 	init_zspage(class, zspage);
 	zspage->pool = pool;
 	zspage->class = class->index;
@@ -1353,7 +1355,7 @@ static unsigned long obj_malloc(struct zs_pool *pool,
 		/* record handle in the header of allocated chunk */
 		link->handle = handle | OBJ_ALLOCATED_TAG;
 	else
-		/* record handle to page->index */
+		/* record handle to zpdesc->handle */
 		zspage->first_zpdesc->handle = handle | OBJ_ALLOCATED_TAG;
 
 	kunmap_atomic(vaddr);
@@ -1443,7 +1445,6 @@ static void obj_free(int class_size, unsigned long obj)
 	unsigned int f_objidx;
 	void *vaddr;
 
-
 	obj_to_location(obj, &f_zpdesc, &f_objidx);
 	f_offset = offset_in_page(class_size * f_objidx);
 	zspage = get_zspage(f_zpdesc);
@@ -1686,19 +1687,19 @@ static int putback_zspage(struct size_class *class, struct zspage *zspage)
 #ifdef CONFIG_COMPACTION
 /*
  * To prevent zspage destroy during migration, zspage freeing should
- * hold locks of all pages in the zspage.
+ * hold locks of all component zpdesc in the zspage.
  */
 static void lock_zspage(struct zspage *zspage)
 {
 	struct zpdesc *curr_zpdesc, *zpdesc;
 
 	/*
-	 * Pages we haven't locked yet can be migrated off the list while we're
+	 * Zpdesc we haven't locked yet can be migrated off the list while we're
 	 * trying to lock them, so we need to be careful and only attempt to
-	 * lock each page under migrate_read_lock(). Otherwise, the page we lock
-	 * may no longer belong to the zspage. This means that we may wait for
-	 * the wrong page to unlock, so we must take a reference to the page
-	 * prior to waiting for it to unlock outside migrate_read_lock().
+	 * lock each zpdesc under migrate_read_lock(). Otherwise, the zpdesc we
+	 * lock may no longer belong to the zspage. This means that we may wait
+	 * for the wrong zpdesc to unlock, so we must take a reference to the
+	 * zpdesc prior to waiting for it to unlock outside migrate_read_lock().
 	 */
 	while (1) {
 		migrate_read_lock(zspage);
@@ -1773,7 +1774,7 @@ static void replace_sub_page(struct size_class *class, struct zspage *zspage,
 		idx++;
 	} while ((zpdesc = get_next_zpdesc(zpdesc)) != NULL);
 
-	create_page_chain(class, zspage, zpdescs);
+	create_zpdesc_chain(class, zspage, zpdescs);
 	first_obj_offset = get_first_obj_offset(oldzpdesc);
 	set_first_obj_offset(newzpdesc, first_obj_offset);
 	if (unlikely(ZsHugePage(zspage)))
@@ -1784,8 +1785,8 @@ static void replace_sub_page(struct size_class *class, struct zspage *zspage,
 static bool zs_page_isolate(struct page *page, isolate_mode_t mode)
 {
 	/*
-	 * Page is locked so zspage couldn't be destroyed. For detail, look at
-	 * lock_zspage in free_zspage.
+	 * Page/zpdesc is locked so zspage couldn't be destroyed. For detail,
+	 * look at lock_zspage in free_zspage.
 	 */
 	VM_BUG_ON_PAGE(PageIsolated(page), page);
 
@@ -1812,7 +1813,7 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
 	/* We're committed, tell the world that this is a Zsmalloc page. */
 	__zpdesc_set_zsmalloc(newzpdesc);
 
-	/* The page is locked, so this pointer must remain valid */
+	/* The zpdesc/page is locked, so this pointer must remain valid */
 	zspage = get_zspage(zpdesc);
 	pool = zspage->pool;
 
@@ -1885,7 +1886,7 @@ static const struct movable_operations zsmalloc_mops = {
 };
 
 /*
- * Caller should hold page_lock of all pages in the zspage
+ * Caller should hold zpdesc locks of all in the zspage
  * In here, we cannot use zspage meta data.
  */
 static void async_free_zspage(struct work_struct *work)
Signature · 1 line
2.46.0
#23 lore raw
In reply to [email protected]
Quoted 5 lines · On (24/09/02 15:21), [email protected] wrote:

The descriptor still overlays the struct page; nothing has changed in that regard.
[..]
This patachset does not increase the descriptor size nor introduce any functional changes, and could save about 122Kbytes zsmalloc.o size.

Is this number accurate? Where does such a large saving come from?

#24 lore raw
Quoted 8 lines · Sergey Senozhatsky
Quoted 5 lines · On (24/09/02 15:21), [email protected] wrote:

The descriptor still overlays the struct page; nothing has changed in that regard.
[..]
This patachset does not increase the descriptor size nor introduce any functional changes, and could save about 122Kbytes zsmalloc.o size.

Is this number accurate? Where does such a large saving come from?

./scripts/bloat-o-meter mm/zsmalloc.o-base mm/zsmalloc.o-patched add/remove: 0/0 grow/shrink: 2/6 up/down: 7/-843 (-836)

Function                                     old     new   delta
obj_free                                     211     215      +4
zs_unmap_object                              568     571      +3
zs_map_object                                661     633     -28
SetZsPageMovable                             135      86     -49
free_zspage                                  310     253     -57
__free_zspage                                284     226     -58
zs_page_migrate                             1304    1136    -168
async_free_zspage                           1099     616    -483
#25 lore raw
Quoted 9 lines · Sergey Senozhatsky
Quoted 8 lines · Sergey Senozhatsky
Quoted 5 lines · On (24/09/02 15:21), [email protected] wrote:

The descriptor still overlays the struct page; nothing has changed in that regard.
[..]
This patachset does not increase the descriptor size nor introduce any functional changes, and could save about 122Kbytes zsmalloc.o size.

Is this number accurate? Where does such a large saving come from?

Hi Sergey,

Thanks for asking, I collected some data on Aug 2, before the patchset, zsmalloc.o is 1200960 bytes, after patched, it's 1076144 bytes. At that time it's saved about 124KB, about 10%, with some debug option enabled.

Just test again with x86defconfig + ZSMALLOC + ZSMALLOC_STAT, on mm-unstable tree, zsmalloc.o reduces to 34960 bytes from 37328 bytes, that's 6.3% saved.

The bloat-o-meter show in machine:

$ ./scripts/bloat-o-meter x86def/mm/zsmalloc.o x86def/mm/zsmalloc-patched.o 
add/remove: 1/1 grow/shrink: 1/5 up/down: 100/-1068 (-968)
Function                                     old     new   delta
create_zpdesc_chain                            -      92     +92
zs_compact                                  2352    2360      +8
zs_malloc                                   1334    1277     -57
__free_zspage                                291     223     -68
free_zspage                                  289     211     -78
create_page_chain                             95       -     -95
zs_page_migrate                              950     807    -143
async_free_zspage                           1252     625    -627
Total: Before=11868, After=10900, chg -8.16%
Quoted 12 lines

./scripts/bloat-o-meter mm/zsmalloc.o-base mm/zsmalloc.o-patched add/remove: 0/0 grow/shrink: 2/6 up/down: 7/-843 (-836)

Function                                     old     new   delta
obj_free                                     211     215      +4
zs_unmap_object                              568     571      +3
zs_map_object                                661     633     -28
SetZsPageMovable                             135      86     -49
free_zspage                                  310     253     -57
__free_zspage                                284     226     -58
zs_page_migrate                             1304    1136    -168
async_free_zspage                           1099     616    -483

Many thanks for detailed data here!

Thanks
Alex

#26 lore raw
In reply to [email protected]
Quoted 2 lines · On 9/2/24 3:21 PM, [email protected] wrote:

From: Alex Shi <[email protected]>

...

Quoted 8 lines

This patchset abstracts the memory descriptor used in zsmalloc by zswap/zram. The descriptor still overlays the struct page; nothing has changed in that regard. What this patchset accomplishes is the use of folios in to save some code size, and the introduction of a new concept, zpdesc. This patchset is just an initial step; it does not bias the potential changes to kmem_alloc or larger zspage modifications.

...

Quoted 4 lines

Thanks a lot for comments and suggestion from Yosry, Yoo, Sergey, Willy and Vishal!

This patchset could save 6.3% code size, and it's a nice abstract of zsmalloc memory usage.
Is there any more comments, or mind to give a reviewed-by?

Thanks
Alex

#27 lore raw
Quoted 17 lines · Alex Shi
Quoted 2 lines · On 9/2/24 3:21 PM, [email protected] wrote:

From: Alex Shi <[email protected]>

...

Quoted 8 lines

This patchset abstracts the memory descriptor used in zsmalloc by zswap/zram. The descriptor still overlays the struct page; nothing has changed in that regard. What this patchset accomplishes is the use of folios in to save some code size, and the introduction of a new concept, zpdesc. This patchset is just an initial step; it does not bias the potential changes to kmem_alloc or larger zspage modifications.

...

Quoted 1 line
Quoted 7 lines
Quoted 3 lines

Thanks a lot for comments and suggestion from Yosry, Yoo, Sergey, Willy and Vishal!

This patchset could save 6.3% code size, and it's a nice abstract of zsmalloc memory usage.
Is there any more comments, or mind to give a reviewed-by?

Please CC me on future versions. Most of the zsmalloc conversions seem ok, but I'd hold off on further iterations of the descriptor patches until the maintainers decide on what/how this descriptor will be used (i.e. our end goals).

Quoted 2 lines

Thanks
Alex

#28 lore raw
Quoted 22 lines · Vishal Moola
Quoted 21 lines · Alex Shi
Quoted 2 lines · On 9/2/24 3:21 PM, [email protected] wrote:

From: Alex Shi <[email protected]>

...

Quoted 8 lines

This patchset abstracts the memory descriptor used in zsmalloc by zswap/zram. The descriptor still overlays the struct page; nothing has changed in that regard. What this patchset accomplishes is the use of folios in to save some code size, and the introduction of a new concept, zpdesc. This patchset is just an initial step; it does not bias the potential changes to kmem_alloc or larger zspage modifications.

...

Quoted 4 lines

Thanks a lot for comments and suggestion from Yosry, Yoo, Sergey, Willy and Vishal!

Quoted 8 lines
Quoted 3 lines

This patchset could save 6.3% code size, and it's a nice abstract of zsmalloc memory usage.
Is there any more comments, or mind to give a reviewed-by?

Please CC me on future versions. Most of the zsmalloc conversions seem ok, but I'd hold off on further iterations of the descriptor patches until the maintainers decide on what/how this descriptor will be used (i.e. our end goals).

Thanks for your care.

Is there some places or some conversion should be changed?

btw, the descriptor is used now and could save a few code size. :)

Thanks

#29 lore raw
In reply to Vishal Moola
Quoted 22 lines · Vishal Moola
Quoted 21 lines · Alex Shi
Quoted 2 lines · On 9/2/24 3:21 PM, [email protected] wrote:

From: Alex Shi <[email protected]>

...

Quoted 8 lines

This patchset abstracts the memory descriptor used in zsmalloc by zswap/zram. The descriptor still overlays the struct page; nothing has changed in that regard. What this patchset accomplishes is the use of folios in to save some code size, and the introduction of a new concept, zpdesc. This patchset is just an initial step; it does not bias the potential changes to kmem_alloc or larger zspage modifications.

...

Quoted 4 lines

Thanks a lot for comments and suggestion from Yosry, Yoo, Sergey, Willy and Vishal!

Quoted 8 lines
Quoted 3 lines

This patchset could save 6.3% code size, and it's a nice abstract of zsmalloc memory usage.
Is there any more comments, or mind to give a reviewed-by?

Please CC me on future versions. Most of the zsmalloc conversions seem ok, but I'd hold off on further iterations of the descriptor patches until the maintainers decide on what/how this descriptor will be used (i.e. our end goals).

I apologize for leaving this in limbo for this long. This patchset is a prerequisite to shrinking struct page, so we should get this memdesc in.

I think it's safe to assume (since we've heard no definitive goal from the maintainers) that in our memdesc world we want zsmalloc + zspage to be similar to how it currently looks today.

Would you like to rebase this on the current mm-unstable? I'll re-review it in case anything changed (and can then give you my reviewed-by).

Quoted 2 lines
Quoted 2 lines

Thanks
Alex

#30 lore raw
Quoted 35 lines · Vishal Moola
Quoted 22 lines · Vishal Moola
Quoted 21 lines · Alex Shi
Quoted 2 lines · On 9/2/24 3:21 PM, [email protected] wrote:

From: Alex Shi <[email protected]>

...

Quoted 8 lines

This patchset abstracts the memory descriptor used in zsmalloc by zswap/zram. The descriptor still overlays the struct page; nothing has changed in that regard. What this patchset accomplishes is the use of folios in to save some code size, and the introduction of a new concept, zpdesc. This patchset is just an initial step; it does not bias the potential changes to kmem_alloc or larger zspage modifications.

...

Quoted 4 lines

Thanks a lot for comments and suggestion from Yosry, Yoo, Sergey, Willy and Vishal!

Quoted 8 lines
Quoted 3 lines

This patchset could save 6.3% code size, and it's a nice abstract of zsmalloc memory usage.
Is there any more comments, or mind to give a reviewed-by?

Please CC me on future versions. Most of the zsmalloc conversions seem ok, but I'd hold off on further iterations of the descriptor patches until the maintainers decide on what/how this descriptor will be used (i.e. our end goals).

I apologize for leaving this in limbo for this long. This patchset is a prerequisite to shrinking struct page, so we should get this memdesc in.

Quoted 6 lines

I think it's safe to assume (since we've heard no definitive goal from the maintainers) that in our memdesc world we want zsmalloc + zspage to be similar to how it currently looks today.

Would you like to rebase this on the current mm-unstable? I'll re-review it in case anything changed (and can then give you my reviewed-by).

Hi, Vishal,

Thanks a lot for the review and kindness, I will try to do the rebase in this weekend.

Cheers!
Alex

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

Thanks
Alex

#31 lore raw
Quoted 43 lines · Alex Shi
Quoted 39 lines · Vishal Moola
Quoted 22 lines · Vishal Moola
Quoted 21 lines · Alex Shi
Quoted 2 lines · On 9/2/24 3:21 PM, [email protected] wrote:

From: Alex Shi <[email protected]>

...

Quoted 8 lines

This patchset abstracts the memory descriptor used in zsmalloc by zswap/zram. The descriptor still overlays the struct page; nothing has changed in that regard. What this patchset accomplishes is the use of folios in to save some code size, and the introduction of a new concept, zpdesc. This patchset is just an initial step; it does not bias the potential changes to kmem_alloc or larger zspage modifications.

...

Quoted 4 lines

Thanks a lot for comments and suggestion from Yosry, Yoo, Sergey, Willy and Vishal!

Quoted 8 lines
Quoted 3 lines

This patchset could save 6.3% code size, and it's a nice abstract of zsmalloc memory usage.
Is there any more comments, or mind to give a reviewed-by?

Please CC me on future versions. Most of the zsmalloc conversions seem ok, but I'd hold off on further iterations of the descriptor patches until the maintainers decide on what/how this descriptor will be used (i.e. our end goals).

I apologize for leaving this in limbo for this long. This patchset is a prerequisite to shrinking struct page, so we should get this memdesc in.

I think it's safe to assume (since we've heard no definitive goal from the maintainers) that in our memdesc world we want zsmalloc + zspage to be similar to how it currently looks today.

Quoted 5 lines
Quoted 2 lines

Would you like to rebase this on the current mm-unstable? I'll re-review it in case anything changed (and can then give you my reviewed-by).

Hi, Vishal,

Thanks a lot for the review and kindness, I will try to do the rebase in this weekend.

For your information, there is a patch series (not merged yet) invalidating the assumption
that zsmalloc always allocates order-0 pages [1].

I'm sorry I wasn't able to dedicate more time to this project this year. Thank you for pushing this forward, Alex!

[1] https://lore.kernel.org/linux-mm/[email protected]/

Best,
Hyeonggon