On Sat, Oct 12, 2024 at 07:23:19PM +0800, Yunsheng Lin wrote: > +Architecture overview > +===================== > + > +.. code-block:: none > + > + +----------------------+ > + | page_frag API caller | > + +----------------------+ > + | > + | > + v > + +------------------------------------------------------------------+ > + | request page fragment | > + +------------------------------------------------------------------+ > + | | | > + | | | > + | Cache not enough | > + | | | > + | +-----------------+ | > + | | reuse old cache |--Usable-->| > + | +-----------------+ | > + | | | > + | Not usable | > + | | | > + | v | > + Cache empty +-----------------+ | > + | | drain old cache | | > + | +-----------------+ | > + | | | > + v_________________________________v | > + | | > + | | > + _________________v_______________ | > + | | Cache is enough > + | | | > + PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE | | > + | | | > + | PAGE_SIZE >= PAGE_FRAG_CACHE_MAX_SIZE | > + v | | > + +----------------------------------+ | | > + | refill cache with order > 0 page | | | > + +----------------------------------+ | | > + | | | | > + | | | | > + | Refill failed | | > + | | | | > + | v v | > + | +------------------------------------+ | > + | | refill cache with order 0 page | | > + | +----------------------------------=-+ | > + | | | > + Refill succeed | | > + | Refill succeed | > + | | | > + v v v > + +------------------------------------------------------------------+ > + | allocate fragment from cache | > + +------------------------------------------------------------------+ > + > +API interface > +============= > +As the design and implementation of page_frag API implies, the allocation side > +does not allow concurrent calling. Instead it is assumed that the caller must > +ensure there is not concurrent alloc calling to the same page_frag_cache > +instance by using its own lock or rely on some lockless guarantee like NAPI > +softirq. > + > +Depending on different aligning requirement, the page_frag API caller may call > +page_frag_*_align*() to ensure the returned virtual address or offset of the > +page is aligned according to the 'align/alignment' parameter. Note the size of > +the allocated fragment is not aligned, the caller needs to provide an aligned > +fragsz if there is an alignment requirement for the size of the fragment. > + > +Depending on different use cases, callers expecting to deal with va, page or > +both va and page for them may call page_frag_alloc, page_frag_refill, or > +page_frag_alloc_refill API accordingly. > + > +There is also a use case that needs minimum memory in order for forward progress, > +but more performant if more memory is available. Using page_frag_*_prepare() and > +page_frag_commit*() related API, the caller requests the minimum memory it needs > +and the prepare API will return the maximum size of the fragment returned. The > +caller needs to either call the commit API to report how much memory it actually > +uses, or not do so if deciding to not use any memory. Looks OK. > +Coding examples > +=============== > + > +Init & Drain API > +---------------- Initialization and draining API? > +Alloc & Free API > +---------------- Shouldn't it be called allocation API? > +Prepare & Commit API > +-------------------- This one looks OK. > +/** > + * page_frag_cache_init() - Init page_frag cache. > + * @nc: page_frag cache from which to init > + * > + * Inline helper to init the page_frag cache. > + */ s/Init/Initialize/ > static inline void page_frag_cache_init(struct page_frag_cache *nc) > { > nc->encoded_page = 0; > } > > +/** > + * page_frag_cache_is_pfmemalloc() - Check for pfmemalloc. > + * @nc: page_frag cache from which to check > + * > + * Used to check if the current page in page_frag cache is pfmemalloc'ed. is allocated by pfmemalloc()? > + * It has the same calling context expectation as the alloc API. > + * > + * Return: > + * true if the current page in page_frag cache is pfmemalloc'ed, otherwise > + * return false. > + */ > static inline bool page_frag_cache_is_pfmemalloc(struct page_frag_cache *nc) > { > return encoded_page_decode_pfmemalloc(nc->encoded_page); > } > > +/** > + * page_frag_cache_page_offset() - Return the current page fragment's offset. > + * @nc: page_frag cache from which to check > + * > + * The API is only used in net/sched/em_meta.c for historical reason, do not use > + * it for new caller unless there is a strong reason. Then what does page_frag_cache_page_offset() do then? > + * > + * Return: > + * the offset of the current page fragment in the page_frag cache. > + */ > static inline unsigned int page_frag_cache_page_offset(const struct page_frag_cache *nc) > { > return nc->offset; > @@ -66,6 +93,19 @@ static inline unsigned int __page_frag_cache_commit(struct page_frag_cache *nc, > return __page_frag_cache_commit_noref(nc, pfrag, used_sz); > } > > +/** > + * __page_frag_alloc_align() - Alloc a page fragment with aligning > + * requirement. > + * @nc: page_frag cache from which to allocate > + * @fragsz: the requested fragment size > + * @gfp_mask: the allocation gfp to use when cache need to be refilled > + * @align_mask: the requested aligning requirement for the 'va' > + * > + * Alloc a page fragment from page_frag cache with aligning requirement. Allocate > + * > + * Return: > + * Virtual address of the page fragment, otherwise return NULL. > + */ > static inline void *__page_frag_alloc_align(struct page_frag_cache *nc, > unsigned int fragsz, gfp_t gfp_mask, > unsigned int align_mask) > @@ -83,6 +123,19 @@ static inline void *__page_frag_alloc_align(struct page_frag_cache *nc, > return va; > } > > +/** > + * page_frag_alloc_align() - Alloc a page fragment with aligning requirement. > + * @nc: page_frag cache from which to allocate > + * @fragsz: the requested fragment size > + * @gfp_mask: the allocation gfp to use when cache needs to be refilled > + * @align: the requested aligning requirement for the fragment > + * > + * WARN_ON_ONCE() checking for @align before allocing a page fragment from allocating > + * page_frag cache with aligning requirement. > + * > + * Return: > + * virtual address of the page fragment, otherwise return NULL. > + */ > static inline void *page_frag_alloc_align(struct page_frag_cache *nc, > unsigned int fragsz, gfp_t gfp_mask, > unsigned int align) > @@ -91,12 +144,36 @@ static inline void *page_frag_alloc_align(struct page_frag_cache *nc, > return __page_frag_alloc_align(nc, fragsz, gfp_mask, -align); > } > > +/** > + * page_frag_alloc() - Alloc a page fragment. > + * @nc: page_frag cache from which to allocate > + * @fragsz: the requested fragment size > + * @gfp_mask: the allocation gfp to use when cache need to be refilled > + * > + * Alloc a page fragment from page_frag cache. Allocate > + * > + * Return: > + * virtual address of the page fragment, otherwise return NULL. > + */ > static inline void *page_frag_alloc(struct page_frag_cache *nc, > unsigned int fragsz, gfp_t gfp_mask) > { > return __page_frag_alloc_align(nc, fragsz, gfp_mask, ~0u); > } > > +/** > + * __page_frag_alloc_refill_prepare_align() - Prepare allocing a fragment and > + * refilling a page_frag with aligning requirement. > + * @nc: page_frag cache from which to allocate and refill > + * @fragsz: the requested fragment size > + * @pfrag: the page_frag to be refilled. > + * @gfp_mask: the allocation gfp to use when cache need to be refilled > + * @align_mask: the requested aligning requirement for the fragment. > + * > + * Prepare allocing a fragment and refilling a page_frag from page_frag cache. Prepare allocating? > + * > + * Return: > + * virtual address of the page fragment, otherwise return NULL. > + */ > static inline void *__page_frag_alloc_refill_prepare_align(struct page_frag_cache *nc, > unsigned int fragsz, > struct page_frag *pfrag, > @@ -166,6 +324,21 @@ static inline void *__page_frag_alloc_refill_prepare_align(struct page_frag_cach > return __page_frag_cache_prepare(nc, fragsz, pfrag, gfp_mask, align_mask); > } Thanks. -- An old man doll... just what I always wanted! - Clara
Attachment:
signature.asc
Description: PGP signature