| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- /* SPDX-License-Identifier: GPL-2.0 */
- /* zpdesc.h: zsmalloc pool memory descriptor
- *
- * Written by Alex Shi <alexs@kernel.org>
- * Hyeonggon Yoo <42.hyeyoo@gmail.com>
- */
- #ifndef __MM_ZPDESC_H__
- #define __MM_ZPDESC_H__
- #include <linux/migrate.h>
- #include <linux/pagemap.h>
- /*
- * struct zpdesc - Memory descriptor for zsmalloc pool memory.
- * @flags: Page flags, mostly unused by zsmalloc.
- * @lru: Indirectly used by page migration.
- * @movable_ops: Used by page migration.
- * @next: Next zpdesc in a zspage in zsmalloc pool.
- * @handle: For huge zspage in zsmalloc pool.
- * @zspage: Points to the zspage this zpdesc is a part of.
- * @first_obj_offset: First object offset in zsmalloc pool.
- * @_refcount: The number of references to this zpdesc.
- *
- * This struct overlays struct page for now. Do not modify without a good
- * understanding of the issues. In particular, do not expand into the overlap
- * with memcg_data.
- *
- * Page flags used:
- * * PG_private identifies the first component page.
- * * PG_locked is used by page migration code.
- */
- struct zpdesc {
- unsigned long flags;
- struct list_head lru;
- unsigned long movable_ops;
- union {
- struct zpdesc *next;
- unsigned long handle;
- };
- struct zspage *zspage;
- /*
- * Only the lower 24 bits are available for offset, limiting a page
- * to 16 MiB. The upper 8 bits are reserved for PGTY_zsmalloc.
- *
- * Do not access this field directly.
- * Instead, use {get,set}_first_obj_offset() helpers.
- */
- unsigned int first_obj_offset;
- atomic_t _refcount;
- };
- #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, movable_ops);
- ZPDESC_MATCH(__folio_index, next);
- ZPDESC_MATCH(__folio_index, handle);
- ZPDESC_MATCH(private, zspage);
- ZPDESC_MATCH(page_type, first_obj_offset);
- ZPDESC_MATCH(_refcount, _refcount);
- #undef ZPDESC_MATCH
- static_assert(sizeof(struct zpdesc) <= sizeof(struct page));
- /*
- * zpdesc_page - The first struct page allocated for a zpdesc
- * @zp: The zpdesc.
- *
- * A convenience wrapper for converting zpdesc to the first struct page of the
- * underlying folio, to communicate with code not yet converted to folio or
- * struct zpdesc.
- *
- */
- #define zpdesc_page(zp) (_Generic((zp), \
- const struct zpdesc *: (const struct page *)(zp), \
- struct zpdesc *: (struct page *)(zp)))
- /**
- * zpdesc_folio - The folio allocated for a zpdesc
- * @zp: The zpdesc.
- *
- * Zpdescs are descriptors for zsmalloc memory. The memory itself is allocated
- * as folios that contain the zsmalloc objects, and zpdesc uses specific
- * fields in the first struct page of the folio - those fields are now accessed
- * by struct zpdesc.
- *
- * It is occasionally necessary convert to back to a folio in order to
- * communicate with the rest of the mm. Please use this helper function
- * instead of casting yourself, as the implementation may change in the future.
- */
- #define zpdesc_folio(zp) (_Generic((zp), \
- const struct zpdesc *: (const struct folio *)(zp), \
- struct zpdesc *: (struct folio *)(zp)))
- /**
- * page_zpdesc - Converts from first struct page to zpdesc.
- * @p: The first (either head of compound or single) page of zpdesc.
- *
- * A temporary wrapper to convert struct page to struct zpdesc in situations
- * where we know the page is the compound head, or single order-0 page.
- *
- * Long-term ideally everything would work with struct zpdesc directly or go
- * through folio to struct zpdesc.
- *
- * Return: The zpdesc which contains this page
- */
- #define page_zpdesc(p) (_Generic((p), \
- 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));
- }
- static inline void *kmap_local_zpdesc(struct zpdesc *zpdesc)
- {
- return kmap_local_page(zpdesc_page(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));
- }
- static inline void __zpdesc_set_movable(struct zpdesc *zpdesc)
- {
- SetPageMovableOps(zpdesc_page(zpdesc));
- }
- static inline void __zpdesc_set_zsmalloc(struct zpdesc *zpdesc)
- {
- __SetPageZsmalloc(zpdesc_page(zpdesc));
- }
- 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 folio_test_locked(zpdesc_folio(zpdesc));
- }
- #endif
|