Skip to content

Commit afba2bc

Browse files
naotakdave
authored andcommitted
btrfs: zoned: implement active zone tracking
Add zone_is_active flag to btrfs_block_group. This flag indicates the underlying zones are all active. Such zone active block groups are tracked by fs_info->active_bg_list. btrfs_dev_{set,clear}_active_zone() take responsibility for the underlying device part. They set/clear the bitmap to indicate zone activeness and count the number of zones we can activate left. btrfs_zone_{activate,finish}() take responsibility for the logical part and the list management. In addition, btrfs_zone_finish() wait for any writes on it and send REQ_OP_ZONE_FINISH to the zone. Signed-off-by: Naohiro Aota <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent dafc340 commit afba2bc

File tree

7 files changed

+226
-2
lines changed

7 files changed

+226
-2
lines changed

fs/btrfs/block-group.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,6 +1896,7 @@ static struct btrfs_block_group *btrfs_create_block_group_cache(
18961896
INIT_LIST_HEAD(&cache->discard_list);
18971897
INIT_LIST_HEAD(&cache->dirty_list);
18981898
INIT_LIST_HEAD(&cache->io_list);
1899+
INIT_LIST_HEAD(&cache->active_bg_list);
18991900
btrfs_init_free_space_ctl(cache, cache->free_space_ctl);
19001901
atomic_set(&cache->frozen, 0);
19011902
mutex_init(&cache->free_space_lock);
@@ -3842,6 +3843,16 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
38423843
}
38433844
spin_unlock(&info->unused_bgs_lock);
38443845

