summaryrefslogtreecommitdiff
path: root/fs/f2fs/super.c
diff options
context:
space:
mode:
authorDamien Le Moal <damien.lemoal@wdc.com>2016-10-28 17:45:05 +0900
committerJaegeuk Kim <jaegeuk@kernel.org>2016-11-23 12:11:22 -0800
commit178053e2f1f9ccdb61ff6c2bd8644b53fc98e72e (patch)
tree55cd63cf12864ca6da6f47d68fd26c1b42c2d6a4 /fs/f2fs/super.c
parent3adc57e97792e4ac9f228bde802829e2e9840afe (diff)
f2fs: Cache zoned block devices zone type
With the zoned block device feature enabled, section discard need to do a zone reset for sections contained in sequential zones, and a regular discard (if supported) for sections stored in conventional zones. Avoid the need for a costly report zones to obtain a section zone type when discarding it by caching the types of the device zones in the super block information. This cache is initialized at mount time for mounts with the zoned block device feature enabled. Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs/f2fs/super.c')
-rw-r--r--fs/f2fs/super.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 3312284aa245..12a4f3f44a2f 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1511,6 +1511,65 @@ static int init_percpu_info(struct f2fs_sb_info *sbi)
GFP_KERNEL);
}
+#ifdef CONFIG_BLK_DEV_ZONED
+static int init_blkz_info(struct f2fs_sb_info *sbi)
+{
+ struct block_device *bdev = sbi->sb->s_bdev;
+ sector_t nr_sectors = bdev->bd_part->nr_sects;
+ sector_t sector = 0;
+ struct blk_zone *zones;
+ unsigned int i, nr_zones;
+ unsigned int n = 0;
+ int err = -EIO;
+
+ if (!f2fs_sb_mounted_blkzoned(sbi->sb))
+ return 0;
+
+ sbi->blocks_per_blkz = SECTOR_TO_BLOCK(bdev_zone_size(bdev));
+ sbi->log_blocks_per_blkz = __ilog2_u32(sbi->blocks_per_blkz);
+ sbi->nr_blkz = SECTOR_TO_BLOCK(nr_sectors) >>
+ sbi->log_blocks_per_blkz;
+ if (nr_sectors & (bdev_zone_size(bdev) - 1))
+ sbi->nr_blkz++;
+
+ sbi->blkz_type = kmalloc(sbi->nr_blkz, GFP_KERNEL);
+ if (!sbi->blkz_type)
+ return -ENOMEM;
+
+#define F2FS_REPORT_NR_ZONES 4096
+
+ zones = kcalloc(F2FS_REPORT_NR_ZONES, sizeof(struct blk_zone),
+ GFP_KERNEL);
+ if (!zones)
+ return -ENOMEM;
+
+ /* Get block zones type */
+ while (zones && sector < nr_sectors) {
+
+ nr_zones = F2FS_REPORT_NR_ZONES;
+ err = blkdev_report_zones(bdev, sector,
+ zones, &nr_zones,
+ GFP_KERNEL);
+ if (err)
+ break;
+ if (!nr_zones) {
+ err = -EIO;
+ break;
+ }
+
+ for (i = 0; i < nr_zones; i++) {
+ sbi->blkz_type[n] = zones[i].type;
+ sector += zones[i].len;
+ n++;
+ }
+ }
+
+ kfree(zones);
+
+ return err;
+}
+#endif
+
/*
* Read f2fs raw super block.
* Because we have two copies of super block, so read both of them
@@ -1757,6 +1816,15 @@ try_onemore:
init_ino_entry_info(sbi);
+#ifdef CONFIG_BLK_DEV_ZONED
+ err = init_blkz_info(sbi);
+ if (err) {
+ f2fs_msg(sb, KERN_ERR,
+ "Failed to initialize F2FS blkzone information");
+ goto free_blkz;
+ }
+#endif
+
/* setup f2fs internal modules */
err = build_segment_manager(sbi);
if (err) {
@@ -1935,6 +2003,10 @@ free_nm:
destroy_node_manager(sbi);
free_sm:
destroy_segment_manager(sbi);
+#ifdef CONFIG_BLK_DEV_ZONED
+free_blkz:
+ kfree(sbi->blkz_type);
+#endif
kfree(sbi->ckpt);
free_meta_inode:
make_bad_inode(sbi->meta_inode);