aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Le Moal <damien.lemoal@wdc.com>2016-10-28 17:45:06 +0900
committerMister Oyster <oysterized@gmail.com>2017-04-13 12:34:24 +0200
commitad704da0526781fde21cd70bb702804621719b08 (patch)
tree677e94b3eedbeb5338431d89007a7970447b6053
parenta94f563f2afffd22c3e8816944215b2769dc422b (diff)
f2fs: Reset sequential zones on zoned block devices
When a zoned block device is mounted, discarding sections contained in sequential zones must reset the zone write pointer. For sections contained in conventional zones, the regular discard is used if the drive supports it. Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> Conflicts: fs/f2fs/segment.c
-rw-r--r--fs/f2fs/segment.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index f56401ecb..76b7b24fb 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -16,6 +16,7 @@
#include <linux/kthread.h>
#include <linux/swap.h>
#include <linux/timer.h>
+#include <linux/timer.h>
#include "f2fs.h"
#include "segment.h"
@@ -643,6 +644,45 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
mutex_unlock(&dirty_i->seglist_lock);
}
+#ifdef CONFIG_BLK_DEV_ZONED
+static int f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
+ block_t blkstart, block_t blklen)
+{
+ sector_t sector = SECTOR_FROM_BLOCK(blkstart);
+ sector_t nr_sects = SECTOR_FROM_BLOCK(blklen);
+ struct block_device *bdev = sbi->sb->s_bdev;
+
+ if (nr_sects != bdev_zone_size(bdev)) {
+ f2fs_msg(sbi->sb, KERN_INFO,
+ "Unaligned discard attempted (sector %llu + %llu)",
+ (unsigned long long)sector,
+ (unsigned long long)nr_sects);
+ return -EIO;
+ }
+
+ /*
+ * We need to know the type of the zone: for conventional zones,
+ * use regular discard if the drive supports it. For sequential
+ * zones, reset the zone write pointer.
+ */
+ switch (get_blkz_type(sbi, blkstart)) {
+
+ case BLK_ZONE_TYPE_CONVENTIONAL:
+ if (!blk_queue_discard(bdev_get_queue(bdev)))
+ return 0;
+ return blkdev_issue_discard(bdev, sector, nr_sects,
+ GFP_NOFS, 0);
+ case BLK_ZONE_TYPE_SEQWRITE_REQ:
+ case BLK_ZONE_TYPE_SEQWRITE_PREF:
+ return blkdev_reset_zones(bdev, sector,
+ nr_sects, GFP_NOFS);
+ default:
+ /* Unknown zone type: broken device ? */
+ return -EIO;
+ }
+}
+#endif
+
static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
block_t blkstart, block_t blklen)
{
@@ -660,6 +700,11 @@ static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
sbi->discard_blks--;
}
trace_f2fs_issue_discard(sbi->sb, blkstart, blklen);
+
+#ifdef CONFIG_BLK_DEV_ZONED
+ if (f2fs_sb_mounted_blkzoned(sbi->sb))
+ return f2fs_issue_discard_zone(sbi, blkstart, blklen);
+#endif
return blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0);
}