Commit c0c589fa authored by Nanzhe Zhao's avatar Nanzhe Zhao Committed by Jaegeuk Kim
Browse files

f2fs: Accounting large folio subpages before bio submission



In f2fs_read_data_large_folio(), read_pages_pending is incremented only
after the subpage has been added to the BIO.  With a heavily fragmented
file, each new subpage can force submission of the previous BIO.

If the BIO completes quickly, f2fs_finish_read_bio() may decrement
read_pages_pending to zero and call folio_end_read() while the read loop
is still processing other subpages of the same large folio.

Fix the ordering by incrementing read_pages_pending before any possible
BIO submission for the current subpage, matching the iomap ordering and
preventing premature folio_end_read().

Signed-off-by: default avatarNanzhe Zhao <nzzhao@126.com>
Reviewed-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 00feea1d
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
@@ -2497,6 +2497,18 @@ static int f2fs_read_data_large_folio(struct inode *inode,
			continue;
		}

		/* We must increment read_pages_pending before possible BIOs submitting
		 * to prevent from premature folio_end_read() call on folio
		 */
		if (folio_test_large(folio)) {
			ffs = ffs_find_or_alloc(folio);

			/* set the bitmap to wait */
			spin_lock_irq(&ffs->state_lock);
			ffs->read_pages_pending++;
			spin_unlock_irq(&ffs->state_lock);
		}

		/*
		 * This page will go to BIO.  Do we need to send this
		 * BIO off first?
@@ -2524,15 +2536,6 @@ static int f2fs_read_data_large_folio(struct inode *inode,
					offset << PAGE_SHIFT))
			goto submit_and_realloc;

		if (folio_test_large(folio)) {
			ffs = ffs_find_or_alloc(folio);

			/* set the bitmap to wait */
			spin_lock_irq(&ffs->state_lock);
			ffs->read_pages_pending++;
			spin_unlock_irq(&ffs->state_lock);
		}

		inc_page_count(F2FS_I_SB(inode), F2FS_RD_DATA);
		f2fs_update_iostat(F2FS_I_SB(inode), NULL, FS_DATA_READ_IO,
				F2FS_BLKSIZE);