Add a helper to report the minimum remaining chargeable space from a page counter up to the root of its hierarchy. This makes the hierarchical margin calculation reusable by callers that need to know whether a smaller charge could still fit after a larger charge failed. Suggested-by: Johannes Weiner Signed-off-by: Xueyuan Chen --- include/linux/page_counter.h | 1 + mm/page_counter.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/linux/page_counter.h b/include/linux/page_counter.h index d649b6bbbc87..07b7cb12249c 100644 --- a/include/linux/page_counter.h +++ b/include/linux/page_counter.h @@ -68,6 +68,7 @@ static inline unsigned long page_counter_read(struct page_counter *counter) return atomic_long_read(&counter->usage); } +long page_counter_margin(struct page_counter *counter); void page_counter_cancel(struct page_counter *counter, unsigned long nr_pages); void page_counter_charge(struct page_counter *counter, unsigned long nr_pages); bool page_counter_try_charge(struct page_counter *counter, diff --git a/mm/page_counter.c b/mm/page_counter.c index 661e0f2a5127..6e55c7628025 100644 --- a/mm/page_counter.c +++ b/mm/page_counter.c @@ -171,6 +171,26 @@ bool page_counter_try_charge(struct page_counter *counter, return false; } +/** + * page_counter_margin - remaining chargeable pages within hierarchical limits + * @counter: counter + * + * Returns the smallest remaining margin between @counter and the root. + */ +long page_counter_margin(struct page_counter *counter) +{ + long margin = PAGE_COUNTER_MAX; + + for (; counter; counter = counter->parent) { + long limit = READ_ONCE(counter->max); + long usage = page_counter_read(counter); + + margin = min(margin, limit - usage); + } + + return margin; +} + /** * page_counter_uncharge - hierarchically uncharge pages * @counter: counter -- 2.47.3