Merge tag 'arm-soc-5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-microblaze.git] / mm / filemap.c
index 4370048..6ce832d 100644 (file)
@@ -1969,8 +1969,14 @@ unlock:
 put:
                put_page(page);
 next:
-               if (!xa_is_value(page) && PageTransHuge(page))
-                       xas_set(&xas, page->index + thp_nr_pages(page));
+               if (!xa_is_value(page) && PageTransHuge(page)) {
+                       unsigned int nr_pages = thp_nr_pages(page);
+
+                       /* Final THP may cross MAX_LFS_FILESIZE on 32-bit */
+                       xas_set(&xas, page->index + nr_pages);
+                       if (xas.xa_index < nr_pages)
+                               break;
+               }
        }
        rcu_read_unlock();
 
@@ -2672,7 +2678,7 @@ loff_t mapping_seek_hole_data(struct address_space *mapping, loff_t start,
                loff_t end, int whence)
 {
        XA_STATE(xas, &mapping->i_pages, start >> PAGE_SHIFT);
-       pgoff_t max = (end - 1) / PAGE_SIZE;
+       pgoff_t max = (end - 1) >> PAGE_SHIFT;
        bool seek_data = (whence == SEEK_DATA);
        struct page *page;
 
@@ -2681,7 +2687,8 @@ loff_t mapping_seek_hole_data(struct address_space *mapping, loff_t start,
 
        rcu_read_lock();
        while ((page = find_get_entry(&xas, max, XA_PRESENT))) {
-               loff_t pos = xas.xa_index * PAGE_SIZE;
+               loff_t pos = (u64)xas.xa_index << PAGE_SHIFT;
+               unsigned int seek_size;
 
                if (start < pos) {
                        if (!seek_data)
@@ -2689,25 +2696,25 @@ loff_t mapping_seek_hole_data(struct address_space *mapping, loff_t start,
                        start = pos;
                }
 
-               pos += seek_page_size(&xas, page);
+               seek_size = seek_page_size(&xas, page);
+               pos = round_up(pos + 1, seek_size);
                start = page_seek_hole_data(&xas, mapping, page, start, pos,
                                seek_data);
                if (start < pos)
                        goto unlock;
+               if (start >= end)
+                       break;
+               if (seek_size > PAGE_SIZE)
+                       xas_set(&xas, pos >> PAGE_SHIFT);
                if (!xa_is_value(page))
                        put_page(page);
        }
-       rcu_read_unlock();
-
        if (seek_data)
-               return -ENXIO;
-       goto out;
-
+               start = -ENXIO;
 unlock:
        rcu_read_unlock();
-       if (!xa_is_value(page))
+       if (page && !xa_is_value(page))
                put_page(page);
-out:
        if (start > end)
                return end;
        return start;