Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

alloc_tag: introduce pgtag_ref_handle to abstract page tag references

To simplify later changes to page tag references, introduce new
pgtag_ref_handle type. This allows easy replacement of page_ext as a
storage of page allocation tags.

Link: https://lkml.kernel.org/r/20241023170759.999909-6-surenb@google.com
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Ard Biesheuvel <ardb@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Borislav Petkov (AMD) <bp@alien8.de>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Daniel Gomez <da.gomez@samsung.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: David Rientjes <rientjes@google.com>
Cc: Dennis Zhou <dennis@kernel.org>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Kalesh Singh <kaleshsingh@google.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Kent Overstreet <kent.overstreet@linux.dev>
Cc: Liam R. Howlett <Liam.Howlett@Oracle.com>
Cc: Luis Chamberlain <mcgrof@kernel.org>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport (Microsoft) <rppt@kernel.org>
Cc: Minchan Kim <minchan@google.com>
Cc: Paul E. McKenney <paulmck@kernel.org>
Cc: Petr Pavlu <petr.pavlu@suse.com>
Cc: Roman Gushchin <roman.gushchin@linux.dev>
Cc: Sami Tolvanen <samitolvanen@google.com>
Cc: Sourav Panda <souravpanda@google.com>
Cc: Steven Rostedt (Google) <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Thomas Huth <thuth@redhat.com>
Cc: Uladzislau Rezki (Sony) <urezki@gmail.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Xiongwei Song <xiongwei.song@windriver.com>
Cc: Yu Zhao <yuzhao@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Suren Baghdasaryan and committed by
Andrew Morton
42895a86 0f9b6856

