aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/zoned.h
blob: e4ee1a50be2d3f1c17ff3edd6889758aafae870f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef BTRFS_ZONED_H
#define BTRFS_ZONED_H

#include <linux/types.h>
#include <linux/blkdev.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;
	u32 nr_zones;
	unsigned long *seq_zones;
	unsigned long *empty_zones;
};

#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);
#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;
}

#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;
}

#endif