From 345c72a9a4e554f83b00acb9aee70e4dadb8517f Mon Sep 17 00:00:00 2001 From: Andrew Perepechko Date: Thu, 20 Oct 2022 14:12:12 +0300 Subject: [PATCH] LUS-10932: SIGBUS is possible on a race with page reclaim We can restart fault handling if page truncation happens in parallel with the fault handler. Change-Id: I6e60783e3334f87e799dc8b0e6e63d0bb358a236 Signed-off-by: Andrew Perepechko --- lustre/include/lustre_compat.h | 4 ++-- lustre/llite/llite_internal.h | 4 ++++ lustre/llite/llite_lib.c | 1 + lustre/llite/llite_mmap.c | 15 +++++++++++++++ lustre/llite/vvp_page.c | 6 ++++++ 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lustre/include/lustre_compat.h b/lustre/include/lustre_compat.h index 276f72e475..831427b7e0 100644 --- a/lustre/include/lustre_compat.h +++ b/lustre/include/lustre_compat.h @@ -372,9 +372,9 @@ static inline void __user *get_vmf_address(struct vm_fault *vmf) } #ifdef HAVE_VM_OPS_USE_VM_FAULT_ONLY -# define ll_filemap_fault(vma, vmf) filemap_fault(vmf) +# define __ll_filemap_fault(vma, vmf) filemap_fault(vmf) #else -# define ll_filemap_fault(vma, vmf) filemap_fault(vma, vmf) +# define __ll_filemap_fault(vma, vmf) filemap_fault(vma, vmf) #endif #ifndef HAVE_CURRENT_TIME diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index c1c693ba26..dbf7296052 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -270,6 +271,7 @@ struct ll_inode_info { struct list_head lli_xattrs; /* ll_xattr_entry->xe_list */ struct list_head lli_lccs; /* list of ll_cl_context */ struct rw_semaphore lli_write_setattr; + seqlock_t lli_page_inv_lock; }; #ifndef HAVE_USER_NAMESPACE_ARG @@ -1772,4 +1774,6 @@ int ll_manage_foreign(struct inode *inode, struct lustre_md *lmd); bool ll_foreign_is_openable(struct dentry *dentry, unsigned int flags); bool ll_foreign_is_removable(struct dentry *dentry, bool unset); +int ll_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf); + #endif /* LLITE_INTERNAL_H */ diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index 0399c38f6b..ca18f90184 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -1227,6 +1227,7 @@ void ll_lli_init(struct ll_inode_info *lli) memset(lli->lli_jobid, 0, sizeof(lli->lli_jobid)); /* ll_cl_context initialize */ INIT_LIST_HEAD(&lli->lli_lccs); + seqlock_init(&lli->lli_page_inv_lock); } #define MAX_STRING_SIZE 128 diff --git a/lustre/llite/llite_mmap.c b/lustre/llite/llite_mmap.c index d976c258c0..e16a667d2e 100644 --- a/lustre/llite/llite_mmap.c +++ b/lustre/llite/llite_mmap.c @@ -250,6 +250,21 @@ static inline int to_fault_error(int result) return result; } +int ll_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct inode *inode = file_inode(vma->vm_file); + int ret; + unsigned seq; + + do { + seq = read_seqbegin(&ll_i2info(inode)->lli_page_inv_lock); + ret = __ll_filemap_fault(vma, vmf); + } while (read_seqretry(&ll_i2info(inode)->lli_page_inv_lock, seq) && + (ret & VM_FAULT_SIGBUS)); + + return ret; +} + /** * Lustre implementation of a vm_operations_struct::fault() method, called by * VM to server page fault (both in kernel and user space). diff --git a/lustre/llite/vvp_page.c b/lustre/llite/vvp_page.c index b829896c32..e66ceaa3e2 100644 --- a/lustre/llite/vvp_page.c +++ b/lustre/llite/vvp_page.c @@ -158,6 +158,7 @@ static void vvp_page_delete(const struct lu_env *env, { struct page *vmpage = cl2vm_page(slice); struct cl_page *page = slice->cpl_page; + struct inode *inode = vmpage->mapping->host; int refc; LASSERT(PageLocked(vmpage)); @@ -170,6 +171,11 @@ static void vvp_page_delete(const struct lu_env *env, ClearPagePrivate(vmpage); vmpage->private = 0; + + write_seqlock(&ll_i2info(inode)->lli_page_inv_lock); + ClearPageUptodate(vmpage); + write_sequnlock(&ll_i2info(inode)->lli_page_inv_lock); + /* * Reference from vmpage to cl_page is removed, but the reference back * is still here. It is removed later in vvp_page_fini(). -- 2.31.1