Commit b771aadc authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

f2fs: enforce single zone capacity



In order to simplify the complicated per-zone capacity, let's support
only one capacity for entire zoned device.

Reviewed-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 14de5fc3
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1235,7 +1235,6 @@ struct f2fs_dev_info {
#ifdef CONFIG_BLK_DEV_ZONED
	unsigned int nr_blkz;		/* Total number of zones */
	unsigned long *blkz_seq;	/* Bitmap indicating sequential zones */
	block_t *zone_capacity_blocks;  /* Array of zone capacity in blks */
#endif
};

@@ -1672,6 +1671,7 @@ struct f2fs_sb_info {
	unsigned int meta_ino_num;		/* meta inode number*/
	unsigned int log_blocks_per_seg;	/* log2 blocks per segment */
	unsigned int blocks_per_seg;		/* blocks per segment */
	unsigned int unusable_blocks_per_sec;	/* unusable blocks per section */
	unsigned int segs_per_sec;		/* segments per section */
	unsigned int secs_per_zone;		/* sections per zone */
	unsigned int total_sections;		/* total section count */
+6 −13
Original line number Diff line number Diff line
@@ -4895,7 +4895,7 @@ static unsigned int get_zone_idx(struct f2fs_sb_info *sbi, unsigned int secno,
static inline unsigned int f2fs_usable_zone_segs_in_sec(
		struct f2fs_sb_info *sbi, unsigned int segno)
{
	unsigned int dev_idx, zone_idx, unusable_segs_in_sec;
	unsigned int dev_idx, zone_idx;

	dev_idx = f2fs_target_device_index(sbi, START_BLOCK(sbi, segno));
	zone_idx = get_zone_idx(sbi, GET_SEC_FROM_SEG(sbi, segno), dev_idx);
@@ -4904,18 +4904,12 @@ static inline unsigned int f2fs_usable_zone_segs_in_sec(
	if (is_conv_zone(sbi, zone_idx, dev_idx))
		return sbi->segs_per_sec;

	/*
	 * If the zone_capacity_blocks array is NULL, then zone capacity
	 * is equal to the zone size for all zones
	 */
	if (!FDEV(dev_idx).zone_capacity_blocks)
	if (!sbi->unusable_blocks_per_sec)
		return sbi->segs_per_sec;

	/* Get the segment count beyond zone capacity block */
	unusable_segs_in_sec = (sbi->blocks_per_blkz -
				FDEV(dev_idx).zone_capacity_blocks[zone_idx]) >>
				sbi->log_blocks_per_seg;
	return sbi->segs_per_sec - unusable_segs_in_sec;
	return sbi->segs_per_sec - (sbi->unusable_blocks_per_sec >>
						sbi->log_blocks_per_seg);
}

/*
@@ -4944,12 +4938,11 @@ static inline unsigned int f2fs_usable_zone_blks_in_seg(
	if (is_conv_zone(sbi, zone_idx, dev_idx))
		return sbi->blocks_per_seg;

	if (!FDEV(dev_idx).zone_capacity_blocks)
	if (!sbi->unusable_blocks_per_sec)
		return sbi->blocks_per_seg;

	sec_start_blkaddr = START_BLOCK(sbi, GET_SEG_FROM_SEC(sbi, secno));
	sec_cap_blkaddr = sec_start_blkaddr +
				FDEV(dev_idx).zone_capacity_blocks[zone_idx];
	sec_cap_blkaddr = sec_start_blkaddr + CAP_BLKS_PER_SEC(sbi);

	/*
	 * If segment starts before zone capacity and spans beyond
+3 −0
Original line number Diff line number Diff line
@@ -101,6 +101,9 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi,
		GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
#define BLKS_PER_SEC(sbi)					\
	((sbi)->segs_per_sec * (sbi)->blocks_per_seg)
#define CAP_BLKS_PER_SEC(sbi)					\
	((sbi)->segs_per_sec * (sbi)->blocks_per_seg -		\
	 (sbi)->unusable_blocks_per_sec)
#define GET_SEC_FROM_SEG(sbi, segno)				\
	(((segno) == -1) ? -1: (segno) / (sbi)->segs_per_sec)
#define GET_SEG_FROM_SEC(sbi, secno)				\
+12 −21
Original line number Diff line number Diff line
@@ -1522,7 +1522,6 @@ static void destroy_device_list(struct f2fs_sb_info *sbi)
		blkdev_put(FDEV(i).bdev, FMODE_EXCL);
#ifdef CONFIG_BLK_DEV_ZONED
		kvfree(FDEV(i).blkz_seq);
		kfree(FDEV(i).zone_capacity_blocks);
#endif
	}
	kvfree(sbi->devs);
@@ -3673,24 +3672,29 @@ static int init_percpu_info(struct f2fs_sb_info *sbi)
#ifdef CONFIG_BLK_DEV_ZONED

struct f2fs_report_zones_args {
	struct f2fs_sb_info *sbi;
	struct f2fs_dev_info *dev;
	bool zone_cap_mismatch;
};

static int f2fs_report_zone_cb(struct blk_zone *zone, unsigned int idx,
			      void *data)
{
	struct f2fs_report_zones_args *rz_args = data;
	block_t unusable_blocks = (zone->len - zone->capacity) >>
					F2FS_LOG_SECTORS_PER_BLOCK;

	if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
		return 0;

	set_bit(idx, rz_args->dev->blkz_seq);
	rz_args->dev->zone_capacity_blocks[idx] = zone->capacity >>
						F2FS_LOG_SECTORS_PER_BLOCK;
	if (zone->len != zone->capacity && !rz_args->zone_cap_mismatch)
		rz_args->zone_cap_mismatch = true;

	if (!rz_args->sbi->unusable_blocks_per_sec) {
		rz_args->sbi->unusable_blocks_per_sec = unusable_blocks;
		return 0;
	}
	if (rz_args->sbi->unusable_blocks_per_sec != unusable_blocks) {
		f2fs_err(rz_args->sbi, "F2FS supports single zone capacity\n");
		return -EINVAL;
	}
	return 0;
}

@@ -3731,26 +3735,13 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi)
	if (!FDEV(devi).blkz_seq)
		return -ENOMEM;

	/* Get block zones type and zone-capacity */
	FDEV(devi).zone_capacity_blocks = f2fs_kzalloc(sbi,
					FDEV(devi).nr_blkz * sizeof(block_t),
					GFP_KERNEL);
	if (!FDEV(devi).zone_capacity_blocks)
		return -ENOMEM;

	rep_zone_arg.sbi = sbi;
	rep_zone_arg.dev = &FDEV(devi);
	rep_zone_arg.zone_cap_mismatch = false;

	ret = blkdev_report_zones(bdev, 0, BLK_ALL_ZONES, f2fs_report_zone_cb,
				  &rep_zone_arg);
	if (ret < 0)
		return ret;

	if (!rep_zone_arg.zone_cap_mismatch) {
		kfree(FDEV(devi).zone_capacity_blocks);
		FDEV(devi).zone_capacity_blocks = NULL;
	}

	return 0;
}
#endif