To simplify later changes to page tag references, introduce new pgalloc_tag_ref and pgtag_ref_handle types. This allows easy replacement of page_ext as a storage of page allocation tags. Signed-off-by: Suren Baghdasaryan <surenb@xxxxxxxxxx> --- include/linux/mm.h | 25 +++++---- include/linux/pgalloc_tag.h | 108 ++++++++++++++++++++++++------------ lib/alloc_tag.c | 3 +- 3 files changed, 88 insertions(+), 48 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 5cd22303fbc0..8efb4a6a1a70 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -4180,37 +4180,38 @@ static inline void pgalloc_tag_split(struct folio *folio, int old_order, int new return; for (i = nr_pages; i < (1 << old_order); i += nr_pages) { - union codetag_ref *ref = get_page_tag_ref(folio_page(folio, i)); + union pgtag_ref_handle handle; + union codetag_ref ref; - if (ref) { + if (get_page_tag_ref(folio_page(folio, i), &ref, &handle)) { /* Set new reference to point to the original tag */ - alloc_tag_ref_set(ref, tag); - put_page_tag_ref(ref); + alloc_tag_ref_set(&ref, tag); + update_page_tag_ref(handle, &ref); + put_page_tag_ref(handle); } } } static inline void pgalloc_tag_copy(struct folio *new, struct folio *old) { + union pgtag_ref_handle handle; + union codetag_ref ref; struct alloc_tag *tag; - union codetag_ref *ref; tag = pgalloc_tag_get(&old->page); if (!tag) return; - ref = get_page_tag_ref(&new->page); - if (!ref) + if (!get_page_tag_ref(&new->page, &ref, &handle)) return; /* Clear the old ref to the original allocation tag. */ clear_page_tag_ref(&old->page); /* Decrement the counters of the tag on get_new_folio. */ - alloc_tag_sub(ref, folio_nr_pages(new)); - - __alloc_tag_ref_set(ref, tag); - - put_page_tag_ref(ref); + alloc_tag_sub(&ref, folio_nr_pages(new)); + __alloc_tag_ref_set(&ref, tag); + update_page_tag_ref(handle, &ref); + put_page_tag_ref(handle); } #else /* !CONFIG_MEM_ALLOC_PROFILING */ static inline void pgalloc_tag_split(struct folio *folio, int old_order, int new_order) diff --git a/include/linux/pgalloc_tag.h b/include/linux/pgalloc_tag.h index 59a3deb792a8..bc65710ee1f9 100644 --- a/include/linux/pgalloc_tag.h +++ b/include/linux/pgalloc_tag.h @@ -9,48 +9,83 @@ #ifdef CONFIG_MEM_ALLOC_PROFILING +typedef union codetag_ref pgalloc_tag_ref; + +static inline void read_pgref(pgalloc_tag_ref *pgref, union codetag_ref *ref) +{ + ref->ct = pgref->ct; +} + +static inline void write_pgref(pgalloc_tag_ref *pgref, union codetag_ref *ref) +{ + pgref->ct = ref->ct; +} + +union pgtag_ref_handle { + pgalloc_tag_ref *pgref; /* reference in page extension */ +}; + #include <linux/page_ext.h> extern struct page_ext_operations page_alloc_tagging_ops; -static inline union codetag_ref *codetag_ref_from_page_ext(struct page_ext *page_ext) +static inline pgalloc_tag_ref *pgref_from_page_ext(struct page_ext *page_ext) { - return (union codetag_ref *)page_ext_data(page_ext, &page_alloc_tagging_ops); + return (pgalloc_tag_ref *)page_ext_data(page_ext, &page_alloc_tagging_ops); } -static inline struct page_ext *page_ext_from_codetag_ref(union codetag_ref *ref) +static inline struct page_ext *page_ext_from_pgref(pgalloc_tag_ref *pgref) { - return (void *)ref - page_alloc_tagging_ops.offset; + return (void *)pgref - page_alloc_tagging_ops.offset; } /* Should be called only if mem_alloc_profiling_enabled() */ -static inline union codetag_ref *get_page_tag_ref(struct page *page) +static inline bool get_page_tag_ref(struct page *page, union codetag_ref *ref, + union pgtag_ref_handle *handle) { - if (page) { - struct page_ext *page_ext = page_ext_get(page); + struct page_ext *page_ext; + pgalloc_tag_ref *pgref; - if (page_ext) - return codetag_ref_from_page_ext(page_ext); - } - return NULL; + if (!page) + return false; + + page_ext = page_ext_get(page); + if (!page_ext) + return false; + + pgref = pgref_from_page_ext(page_ext); + read_pgref(pgref, ref); + handle->pgref = pgref; + return true; +} + +static inline void put_page_tag_ref(union pgtag_ref_handle handle) +{ + if (WARN_ON(!handle.pgref)) + return; + + page_ext_put(page_ext_from_pgref(handle.pgref)); } -static inline void put_page_tag_ref(union codetag_ref *ref) +static inline void update_page_tag_ref(union pgtag_ref_handle handle, + union codetag_ref *ref) { - if (WARN_ON(!ref)) + if (WARN_ON(!handle.pgref || !ref)) return; - page_ext_put(page_ext_from_codetag_ref(ref)); + write_pgref(handle.pgref, ref); } static inline void clear_page_tag_ref(struct page *page) { if (mem_alloc_profiling_enabled()) { - union codetag_ref *ref = get_page_tag_ref(page); + union pgtag_ref_handle handle; + union codetag_ref ref; - if (ref) { - set_codetag_empty(ref); - put_page_tag_ref(ref); + if (get_page_tag_ref(page, &ref, &handle)) { + set_codetag_empty(&ref); + update_page_tag_ref(handle, &ref); + put_page_tag_ref(handle); } } } @@ -59,11 +94,13 @@ static inline void pgalloc_tag_add(struct page *page, struct task_struct *task, unsigned int nr) { if (mem_alloc_profiling_enabled()) { - union codetag_ref *ref = get_page_tag_ref(page); + union pgtag_ref_handle handle; + union codetag_ref ref; - if (ref) { - alloc_tag_add(ref, task->alloc_tag, PAGE_SIZE * nr); - put_page_tag_ref(ref); + if (get_page_tag_ref(page, &ref, &handle)) { + alloc_tag_add(&ref, task->alloc_tag, PAGE_SIZE * nr); + update_page_tag_ref(handle, &ref); + put_page_tag_ref(handle); } } } @@ -71,11 +108,13 @@ static inline void pgalloc_tag_add(struct page *page, struct task_struct *task, static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) { if (mem_alloc_profiling_enabled()) { - union codetag_ref *ref = get_page_tag_ref(page); + union pgtag_ref_handle handle; + union codetag_ref ref; - if (ref) { - alloc_tag_sub(ref, PAGE_SIZE * nr); - put_page_tag_ref(ref); + if (get_page_tag_ref(page, &ref, &handle)) { + alloc_tag_sub(&ref, PAGE_SIZE * nr); + update_page_tag_ref(handle, &ref); + put_page_tag_ref(handle); } } } @@ -85,13 +124,14 @@ static inline struct alloc_tag *pgalloc_tag_get(struct page *page) struct alloc_tag *tag = NULL; if (mem_alloc_profiling_enabled()) { - union codetag_ref *ref = get_page_tag_ref(page); - - alloc_tag_sub_check(ref); - if (ref) { - if (ref->ct) - tag = ct_to_alloc_tag(ref->ct); - put_page_tag_ref(ref); + union pgtag_ref_handle handle; + union codetag_ref ref; + + if (get_page_tag_ref(page, &ref, &handle)) { + alloc_tag_sub_check(&ref); + if (ref.ct) + tag = ct_to_alloc_tag(ref.ct); + put_page_tag_ref(handle); } } @@ -106,8 +146,6 @@ static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) #else /* CONFIG_MEM_ALLOC_PROFILING */ -static inline union codetag_ref *get_page_tag_ref(struct page *page) { return NULL; } -static inline void put_page_tag_ref(union codetag_ref *ref) {} static inline void clear_page_tag_ref(struct page *page) {} static inline void pgalloc_tag_add(struct page *page, struct task_struct *task, unsigned int nr) {} diff --git a/lib/alloc_tag.c b/lib/alloc_tag.c index 648f32d52b8d..2ef762acc203 100644 --- a/lib/alloc_tag.c +++ b/lib/alloc_tag.c @@ -5,6 +5,7 @@ #include <linux/gfp.h> #include <linux/module.h> #include <linux/page_ext.h> +#include <linux/pgalloc_tag.h> #include <linux/proc_fs.h> #include <linux/seq_buf.h> #include <linux/seq_file.h> @@ -474,7 +475,7 @@ static __init void init_page_alloc_tagging(void) } struct page_ext_operations page_alloc_tagging_ops = { - .size = sizeof(union codetag_ref), + .size = sizeof(pgalloc_tag_ref), .need = need_page_alloc_tagging, .init = init_page_alloc_tagging, }; -- 2.47.0.rc1.288.g06298d1525-goog