mm: userfaultfd: extract file size check out into a helper
authorAxel Rasmussen <axelrasmussen@google.com>
Fri, 7 Jul 2023 21:55:35 +0000 (14:55 -0700)
committerAndrew Morton <akpm@linux-foundation.org>
Fri, 18 Aug 2023 17:12:16 +0000 (10:12 -0700)
This code is already duplicated twice, and UFFDIO_POISON will do the same
check a third time.  So, it's worth extracting into a helper to save
repetitive lines of code.

Link: https://lkml.kernel.org/r/20230707215540.2324998-4-axelrasmussen@google.com
Signed-off-by: Axel Rasmussen <axelrasmussen@google.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Brian Geffon <bgeffon@google.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: David Hildenbrand <david@redhat.com>
Cc: Gaosheng Cui <cuigaosheng1@huawei.com>
Cc: Huang, Ying <ying.huang@intel.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: James Houghton <jthoughton@google.com>
Cc: Jan Alexander Steffens (heftig) <heftig@archlinux.org>
Cc: Jiaqi Yan <jiaqiyan@google.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Liam R. Howlett <Liam.Howlett@oracle.com>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Mike Rapoport (IBM) <rppt@kernel.org>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Nadav Amit <namit@vmware.com>
Cc: Naoya Horiguchi <naoya.horiguchi@nec.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Suleiman Souhlal <suleiman@google.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: T.J. Alumbaugh <talumbau@google.com>
Cc: Yu Zhao <yuzhao@google.com>
Cc: ZhangPeng <zhangpeng362@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/userfaultfd.c

index a2bf37e..4244ca7 100644 (file)
@@ -45,6 +45,22 @@ struct vm_area_struct *find_dst_vma(struct mm_struct *dst_mm,
        return dst_vma;
 }
 
+/* Check if dst_addr is outside of file's size. Must be called with ptl held. */
+static bool mfill_file_over_size(struct vm_area_struct *dst_vma,
+                                unsigned long dst_addr)
+{
+       struct inode *inode;
+       pgoff_t offset, max_off;
+
+       if (!dst_vma->vm_file)
+               return false;
+
+       inode = dst_vma->vm_file->f_inode;
+       offset = linear_page_index(dst_vma, dst_addr);
+       max_off = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
+       return offset >= max_off;
+}
+
 /*
  * Install PTEs, to map dst_addr (within dst_vma) to page.
  *
@@ -64,8 +80,6 @@ int mfill_atomic_install_pte(pmd_t *dst_pmd,
        bool page_in_cache = page_mapping(page);
        spinlock_t *ptl;
        struct folio *folio;
-       struct inode *inode;
-       pgoff_t offset, max_off;
 
        _dst_pte = mk_pte(page, dst_vma->vm_page_prot);
        _dst_pte = pte_mkdirty(_dst_pte);
@@ -81,14 +95,9 @@ int mfill_atomic_install_pte(pmd_t *dst_pmd,
        if (!dst_pte)
                goto out;
 
-       if (vma_is_shmem(dst_vma)) {
-               /* serialize against truncate with the page table lock */
-               inode = dst_vma->vm_file->f_inode;
-               offset = linear_page_index(dst_vma, dst_addr);
-               max_off = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
+       if (mfill_file_over_size(dst_vma, dst_addr)) {
                ret = -EFAULT;
-               if (unlikely(offset >= max_off))
-                       goto out_unlock;
+               goto out_unlock;
        }
 
        ret = -EEXIST;
@@ -211,8 +220,6 @@ static int mfill_atomic_pte_zeropage(pmd_t *dst_pmd,
        pte_t _dst_pte, *dst_pte;
        spinlock_t *ptl;
        int ret;
-       pgoff_t offset, max_off;
-       struct inode *inode;
 
        _dst_pte = pte_mkspecial(pfn_pte(my_zero_pfn(dst_addr),
                                         dst_vma->vm_page_prot));
@@ -220,14 +227,9 @@ static int mfill_atomic_pte_zeropage(pmd_t *dst_pmd,
        dst_pte = pte_offset_map_lock(dst_vma->vm_mm, dst_pmd, dst_addr, &ptl);
        if (!dst_pte)
                goto out;
-       if (dst_vma->vm_file) {
-               /* the shmem MAP_PRIVATE case requires checking the i_size */
-               inode = dst_vma->vm_file->f_inode;
-               offset = linear_page_index(dst_vma, dst_addr);
-               max_off = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE);
+       if (mfill_file_over_size(dst_vma, dst_addr)) {
                ret = -EFAULT;
-               if (unlikely(offset >= max_off))
-                       goto out_unlock;
+               goto out_unlock;
        }
        ret = -EEXIST;
        if (!pte_none(ptep_get(dst_pte)))