From 4a134425bd9d03f5e40e489fd7e9acf4788e9da1 Mon Sep 17 00:00:00 2001 From: Patrick Farrell Date: Tue, 9 May 2023 11:06:47 -0400 Subject: [PATCH] LU-14541 llite: Check for page deletion after fault Before completing a page fault and returning to the kernel, we lock the page and verify it has not been truncated. But we must also verify the page has not been deleted from Lustre, or we can return a disconnected (ie, not tracked by Lustre) page to the kernel. We mark deleted pages !uptodate, but this doesn't matter for faulted pages, because the kernel assumes they are returned uptodate, and maps them in to the process address space. Once mapped, the page state is not checked until the page is unmapped. But because the page is referenced by the mapping, it stays in the page cache even though it's been disconnected from Lustre. Because the page is disconnected from Lustre, it will not be found and cancelled on lock cancellation. This can result in stale data reads. This is particularly an issue with releasepage (called from drop_caches or under memory pressure), which can delete pages separately from cancelling covering locks. If releasepage is disabled, which is effectively what "LU-14541 llite: Check vmpage in releasepage" does, this is not an issue. But disabling releasepage causes other problems and is incorrect anyway. Lustre-change: https://review.whamcloud.com/49653 Lustre-commit: b3d2114e538cf95a7e036f8313e9095fe821da79 Signed-off-by: Patrick Farrell Change-Id: If1164db8f8e92a1cf811431d56d15f30d8eb3faa Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/50598 Tested-by: jenkins Tested-by: Maloo Reviewed-by: Qian Yingjin Reviewed-by: Oleg Drokin --- lustre/llite/llite_mmap.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lustre/llite/llite_mmap.c b/lustre/llite/llite_mmap.c index a68915e..1485a29 100644 --- a/lustre/llite/llite_mmap.c +++ b/lustre/llite/llite_mmap.c @@ -411,15 +411,22 @@ restart: !(result & (VM_FAULT_RETRY | VM_FAULT_ERROR | VM_FAULT_LOCKED))) { struct page *vmpage = vmf->page; - /* check if this page has been truncated */ + /* lock the page, then check if this page has been truncated + * or deleted from Lustre and retry if so + */ lock_page(vmpage); - if (unlikely(vmpage->mapping == NULL)) { /* unlucky */ + if (unlikely(vmpage->mapping == NULL) || + vmpage->private == 0) { /* unlucky */ unlock_page(vmpage); put_page(vmpage); vmf->page = NULL; if (!printed && ++count > 16) { - CWARN("the page is under heavy contention, maybe your app(%s) needs revising :-)\n", + struct inode *inode = file_inode(vma->vm_file); + + CWARN("%s: FID "DFID" under heavy mmap contention by '%s', consider revising IO pattern\n", + ll_i2sbi(inode)->ll_fsname, + PFID(&ll_i2info(inode)->lli_fid), current->comm); printed = true; } -- 1.8.3.1