On Wed, Feb 12, 2020 at 10:28:51AM -0800, Matthew Wilcox wrote: > On Wed, Feb 12, 2020 at 09:40:15AM -0800, Minchan Kim wrote: > > How about this? > > > > diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h > > index 1bf83c8fcaa7..d07d602476df 100644 > > --- a/include/linux/page-flags.h > > +++ b/include/linux/page-flags.h > > @@ -363,8 +363,28 @@ PAGEFLAG(MappedToDisk, mappedtodisk, PF_NO_TAIL) > > /* PG_readahead is only used for reads; PG_reclaim is only for writes */ > > PAGEFLAG(Reclaim, reclaim, PF_NO_TAIL) > > TESTCLEARFLAG(Reclaim, reclaim, PF_NO_TAIL) > > -PAGEFLAG(Readahead, reclaim, PF_NO_COMPOUND) > > - TESTCLEARFLAG(Readahead, reclaim, PF_NO_COMPOUND) > > + > > +SETPAGEFLAG(Readahead, reclaim, PF_NO_COMPOUND) > > +CLEARPAGEFLAG(Readahead, reclaim, PF_NO_COMPOUND) > > + > > +/* > > + * Since PG_readahead is shared with PG_reclaim of the page flags, > > + * PageReadahead should double check whether it's readahead marker > > + * or PG_reclaim. It could be done by PageWriteback check because > > + * PG_reclaim is always with PG_writeback. > > + */ > > +static inline int PageReadahead(struct page *page) > > +{ > > + VM_BUG_ON_PGFLAGS(PageCompound(page), page); > > + return test_bit(PG_reclaim, &(page)->flags) && !PageWriteback(page); > > Why not ... > > return page->flags & (1UL << PG_reclaim | 1UL << PG_writeback) == > (1UL << PG_reclaim); > > > +static inline int TestClearPageReadahead(struct page *page) > > +{ > > + VM_BUG_ON_PGFLAGS(PageCompound(page), page); > > + > > + return test_and_clear_bit(PG_reclaim, &page->flags) && !PageWriteback(page); > > That's definitely wrong. It'll clear PageReclaim and then pretend it did > nothing wrong. > > return !PageWriteback(page) || > test_and_clear_bit(PG_reclaim, &page->flags); > Much better, Thanks for the review, Matthew! If there is no objection, I will send two patches to Andrew. One is PageReadahead strict, the other is limit retry from mm_populate. >From 351236413beda22cb7fec1713cad4360de930188 Mon Sep 17 00:00:00 2001 From: Minchan Kim <minchan@xxxxxxxxxx> Date: Wed, 12 Feb 2020 09:28:21 -0800 Subject: [PATCH] mm: make PageReadahead more strict PG_readahead flag is shared with PG_reclaim but PG_reclaim is only used in write context while PG_readahead is used for read context. To make it clear, let's introduce PageReadahead wrapper with !PageWriteback check so it could make code clear and we could drop PageWriteback check in page_cache_async_readahead, which removes pointless dropping mmap_sem. Signed-off-by: Minchan Kim <minchan@xxxxxxxxxx> --- include/linux/page-flags.h | 28 ++++++++++++++++++++++++++-- mm/readahead.c | 6 ------ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 1bf83c8fcaa7..f91a9b2a49bd 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -363,8 +363,32 @@ PAGEFLAG(MappedToDisk, mappedtodisk, PF_NO_TAIL) /* PG_readahead is only used for reads; PG_reclaim is only for writes */ PAGEFLAG(Reclaim, reclaim, PF_NO_TAIL) TESTCLEARFLAG(Reclaim, reclaim, PF_NO_TAIL) -PAGEFLAG(Readahead, reclaim, PF_NO_COMPOUND) - TESTCLEARFLAG(Readahead, reclaim, PF_NO_COMPOUND) + +SETPAGEFLAG(Readahead, reclaim, PF_NO_COMPOUND) +CLEARPAGEFLAG(Readahead, reclaim, PF_NO_COMPOUND) + +/* + * Since PG_readahead is shared with PG_reclaim of the page flags, + * PageReadahead should double check whether it's readahead marker + * or PG_reclaim. It could be done by PageWriteback check because + * PG_reclaim is always with PG_writeback. + */ +static inline int PageReadahead(struct page *page) +{ + VM_BUG_ON_PGFLAGS(PageCompound(page), page); + + return (page->flags & (1UL << PG_reclaim | 1UL << PG_writeback)) == + (1UL << PG_reclaim); +} + +/* Clear PG_readahead only if it's PG_readahead, not PG_reclaim */ +static inline int TestClearPageReadahead(struct page *page) +{ + VM_BUG_ON_PGFLAGS(PageCompound(page), page); + + return !PageWriteback(page) || + test_and_clear_bit(PG_reclaim, &page->flags); +} #ifdef CONFIG_HIGHMEM /* diff --git a/mm/readahead.c b/mm/readahead.c index 2fe72cd29b47..85b15e5a1d7b 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -553,12 +553,6 @@ page_cache_async_readahead(struct address_space *mapping, if (!ra->ra_pages) return; - /* - * Same bit is used for PG_readahead and PG_reclaim. - */ - if (PageWriteback(page)) - return; - ClearPageReadahead(page); /* -- 2.25.0.225.g125e21ebc7-goog