3846+
spin_lock(&info->zone_active_bgs_lock);
3847+
while (!list_empty(&info->zone_active_bgs)) {
3848+
block_group = list_first_entry(&info->zone_active_bgs,
3849+
struct btrfs_block_group,
3850+
active_bg_list);
3851+
list_del_init(&block_group->active_bg_list);
3852+
btrfs_put_block_group(block_group);
3853+
}
3854+
spin_unlock(&info->zone_active_bgs_lock);
3855+
38453856
spin_lock(&info->block_group_cache_lock);
38463857
while ((n = rb_last(&info->block_group_cache_tree)) != NULL) {
38473858
block_group = rb_entry(n, struct btrfs_block_group,

fs/btrfs/block-group.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ struct btrfs_block_group {
9898
unsigned int to_copy:1;
9999
unsigned int relocating_repair:1;
100100
unsigned int chunk_item_inserted:1;
101+
unsigned int zone_is_active:1;
101102

102103
int disk_cache_state;
103104

@@ -205,6 +206,7 @@ struct btrfs_block_group {
205206
u64 zone_capacity;
206207
u64 meta_write_pointer;
207208
struct map_lookup *physical_map;
209+
struct list_head active_bg_list;
208210
};
209211

210212
static inline u64 btrfs_block_group_end(struct btrfs_block_group *block_group)

fs/btrfs/ctree.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,9 @@ struct btrfs_fs_info {
10181018
spinlock_t treelog_bg_lock;
10191019
u64 treelog_bg;
10201020

1021+
spinlock_t zone_active_bgs_lock;
1022+
struct list_head zone_active_bgs;
1023+
10211024
#ifdef CONFIG_BTRFS_FS_REF_VERIFY
10221025
spinlock_t ref_verify_lock;
10231026
struct rb_root block_tree;

fs/btrfs/disk-io.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2884,6 +2884,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
28842884
spin_lock_init(&fs_info->buffer_lock);
28852885
spin_lock_init(&fs_info->unused_bgs_lock);
28862886
spin_lock_init(&fs_info->treelog_bg_lock);
2887+
spin_lock_init(&fs_info->zone_active_bgs_lock);
28872888
rwlock_init(&fs_info->tree_mod_log_lock);
28882889
mutex_init(&fs_info->unused_bg_unpin_mutex);
28892890
mutex_init(&fs_info->reclaim_bgs_lock);
@@ -2897,6 +2898,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
28972898
INIT_LIST_HEAD(&fs_info->tree_mod_seq_list);
28982899
INIT_LIST_HEAD(&fs_info->unused_bgs);
28992900
INIT_LIST_HEAD(&fs_info->reclaim_bgs);
2901+
INIT_LIST_HEAD(&fs_info->zone_active_bgs);
29002902
#ifdef CONFIG_BTRFS_DEBUG
29012903
INIT_LIST_HEAD(&fs_info->allocated_roots);
29022904
INIT_LIST_HEAD(&fs_info->allocated_ebs);

fs/btrfs/free-space-cache.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2763,8 +2763,9 @@ void btrfs_dump_free_space(struct btrfs_block_group *block_group,
27632763
* out the free space after the allocation offset.
27642764
*/
27652765
if (btrfs_is_zoned(fs_info)) {
2766-
btrfs_info(fs_info, "free space %llu",
2767-
block_group->zone_capacity - block_group->alloc_offset);
2766+
btrfs_info(fs_info, "free space %llu active %d",
2767+
block_group->zone_capacity - block_group->alloc_offset,
2768+
block_group->zone_is_active);
27682769
return;
27692770
}
27702771

fs/btrfs/zoned.c

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -989,6 +989,41 @@ u64 btrfs_find_allocatable_zones(struct btrfs_device *device, u64 hole_start,
989989
return pos;
990990
}
991991

992+
static bool btrfs_dev_set_active_zone(struct btrfs_device *device, u64 pos)
993+
{
994+
struct btrfs_zoned_device_info *zone_info = device->zone_info;
995+
unsigned int zno = (pos >> zone_info->zone_size_shift);
996+
997+
/* We can use any number of zones */
998+
if (zone_info->max_active_zones == 0)
999+
return true;
1000+
1001+
if (!test_bit(zno, zone_info->active_zones)) {
1002+
/* Active zone left? */
1003+
if (atomic_dec_if_positive(&zone_info->active_zones_left) < 0)
1004+
return false;
1005+
if (test_and_set_bit(zno, zone_info->active_zones)) {
1006+
/* Someone already set the bit */
1007+
atomic_inc(&zone_info->active_zones_left);
1008+
}
1009+
}
1010+
1011+
return true;
1012+
}
1013+
1014+
static void btrfs_dev_clear_active_zone(struct btrfs_device *device, u64 pos)
1015+
{
1016+
struct btrfs_zoned_device_info *zone_info = device->zone_info;
1017+
unsigned int zno = (pos >> zone_info->zone_size_shift);
1018+
1019+
/* We can use any number of zones */
1020+
if (zone_info->max_active_zones == 0)
1021+
return;
1022+
1023+
if (test_and_clear_bit(zno, zone_info->active_zones))
1024+
atomic_inc(&zone_info->active_zones_left);
1025+
}
1026+
9921027
int btrfs_reset_device_zone(struct btrfs_device *device, u64 physical,
9931028
u64 length, u64 *bytes)
9941029
{
@@ -1004,6 +1039,7 @@ int btrfs_reset_device_zone(struct btrfs_device *device, u64 physical,
10041039
*bytes = length;
10051040
while (length) {
10061041
btrfs_dev_set_zone_empty(device, physical);
1042+
btrfs_dev_clear_active_zone(device, physical);
10071043
physical += device->zone_info->zone_size;
10081044
length -= device->zone_info->zone_size;
10091045
}
@@ -1656,3 +1692,160 @@ struct btrfs_device *btrfs_zoned_get_device(struct btrfs_fs_info *fs_info,
16561692

16571693
return device;
16581694
}
1695+
1696+
/**
1697+
* Activate block group and underlying device zones
1698+
*
1699+
* @block_group: the block group to activate
1700+
*
1701+
* Return: true on success, false otherwise
1702+
*/
1703+
bool btrfs_zone_activate(struct btrfs_block_group *block_group)
1704+
{
1705+
struct btrfs_fs_info *fs_info = block_group->fs_info;
1706+
struct map_lookup *map;
1707+
struct btrfs_device *device;
1708+
u64 physical;
1709+
bool ret;
1710+
1711+
if (!btrfs_is_zoned(block_group->fs_info))
1712+
return true;
1713+
1714+
map = block_group->physical_map;
1715+
/* Currently support SINGLE profile only */
1716+
ASSERT(map->num_stripes == 1);
1717+
device = map->stripes[0].dev;
1718+
physical = map->stripes[0].physical;
1719+
1720+
if (device->zone_info->max_active_zones == 0)
1721+
return true;
1722+
1723+
spin_lock(&block_group->lock);
1724+
1725+
if (block_group->zone_is_active) {
1726+
ret = true;
1727+
goto out_unlock;
1728+
}
1729+
1730+
/* No space left */
1731+
if (block_group->alloc_offset == block_group->zone_capacity) {
1732+
ret = false;
1733+
goto out_unlock;
1734+
}
1735+
1736+
if (!btrfs_dev_set_active_zone(device, physical)) {
1737+
/* Cannot activate the zone */
1738+
ret = false;
1739+
goto out_unlock;
1740+
}
1741+
1742+
/* Successfully activated all the zones */
1743+
block_group->zone_is_active = 1;
1744+
1745+
spin_unlock(&block_group->lock);
1746+
1747+
/* For the active block group list */
1748+
btrfs_get_block_group(block_group);
1749+
1750+
spin_lock(&fs_info->zone_active_bgs_lock);
1751+
ASSERT(list_empty(&block_group->active_bg_list));
1752+
list_add_tail(&block_group->active_bg_list, &fs_info->zone_active_bgs);
1753+
spin_unlock(&fs_info->zone_active_bgs_lock);
1754+
1755+
return true;
1756+
1757+
out_unlock:
1758+
spin_unlock(&block_group->lock);
1759+
return ret;
1760+
}
1761+
1762+
int btrfs_zone_finish(struct btrfs_block_group *block_group)
1763+
{
1764+
struct btrfs_fs_info *fs_info = block_group->fs_info;
1765+
struct map_lookup *map;
1766+
struct btrfs_device *device;
1767+
u64 physical;
1768+
int ret = 0;
1769+
1770+
if (!btrfs_is_zoned(fs_info))
1771+
return 0;
1772+
1773+
map = block_group->physical_map;
1774+
/* Currently support SINGLE profile only */
1775+
ASSERT(map->num_stripes == 1);
1776+
1777+
device = map->stripes[0].dev;
1778+
physical = map->stripes[0].physical;
1779+
1780+
if (device->zone_info->max_active_zones == 0)
1781+
return 0;
1782+
1783+
spin_lock(&block_group->lock);
1784+
if (!block_group->zone_is_active) {
1785+
spin_unlock(&block_group->lock);
1786+
return 0;
1787+
}
1788+
1789+
/* Check if we have unwritten allocated space */
1790+
if ((block_group->flags &
1791+
(BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_SYSTEM)) &&
1792+
block_group->alloc_offset > block_group->meta_write_pointer) {
1793+
spin_unlock(&block_group->lock);
1794+
return -EAGAIN;
1795+
}
1796+
spin_unlock(&block_group->lock);
1797+
1798+
ret = btrfs_inc_block_group_ro(block_group, false);
1799+
if (ret)
1800+
return ret;
1801+
1802+
/* Ensure all writes in this block group finish */
1803+
btrfs_wait_block_group_reservations(block_group);
1804+
/* No need to wait for NOCOW writers. Zoned mode does not allow that. */
1805+
btrfs_wait_ordered_roots(fs_info, U64_MAX, block_group->start,
1806+
block_group->length);
1807+
1808+
spin_lock(&block_group->lock);
1809+
1810+
/*
1811+
* Bail out if someone already deactivated the block group, or
1812+
* allocated space is left in the block group.
1813+
*/
1814+
if (!block_group->zone_is_active) {
1815+
spin_unlock(&block_group->lock);
1816+
btrfs_dec_block_group_ro(block_group);
1817+
return 0;
1818+
}
1819+
1820+
if (block_group->reserved) {
1821+
spin_unlock(&block_group->lock);
1822+
btrfs_dec_block_group_ro(block_group);
1823+
return -EAGAIN;
1824+
}
1825+
1826+
block_group->zone_is_active = 0;
1827+
block_group->alloc_offset = block_group->zone_capacity;
1828+
block_group->free_space_ctl->free_space = 0;
1829+
btrfs_clear_treelog_bg(block_group);
1830+
spin_unlock(&block_group->lock);
1831+
1832+
ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
1833+
physical >> SECTOR_SHIFT,
1834+
device->zone_info->zone_size >> SECTOR_SHIFT,
1835+
GFP_NOFS);
1836+
btrfs_dec_block_group_ro(block_group);
1837+
1838+
if (!ret) {
1839+
btrfs_dev_clear_active_zone(device, physical);
1840+
1841+
spin_lock(&fs_info->zone_active_bgs_lock);
1842+
ASSERT(!list_empty(&block_group->active_bg_list));
1843+
list_del_init(&block_group->active_bg_list);
1844+
spin_unlock(&fs_info->zone_active_bgs_lock);
1845+
1846+
/* For active_bg_list */
1847+
btrfs_put_block_group(block_group);
1848+
}
1849+
1850+
return ret;
1851+
}

fs/btrfs/zoned.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ int btrfs_sync_zone_write_pointer(struct btrfs_device *tgt_dev, u64 logical,
6969
u64 physical_start, u64 physical_pos);
7070
struct btrfs_device *btrfs_zoned_get_device(struct btrfs_fs_info *fs_info,
7171
u64 logical, u64 length);
72+
bool btrfs_zone_activate(struct btrfs_block_group *block_group);
73+
int btrfs_zone_finish(struct btrfs_block_group *block_group);
7274
#else /* CONFIG_BLK_DEV_ZONED */
7375
static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
7476
struct blk_zone *zone)
@@ -204,6 +206,16 @@ static inline struct btrfs_device *btrfs_zoned_get_device(
204206
return ERR_PTR(-EOPNOTSUPP);
205207
}
206208

209+
static inline bool btrfs_zone_activate(struct btrfs_block_group *block_group)
210+
{
211+
return true;
212+
}
213+
214+
static inline int btrfs_zone_finish(struct btrfs_block_group *block_group)
215+
{
216+
return 0;
217+
}
218+
207219
#endif
208220

209221
static inline bool btrfs_dev_is_sequential(struct btrfs_device *device, u64 pos)

0 commit comments

Comments
 (0)