xref: /linux/mm/zpdesc.h (revision a4a508df2aa34f8650afde54ea804321c618f45f)
1f4e33d32SAlex Shi /* SPDX-License-Identifier: GPL-2.0 */
2*2f5bd89bSJohannes Weiner /* zpdesc.h: zsmalloc pool memory descriptor
3f4e33d32SAlex Shi  *
4f4e33d32SAlex Shi  * Written by Alex Shi <alexs@kernel.org>
5f4e33d32SAlex Shi  *	      Hyeonggon Yoo <42.hyeyoo@gmail.com>
6f4e33d32SAlex Shi  */
7f4e33d32SAlex Shi #ifndef __MM_ZPDESC_H__
8f4e33d32SAlex Shi #define __MM_ZPDESC_H__
9f4e33d32SAlex Shi 
107eeafde0SSergey Senozhatsky #include <linux/migrate.h>
117eeafde0SSergey Senozhatsky #include <linux/pagemap.h>
127eeafde0SSergey Senozhatsky 
13f4e33d32SAlex Shi /*
14*2f5bd89bSJohannes Weiner  * struct zpdesc -	Memory descriptor for zsmalloc pool memory.
15f4e33d32SAlex Shi  * @flags:		Page flags, mostly unused by zsmalloc.
16f4e33d32SAlex Shi  * @lru:		Indirectly used by page migration.
17f4e33d32SAlex Shi  * @movable_ops:	Used by page migration.
18*2f5bd89bSJohannes Weiner  * @next:		Next zpdesc in a zspage in zsmalloc pool.
19*2f5bd89bSJohannes Weiner  * @handle:		For huge zspage in zsmalloc pool.
20f4e33d32SAlex Shi  * @zspage:		Points to the zspage this zpdesc is a part of.
21*2f5bd89bSJohannes Weiner  * @first_obj_offset:	First object offset in zsmalloc pool.
22f4e33d32SAlex Shi  * @_refcount:		The number of references to this zpdesc.
23f4e33d32SAlex Shi  *
24f4e33d32SAlex Shi  * This struct overlays struct page for now. Do not modify without a good
25f4e33d32SAlex Shi  * understanding of the issues. In particular, do not expand into the overlap
26f4e33d32SAlex Shi  * with memcg_data.
27f4e33d32SAlex Shi  *
28f4e33d32SAlex Shi  * Page flags used:
29f4e33d32SAlex Shi  * * PG_private identifies the first component page.
30f4e33d32SAlex Shi  * * PG_locked is used by page migration code.
31f4e33d32SAlex Shi  */
32f4e33d32SAlex Shi struct zpdesc {
33f4e33d32SAlex Shi 	unsigned long flags;
34f4e33d32SAlex Shi 	struct list_head lru;
35f4e33d32SAlex Shi 	unsigned long movable_ops;
36f4e33d32SAlex Shi 	union {
37f4e33d32SAlex Shi 		struct zpdesc *next;
38f4e33d32SAlex Shi 		unsigned long handle;
39f4e33d32SAlex Shi 	};
40f4e33d32SAlex Shi 	struct zspage *zspage;
41f4e33d32SAlex Shi 	/*
42f4e33d32SAlex Shi 	 * Only the lower 24 bits are available for offset, limiting a page
43f4e33d32SAlex Shi 	 * to 16 MiB. The upper 8 bits are reserved for PGTY_zsmalloc.
44f4e33d32SAlex Shi 	 *
45f4e33d32SAlex Shi 	 * Do not access this field directly.
46f4e33d32SAlex Shi 	 * Instead, use {get,set}_first_obj_offset() helpers.
47f4e33d32SAlex Shi 	 */
48f4e33d32SAlex Shi 	unsigned int first_obj_offset;
49f4e33d32SAlex Shi 	atomic_t _refcount;
50f4e33d32SAlex Shi };
51f4e33d32SAlex Shi #define ZPDESC_MATCH(pg, zp) \
52f4e33d32SAlex Shi 	static_assert(offsetof(struct page, pg) == offsetof(struct zpdesc, zp))
53f4e33d32SAlex Shi 
54f4e33d32SAlex Shi ZPDESC_MATCH(flags, flags);
55f4e33d32SAlex Shi ZPDESC_MATCH(lru, lru);
56f4e33d32SAlex Shi ZPDESC_MATCH(mapping, movable_ops);
57acc53a0bSMatthew Wilcox (Oracle) ZPDESC_MATCH(__folio_index, next);
58acc53a0bSMatthew Wilcox (Oracle) ZPDESC_MATCH(__folio_index, handle);
59f4e33d32SAlex Shi ZPDESC_MATCH(private, zspage);
60f4e33d32SAlex Shi ZPDESC_MATCH(page_type, first_obj_offset);
61f4e33d32SAlex Shi ZPDESC_MATCH(_refcount, _refcount);
62f4e33d32SAlex Shi #undef ZPDESC_MATCH
63f4e33d32SAlex Shi static_assert(sizeof(struct zpdesc) <= sizeof(struct page));
64f4e33d32SAlex Shi 
65f4e33d32SAlex Shi /*
66f4e33d32SAlex Shi  * zpdesc_page - The first struct page allocated for a zpdesc
67f4e33d32SAlex Shi  * @zp: The zpdesc.
68f4e33d32SAlex Shi  *
69f4e33d32SAlex Shi  * A convenience wrapper for converting zpdesc to the first struct page of the
70f4e33d32SAlex Shi  * underlying folio, to communicate with code not yet converted to folio or
71f4e33d32SAlex Shi  * struct zpdesc.
72f4e33d32SAlex Shi  *
73f4e33d32SAlex Shi  */
74f4e33d32SAlex Shi #define zpdesc_page(zp)			(_Generic((zp),			\
75f4e33d32SAlex Shi 	const struct zpdesc *:		(const struct page *)(zp),	\
76f4e33d32SAlex Shi 	struct zpdesc *:		(struct page *)(zp)))
77f4e33d32SAlex Shi 
78f4e33d32SAlex Shi /**
79f4e33d32SAlex Shi  * zpdesc_folio - The folio allocated for a zpdesc
80f4e33d32SAlex Shi  * @zp: The zpdesc.
81f4e33d32SAlex Shi  *
82*2f5bd89bSJohannes Weiner  * Zpdescs are descriptors for zsmalloc memory. The memory itself is allocated
83*2f5bd89bSJohannes Weiner  * as folios that contain the zsmalloc objects, and zpdesc uses specific
84f4e33d32SAlex Shi  * fields in the first struct page of the folio - those fields are now accessed
85f4e33d32SAlex Shi  * by struct zpdesc.
86f4e33d32SAlex Shi  *
87f4e33d32SAlex Shi  * It is occasionally necessary convert to back to a folio in order to
88f4e33d32SAlex Shi  * communicate with the rest of the mm. Please use this helper function
89f4e33d32SAlex Shi  * instead of casting yourself, as the implementation may change in the future.
90f4e33d32SAlex Shi  */
91f4e33d32SAlex Shi #define zpdesc_folio(zp)		(_Generic((zp),			\
92f4e33d32SAlex Shi 	const struct zpdesc *:		(const struct folio *)(zp),	\
93f4e33d32SAlex Shi 	struct zpdesc *:		(struct folio *)(zp)))
94f4e33d32SAlex Shi /**
95f4e33d32SAlex Shi  * page_zpdesc - Converts from first struct page to zpdesc.
96f4e33d32SAlex Shi  * @p: The first (either head of compound or single) page of zpdesc.
97f4e33d32SAlex Shi  *
98f4e33d32SAlex Shi  * A temporary wrapper to convert struct page to struct zpdesc in situations
99f4e33d32SAlex Shi  * where we know the page is the compound head, or single order-0 page.
100f4e33d32SAlex Shi  *
101f4e33d32SAlex Shi  * Long-term ideally everything would work with struct zpdesc directly or go
102f4e33d32SAlex Shi  * through folio to struct zpdesc.
103f4e33d32SAlex Shi  *
104f4e33d32SAlex Shi  * Return: The zpdesc which contains this page
105f4e33d32SAlex Shi  */
106f4e33d32SAlex Shi #define page_zpdesc(p)			(_Generic((p),			\
107f4e33d32SAlex Shi 	const struct page *:		(const struct zpdesc *)(p),	\
108f4e33d32SAlex Shi 	struct page *:			(struct zpdesc *)(p)))
109f4e33d32SAlex Shi 
zpdesc_lock(struct zpdesc * zpdesc)110c1b3bb73SAlex Shi static inline void zpdesc_lock(struct zpdesc *zpdesc)
111c1b3bb73SAlex Shi {
112c1b3bb73SAlex Shi 	folio_lock(zpdesc_folio(zpdesc));
113c1b3bb73SAlex Shi }
114c1b3bb73SAlex Shi 
zpdesc_trylock(struct zpdesc * zpdesc)115c1b3bb73SAlex Shi static inline bool zpdesc_trylock(struct zpdesc *zpdesc)
116c1b3bb73SAlex Shi {
117c1b3bb73SAlex Shi 	return folio_trylock(zpdesc_folio(zpdesc));
118c1b3bb73SAlex Shi }
119c1b3bb73SAlex Shi 
zpdesc_unlock(struct zpdesc * zpdesc)120c1b3bb73SAlex Shi static inline void zpdesc_unlock(struct zpdesc *zpdesc)
121c1b3bb73SAlex Shi {
122c1b3bb73SAlex Shi 	folio_unlock(zpdesc_folio(zpdesc));
123c1b3bb73SAlex Shi }
124c1b3bb73SAlex Shi 
zpdesc_wait_locked(struct zpdesc * zpdesc)125c1b3bb73SAlex Shi static inline void zpdesc_wait_locked(struct zpdesc *zpdesc)
126c1b3bb73SAlex Shi {
127c1b3bb73SAlex Shi 	folio_wait_locked(zpdesc_folio(zpdesc));
128c1b3bb73SAlex Shi }
129c1b3bb73SAlex Shi 
zpdesc_get(struct zpdesc * zpdesc)130c1b3bb73SAlex Shi static inline void zpdesc_get(struct zpdesc *zpdesc)
131c1b3bb73SAlex Shi {
132c1b3bb73SAlex Shi 	folio_get(zpdesc_folio(zpdesc));
133c1b3bb73SAlex Shi }
134c1b3bb73SAlex Shi 
zpdesc_put(struct zpdesc * zpdesc)135c1b3bb73SAlex Shi static inline void zpdesc_put(struct zpdesc *zpdesc)
136c1b3bb73SAlex Shi {
137c1b3bb73SAlex Shi 	folio_put(zpdesc_folio(zpdesc));
138c1b3bb73SAlex Shi }
139c1b3bb73SAlex Shi 
kmap_local_zpdesc(struct zpdesc * zpdesc)140b5c1d8b5SHyeonggon Yoo static inline void *kmap_local_zpdesc(struct zpdesc *zpdesc)
141b5c1d8b5SHyeonggon Yoo {
142b5c1d8b5SHyeonggon Yoo 	return kmap_local_page(zpdesc_page(zpdesc));
143b5c1d8b5SHyeonggon Yoo }
144b5c1d8b5SHyeonggon Yoo 
zpdesc_pfn(struct zpdesc * zpdesc)145b5c1d8b5SHyeonggon Yoo static inline unsigned long zpdesc_pfn(struct zpdesc *zpdesc)
146b5c1d8b5SHyeonggon Yoo {
147b5c1d8b5SHyeonggon Yoo 	return page_to_pfn(zpdesc_page(zpdesc));
148b5c1d8b5SHyeonggon Yoo }
149b5c1d8b5SHyeonggon Yoo 
pfn_zpdesc(unsigned long pfn)150b5c1d8b5SHyeonggon Yoo static inline struct zpdesc *pfn_zpdesc(unsigned long pfn)
151b5c1d8b5SHyeonggon Yoo {
152b5c1d8b5SHyeonggon Yoo 	return page_zpdesc(pfn_to_page(pfn));
153b5c1d8b5SHyeonggon Yoo }
1547d2e1a69SAlex Shi 
__zpdesc_set_movable(struct zpdesc * zpdesc)15584caf988SDavid Hildenbrand static inline void __zpdesc_set_movable(struct zpdesc *zpdesc)
1567d2e1a69SAlex Shi {
1573d388584SDavid Hildenbrand 	SetPageMovableOps(zpdesc_page(zpdesc));
1587d2e1a69SAlex Shi }
15968721300SHyeonggon Yoo 
__zpdesc_set_zsmalloc(struct zpdesc * zpdesc)160b5f469a1SAlex Shi static inline void __zpdesc_set_zsmalloc(struct zpdesc *zpdesc)
161b5f469a1SAlex Shi {
162b5f469a1SAlex Shi 	__SetPageZsmalloc(zpdesc_page(zpdesc));
163b5f469a1SAlex Shi }
164b5f469a1SAlex Shi 
zpdesc_zone(struct zpdesc * zpdesc)16568721300SHyeonggon Yoo static inline struct zone *zpdesc_zone(struct zpdesc *zpdesc)
16668721300SHyeonggon Yoo {
16768721300SHyeonggon Yoo 	return page_zone(zpdesc_page(zpdesc));
16868721300SHyeonggon Yoo }
16968721300SHyeonggon Yoo 
zpdesc_is_locked(struct zpdesc * zpdesc)1707f0b0c66SHyeonggon Yoo static inline bool zpdesc_is_locked(struct zpdesc *zpdesc)
1717f0b0c66SHyeonggon Yoo {
1727f0b0c66SHyeonggon Yoo 	return folio_test_locked(zpdesc_folio(zpdesc));
1737f0b0c66SHyeonggon Yoo }
174f4e33d32SAlex Shi #endif
175