* [PATCH] mm/codetag: sub in advance when free non-compound high order pages @ 2025-05-04 6:19 David Wang 2025-05-05 13:12 ` Vlastimil Babka 0 siblings, 1 reply; 12+ messages in thread From: David Wang @ 2025-05-04 6:19 UTC (permalink / raw) To: akpm, vbabka, surenb, mhocko, jackmanb, hannes, ziy Cc: linux-mm, linux-kernel, David Wang When page is non-compound, page[0] could be released by other thread right after put_page_testzero failed in current thread, pgalloc_tag_sub_pages afterwards would manipulate an invalid page for accounting remaining pages: [timeline] [thread1] [thread2] | alloc_page non-compound V | get_page, rf counter inc V | in ___free_pages | put_page_testzero fails V | put_page, page released V | in ___free_pages, | pgalloc_tag_sub_pages | manipulate an invalid page V V Move the tag page accounting ahead, and only account remaining pages for non-compound pages with non-zero order. Signed-off-by: David Wang <00107082@163.com> --- mm/page_alloc.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5669baf2a6fe..c42e41ed35fe 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1163,12 +1163,25 @@ static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) this_cpu_sub(tag->counters->bytes, PAGE_SIZE * nr); } +static inline void pgalloc_tag_add_pages(struct page *page, unsigned int nr) +{ + struct alloc_tag *tag; + + if (!mem_alloc_profiling_enabled()) + return; + + tag = __pgalloc_tag_get(page); + if (tag) + this_cpu_add(tag->counters->bytes, PAGE_SIZE * nr); +} + #else /* CONFIG_MEM_ALLOC_PROFILING */ static inline void pgalloc_tag_add(struct page *page, struct task_struct *task, unsigned int nr) {} static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) {} static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) {} +static inline void pgalloc_tag_add_pages(struct page *page, unsigned int nr) {} #endif /* CONFIG_MEM_ALLOC_PROFILING */ @@ -5065,11 +5078,28 @@ static void ___free_pages(struct page *page, unsigned int order, { /* get PageHead before we drop reference */ int head = PageHead(page); + /* + * For remaining pages other than the first page of + * a non-compound allocation, we decrease its tag + * pages in advance, in case the first page is released + * by other thread inbetween our put_page_testzero and any + * accounting behavior afterwards. + */ + unsigned int remaining_tag_pages = 0; - if (put_page_testzero(page)) + if (order > 0 && !head) { + if (unlikely(page_ref_count(page) > 1)) { + remaining_tag_pages = (1 << order) - 1; + pgalloc_tag_sub_pages(page, remaining_tag_pages); + } + } + + if (put_page_testzero(page)) { + /* no need special treat for remaining pages, add it back. */ + if (unlikely(remaining_tag_pages > 0)) + pgalloc_tag_add_pages(page, remaining_tag_pages); __free_frozen_pages(page, order, fpi_flags); - else if (!head) { - pgalloc_tag_sub_pages(page, (1 << order) - 1); + } else if (!head) { while (order-- > 0) __free_frozen_pages(page + (1 << order), order, fpi_flags); -- 2.39.2 ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] mm/codetag: sub in advance when free non-compound high order pages 2025-05-04 6:19 [PATCH] mm/codetag: sub in advance when free non-compound high order pages David Wang @ 2025-05-05 13:12 ` Vlastimil Babka 2025-05-05 14:31 ` David Wang 0 siblings, 1 reply; 12+ messages in thread From: Vlastimil Babka @ 2025-05-05 13:12 UTC (permalink / raw) To: David Wang, akpm, surenb, mhocko, jackmanb, hannes, ziy Cc: linux-mm, linux-kernel, Shakeel Butt On 5/4/25 08:19, David Wang wrote: > When page is non-compound, page[0] could be released by other > thread right after put_page_testzero failed in current thread, > pgalloc_tag_sub_pages afterwards would manipulate an invalid > page for accounting remaining pages: > > [timeline] [thread1] [thread2] > | alloc_page non-compound > V > | get_page, rf counter inc > V > | in ___free_pages > | put_page_testzero fails > V > | put_page, page released > V > | in ___free_pages, > | pgalloc_tag_sub_pages > | manipulate an invalid page > V > V > > Move the tag page accounting ahead, and only account remaining pages > for non-compound pages with non-zero order. > > Signed-off-by: David Wang <00107082@163.com> Hmm, I think the problem was introduced by 51ff4d7486f0 ("mm: avoid extra mem_alloc_profiling_enabled() checks"). Previously we'd get the tag pointer upfront and avoid the page use-after-free. It would likely be nicer to fix it by going back to that approach for ___free_pages(), while hopefully keeping the optimisations of 51ff4d7486f0 for the other call sites where it applies? > --- > mm/page_alloc.c | 36 +++++++++++++++++++++++++++++++++--- > 1 file changed, 33 insertions(+), 3 deletions(-) > > diff --git a/mm/page_alloc.c b/mm/page_alloc.c > index 5669baf2a6fe..c42e41ed35fe 100644 > --- a/mm/page_alloc.c > +++ b/mm/page_alloc.c > @@ -1163,12 +1163,25 @@ static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) > this_cpu_sub(tag->counters->bytes, PAGE_SIZE * nr); > } > > +static inline void pgalloc_tag_add_pages(struct page *page, unsigned int nr) > +{ > + struct alloc_tag *tag; > + > + if (!mem_alloc_profiling_enabled()) > + return; > + > + tag = __pgalloc_tag_get(page); > + if (tag) > + this_cpu_add(tag->counters->bytes, PAGE_SIZE * nr); > +} > + > #else /* CONFIG_MEM_ALLOC_PROFILING */ > > static inline void pgalloc_tag_add(struct page *page, struct task_struct *task, > unsigned int nr) {} > static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) {} > static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) {} > +static inline void pgalloc_tag_add_pages(struct page *page, unsigned int nr) {} > > #endif /* CONFIG_MEM_ALLOC_PROFILING */ > > @@ -5065,11 +5078,28 @@ static void ___free_pages(struct page *page, unsigned int order, > { > /* get PageHead before we drop reference */ > int head = PageHead(page); > + /* > + * For remaining pages other than the first page of > + * a non-compound allocation, we decrease its tag > + * pages in advance, in case the first page is released > + * by other thread inbetween our put_page_testzero and any > + * accounting behavior afterwards. > + */ > + unsigned int remaining_tag_pages = 0; > > - if (put_page_testzero(page)) > + if (order > 0 && !head) { > + if (unlikely(page_ref_count(page) > 1)) { > + remaining_tag_pages = (1 << order) - 1; > + pgalloc_tag_sub_pages(page, remaining_tag_pages); > + } > + } > + > + if (put_page_testzero(page)) { > + /* no need special treat for remaining pages, add it back. */ > + if (unlikely(remaining_tag_pages > 0)) > + pgalloc_tag_add_pages(page, remaining_tag_pages); > __free_frozen_pages(page, order, fpi_flags); > - else if (!head) { > - pgalloc_tag_sub_pages(page, (1 << order) - 1); > + } else if (!head) { > while (order-- > 0) > __free_frozen_pages(page + (1 << order), order, > fpi_flags); ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] mm/codetag: sub in advance when free non-compound high order pages 2025-05-05 13:12 ` Vlastimil Babka @ 2025-05-05 14:31 ` David Wang 2025-05-05 14:55 ` Vlastimil Babka 0 siblings, 1 reply; 12+ messages in thread From: David Wang @ 2025-05-05 14:31 UTC (permalink / raw) To: Vlastimil Babka Cc: akpm, surenb, mhocko, jackmanb, hannes, ziy, linux-mm, linux-kernel, Shakeel Butt At 2025-05-05 21:12:55, "Vlastimil Babka" <vbabka@suse.cz> wrote: >On 5/4/25 08:19, David Wang wrote: >> When page is non-compound, page[0] could be released by other >> thread right after put_page_testzero failed in current thread, >> pgalloc_tag_sub_pages afterwards would manipulate an invalid >> page for accounting remaining pages: >> >> [timeline] [thread1] [thread2] >> | alloc_page non-compound >> V >> | get_page, rf counter inc >> V >> | in ___free_pages >> | put_page_testzero fails >> V >> | put_page, page released >> V >> | in ___free_pages, >> | pgalloc_tag_sub_pages >> | manipulate an invalid page >> V >> V >> >> Move the tag page accounting ahead, and only account remaining pages >> for non-compound pages with non-zero order. >> >> Signed-off-by: David Wang <00107082@163.com> > >Hmm, I think the problem was introduced by 51ff4d7486f0 ("mm: avoid extra >mem_alloc_profiling_enabled() checks"). Previously we'd get the tag pointer >upfront and avoid the page use-after-free. Oh, you're right. I forgot to check history...... > >It would likely be nicer to fix it by going back to that approach for >___free_pages(), while hopefully keeping the optimisations of 51ff4d7486f0 >for the other call sites where it applies? After checking that commit, I kind of feels the changes in __free_pages are the major optimization of the commit.... What about revert that commit and make optimization by condition checks, similar to what this patch did? David ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] mm/codetag: sub in advance when free non-compound high order pages 2025-05-05 14:31 ` David Wang @ 2025-05-05 14:55 ` Vlastimil Babka 2025-05-05 15:33 ` Suren Baghdasaryan 0 siblings, 1 reply; 12+ messages in thread From: Vlastimil Babka @ 2025-05-05 14:55 UTC (permalink / raw) To: David Wang Cc: akpm, surenb, mhocko, jackmanb, hannes, ziy, linux-mm, linux-kernel, Shakeel Butt On 5/5/25 16:31, David Wang wrote: > > > At 2025-05-05 21:12:55, "Vlastimil Babka" <vbabka@suse.cz> wrote: >>On 5/4/25 08:19, David Wang wrote: >>> When page is non-compound, page[0] could be released by other >>> thread right after put_page_testzero failed in current thread, >>> pgalloc_tag_sub_pages afterwards would manipulate an invalid >>> page for accounting remaining pages: >>> >>> [timeline] [thread1] [thread2] >>> | alloc_page non-compound >>> V >>> | get_page, rf counter inc >>> V >>> | in ___free_pages >>> | put_page_testzero fails >>> V >>> | put_page, page released >>> V >>> | in ___free_pages, >>> | pgalloc_tag_sub_pages >>> | manipulate an invalid page >>> V >>> V >>> >>> Move the tag page accounting ahead, and only account remaining pages >>> for non-compound pages with non-zero order. >>> >>> Signed-off-by: David Wang <00107082@163.com> >> >>Hmm, I think the problem was introduced by 51ff4d7486f0 ("mm: avoid extra >>mem_alloc_profiling_enabled() checks"). Previously we'd get the tag pointer >>upfront and avoid the page use-after-free. > > > Oh, you're right. I forgot to check history...... > > >> >>It would likely be nicer to fix it by going back to that approach for >>___free_pages(), while hopefully keeping the optimisations of 51ff4d7486f0 >>for the other call sites where it applies? > > After checking that commit, I kind of feels the changes in __free_pages are > the major optimization of the commit.... We could have both pgalloc_tag_get() to use in __free_page() as before 51ff4d7486f0, and keep __pgalloc_tag_get() to use in pgalloc_tag_split() and pgalloc_tag_swap(). I think __free_page() didn't benefit from the stated purpose of "avoiding mem_alloc_profiling_enabled() ... which is often called after that check was already done" > What about revert that commit and make optimization by condition checks, > similar to what this patch did? The downside of the condition checks is they make the code more complex and might actually increase overhead when mem_alloc_profiling_enabled() is false, as those checks add non-static branches outside of the static branch that's mem_alloc_profiling_enabled(). I think __free_pages() before 51ff4d7486f0 was quite ok. - pgalloc_tag_get() is done unconditionally, but its code is all inside the mem_alloc_profiling_enabled() static branch so that's a no-op when profiling is not enabled - pgalloc_tag_sub_pages() is also all behind the static branch inside. Also it's a very rare path anyway, most freeing should go through the put_page_testzero() being true. > David > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] mm/codetag: sub in advance when free non-compound high order pages 2025-05-05 14:55 ` Vlastimil Babka @ 2025-05-05 15:33 ` Suren Baghdasaryan 2025-05-05 16:42 ` David Wang 0 siblings, 1 reply; 12+ messages in thread From: Suren Baghdasaryan @ 2025-05-05 15:33 UTC (permalink / raw) To: Vlastimil Babka Cc: David Wang, akpm, mhocko, jackmanb, hannes, ziy, linux-mm, linux-kernel, Shakeel Butt On Mon, May 5, 2025 at 7:55 AM Vlastimil Babka <vbabka@suse.cz> wrote: > > On 5/5/25 16:31, David Wang wrote: > > > > > > At 2025-05-05 21:12:55, "Vlastimil Babka" <vbabka@suse.cz> wrote: > >>On 5/4/25 08:19, David Wang wrote: > >>> When page is non-compound, page[0] could be released by other > >>> thread right after put_page_testzero failed in current thread, > >>> pgalloc_tag_sub_pages afterwards would manipulate an invalid > >>> page for accounting remaining pages: > >>> > >>> [timeline] [thread1] [thread2] > >>> | alloc_page non-compound > >>> V > >>> | get_page, rf counter inc > >>> V > >>> | in ___free_pages > >>> | put_page_testzero fails > >>> V > >>> | put_page, page released > >>> V > >>> | in ___free_pages, > >>> | pgalloc_tag_sub_pages > >>> | manipulate an invalid page > >>> V > >>> V > >>> > >>> Move the tag page accounting ahead, and only account remaining pages > >>> for non-compound pages with non-zero order. > >>> > >>> Signed-off-by: David Wang <00107082@163.com> Thanks for reporting! > >> > >>Hmm, I think the problem was introduced by 51ff4d7486f0 ("mm: avoid extra > >>mem_alloc_profiling_enabled() checks"). Previously we'd get the tag pointer > >>upfront and avoid the page use-after-free. Right, sorry I missed that. > > > > > > Oh, you're right. I forgot to check history...... > > > > > >> > >>It would likely be nicer to fix it by going back to that approach for > >>___free_pages(), while hopefully keeping the optimisations of 51ff4d7486f0 > >>for the other call sites where it applies? > > > > After checking that commit, I kind of feels the changes in __free_pages are > > the major optimization of the commit.... > > We could have both pgalloc_tag_get() to use in __free_page() as before > 51ff4d7486f0, and keep __pgalloc_tag_get() to use in pgalloc_tag_split() and > pgalloc_tag_swap(). Yes, we can add back pgalloc_tag_get() which would call __pgalloc_tag_get() if mem_alloc_profiling_enabled() is true and change pgalloc_tag_sub_pages() back to use tags instead of pages. __free_pages() is the only user of that function, so that change should not affect anything else. > > I think __free_page() didn't benefit from the stated purpose of "avoiding > mem_alloc_profiling_enabled() ... which is often called after that check was > already done" > > > What about revert that commit and make optimization by condition checks, > > similar to what this patch did? > > The downside of the condition checks is they make the code more complex and > might actually increase overhead when mem_alloc_profiling_enabled() is > false, as those checks add non-static branches outside of the static branch > that's mem_alloc_profiling_enabled(). > > I think __free_pages() before 51ff4d7486f0 was quite ok. > > - pgalloc_tag_get() is done unconditionally, but its code is all inside the > mem_alloc_profiling_enabled() static branch so that's a no-op when profiling > is not enabled > > - pgalloc_tag_sub_pages() is also all behind the static branch inside. Also > it's a very rare path anyway, most freeing should go through the > put_page_testzero() being true. Yeah, the main goal of that change in __free_page() was to make __pgalloc_tag_get() a local function for alloc_tags and limiting the direct use of struct alloc_tag in the core mm code. Obviously I screwed up forgetting why we had to store the tag in the first place. An additional comment in __free_page() is probably a good idea to avoid confusion in the future. Thanks, Suren. > > > David > > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] mm/codetag: sub in advance when free non-compound high order pages 2025-05-05 15:33 ` Suren Baghdasaryan @ 2025-05-05 16:42 ` David Wang 2025-05-05 16:53 ` Suren Baghdasaryan 0 siblings, 1 reply; 12+ messages in thread From: David Wang @ 2025-05-05 16:42 UTC (permalink / raw) To: Suren Baghdasaryan Cc: Vlastimil Babka, akpm, mhocko, jackmanb, hannes, ziy, linux-mm, linux-kernel, Shakeel Butt At 2025-05-05 23:33:50, "Suren Baghdasaryan" <surenb@google.com> wrote: >On Mon, May 5, 2025 at 7:55 AM Vlastimil Babka <vbabka@suse.cz> wrote: >> >> On 5/5/25 16:31, David Wang wrote: >> > >> > >> > At 2025-05-05 21:12:55, "Vlastimil Babka" <vbabka@suse.cz> wrote: >> >>On 5/4/25 08:19, David Wang wrote: >> >>> When page is non-compound, page[0] could be released by other >> >>> thread right after put_page_testzero failed in current thread, >> >>> pgalloc_tag_sub_pages afterwards would manipulate an invalid >> >>> page for accounting remaining pages: >> >>> >> >>> [timeline] [thread1] [thread2] >> >>> | alloc_page non-compound >> >>> V >> >>> | get_page, rf counter inc >> >>> V >> >>> | in ___free_pages >> >>> | put_page_testzero fails >> >>> V >> >>> | put_page, page released >> >>> V >> >>> | in ___free_pages, >> >>> | pgalloc_tag_sub_pages >> >>> | manipulate an invalid page >> >>> V >> >>> V >> >>> >> >>> Move the tag page accounting ahead, and only account remaining pages >> >>> for non-compound pages with non-zero order. >> >>> >> >>> Signed-off-by: David Wang <00107082@163.com> > >Thanks for reporting! > >> >> >> >>Hmm, I think the problem was introduced by 51ff4d7486f0 ("mm: avoid extra >> >>mem_alloc_profiling_enabled() checks"). Previously we'd get the tag pointer >> >>upfront and avoid the page use-after-free. > >Right, sorry I missed that. > >> > >> > >> > Oh, you're right. I forgot to check history...... >> > >> > >> >> >> >>It would likely be nicer to fix it by going back to that approach for >> >>___free_pages(), while hopefully keeping the optimisations of 51ff4d7486f0 >> >>for the other call sites where it applies? >> > >> > After checking that commit, I kind of feels the changes in __free_pages are >> > the major optimization of the commit.... >> >> We could have both pgalloc_tag_get() to use in __free_page() as before >> 51ff4d7486f0, and keep __pgalloc_tag_get() to use in pgalloc_tag_split() and >> pgalloc_tag_swap(). > >Yes, we can add back pgalloc_tag_get() which would call >__pgalloc_tag_get() if mem_alloc_profiling_enabled() is true and >change pgalloc_tag_sub_pages() back to use tags instead of pages. >__free_pages() is the only user of that function, so that change >should not affect anything else. Adding back pgalloc_tag_get() seems just reverting 51ff4d7486f0..... Do you want me to do it or you take over and make further adjustments? > >> >> I think __free_page() didn't benefit from the stated purpose of "avoiding >> mem_alloc_profiling_enabled() ... which is often called after that check was >> already done" >> >> > What about revert that commit and make optimization by condition checks, >> > similar to what this patch did? >> >> The downside of the condition checks is they make the code more complex and >> might actually increase overhead when mem_alloc_profiling_enabled() is >> false, as those checks add non-static branches outside of the static branch >> that's mem_alloc_profiling_enabled(). >> >> I think __free_pages() before 51ff4d7486f0 was quite ok. >> >> - pgalloc_tag_get() is done unconditionally, but its code is all inside the >> mem_alloc_profiling_enabled() static branch so that's a no-op when profiling >> is not enabled >> >> - pgalloc_tag_sub_pages() is also all behind the static branch inside. Also >> it's a very rare path anyway, most freeing should go through the >> put_page_testzero() being true. > >Yeah, the main goal of that change in __free_page() was to make >__pgalloc_tag_get() a local function for alloc_tags and limiting the >direct use of struct alloc_tag in the core mm code. Obviously I >screwed up forgetting why we had to store the tag in the first place. >An additional comment in __free_page() is probably a good idea to >avoid confusion in the future. >Thanks, >Suren. > >> >> > David >> > >> ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] mm/codetag: sub in advance when free non-compound high order pages 2025-05-05 16:42 ` David Wang @ 2025-05-05 16:53 ` Suren Baghdasaryan 2025-05-05 18:34 ` [PATCH v2] mm/codetag: move tag retrieval back upfront in __free_pages() David Wang 2025-05-05 19:30 ` [PATCH v3] " David Wang 0 siblings, 2 replies; 12+ messages in thread From: Suren Baghdasaryan @ 2025-05-05 16:53 UTC (permalink / raw) To: David Wang Cc: Vlastimil Babka, akpm, mhocko, jackmanb, hannes, ziy, linux-mm, linux-kernel, Shakeel Butt On Mon, May 5, 2025 at 9:43 AM David Wang <00107082@163.com> wrote: > > > > > At 2025-05-05 23:33:50, "Suren Baghdasaryan" <surenb@google.com> wrote: > >On Mon, May 5, 2025 at 7:55 AM Vlastimil Babka <vbabka@suse.cz> wrote: > >> > >> On 5/5/25 16:31, David Wang wrote: > >> > > >> > > >> > At 2025-05-05 21:12:55, "Vlastimil Babka" <vbabka@suse.cz> wrote: > >> >>On 5/4/25 08:19, David Wang wrote: > >> >>> When page is non-compound, page[0] could be released by other > >> >>> thread right after put_page_testzero failed in current thread, > >> >>> pgalloc_tag_sub_pages afterwards would manipulate an invalid > >> >>> page for accounting remaining pages: > >> >>> > >> >>> [timeline] [thread1] [thread2] > >> >>> | alloc_page non-compound > >> >>> V > >> >>> | get_page, rf counter inc > >> >>> V > >> >>> | in ___free_pages > >> >>> | put_page_testzero fails > >> >>> V > >> >>> | put_page, page released > >> >>> V > >> >>> | in ___free_pages, > >> >>> | pgalloc_tag_sub_pages > >> >>> | manipulate an invalid page > >> >>> V > >> >>> V > >> >>> > >> >>> Move the tag page accounting ahead, and only account remaining pages > >> >>> for non-compound pages with non-zero order. > >> >>> > >> >>> Signed-off-by: David Wang <00107082@163.com> > > > >Thanks for reporting! > > > >> >> > >> >>Hmm, I think the problem was introduced by 51ff4d7486f0 ("mm: avoid extra > >> >>mem_alloc_profiling_enabled() checks"). Previously we'd get the tag pointer > >> >>upfront and avoid the page use-after-free. > > > >Right, sorry I missed that. > > > >> > > >> > > >> > Oh, you're right. I forgot to check history...... > >> > > >> > > >> >> > >> >>It would likely be nicer to fix it by going back to that approach for > >> >>___free_pages(), while hopefully keeping the optimisations of 51ff4d7486f0 > >> >>for the other call sites where it applies? > >> > > >> > After checking that commit, I kind of feels the changes in __free_pages are > >> > the major optimization of the commit.... > >> > >> We could have both pgalloc_tag_get() to use in __free_page() as before > >> 51ff4d7486f0, and keep __pgalloc_tag_get() to use in pgalloc_tag_split() and > >> pgalloc_tag_swap(). > > > >Yes, we can add back pgalloc_tag_get() which would call > >__pgalloc_tag_get() if mem_alloc_profiling_enabled() is true and > >change pgalloc_tag_sub_pages() back to use tags instead of pages. > >__free_pages() is the only user of that function, so that change > >should not affect anything else. > > > Adding back pgalloc_tag_get() seems just reverting 51ff4d7486f0..... Not quite. pgalloc_tag_split() and pgalloc_tag_swap() will still be using __pgalloc_tag_get(), so would avoid the extra checks. > Do you want me to do it or you take over and make further adjustments? The change I suggested should be simple, so take a stab at it and I'll review and ack. If you prefer me to make the change, let me know. > > > > > > >> > >> I think __free_page() didn't benefit from the stated purpose of "avoiding > >> mem_alloc_profiling_enabled() ... which is often called after that check was > >> already done" > >> > >> > What about revert that commit and make optimization by condition checks, > >> > similar to what this patch did? > >> > >> The downside of the condition checks is they make the code more complex and > >> might actually increase overhead when mem_alloc_profiling_enabled() is > >> false, as those checks add non-static branches outside of the static branch > >> that's mem_alloc_profiling_enabled(). > >> > >> I think __free_pages() before 51ff4d7486f0 was quite ok. > >> > >> - pgalloc_tag_get() is done unconditionally, but its code is all inside the > >> mem_alloc_profiling_enabled() static branch so that's a no-op when profiling > >> is not enabled > >> > >> - pgalloc_tag_sub_pages() is also all behind the static branch inside. Also > >> it's a very rare path anyway, most freeing should go through the > >> put_page_testzero() being true. > > > >Yeah, the main goal of that change in __free_page() was to make > >__pgalloc_tag_get() a local function for alloc_tags and limiting the > >direct use of struct alloc_tag in the core mm code. Obviously I > >screwed up forgetting why we had to store the tag in the first place. > >An additional comment in __free_page() is probably a good idea to > >avoid confusion in the future. > >Thanks, > >Suren. > > > >> > >> > David > >> > > >> ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2] mm/codetag: move tag retrieval back upfront in __free_pages() 2025-05-05 16:53 ` Suren Baghdasaryan @ 2025-05-05 18:34 ` David Wang 2025-05-05 19:17 ` David Wang 2025-05-05 19:30 ` [PATCH v3] " David Wang 1 sibling, 1 reply; 12+ messages in thread From: David Wang @ 2025-05-05 18:34 UTC (permalink / raw) To: akpm, vbabka, surenb, mhocko, jackmanb, hannes, ziy Cc: linux-mm, linux-kernel, David Wang Commit 51ff4d7486f0 ("mm: avoid extra mem_alloc_profiling_enabled() checks") introduces a possible use-after-free scenario, when page is non-compound, page[0] could be released by other thread right after put_page_testzero failed in current thread, pgalloc_tag_sub_pages afterwards would manipulate an invalid page for accounting remaining pages: [timeline] [thread1] [thread2] | alloc_page non-compound V | get_page, rf counter inc V | in ___free_pages | put_page_testzero fails V | put_page, page released V | in ___free_pages, | pgalloc_tag_sub_pages | manipulate an invalid page V Restore __free_pages() to its state before, retrieve alloc tag beforehand. Fixes: 51ff4d7486f0 ("mm: avoid extra mem_alloc_profiling_enabled() checks") Signed-off-by: David Wang <00107082@163.com> --- include/linux/pgalloc_tag.h | 7 +++++++ mm/page_alloc.c | 15 ++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/include/linux/pgalloc_tag.h b/include/linux/pgalloc_tag.h index c74077977830..97eb4835568e 100644 --- a/include/linux/pgalloc_tag.h +++ b/include/linux/pgalloc_tag.h @@ -188,6 +188,13 @@ static inline struct alloc_tag *__pgalloc_tag_get(struct page *page) return tag; } +static inline struct alloc_tag *pgalloc_tag_get(struct page *page) +{ + if (mem_alloc_profiling_enabled()) + return __pgalloc_tag_get(page); + return NULL; +} + void pgalloc_tag_split(struct folio *folio, int old_order, int new_order); void pgalloc_tag_swap(struct folio *new, struct folio *old); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5669baf2a6fe..1b00e14a9780 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1151,14 +1151,9 @@ static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) __pgalloc_tag_sub(page, nr); } -static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) +/* When tag is not NULL, assuming mem_alloc_profiling_enabled */ +static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) { - struct alloc_tag *tag; - - if (!mem_alloc_profiling_enabled()) - return; - - tag = __pgalloc_tag_get(page); if (tag) this_cpu_sub(tag->counters->bytes, PAGE_SIZE * nr); } @@ -1168,7 +1163,7 @@ static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) static inline void pgalloc_tag_add(struct page *page, struct task_struct *task, unsigned int nr) {} static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) {} -static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) {} +static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) {} #endif /* CONFIG_MEM_ALLOC_PROFILING */ @@ -5065,11 +5060,13 @@ static void ___free_pages(struct page *page, unsigned int order, { /* get PageHead before we drop reference */ int head = PageHead(page); + /* get alloc tag in case the page is released by others */ + struct alloc_tag *tag = pgalloc_tag_get(page); if (put_page_testzero(page)) __free_frozen_pages(page, order, fpi_flags); else if (!head) { - pgalloc_tag_sub_pages(page, (1 << order) - 1); + pgalloc_tag_sub_pages(tag, (1 << order) - 1); while (order-- > 0) __free_frozen_pages(page + (1 << order), order, fpi_flags); -- 2.39.2 ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re:[PATCH v2] mm/codetag: move tag retrieval back upfront in __free_pages() 2025-05-05 18:34 ` [PATCH v2] mm/codetag: move tag retrieval back upfront in __free_pages() David Wang @ 2025-05-05 19:17 ` David Wang 0 siblings, 0 replies; 12+ messages in thread From: David Wang @ 2025-05-05 19:17 UTC (permalink / raw) To: akpm, vbabka, surenb, mhocko, jackmanb, hannes, ziy Cc: linux-mm, linux-kernel Sorry, I made a mistake, pgalloc_tag_get should have a dummy definition when CONFIG_MEM_ALLOC_PROFILING not defined, will send another patch. At 2025-05-06 02:34:23, "David Wang" <00107082@163.com> wrote: >Commit 51ff4d7486f0 ("mm: avoid extra mem_alloc_profiling_enabled() > checks") introduces a possible use-after-free scenario, when page >is non-compound, page[0] could be released by other thread right >after put_page_testzero failed in current thread, pgalloc_tag_sub_pages >afterwards would manipulate an invalid page for accounting remaining >pages: > >[timeline] [thread1] [thread2] > | alloc_page non-compound > V > | get_page, rf counter inc > V > | in ___free_pages > | put_page_testzero fails > V > | put_page, page released > V > | in ___free_pages, > | pgalloc_tag_sub_pages > | manipulate an invalid page > V > >Restore __free_pages() to its state before, retrieve alloc tag >beforehand. > >Fixes: 51ff4d7486f0 ("mm: avoid extra mem_alloc_profiling_enabled() checks") >Signed-off-by: David Wang <00107082@163.com> >--- > include/linux/pgalloc_tag.h | 7 +++++++ > mm/page_alloc.c | 15 ++++++--------- > 2 files changed, 13 insertions(+), 9 deletions(-) > >diff --git a/include/linux/pgalloc_tag.h b/include/linux/pgalloc_tag.h >index c74077977830..97eb4835568e 100644 >--- a/include/linux/pgalloc_tag.h >+++ b/include/linux/pgalloc_tag.h >@@ -188,6 +188,13 @@ static inline struct alloc_tag *__pgalloc_tag_get(struct page *page) > return tag; > } > >+static inline struct alloc_tag *pgalloc_tag_get(struct page *page) >+{ >+ if (mem_alloc_profiling_enabled()) >+ return __pgalloc_tag_get(page); >+ return NULL; >+} >+ > void pgalloc_tag_split(struct folio *folio, int old_order, int new_order); > void pgalloc_tag_swap(struct folio *new, struct folio *old); > >diff --git a/mm/page_alloc.c b/mm/page_alloc.c >index 5669baf2a6fe..1b00e14a9780 100644 >--- a/mm/page_alloc.c >+++ b/mm/page_alloc.c >@@ -1151,14 +1151,9 @@ static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) > __pgalloc_tag_sub(page, nr); > } > >-static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) >+/* When tag is not NULL, assuming mem_alloc_profiling_enabled */ >+static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) > { >- struct alloc_tag *tag; >- >- if (!mem_alloc_profiling_enabled()) >- return; >- >- tag = __pgalloc_tag_get(page); > if (tag) > this_cpu_sub(tag->counters->bytes, PAGE_SIZE * nr); > } >@@ -1168,7 +1163,7 @@ static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) > static inline void pgalloc_tag_add(struct page *page, struct task_struct *task, > unsigned int nr) {} > static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) {} >-static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) {} >+static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) {} > > #endif /* CONFIG_MEM_ALLOC_PROFILING */ > >@@ -5065,11 +5060,13 @@ static void ___free_pages(struct page *page, unsigned int order, > { > /* get PageHead before we drop reference */ > int head = PageHead(page); >+ /* get alloc tag in case the page is released by others */ >+ struct alloc_tag *tag = pgalloc_tag_get(page); > > if (put_page_testzero(page)) > __free_frozen_pages(page, order, fpi_flags); > else if (!head) { >- pgalloc_tag_sub_pages(page, (1 << order) - 1); >+ pgalloc_tag_sub_pages(tag, (1 << order) - 1); > while (order-- > 0) > __free_frozen_pages(page + (1 << order), order, > fpi_flags); >-- >2.39.2 ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3] mm/codetag: move tag retrieval back upfront in __free_pages() 2025-05-05 16:53 ` Suren Baghdasaryan 2025-05-05 18:34 ` [PATCH v2] mm/codetag: move tag retrieval back upfront in __free_pages() David Wang @ 2025-05-05 19:30 ` David Wang 2025-05-05 20:32 ` Suren Baghdasaryan 2025-05-06 7:58 ` Vlastimil Babka 1 sibling, 2 replies; 12+ messages in thread From: David Wang @ 2025-05-05 19:30 UTC (permalink / raw) To: akpm, vbabka, surenb, mhocko, jackmanb, hannes, ziy Cc: linux-mm, linux-kernel, David Wang Commit 51ff4d7486f0 ("mm: avoid extra mem_alloc_profiling_enabled() checks") introduces a possible use-after-free scenario, when page is non-compound, page[0] could be released by other thread right after put_page_testzero failed in current thread, pgalloc_tag_sub_pages afterwards would manipulate an invalid page for accounting remaining pages: [timeline] [thread1] [thread2] | alloc_page non-compound V | get_page, rf counter inc V | in ___free_pages | put_page_testzero fails V | put_page, page released V | in ___free_pages, | pgalloc_tag_sub_pages | manipulate an invalid page V Restore __free_pages() to its state before, retrieve alloc tag beforehand. Fixes: 51ff4d7486f0 ("mm: avoid extra mem_alloc_profiling_enabled() checks") Signed-off-by: David Wang <00107082@163.com> --- include/linux/pgalloc_tag.h | 8 ++++++++ mm/page_alloc.c | 15 ++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/linux/pgalloc_tag.h b/include/linux/pgalloc_tag.h index c74077977830..8a7f4f802c57 100644 --- a/include/linux/pgalloc_tag.h +++ b/include/linux/pgalloc_tag.h @@ -188,6 +188,13 @@ static inline struct alloc_tag *__pgalloc_tag_get(struct page *page) return tag; } +static inline struct alloc_tag *pgalloc_tag_get(struct page *page) +{ + if (mem_alloc_profiling_enabled()) + return __pgalloc_tag_get(page); + return NULL; +} + void pgalloc_tag_split(struct folio *folio, int old_order, int new_order); void pgalloc_tag_swap(struct folio *new, struct folio *old); @@ -199,6 +206,7 @@ static inline void clear_page_tag_ref(struct page *page) {} static inline void alloc_tag_sec_init(void) {} static inline void pgalloc_tag_split(struct folio *folio, int old_order, int new_order) {} static inline void pgalloc_tag_swap(struct folio *new, struct folio *old) {} +static inline struct alloc_tag *pgalloc_tag_get(struct page *page) { return NULL; } #endif /* CONFIG_MEM_ALLOC_PROFILING */ diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5669baf2a6fe..1b00e14a9780 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -1151,14 +1151,9 @@ static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) __pgalloc_tag_sub(page, nr); } -static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) +/* When tag is not NULL, assuming mem_alloc_profiling_enabled */ +static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) { - struct alloc_tag *tag; - - if (!mem_alloc_profiling_enabled()) - return; - - tag = __pgalloc_tag_get(page); if (tag) this_cpu_sub(tag->counters->bytes, PAGE_SIZE * nr); } @@ -1168,7 +1163,7 @@ static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) static inline void pgalloc_tag_add(struct page *page, struct task_struct *task, unsigned int nr) {} static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) {} -static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) {} +static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) {} #endif /* CONFIG_MEM_ALLOC_PROFILING */ @@ -5065,11 +5060,13 @@ static void ___free_pages(struct page *page, unsigned int order, { /* get PageHead before we drop reference */ int head = PageHead(page); + /* get alloc tag in case the page is released by others */ + struct alloc_tag *tag = pgalloc_tag_get(page); if (put_page_testzero(page)) __free_frozen_pages(page, order, fpi_flags); else if (!head) { - pgalloc_tag_sub_pages(page, (1 << order) - 1); + pgalloc_tag_sub_pages(tag, (1 << order) - 1); while (order-- > 0) __free_frozen_pages(page + (1 << order), order, fpi_flags); -- 2.39.2 ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3] mm/codetag: move tag retrieval back upfront in __free_pages() 2025-05-05 19:30 ` [PATCH v3] " David Wang @ 2025-05-05 20:32 ` Suren Baghdasaryan 2025-05-06 7:58 ` Vlastimil Babka 1 sibling, 0 replies; 12+ messages in thread From: Suren Baghdasaryan @ 2025-05-05 20:32 UTC (permalink / raw) To: David Wang Cc: akpm, vbabka, mhocko, jackmanb, hannes, ziy, linux-mm, linux-kernel On Mon, May 5, 2025 at 12:31 PM David Wang <00107082@163.com> wrote: > > Commit 51ff4d7486f0 ("mm: avoid extra mem_alloc_profiling_enabled() > checks") introduces a possible use-after-free scenario, when page > is non-compound, page[0] could be released by other thread right > after put_page_testzero failed in current thread, pgalloc_tag_sub_pages > afterwards would manipulate an invalid page for accounting remaining > pages: > > [timeline] [thread1] [thread2] > | alloc_page non-compound > V > | get_page, rf counter inc > V > | in ___free_pages > | put_page_testzero fails > V > | put_page, page released > V > | in ___free_pages, > | pgalloc_tag_sub_pages > | manipulate an invalid page > V > > Restore __free_pages() to its state before, retrieve alloc tag > beforehand. > > Fixes: 51ff4d7486f0 ("mm: avoid extra mem_alloc_profiling_enabled() checks") > Signed-off-by: David Wang <00107082@163.com> Acked-by: Suren Baghdasaryan <surenb@google.com> Thanks! > --- > include/linux/pgalloc_tag.h | 8 ++++++++ > mm/page_alloc.c | 15 ++++++--------- > 2 files changed, 14 insertions(+), 9 deletions(-) > > diff --git a/include/linux/pgalloc_tag.h b/include/linux/pgalloc_tag.h > index c74077977830..8a7f4f802c57 100644 > --- a/include/linux/pgalloc_tag.h > +++ b/include/linux/pgalloc_tag.h > @@ -188,6 +188,13 @@ static inline struct alloc_tag *__pgalloc_tag_get(struct page *page) > return tag; > } > > +static inline struct alloc_tag *pgalloc_tag_get(struct page *page) > +{ > + if (mem_alloc_profiling_enabled()) > + return __pgalloc_tag_get(page); > + return NULL; > +} > + > void pgalloc_tag_split(struct folio *folio, int old_order, int new_order); > void pgalloc_tag_swap(struct folio *new, struct folio *old); > > @@ -199,6 +206,7 @@ static inline void clear_page_tag_ref(struct page *page) {} > static inline void alloc_tag_sec_init(void) {} > static inline void pgalloc_tag_split(struct folio *folio, int old_order, int new_order) {} > static inline void pgalloc_tag_swap(struct folio *new, struct folio *old) {} > +static inline struct alloc_tag *pgalloc_tag_get(struct page *page) { return NULL; } > > #endif /* CONFIG_MEM_ALLOC_PROFILING */ > > diff --git a/mm/page_alloc.c b/mm/page_alloc.c > index 5669baf2a6fe..1b00e14a9780 100644 > --- a/mm/page_alloc.c > +++ b/mm/page_alloc.c > @@ -1151,14 +1151,9 @@ static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) > __pgalloc_tag_sub(page, nr); > } > > -static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) > +/* When tag is not NULL, assuming mem_alloc_profiling_enabled */ > +static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) > { > - struct alloc_tag *tag; > - > - if (!mem_alloc_profiling_enabled()) > - return; > - > - tag = __pgalloc_tag_get(page); > if (tag) > this_cpu_sub(tag->counters->bytes, PAGE_SIZE * nr); > } > @@ -1168,7 +1163,7 @@ static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) > static inline void pgalloc_tag_add(struct page *page, struct task_struct *task, > unsigned int nr) {} > static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) {} > -static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) {} > +static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) {} > > #endif /* CONFIG_MEM_ALLOC_PROFILING */ > > @@ -5065,11 +5060,13 @@ static void ___free_pages(struct page *page, unsigned int order, > { > /* get PageHead before we drop reference */ > int head = PageHead(page); > + /* get alloc tag in case the page is released by others */ > + struct alloc_tag *tag = pgalloc_tag_get(page); > > if (put_page_testzero(page)) > __free_frozen_pages(page, order, fpi_flags); > else if (!head) { > - pgalloc_tag_sub_pages(page, (1 << order) - 1); > + pgalloc_tag_sub_pages(tag, (1 << order) - 1); > while (order-- > 0) > __free_frozen_pages(page + (1 << order), order, > fpi_flags); > -- > 2.39.2 > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3] mm/codetag: move tag retrieval back upfront in __free_pages() 2025-05-05 19:30 ` [PATCH v3] " David Wang 2025-05-05 20:32 ` Suren Baghdasaryan @ 2025-05-06 7:58 ` Vlastimil Babka 1 sibling, 0 replies; 12+ messages in thread From: Vlastimil Babka @ 2025-05-06 7:58 UTC (permalink / raw) To: David Wang, akpm, surenb, mhocko, jackmanb, hannes, ziy Cc: linux-mm, linux-kernel On 5/5/25 21:30, David Wang wrote: > Commit 51ff4d7486f0 ("mm: avoid extra mem_alloc_profiling_enabled() > checks") introduces a possible use-after-free scenario, when page > is non-compound, page[0] could be released by other thread right > after put_page_testzero failed in current thread, pgalloc_tag_sub_pages > afterwards would manipulate an invalid page for accounting remaining > pages: > > [timeline] [thread1] [thread2] > | alloc_page non-compound > V > | get_page, rf counter inc > V > | in ___free_pages > | put_page_testzero fails > V > | put_page, page released > V > | in ___free_pages, > | pgalloc_tag_sub_pages > | manipulate an invalid page > V > > Restore __free_pages() to its state before, retrieve alloc tag > beforehand. > > Fixes: 51ff4d7486f0 ("mm: avoid extra mem_alloc_profiling_enabled() checks") That's a 6.15-rc1 commit, so no cc: stable needed, but should go to mm-hotfixes. > Signed-off-by: David Wang <00107082@163.com> Reviewed-by: Vlastimil Babka <vbabka@suse.cz> Thanks! > --- > include/linux/pgalloc_tag.h | 8 ++++++++ > mm/page_alloc.c | 15 ++++++--------- > 2 files changed, 14 insertions(+), 9 deletions(-) > > diff --git a/include/linux/pgalloc_tag.h b/include/linux/pgalloc_tag.h > index c74077977830..8a7f4f802c57 100644 > --- a/include/linux/pgalloc_tag.h > +++ b/include/linux/pgalloc_tag.h > @@ -188,6 +188,13 @@ static inline struct alloc_tag *__pgalloc_tag_get(struct page *page) > return tag; > } > > +static inline struct alloc_tag *pgalloc_tag_get(struct page *page) > +{ > + if (mem_alloc_profiling_enabled()) > + return __pgalloc_tag_get(page); > + return NULL; > +} > + > void pgalloc_tag_split(struct folio *folio, int old_order, int new_order); > void pgalloc_tag_swap(struct folio *new, struct folio *old); > > @@ -199,6 +206,7 @@ static inline void clear_page_tag_ref(struct page *page) {} > static inline void alloc_tag_sec_init(void) {} > static inline void pgalloc_tag_split(struct folio *folio, int old_order, int new_order) {} > static inline void pgalloc_tag_swap(struct folio *new, struct folio *old) {} > +static inline struct alloc_tag *pgalloc_tag_get(struct page *page) { return NULL; } > > #endif /* CONFIG_MEM_ALLOC_PROFILING */ > > diff --git a/mm/page_alloc.c b/mm/page_alloc.c > index 5669baf2a6fe..1b00e14a9780 100644 > --- a/mm/page_alloc.c > +++ b/mm/page_alloc.c > @@ -1151,14 +1151,9 @@ static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) > __pgalloc_tag_sub(page, nr); > } > > -static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) > +/* When tag is not NULL, assuming mem_alloc_profiling_enabled */ > +static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) > { > - struct alloc_tag *tag; > - > - if (!mem_alloc_profiling_enabled()) > - return; > - > - tag = __pgalloc_tag_get(page); > if (tag) > this_cpu_sub(tag->counters->bytes, PAGE_SIZE * nr); > } > @@ -1168,7 +1163,7 @@ static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) > static inline void pgalloc_tag_add(struct page *page, struct task_struct *task, > unsigned int nr) {} > static inline void pgalloc_tag_sub(struct page *page, unsigned int nr) {} > -static inline void pgalloc_tag_sub_pages(struct page *page, unsigned int nr) {} > +static inline void pgalloc_tag_sub_pages(struct alloc_tag *tag, unsigned int nr) {} > > #endif /* CONFIG_MEM_ALLOC_PROFILING */ > > @@ -5065,11 +5060,13 @@ static void ___free_pages(struct page *page, unsigned int order, > { > /* get PageHead before we drop reference */ > int head = PageHead(page); > + /* get alloc tag in case the page is released by others */ > + struct alloc_tag *tag = pgalloc_tag_get(page); > > if (put_page_testzero(page)) > __free_frozen_pages(page, order, fpi_flags); > else if (!head) { > - pgalloc_tag_sub_pages(page, (1 << order) - 1); > + pgalloc_tag_sub_pages(tag, (1 << order) - 1); > while (order-- > 0) > __free_frozen_pages(page + (1 << order), order, > fpi_flags); ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-05-06 7:58 UTC | newest] Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2025-05-04 6:19 [PATCH] mm/codetag: sub in advance when free non-compound high order pages David Wang 2025-05-05 13:12 ` Vlastimil Babka 2025-05-05 14:31 ` David Wang 2025-05-05 14:55 ` Vlastimil Babka 2025-05-05 15:33 ` Suren Baghdasaryan 2025-05-05 16:42 ` David Wang 2025-05-05 16:53 ` Suren Baghdasaryan 2025-05-05 18:34 ` [PATCH v2] mm/codetag: move tag retrieval back upfront in __free_pages() David Wang 2025-05-05 19:17 ` David Wang 2025-05-05 19:30 ` [PATCH v3] " David Wang 2025-05-05 20:32 ` Suren Baghdasaryan 2025-05-06 7:58 ` Vlastimil Babka
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox