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