Usually PG_locked bit is updated by lock_page() or unlock_page(). However, it can be also updated through __SetPageLocked() or __ClearPageLockded(). They have to be considered, to get paired between acquire and release. Furthermore, e.g. __SetPageLocked() in add_to_page_cache_lru() is called frequently. We might miss many chances to check deadlock if we ignore it. Make __Set(__Clear)PageLockded considered as well. Signed-off-by: Byungchul Park <byungchul.park@xxxxxxx> --- include/linux/page-flags.h | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 584b14c..108d2dd 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -262,7 +262,6 @@ static __always_inline int PageCompound(struct page *page) #define TESTSCFLAG_FALSE(uname) \ TESTSETFLAG_FALSE(uname) TESTCLEARFLAG_FALSE(uname) -__PAGEFLAG(Locked, locked, PF_NO_TAIL) PAGEFLAG(Waiters, waiters, PF_ONLY_HEAD) __CLEARPAGEFLAG(Waiters, waiters, PF_ONLY_HEAD) PAGEFLAG(Error, error, PF_NO_COMPOUND) TESTCLEARFLAG(Error, error, PF_NO_COMPOUND) PAGEFLAG(Referenced, referenced, PF_HEAD) @@ -374,6 +373,35 @@ static __always_inline int PageSwapCache(struct page *page) PAGEFLAG(Idle, idle, PF_ANY) #endif +#ifdef CONFIG_LOCKDEP_PAGELOCK +#include <linux/lockdep.h> + +TESTPAGEFLAG(Locked, locked, PF_NO_TAIL) + +static __always_inline void __SetPageLocked(struct page *page) +{ + __set_bit(PG_locked, &PF_NO_TAIL(page, 1)->flags); + + page = compound_head(page); + lock_acquire_exclusive((struct lockdep_map *)&page->map, 0, 1, NULL, _RET_IP_); +} + +static __always_inline void __ClearPageLocked(struct page *page) +{ + __clear_bit(PG_locked, &PF_NO_TAIL(page, 1)->flags); + + page = compound_head(page); + /* + * lock_commit_crosslock() is necessary for crosslock + * when the lock is released, before lock_release(). + */ + lock_commit_crosslock((struct lockdep_map *)&page->map); + lock_release((struct lockdep_map *)&page->map, 0, _RET_IP_); +} +#else +__PAGEFLAG(Locked, locked, PF_NO_TAIL) +#endif + /* * On an anonymous page mapped into a user virtual memory area, * page->mapping points to its anon_vma, not to a struct address_space; -- 1.9.1