anolis: mm: duptext: rework handling of mlock

ANBZ: #7814

Truncating routines should always succeed, perhaps with multiple attempts,
usually accompanied by unmap_mapping_range().  In orer to coordinate with
truncating, __dedup_page() should better succeed in this scenario, with
ignore_mlock as true.

On the other hand, invalidating routines have __dup_page_mapped() check in
common helper, i.e., invalidate_inode_page(). That is to say, mapped slave
pages should not be invalidated irrespective of whether mlocked or not.

Finally the only place currently where mlock is honoured is reclaiming
routines, e.g., shrink_page_list, where __dedup_page() can be called with
ignore_mlock as false.

This patch restores the ignore_mlock handling of dedup_page(), and
introduces a new helper, i.e., dedup_page2(), which is called currently
only in shrink_page_list() explicitly to honour mlock().

Fixes: 07d077abe3 ("anolis: mm: avoid conflicts between mlock and duptext")
Reported-by: Lang Zheng <zhenglang.zl@alibaba-inc.com>
Signed-off-by: Xu Yu <xuyu@linux.alibaba.com>
Tested-by: Lang Zheng <zhenglang.zl@alibaba-inc.com>
Reviewed-by: Kaihao Bai <carlo.bai@linux.alibaba.com>
Link: https://gitee.com/anolis/cloud-kernel/pulls/2611
This commit is contained in:
Xu Yu 2024-01-15 12:51:15 +08:00 committed by 小龙
parent 877afe6642
commit fb7067d865
3 changed files with 31 additions and 9 deletions

View File

@ -114,7 +114,14 @@ static inline bool dup_page_mapped(struct page *page)
static inline bool dedup_page(struct page *page, bool locked)
{
if (page_dup_master(page))
return __dedup_page(page, locked, false);
return __dedup_page(page, locked, true);
return true;
}
static inline bool dedup_page2(struct page *page, bool locked, bool ignore_mlock)
{
if (page_dup_master(page))
return __dedup_page(page, locked, ignore_mlock);
return true;
}
#endif /* _LINUX_PAGE_DUP_H_ */

View File

@ -461,6 +461,22 @@ struct page *__dup_page(struct page *page, struct vm_area_struct *vma)
: dup_hpage;
}
/*
* NOTE Be careful if you want to call __dedup_page with ignore_mlock as false.
*
* Truncating routines should always succeed, perhaps with multiple attempts,
* usually accompanied by unmap_mapping_range(). In orer to coordinate with
* truncating, __dedup_page() should better succeed in this scenario, with
* ignore_mlock as true.
*
* On the other hand, invalidating routines have __dup_page_mapped() check in
* common helper, i.e., invalidate_inode_page(). That is to say, mapped slave
* pages should not be invalidated irrespective of whether mlocked or not.
*
* Finally the only place currently where mlock is honoured is reclaiming
* routines, e.g., shrink_page_list, where __dedup_page() can be called with
* ignore_mlock as false.
*/
bool __dedup_page(struct page *page, bool locked, bool ignore_mlock)
{
page = compound_head(page);

View File

@ -1038,15 +1038,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
BUG_ON(!PageLocked(page));
BUG_ON(mapping != page_mapping(page));
/*
* If duplicated slaver pages can not be released, maintain master
* page here.
*/
if (!dedup_page(page, false))
return 0;
xa_lock_irqsave(&mapping->i_pages, flags);
/*
* The non racy check for a busy page.
*
@ -1119,6 +1111,8 @@ static int __remove_mapping(struct address_space *mapping, struct page *page,
if (freepage != NULL)
freepage(page);
dedup_page(page, false);
}
return 1;
@ -1508,6 +1502,11 @@ static unsigned int shrink_page_list(struct list_head *page_list,
}
}
if (unlikely(dup_page_mapped(page))) {
if (!dedup_page2(page, false, false))
goto activate_locked;
}
if (PageDirty(page)) {
/*
* Only kswapd can writeback filesystem pages