/* SPDX-License-Identifier: GPL-2.0 */ #ifndef BTRFS_ZONED_H #define BTRFS_ZONED_H #include #include #include "volumes.h" #include "disk-io.h" struct btrfs_zoned_device_info { /* * Number of zones, zone size and types of zones if bdev is a * zoned block device. */ u64 zone_size; u8 zone_size_shift; u64 max_zone_append_size; u32 nr_zones; unsigned long *seq_zones; unsigned long *empty_zones; struct blk_zone sb_zones[2 * BTRFS_SUPER_MIRROR_MAX]; }; #ifdef CONFIG_BLK_DEV_ZONED int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos, struct blk_zone *zone); int btrfs_get_dev_zone_info(struct btrfs_device *device); void btrfs_destroy_dev_zone_info(struct btrfs_device *device); int btrfs_check_zoned_mode(struct btrfs_fs_info *fs_info); int btrfs_check_mountopts_zoned(struct btrfs_fs_info *info); int btrfs_sb_log_location_bdev(struct block_device *bdev, int mirror, int rw, u64 *bytenr_ret); int btrfs_sb_log_location(struct btrfs_device *device, int mirror, int rw, u64 *bytenr_ret); void btrfs_advance_sb_log(struct btrfs_device *device, int mirror); int btrfs_reset_sb_log_zones(struct block_device *bdev, int mirror); #else /* CONFIG_BLK_DEV_ZONED */ static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos, struct blk_zone *zone) { return 0; } static inline int btrfs_get_dev_zone_info(struct btrfs_device *device) { return 0; } static inline void btrfs_destroy_dev_zone_info(struct btrfs_device *device) { } static inline int btrfs_check_zoned_mode(const struct btrfs_fs_info *fs_info) { if (!btrfs_is_zoned(fs_info)) return 0; btrfs_err(fs_info, "zoned block devices support is not enabled"); return -EOPNOTSUPP; } static inline int btrfs_check_mountopts_zoned(struct btrfs_fs_info *info) { return 0; } static inline int btrfs_sb_log_location_bdev(struct block_device *bdev, int mirror, int rw, u64 *bytenr_ret) { *bytenr_ret = btrfs_sb_offset(mirror); return 0; } static inline int btrfs_sb_log_location(struct btrfs_device *device, int mirror, int rw, u64 *bytenr_ret) { *bytenr_ret = btrfs_sb_offset(mirror); return 0; } static inline void btrfs_advance_sb_log(struct btrfs_device *device, int mirror) { } static inline int btrfs_reset_sb_log_zones(struct block_device *bdev, int mirror) { return 0; } #endif static inline bool btrfs_dev_is_sequential(struct btrfs_device *device, u64 pos) { struct btrfs_zoned_device_info *zone_info = device->zone_info; if (!zone_info) return false; return test_bit(pos >> zone_info->zone_size_shift, zone_info->seq_zones); } static inline bool btrfs_dev_is_empty_zone(struct btrfs_device *device, u64 pos) { struct btrfs_zoned_device_info *zone_info = device->zone_info; if (!zone_info) return true; return test_bit(pos >> zone_info->zone_size_shift, zone_info->empty_zones); } static inline void btrfs_dev_set_empty_zone_bit(struct btrfs_device *device, u64 pos, bool set) { struct btrfs_zoned_device_info *zone_info = device->zone_info; unsigned int zno; if (!zone_info) return; zno = pos >> zone_info->zone_size_shift; if (set) set_bit(zno, zone_info->empty_zones); else clear_bit(zno, zone_info->empty_zones); } static inline void btrfs_dev_set_zone_empty(struct btrfs_device *device, u64 pos) { btrfs_dev_set_empty_zone_bit(device, pos, true); } static inline void btrfs_dev_clear_zone_empty(struct btrfs_device *device, u64 pos) { btrfs_dev_set_empty_zone_bit(device, pos, false); } static inline bool btrfs_check_device_zone_type(const struct btrfs_fs_info *fs_info, struct block_device *bdev) { u64 zone_size; if (btrfs_is_zoned(fs_info)) { zone_size = bdev_zone_sectors(bdev) << SECTOR_SHIFT; /* Do not allow non-zoned device */ return bdev_is_zoned(bdev) && fs_info->zone_size == zone_size; } /* Do not allow Host Manged zoned device */ return bdev_zoned_model(bdev) != BLK_ZONED_HM; } static inline bool btrfs_check_super_location(struct btrfs_device *device, u64 pos) { /* * On a non-zoned device, any address is OK. On a zoned device, * non-SEQUENTIAL WRITE REQUIRED zones are capable. */ return device->zone_info == NULL || !btrfs_dev_is_sequential(device, pos); } #endif