From: Zhang Yi <yi.zhang@xxxxxxxxxx> block_read_full_folio() uses an on-stack array to save the un-uptodated buffers. This approach is acceptable for small folios, as there are not too many buffers in a single folio. However, if the folio is a large folio, the number of buffers could reach up to 2,000 for a 2MB folio size with a 1KB block size. Therefore, we cannot use the 'arr' array for large folios, instead, we should iterate through the buffers using 'bh = bh->b_this_page'. Signed-off-by: Zhang Yi <yi.zhang@xxxxxxxxxx> --- fs/buffer.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index 1fc9a50def0b..54e608c8912e 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2366,7 +2366,7 @@ int block_read_full_folio(struct folio *folio, get_block_t *get_block) { struct inode *inode = folio->mapping->host; sector_t iblock, lblock; - struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE]; + struct buffer_head *bh, *head; size_t blocksize; int nr, i; int fully_mapped = 1; @@ -2377,8 +2377,6 @@ int block_read_full_folio(struct folio *folio, get_block_t *get_block) if (IS_ENABLED(CONFIG_FS_VERITY) && IS_VERITY(inode)) limit = inode->i_sb->s_maxbytes; - VM_BUG_ON_FOLIO(folio_test_large(folio), folio); - head = folio_create_buffers(folio, inode, 0); blocksize = head->b_size; @@ -2416,7 +2414,10 @@ int block_read_full_folio(struct folio *folio, get_block_t *get_block) if (buffer_uptodate(bh)) continue; } - arr[nr++] = bh; + /* lock the buffer */ + lock_buffer(bh); + mark_buffer_async_read(bh); + nr++; } while (i++, iblock++, (bh = bh->b_this_page) != head); if (fully_mapped) @@ -2431,25 +2432,24 @@ int block_read_full_folio(struct folio *folio, get_block_t *get_block) return 0; } - /* Stage two: lock the buffers */ - for (i = 0; i < nr; i++) { - bh = arr[i]; - lock_buffer(bh); - mark_buffer_async_read(bh); - } - /* - * Stage 3: start the IO. Check for uptodateness - * inside the buffer lock in case another process reading - * the underlying blockdev brought it uptodate (the sct fix). + * Start the IO. Check for uptodateness inside the buffer lock + * in case another process reading the underlying blockdev brought + * it uptodate (the sct fix). */ - for (i = 0; i < nr; i++) { - bh = arr[i]; + bh = head; + do { + if (!buffer_async_read(bh)) + continue; + if (buffer_uptodate(bh)) end_buffer_async_read(bh, 1); else submit_bh(REQ_OP_READ, bh); - } + + nr--; + } while (nr && (bh = bh->b_this_page) != head); + return 0; } EXPORT_SYMBOL(block_read_full_folio); -- 2.46.1