In shared mode mmap, if overlayfs' inode does not have data in upper layer, it should call maybe_unlock_mmap_for_io() to release lock and waiting for IO in ->fault handler. Meanwhile, in order to avoid endless retry we should also check flag FAULT_FLAG_TRIED carefully in ->fault handler. Signed-off-by: Chengguang Xu <cgxu519@xxxxxxxxxxxx> --- include/linux/mm.h | 2 ++ mm/filemap.c | 28 ++++++++++++++++++++++++++++ mm/internal.h | 22 ---------------------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index dc7b87310c10..214b23734eed 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1656,6 +1656,8 @@ void unmap_mapping_pages(struct address_space *mapping, pgoff_t start, pgoff_t nr, bool even_cows); void unmap_mapping_range(struct address_space *mapping, loff_t const holebegin, loff_t const holelen, int even_cows); +struct file *maybe_unlock_mmap_for_io(struct vm_fault *vmf, struct file *fpin); +bool fault_flag_check(struct vm_fault *vmf, unsigned int flag); #else static inline vm_fault_t handle_mm_fault(struct vm_area_struct *vma, unsigned long address, unsigned int flags) diff --git a/mm/filemap.c b/mm/filemap.c index f0ae9a6308cb..8a226f8ca262 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2704,6 +2704,34 @@ int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; return generic_file_mmap(file, vma); } + +struct file *maybe_unlock_mmap_for_io(struct vm_fault *vmf, + struct file *fpin) +{ + int flags = vmf->flags; + + if (fpin) + return fpin; + + /* + * FAULT_FLAG_RETRY_NOWAIT means we don't want to wait on page locks or + * anything, so we only pin the file and drop the mmap_lock if only + * FAULT_FLAG_ALLOW_RETRY is set, while this is the first attempt. + */ + if (fault_flag_allow_retry_first(flags) && + !(flags & FAULT_FLAG_RETRY_NOWAIT)) { + fpin = get_file(vmf->vma->vm_file); + mmap_read_unlock(vmf->vma->vm_mm); + } + return fpin; +} +EXPORT_SYMBOL(maybe_unlock_mmap_for_io); + +bool fault_flag_check(struct vm_fault *vmf, unsigned int flag) +{ + return vmf->flags & flag; +} +EXPORT_SYMBOL(fault_flag_check); #else vm_fault_t filemap_page_mkwrite(struct vm_fault *vmf) { diff --git a/mm/internal.h b/mm/internal.h index 9886db20d94f..ef19235c6bf1 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -402,28 +402,6 @@ vma_address(struct page *page, struct vm_area_struct *vma) return max(start, vma->vm_start); } - -static inline struct file *maybe_unlock_mmap_for_io(struct vm_fault *vmf, - struct file *fpin) -{ - int flags = vmf->flags; - - if (fpin) - return fpin; - - /* - * FAULT_FLAG_RETRY_NOWAIT means we don't want to wait on page locks or - * anything, so we only pin the file and drop the mmap_lock if only - * FAULT_FLAG_ALLOW_RETRY is set, while this is the first attempt. - */ - if (fault_flag_allow_retry_first(flags) && - !(flags & FAULT_FLAG_RETRY_NOWAIT)) { - fpin = get_file(vmf->vma->vm_file); - mmap_read_unlock(vmf->vma->vm_mm); - } - return fpin; -} - #else /* !CONFIG_MMU */ static inline void clear_page_mlock(struct page *page) { } static inline void mlock_vma_page(struct page *page) { } -- 2.20.1