• Yunsheng Lin's avatar
    page_pool: unify frag_count handling in page_pool_is_last_frag() · 58d53d8f
    Yunsheng Lin authored
    Currently when page_pool_create() is called with
    PP_FLAG_PAGE_FRAG flag, page_pool_alloc_pages() is only
    allowed to be called under the below constraints:
    1. page_pool_fragment_page() need to be called to setup
       page->pp_frag_count immediately.
    2. page_pool_defrag_page() often need to be called to drain
       the page->pp_frag_count when there is no more user will
       be holding on to that page.
    
    Those constraints exist in order to support a page to be
    split into multi fragments.
    
    And those constraints have some overhead because of the
    cache line dirtying/bouncing and atomic update.
    
    Those constraints are unavoidable for case when we need a
    page to be split into more than one fragment, but there is
    also case that we want to avoid the above constraints and
    their overhead when a page can't be split as it can only
    hold a fragment as requested by user, depending on different
    use cases:
    use case 1: allocate page without page splitting.
    use case 2: allocate page with page splitting.
    use case 3: allocate page with or without page splitting
                depending on the fragment size.
    
    Currently page pool only provide page_pool_alloc_pages() and
    page_pool_alloc_frag() API to enable the 1 & 2 separately,
    so we can not use a combination of 1 & 2 to enable 3, it is
    not possible yet because of the per page_pool flag
    PP_FLAG_PAGE_FRAG.
    
    So in order to allow allocating unsplit page without the
    overhead of split page while still allow allocating split
    page we need to remove the per page_pool flag in
    page_pool_is_last_frag(), as best as I can think of, it seems
    there are two methods as below:
    1. Add per page flag/bit to indicate a page is split or
       not, which means we might need to update that flag/bit
       everytime the page is recycled, dirtying the cache line
       of 'struct page' for use case 1.
    2. Unify the page->pp_frag_count handling for both split and
       unsplit page by assuming all pages in the page pool is split
       into a big fragment initially.
    
    As page pool already supports use case 1 without dirtying the
    cache line of 'struct page' whenever a page is recyclable, we
    need to support the above use case 3 with minimal overhead,
    especially not adding any noticeable overhead for use case 1,
    and we are already doing an optimization by not updating
    pp_frag_count in page_pool_defrag_page() for the last fragment
    user, this patch chooses to unify the pp_frag_count handling
    to support the above use case 3.
    
    There is no noticeable performance degradation and some
    justification for unifying the frag_count handling with this
    patch applied using a micro-benchmark testing in [1].
    
    1. https://lore.kernel.org/all/bf2591f8-7b3c-4480-bb2c-31dc9da1d6ac@huawei.com/Signed-off-by: default avatarYunsheng Lin <linyunsheng@huawei.com>
    CC: Lorenzo Bianconi <lorenzo@kernel.org>
    CC: Alexander Duyck <alexander.duyck@gmail.com>
    CC: Liang Chen <liangchen.linux@gmail.com>
    CC: Alexander Lobakin <aleksander.lobakin@intel.com>
    Link: https://lore.kernel.org/r/20231020095952.11055-2-linyunsheng@huawei.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
    58d53d8f
helpers.h 8.34 KB