btrfs: allocate page arrays using bulk page allocator
authorSweet Tea Dorminy <sweettea-kernel@dorminy.me>
Wed, 30 Mar 2022 20:11:23 +0000 (16:11 -0400)
committerDavid Sterba <dsterba@suse.com>
Mon, 16 May 2022 15:03:11 +0000 (17:03 +0200)
While calling alloc_page() in a loop is an effective way to populate an
array of pages, the MM subsystem provides a method to allocate pages in
bulk.  alloc_pages_bulk_array() populates the NULL slots in a page
array, trying to grab more than one page at a time.

Unfortunately, it doesn't guarantee allocating all slots in the array,
but it's easy to call it in a loop and return an error if no progress
occurs.

Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/extent_io.c

index e472886..cfcbfd5 100644 (file)
@@ -3146,17 +3146,20 @@ readpage_ok:
  */
 int btrfs_alloc_page_array(unsigned int nr_pages, struct page **page_array)
 {
-       int i;
+       unsigned int allocated;
 
-       for (i = 0; i < nr_pages; i++) {
-               struct page *page;
+       for (allocated = 0; allocated < nr_pages;) {
+               unsigned int last = allocated;
 
-               if (page_array[i])
-                       continue;
-               page = alloc_page(GFP_NOFS);
-               if (!page)
+               allocated = alloc_pages_bulk_array(GFP_NOFS, nr_pages, page_array);
+
+               /*
+                * During this iteration, no page could be allocated, even
+                * though alloc_pages_bulk_array() falls back to alloc_page()
+                * if  it could not bulk-allocate. So we must be out of memory.
+                */
+               if (allocated == last)
                        return -ENOMEM;
-               page_array[i] = page;
        }
        return 0;
 }