Commit 1ccd9196 authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

f2fs: let's finish or reset zones all the time



In order to limit # of open zones, let's finish or reset zones given # of
valid blocks per section and its zone condition.

Reviewed-by: default avatarDaeho Jeong <daehojeong@google.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent aca90eea
Loading
Loading
Loading
Loading
+17 −58
Original line number Diff line number Diff line
@@ -4870,82 +4870,43 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi,
				    struct f2fs_dev_info *fdev,
				    struct blk_zone *zone)
{
	unsigned int wp_segno, wp_blkoff, zone_secno, zone_segno, segno;
	block_t zone_block, wp_block, last_valid_block;
	unsigned int zone_segno;
	block_t zone_block, valid_block_cnt;
	unsigned int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT;
	int i, s, b, ret;
	struct seg_entry *se;
	int ret;

	if (zone->type != BLK_ZONE_TYPE_SEQWRITE_REQ)
		return 0;

	wp_block = fdev->start_blk + (zone->wp >> log_sectors_per_block);
	wp_segno = GET_SEGNO(sbi, wp_block);
	wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno);
	zone_block = fdev->start_blk + (zone->start >> log_sectors_per_block);
	zone_segno = GET_SEGNO(sbi, zone_block);
	zone_secno = GET_SEC_FROM_SEG(sbi, zone_segno);

	if (zone_segno >= MAIN_SEGS(sbi))
		return 0;

	/*
	 * Skip check of zones cursegs point to, since
	 * fix_curseg_write_pointer() checks them.
	 */
	for (i = 0; i < NO_CHECK_TYPE; i++)
		if (zone_secno == GET_SEC_FROM_SEG(sbi,
						   CURSEG_I(sbi, i)->segno))
	if (zone_segno >= MAIN_SEGS(sbi) ||
	    IS_CURSEC(sbi, GET_SEC_FROM_SEG(sbi, zone_segno)))
		return 0;

	/*
	 * Get last valid block of the zone.
	 * Get # of valid block of the zone.
	 */
	last_valid_block = zone_block - 1;
	for (s = sbi->segs_per_sec - 1; s >= 0; s--) {
		segno = zone_segno + s;
		se = get_seg_entry(sbi, segno);
		for (b = sbi->blocks_per_seg - 1; b >= 0; b--)
			if (f2fs_test_bit(b, se->cur_valid_map)) {
				last_valid_block = START_BLOCK(sbi, segno) + b;
				break;
			}
		if (last_valid_block >= zone_block)
			break;
	}
	valid_block_cnt = get_valid_blocks(sbi, zone_segno, true);

	/*
	 * When safely unmounted in the previous mount, we can trust write
	 * pointers. Otherwise, finish zones.
	 */
	if (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
		/*
		 * The write pointer matches with the valid blocks or
		 * already points to the end of the zone.
		 */
		if ((last_valid_block + 1 == wp_block) ||
				(zone->wp == zone->start + zone->len))
	if ((!valid_block_cnt && zone->cond == BLK_ZONE_COND_EMPTY) ||
	    (valid_block_cnt && zone->cond == BLK_ZONE_COND_FULL))
		return 0;
	}

	if (last_valid_block + 1 == zone_block) {
		if (is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
			/*
			 * If there is no valid block in the zone and if write
			 * pointer is not at zone start, reset the write
			 * pointer.
			 */
			f2fs_notice(sbi,
			      "Zone without valid block has non-zero write "
			      "pointer. Reset the write pointer: wp[0x%x,0x%x]",
			      wp_segno, wp_blkoff);
		}
	if (!valid_block_cnt) {
		f2fs_notice(sbi, "Zone without valid block has non-zero write "
			    "pointer. Reset the write pointer: cond[0x%x]",
			    zone->cond);
		ret = __f2fs_issue_discard_zone(sbi, fdev->bdev, zone_block,
					zone->len >> log_sectors_per_block);
		if (ret)
			f2fs_err(sbi, "Discard zone failed: %s (errno=%d)",
				 fdev->path, ret);

		return ret;
	}

@@ -4957,10 +4918,8 @@ static int check_zone_write_pointer(struct f2fs_sb_info *sbi,
	 * selected for write operation until it get discarded.
	 */
	f2fs_notice(sbi, "Valid blocks are not aligned with write "
			    "pointer: valid block[0x%x,0x%x] wp[0x%x,0x%x]",
			    GET_SEGNO(sbi, last_valid_block),
			    GET_BLKOFF_FROM_SEG0(sbi, last_valid_block),
			    wp_segno, wp_blkoff);
		    "pointer: valid block[0x%x,0x%x] cond[0x%x]",
		    zone_segno, valid_block_cnt, zone->cond);

	ret = blkdev_zone_mgmt(fdev->bdev, REQ_OP_ZONE_FINISH,
				zone->start, zone->len, GFP_NOFS);