Skip to content

Commit f4f451a

Browse files
Muchun Songakpm00
authored andcommitted
mm: fix missing wake-up event for FSDAX pages
FSDAX page refcounts are 1-based, rather than 0-based: if refcount is 1, then the page is freed. The FSDAX pages can be pinned through GUP, then they will be unpinned via unpin_user_page() using a folio variant to put the page, however, folio variants did not consider this special case, the result will be to miss a wakeup event (like the user of __fuse_dax_break_layouts()). This results in a task being permanently stuck in TASK_INTERRUPTIBLE state. Since FSDAX pages are only possibly obtained by GUP users, so fix GUP instead of folio_put() to lower overhead. Link: https://lkml.kernel.org/r/20220705123532.283-1-songmuchun@bytedance.com Fixes: d8ddc09 ("mm/gup: Add gup_put_folio()") Signed-off-by: Muchun Song <songmuchun@bytedance.com> Suggested-by: Matthew Wilcox <willy@infradead.org> Cc: Jason Gunthorpe <jgg@ziepe.ca> Cc: John Hubbard <jhubbard@nvidia.com> Cc: William Kucharski <william.kucharski@oracle.com> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Jan Kara <jack@suse.cz> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 3fe2895 commit f4f451a

File tree

3 files changed

+16
-10
lines changed

3 files changed

+16
-10
lines changed

include/linux/mm.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,23 +1130,27 @@ static inline bool is_zone_movable_page(const struct page *page)
11301130
#if defined(CONFIG_ZONE_DEVICE) && defined(CONFIG_FS_DAX)
11311131
DECLARE_STATIC_KEY_FALSE(devmap_managed_key);
11321132

1133-
bool __put_devmap_managed_page(struct page *page);
1134-
static inline bool put_devmap_managed_page(struct page *page)
1133+
bool __put_devmap_managed_page_refs(struct page *page, int refs);
1134+
static inline bool put_devmap_managed_page_refs(struct page *page, int refs)
11351135
{
11361136
if (!static_branch_unlikely(&devmap_managed_key))
11371137
return false;
11381138
if (!is_zone_device_page(page))
11391139
return false;
1140-
return __put_devmap_managed_page(page);
1140+
return __put_devmap_managed_page_refs(page, refs);
11411141
}
1142-
11431142
#else /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */
1144-
static inline bool put_devmap_managed_page(struct page *page)
1143+
static inline bool put_devmap_managed_page_refs(struct page *page, int refs)
11451144
{
11461145
return false;
11471146
}
11481147
#endif /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */
11491148

1149+
static inline bool put_devmap_managed_page(struct page *page)
1150+
{
1151+
return put_devmap_managed_page_refs(page, 1);
1152+
}
1153+
11501154
/* 127: arbitrary random number, small enough to assemble well */
11511155
#define folio_ref_zero_or_close_to_overflow(folio) \
11521156
((unsigned int) folio_ref_count(folio) + 127u <= 127u)

mm/gup.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ static inline struct folio *try_get_folio(struct page *page, int refs)
8787
* belongs to this folio.
8888
*/
8989
if (unlikely(page_folio(page) != folio)) {
90-
folio_put_refs(folio, refs);
90+
if (!put_devmap_managed_page_refs(&folio->page, refs))
91+
folio_put_refs(folio, refs);
9192
goto retry;
9293
}
9394

@@ -176,7 +177,8 @@ static void gup_put_folio(struct folio *folio, int refs, unsigned int flags)
176177
refs *= GUP_PIN_COUNTING_BIAS;
177178
}
178179

179-
folio_put_refs(folio, refs);
180+
if (!put_devmap_managed_page_refs(&folio->page, refs))
181+
folio_put_refs(folio, refs);
180182
}
181183

182184
/**

mm/memremap.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ void free_zone_device_page(struct page *page)
499499
}
500500

501501
#ifdef CONFIG_FS_DAX
502-
bool __put_devmap_managed_page(struct page *page)
502+
bool __put_devmap_managed_page_refs(struct page *page, int refs)
503503
{
504504
if (page->pgmap->type != MEMORY_DEVICE_FS_DAX)
505505
return false;
@@ -509,9 +509,9 @@ bool __put_devmap_managed_page(struct page *page)
509509
* refcount is 1, then the page is free and the refcount is
510510
* stable because nobody holds a reference on the page.
511511
*/
512-
if (page_ref_dec_return(page) == 1)
512+
if (page_ref_sub_return(page, refs) == 1)
513513
wake_up_var(&page->_refcount);
514514
return true;
515515
}
516-
EXPORT_SYMBOL(__put_devmap_managed_page);
516+
EXPORT_SYMBOL(__put_devmap_managed_page_refs);
517517
#endif /* CONFIG_FS_DAX */

0 commit comments

Comments
 (0)