+69 -52
+13 -12
include/linux/mm.h
··· 4181 4181 return; 4182 4182 4183 4183 for (i = nr_pages; i < (1 << old_order); i += nr_pages) { 4184 - union codetag_ref *ref = get_page_tag_ref(folio_page(folio, i)); 4184 + union pgtag_ref_handle handle; 4185 + union codetag_ref ref; 4185 4186 4186 - if (ref) { 4187 + if (get_page_tag_ref(folio_page(folio, i), &ref, &handle)) { 4187 4188 /* Set new reference to point to the original tag */ 4188 - alloc_tag_ref_set(ref, tag); 4189 - put_page_tag_ref(ref); 4189 + alloc_tag_ref_set(&ref, tag); 4190 + update_page_tag_ref(handle, &ref); 4191 + put_page_tag_ref(handle); 4190 4192 } 4191 4193 } 4192 4194 } 4193 4195 4194 4196 static inline void pgalloc_tag_copy(struct folio *new, struct folio *old) 4195 4197 { 4198 + union pgtag_ref_handle handle; 4199 + union codetag_ref ref; 4196 4200 struct alloc_tag *tag; 4197 - union codetag_ref *ref; 4198 4201 4199 4202 tag = pgalloc_tag_get(&old->page); 4200 4203 if (!tag) 4201 4204 return; 4202 4205 4203 - ref = get_page_tag_ref(&new->page); 4204 - if (!ref) 4206 + if (!get_page_tag_ref(&new->page, &ref, &handle)) 4205 4207 return; 4206 4208 4207 4209 /* Clear the old ref to the original allocation tag. */ 4208 4210 clear_page_tag_ref(&old->page); 4209 4211 /* Decrement the counters of the tag on get_new_folio. */ 4210 - alloc_tag_sub(ref, folio_size(new)); 4211 - 4212 - __alloc_tag_ref_set(ref, tag); 4213 - 4214 - put_page_tag_ref(ref); 4212 + alloc_tag_sub(&ref, folio_size(new)); 4213 + __alloc_tag_ref_set(&ref, tag); 4214 + update_page_tag_ref(handle, &ref); 4215 + put_page_tag_ref(handle); 4215 4216 } 4216 4217 #else /* !CONFIG_MEM_ALLOC_PROFILING */ 4217 4218 static inline void pgalloc_tag_split(struct folio *folio, int old_order, int new_order)
+56 -40
include/linux/pgalloc_tag.h
··· 11 11 12 12 #include <linux/page_ext.h> 13 13 14 + union pgtag_ref_handle { 15 + union codetag_ref *ref; /* reference in page extension */ 16 + }; 17 + 14 18 extern struct page_ext_operations page_alloc_tagging_ops; 15 19 16 - static inline union codetag_ref *codetag_ref_from_page_ext(struct page_ext *page_ext) 17 - { 18 - return (union codetag_ref *)page_ext_data(page_ext, &page_alloc_tagging_ops); 19 - } 20 - 21 - static inline struct page_ext *page_ext_from_codetag_ref(union codetag_ref *ref) 22 - { 23 - return (void *)ref - page_alloc_tagging_ops.offset; 24 - } 25 - 26 20 /* Should be called only if mem_alloc_profiling_enabled() */ 27 - static inline union codetag_ref *get_page_tag_ref(struct page *page) 21 + static inline bool get_page_tag_ref(struct page *page, union codetag_ref *ref, 22 + union pgtag_ref_handle *handle) 28 23 { 29 - if (page) { 30 - struct page_ext *page_ext = page_ext_get(page); 24 + struct page_ext *page_ext; 25 + union codetag_ref *tmp; 31 26 32 - if (page_ext) 33 - return codetag_ref_from_page_ext(page_ext); 34 - } 35 - return NULL; 27 + if (!page) 28 + return false; 29 + 30 + page_ext = page_ext_get(page); 31 + if (!page_ext) 32 + return false; 33 + 34 + tmp = (union codetag_ref *)page_ext_data(page_ext, &page_alloc_tagging_ops); 35 + ref->ct = tmp->ct; 36 + handle->ref = tmp; 37 + return true; 36 38 } 37 39 38 - static inline void put_page_tag_ref(union codetag_ref *ref) 40 + static inline void put_page_tag_ref(union pgtag_ref_handle handle) 39 41 { 40 - if (WARN_ON(!ref)) 42 + if (WARN_ON(!handle.ref)) 41 43 return; 42 44 43 - page_ext_put(page_ext_from_codetag_ref(ref)); 45 + page_ext_put((void *)handle.ref - page_alloc_tagging_ops.offset); 46 + } 47 + 48 + static inline void update_page_tag_ref(union pgtag_ref_handle handle, 49 + union codetag_ref *ref) 50 + { 51 + if (WARN_ON(!handle.ref || !ref)) 52 + return; 53 + 54 + handle.ref->ct = ref->ct; 44 55 } 45 56 46 57 static inline void clear_page_tag_ref(struct page *page) 47 58 { 48 59 if (mem_alloc_profiling_enabled()) { 49 - union codetag_ref *ref = get_page_tag_ref(page); 60 + union pgtag_ref_handle handle; 61 + union codetag_ref ref; 50 62 51 - if (ref) { 52 - set_codetag_empty(ref); 53 - put_page_tag_ref(ref); 63 + if (get_page_tag_ref(page, &ref, &handle)) { 64 + set_codetag_empty(&ref); 65 + update_page_tag_ref(handle, &ref); 66 + put_page_tag_ref(handle); 54 67 } 55 68 } 56 69 } ··· 72 59 unsigned int nr) 73 60 { 74 61 if (mem_alloc_profiling_enabled()) { 75 - union codetag_ref *ref = get_page_tag_ref(page); 62 + union pgtag_ref_handle handle; 63 + union codetag_ref ref; 76 64 77 - if (ref) { 78 - alloc_tag_add(ref, task->alloc_tag, PAGE_SIZE * nr); 79 - put_page_tag_ref(ref); 65 + if (get_page_tag_ref(page, &ref, &handle)) { 66 + alloc_tag_add(&ref, task->alloc_tag, PAGE_SIZE * nr); 67 + update_page_tag_ref(handle, &ref); 68 + put_page_tag_ref(handle); 80 69 } 81 70 } 82 71 } ··· 86 71 static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) 87 72 { 88 73 if (mem_alloc_profiling_enabled()) { 89 - union codetag_ref *ref = get_page_tag_ref(page); 74 + union pgtag_ref_handle handle; 75 + union codetag_ref ref; 90 76 91 - if (ref) { 92 - alloc_tag_sub(ref, PAGE_SIZE * nr); 93 - put_page_tag_ref(ref); 77 + if (get_page_tag_ref(page, &ref, &handle)) { 78 + alloc_tag_sub(&ref, PAGE_SIZE * nr); 79 + update_page_tag_ref(handle, &ref); 80 + put_page_tag_ref(handle); 94 81 } 95 82 } 96 83 } ··· 102 85 struct alloc_tag *tag = NULL; 103 86 104 87 if (mem_alloc_profiling_enabled()) { 105 - union codetag_ref *ref = get_page_tag_ref(page); 88 + union pgtag_ref_handle handle; 89 + union codetag_ref ref; 106 90 107 - alloc_tag_sub_check(ref); 108 - if (ref) { 109 - if (ref->ct) 110 - tag = ct_to_alloc_tag(ref->ct); 111 - put_page_tag_ref(ref); 91 + if (get_page_tag_ref(page, &ref, &handle)) { 92 + alloc_tag_sub_check(&ref); 93 + if (ref.ct) 94 + tag = ct_to_alloc_tag(ref.ct); 95 + put_page_tag_ref(handle); 112 96 } 113 97 } 114 98 ··· 124 106 125 107 #else /* CONFIG_MEM_ALLOC_PROFILING */ 126 108 127 - static inline union codetag_ref *get_page_tag_ref(struct page *page) { return NULL; } 128 - static inline void put_page_tag_ref(union codetag_ref *ref) {} 129 109 static inline void clear_page_tag_ref(struct page *page) {} 130 110 static inline void pgalloc_tag_add(struct page *page, struct task_struct *task, 131 111 unsigned int nr) {}