Messages in this thread Patch in this message | | | From | Sweet Tea Dorminy <> | Subject | [PATCH v2 2/2] btrfs: allocate page arrays using bulk page allocator | Date | Wed, 30 Mar 2022 12:44:07 -0400 |
| |
While calling alloc_page() in a loop is an effective way to populate an array of pages, the kernel 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. Similar code can be found in xfs/xfs_buf.c:xfs_buf_alloc_pages().
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me> Reviewed-by: Nikolay Borisov <nborisov@suse.com> --- Changes in v2: - Moved from ctree.c to extent_io.c --- fs/btrfs/extent_io.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 5700fcc23271..52abad421ba1 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -3144,17 +3144,24 @@ static void end_bio_extent_readpage(struct bio *bio) */ int btrfs_alloc_page_array(unsigned long nr_pages, struct page **page_array) { - int i; - for (i = 0; i < nr_pages; i++) { - struct page *page; - if (page_array[i]) + long allocated = 0; + for (;;) { + long last = allocated; + + allocated = alloc_pages_bulk_array(GFP_NOFS, nr_pages, + page_array); + if (allocated == nr_pages) + return 0; + + if (allocated != last) continue; - page = alloc_page(GFP_NOFS); - if (!page) - return -ENOMEM; - page_array[i] = page; + /* + * 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. + */ + return -ENOMEM; } - return 0; } /* -- 2.35.1
| |