Commit c73e680d authored by Sungjong Seo's avatar Sungjong Seo Committed by Namjae Jeon
Browse files

exfat: call bh_read in get_block only when necessary



With commit 11a347fb ("exfat: change to get file size from DataLength"),
exfat_get_block() can now handle valid_size. However, most partial
unwritten blocks that could be mapped with other blocks are being
inefficiently processed separately as individual blocks.

Except for partial unwritten blocks that require independent processing,
let's handle them simply as before.

Signed-off-by: default avatarSungjong Seo <sj1557.seo@samsung.com>
Reviewed-by: default avatarYuezhang Mo <Yuezhang.Mo@sony.com>
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
parent 59c30e31
Loading
Loading
Loading
Loading
+77 −82
Original line number Diff line number Diff line
@@ -274,9 +274,11 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
	sector_t last_block;
	sector_t phys = 0;
	sector_t valid_blks;
	loff_t i_size;

	mutex_lock(&sbi->s_lock);
	last_block = EXFAT_B_TO_BLK_ROUND_UP(i_size_read(inode), sb);
	i_size = i_size_read(inode);
	last_block = EXFAT_B_TO_BLK_ROUND_UP(i_size, sb);
	if (iblock >= last_block && !create)
		goto done;

@@ -305,64 +307,59 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
	if (buffer_delay(bh_result))
		clear_buffer_delay(bh_result);

	if (create) {
	/*
	 * In most cases, we just need to set bh_result to mapped, unmapped
	 * or new status as follows:
	 *  1. i_size == valid_size
	 *  2. write case (create == 1)
	 *  3. direct_read (!bh_result->b_folio)
	 *     -> the unwritten part will be zeroed in exfat_direct_IO()
	 *
	 * Otherwise, in the case of buffered read, it is necessary to take
	 * care the last nested block if valid_size is not equal to i_size.
	 */
	if (i_size == ei->valid_size || create || !bh_result->b_folio)
		valid_blks = EXFAT_B_TO_BLK_ROUND_UP(ei->valid_size, sb);
	else
		valid_blks = EXFAT_B_TO_BLK(ei->valid_size, sb);

		if (iblock + max_blocks < valid_blks) {
			/* The range has been written, map it */
	/* The range has been fully written, map it */
	if (iblock + max_blocks < valid_blks)
		goto done;
		} else if (iblock < valid_blks) {
			/*
			 * The range has been partially written,
			 * map the written part.
			 */

	/* The range has been partially written, map the written part */
	if (iblock < valid_blks) {
		max_blocks = valid_blks - iblock;
		goto done;
	}

		/* The area has not been written, map and mark as new. */
	/* The area has not been written, map and mark as new for create case */
	if (create) {
		set_buffer_new(bh_result);

		ei->valid_size = EXFAT_BLK_TO_B(iblock + max_blocks, sb);
		mark_inode_dirty(inode);
	} else {
		valid_blks = EXFAT_B_TO_BLK(ei->valid_size, sb);

		if (iblock + max_blocks < valid_blks) {
			/* The range has been written, map it */
		goto done;
		} else if (iblock < valid_blks) {
	}

	/*
			 * The area has been partially written,
			 * map the written part.
	 * The area has just one block partially written.
	 * In that case, we should read and fill the unwritten part of
	 * a block with zero.
	 */
			max_blocks = valid_blks - iblock;
			goto done;
		} else if (iblock == valid_blks &&
	if (bh_result->b_folio && iblock == valid_blks &&
	    (ei->valid_size & (sb->s_blocksize - 1))) {
			/*
			 * The block has been partially written,
			 * zero the unwritten part and map the block.
			 */
		loff_t size, pos;
		void *addr;

		max_blocks = 1;

			/*
			 * For direct read, the unwritten part will be zeroed in
			 * exfat_direct_IO()
			 */
			if (!bh_result->b_folio)
				goto done;

		/*
		 * No buffer_head is allocated.
			 * (1) bmap: It's enough to fill bh_result without I/O.
			 * (2) read: The unwritten part should be filled with 0
		 * (1) bmap: It's enough to set blocknr without I/O.
		 * (2) read: The unwritten part should be filled with zero.
		 *           If a folio does not have any buffers,
		 *           let's returns -EAGAIN to fallback to
			 *           per-bh IO like block_read_full_folio().
		 *           block_read_full_folio() for per-bh IO.
		 */
		if (!folio_buffers(bh_result->b_folio)) {
			err = -EAGAIN;
@@ -389,18 +386,16 @@ static int exfat_get_block(struct inode *inode, sector_t iblock,
			goto done;

		/* Zero unwritten part of a block */
			memset(bh_result->b_data + size, 0,
			       bh_result->b_size - size);

		memset(bh_result->b_data + size, 0, bh_result->b_size - size);
		err = 0;
		} else {
		goto done;
	}

	/*
			 * The range has not been written, clear the mapped flag
			 * to only zero the cache and do not read from disk.
	 * The area has not been written, clear mapped for read/bmap cases.
	 * If so, it will be filled with zero without reading from disk.
	 */
	clear_buffer_mapped(bh_result);
		}
	}
done:
	bh_result->b_size = EXFAT_BLK_TO_B(max_blocks, sb);
	if (err < 0)