ANDROID: 16K: Handle pgoff > file_size for shmem and file backed VMAs
VMAs can be created to be larger than the backing file: See [1] (This is also true for shmem backed VMAs.) Faulting off the end of a file will result in SIGBUS since there is no file page for the given file offset. shmem pages live in page cache or swap cache. Looking up a page cache page with an index (pgoff) beyond the file is invalid and will result in shmem_get_folio_gfp() returning -EINVAL. Insert fixup anon vmas for such file backed and shmem backed VMAs, to prevent the invalid faults in emulated 16kB mode. Although the 16K emulators currently use ext4 for the /data partition, also handle the case for f2fs which overrides the default filemap_fault with f2f2_filemap_fault(). [1] https://r.android.com/2967716 Bug: 383389337 Bug: 355274435 Test: adb root && adb shell && adb shell cp /system/bin/strace /dev/ && adb shell /dev/strace -h Change-Id: Iede02e82fc5958b3aafaf75383404f2f7f59bb23 Signed-off-by: Kalesh Singh <kaleshsingh@google.com>
This commit is contained in:
committed by
Carlos Llamas
parent
cd48f9a1f7
commit
5c1d7ef671
@@ -38,7 +38,7 @@
|
||||
#undef CREATE_TRACE_POINTS
|
||||
#include <trace/hooks/fs.h>
|
||||
|
||||
static vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
|
||||
vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf)
|
||||
{
|
||||
struct inode *inode = file_inode(vmf->vma->vm_file);
|
||||
vm_flags_t flags = vmf->vma->vm_flags;
|
||||
|
||||
@@ -40,6 +40,14 @@
|
||||
DECLARE_STATIC_KEY_FALSE(page_shift_compat_enabled);
|
||||
extern int page_shift_compat __ro_after_init;
|
||||
|
||||
#ifdef CONFIG_SHMEM
|
||||
extern vm_fault_t shmem_fault(struct vm_fault *vmf);
|
||||
#endif /* CONFIG_SHMEM */
|
||||
|
||||
#ifdef CONFIG_F2FS_FS
|
||||
extern vm_fault_t f2fs_filemap_fault(struct vm_fault *vmf);
|
||||
#endif /* CONFIG_F2FS_FS */
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static __always_inline unsigned __page_shift(void)
|
||||
{
|
||||
|
||||
@@ -96,6 +96,29 @@ unsigned long ___filemap_len(struct inode *inode, unsigned long pgoff, unsigned
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline bool is_shmem_fault(const struct vm_operations_struct *vm_ops)
|
||||
{
|
||||
#ifdef CONFIG_SHMEM
|
||||
return vm_ops->fault == shmem_fault;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool is_f2fs_filemap_fault(const struct vm_operations_struct *vm_ops)
|
||||
{
|
||||
#ifdef CONFIG_F2FS_FS
|
||||
return vm_ops->fault == f2fs_filemap_fault;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool is_filemap_fault(const struct vm_operations_struct *vm_ops)
|
||||
{
|
||||
return vm_ops->fault == filemap_fault;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called to fill any holes created by ___filemap_len()
|
||||
* with an anonymous mapping.
|
||||
@@ -108,6 +131,7 @@ void ___filemap_fixup(unsigned long addr, unsigned long prot, unsigned long old_
|
||||
struct mm_struct *mm = current->mm;
|
||||
unsigned long populate = 0;
|
||||
struct vm_area_struct *vma;
|
||||
const struct vm_operations_struct *vm_ops;
|
||||
|
||||
if (!anon_len)
|
||||
return;
|
||||
@@ -126,8 +150,22 @@ void ___filemap_fixup(unsigned long addr, unsigned long prot, unsigned long old_
|
||||
*/
|
||||
BUG_ON(!vma);
|
||||
|
||||
/* Only handle fixups for filemap faults */
|
||||
if (vma->vm_ops && vma->vm_ops->fault != filemap_fault)
|
||||
vm_ops = vma->vm_ops;
|
||||
if (!vm_ops)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Insert fixup vmas for file backed and shmem backed VMAs.
|
||||
*
|
||||
* Faulting off the end of a file will result in SIGBUS since there is no
|
||||
* file page for the given file offset.
|
||||
*
|
||||
* shmem pages live in page cache or swap cache. Looking up a page cache
|
||||
* page with an index (pgoff) beyond the file is invalid and will result
|
||||
* in shmem_get_folio_gfp() returning -EINVAL.
|
||||
*/
|
||||
if (!is_filemap_fault(vm_ops) && !is_f2fs_filemap_fault(vm_ops) &&
|
||||
!is_shmem_fault(vm_ops))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
||||
@@ -2538,7 +2538,7 @@ static vm_fault_t shmem_falloc_wait(struct vm_fault *vmf, struct inode *inode)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static vm_fault_t shmem_fault(struct vm_fault *vmf)
|
||||
vm_fault_t shmem_fault(struct vm_fault *vmf)
|
||||
{
|
||||
struct inode *inode = file_inode(vmf->vma->vm_file);
|
||||
gfp_t gfp = mapping_gfp_mask(inode->i_mapping);
|
||||
|
||||
Reference in New Issue
Block a user