|
@@ -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"
|
|
@@ -635,15 +636,19 @@ static void f2fs_submit_bio_wait_endio(struct bio *bio)
|
|
|
}
|
|
|
|
|
|
/* this function is copied from blkdev_issue_discard from block/blk-lib.c */
|
|
|
-static int __f2fs_issue_discard_async(struct f2fs_sb_info *sbi, sector_t sector,
|
|
|
- sector_t nr_sects, gfp_t gfp_mask, unsigned long flags)
|
|
|
+static int __f2fs_issue_discard_async(struct f2fs_sb_info *sbi,
|
|
|
+ block_t blkstart, block_t blklen)
|
|
|
{
|
|
|
struct block_device *bdev = sbi->sb->s_bdev;
|
|
|
struct bio *bio = NULL;
|
|
|
int err;
|
|
|
|
|
|
- err = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, flags,
|
|
|
- &bio);
|
|
|
+ trace_f2fs_issue_discard(sbi->sb, blkstart, blklen);
|
|
|
+
|
|
|
+ err = __blkdev_issue_discard(bdev,
|
|
|
+ SECTOR_FROM_BLOCK(blkstart),
|
|
|
+ SECTOR_FROM_BLOCK(blklen),
|
|
|
+ GFP_NOFS, 0, &bio);
|
|
|
if (!err && bio) {
|
|
|
struct bio_entry *be = __add_bio_entry(sbi, bio);
|
|
|
|
|
@@ -656,11 +661,49 @@ static int __f2fs_issue_discard_async(struct f2fs_sb_info *sbi, sector_t sector,
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+#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 __f2fs_issue_discard_async(sbi, blkstart,
|
|
|
+ blklen);
|
|
|
+
|
|
|
+ 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)
|
|
|
{
|
|
|
- sector_t start = SECTOR_FROM_BLOCK(blkstart);
|
|
|
- sector_t len = SECTOR_FROM_BLOCK(blklen);
|
|
|
struct seg_entry *se;
|
|
|
unsigned int offset;
|
|
|
block_t i;
|
|
@@ -672,8 +715,12 @@ static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
|
|
|
if (!f2fs_test_and_set_bit(offset, se->discard_map))
|
|
|
sbi->discard_blks--;
|
|
|
}
|
|
|
- trace_f2fs_issue_discard(sbi->sb, blkstart, blklen);
|
|
|
- return __f2fs_issue_discard_async(sbi, start, len, GFP_NOFS, 0);
|
|
|
+
|
|
|
+#ifdef CONFIG_BLK_DEV_ZONED
|
|
|
+ if (f2fs_sb_mounted_blkzoned(sbi->sb))
|
|
|
+ return f2fs_issue_discard_zone(sbi, blkstart, blklen);
|
|
|
+#endif
|
|
|
+ return __f2fs_issue_discard_async(sbi, blkstart, blklen);
|
|
|
}
|
|
|
|
|
|
static void __add_discard_entry(struct f2fs_sb_info *sbi,
|