#ifndef BTRFS_SPACE_INFO_H
#define BTRFS_SPACE_INFO_H
#include <trace/events/btrfs.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/kobject.h>
#include <linux/lockdep.h>
#include <linux/wait.h>
#include <linux/rwsem.h>
#include "volumes.h"
struct btrfs_fs_info;
struct btrfs_block_group;
enum btrfs_reserve_flush_enum {
BTRFS_RESERVE_NO_FLUSH,
BTRFS_RESERVE_FLUSH_LIMIT,
BTRFS_RESERVE_FLUSH_EVICT,
BTRFS_RESERVE_FLUSH_DATA,
BTRFS_RESERVE_FLUSH_FREE_SPACE_INODE,
BTRFS_RESERVE_FLUSH_ALL,
BTRFS_RESERVE_FLUSH_ALL_STEAL,
BTRFS_RESERVE_FLUSH_EMERGENCY,
};
enum btrfs_flush_state {
FLUSH_DELAYED_ITEMS_NR = 1,
FLUSH_DELAYED_ITEMS = 2,
FLUSH_DELAYED_REFS_NR = 3,
FLUSH_DELAYED_REFS = 4,
FLUSH_DELALLOC = 5,
FLUSH_DELALLOC_WAIT = 6,
FLUSH_DELALLOC_FULL = 7,
ALLOC_CHUNK = 8,
ALLOC_CHUNK_FORCE = 9,
RUN_DELAYED_IPUTS = 10,
COMMIT_TRANS = 11,
RESET_ZONES = 12,
};
enum btrfs_space_info_sub_group {
BTRFS_SUB_GROUP_PRIMARY,
BTRFS_SUB_GROUP_DATA_RELOC,
BTRFS_SUB_GROUP_TREELOG,
};
#define BTRFS_SPACE_INFO_SUB_GROUP_MAX 1
struct btrfs_space_info {
struct btrfs_fs_info *fs_info;
struct btrfs_space_info *parent;
struct btrfs_space_info *sub_group[BTRFS_SPACE_INFO_SUB_GROUP_MAX];
int subgroup_id;
spinlock_t lock;
u64 total_bytes;
u64 bytes_used;
u64 bytes_pinned;
u64 bytes_reserved;
u64 bytes_may_use;
u64 bytes_readonly;
u64 bytes_zone_unusable;
u64 max_extent_size;
u64 chunk_size;
int bg_reclaim_threshold;
int clamp;
bool full;
bool chunk_alloc;
bool flush;
unsigned int force_alloc;
u64 disk_used;
u64 disk_total;
u64 flags;
struct list_head list;
struct list_head ro_bgs;
struct list_head priority_tickets;
struct list_head tickets;
u64 reclaim_size;
u64 tickets_id;
struct rw_semaphore groups_sem;
struct list_head block_groups[BTRFS_NR_RAID_TYPES];
struct kobject kobj;
struct kobject *block_group_kobjs[BTRFS_NR_RAID_TYPES];
u64 reclaim_count;
u64 reclaim_bytes;
u64 reclaim_errors;
bool dynamic_reclaim;
bool periodic_reclaim;
bool periodic_reclaim_ready;
s64 reclaimable_bytes;
};
static inline bool btrfs_mixed_space_info(const struct btrfs_space_info *space_info)
{
return ((space_info->flags & BTRFS_BLOCK_GROUP_METADATA) &&
(space_info->flags & BTRFS_BLOCK_GROUP_DATA));
}
#define DECLARE_SPACE_INFO_UPDATE(name, trace_name) \
static inline void \
btrfs_space_info_update_##name(struct btrfs_space_info *sinfo, \
s64 bytes) \
{ \
struct btrfs_fs_info *fs_info = sinfo->fs_info; \
const u64 abs_bytes = (bytes < 0) ? -bytes : bytes; \
lockdep_assert_held(&sinfo->lock); \
trace_update_##name(fs_info, sinfo, sinfo->name, bytes); \
trace_btrfs_space_reservation(fs_info, trace_name, \
sinfo->flags, abs_bytes, \
bytes > 0); \
if (bytes < 0 && sinfo->name < -bytes) { \
WARN_ON(1); \
sinfo->name = 0; \
return; \
} \
sinfo->name += bytes; \
}
DECLARE_SPACE_INFO_UPDATE(bytes_may_use, "space_info");
DECLARE_SPACE_INFO_UPDATE(bytes_pinned, "pinned");
DECLARE_SPACE_INFO_UPDATE(bytes_zone_unusable, "zone_unusable");
static inline u64 btrfs_space_info_used(const struct btrfs_space_info *s_info,
bool may_use_included)
{
lockdep_assert_held(&s_info->lock);
return s_info->bytes_used + s_info->bytes_reserved +
s_info->bytes_pinned + s_info->bytes_readonly +
s_info->bytes_zone_unusable +
(may_use_included ? s_info->bytes_may_use : 0);
}
int btrfs_init_space_info(struct btrfs_fs_info *fs_info);
void btrfs_add_bg_to_space_info(struct btrfs_fs_info *info,
struct btrfs_block_group *block_group);
void btrfs_update_space_info_chunk_size(struct btrfs_space_info *space_info,
u64 chunk_size);
struct btrfs_space_info *btrfs_find_space_info(struct btrfs_fs_info *info,
u64 flags);
void btrfs_clear_space_info_full(struct btrfs_fs_info *info);
void btrfs_dump_space_info(struct btrfs_space_info *info, u64 bytes,
bool dump_block_groups);
int btrfs_reserve_metadata_bytes(struct btrfs_space_info *space_info,
u64 orig_bytes,
enum btrfs_reserve_flush_enum flush);
void btrfs_try_granting_tickets(struct btrfs_space_info *space_info);
bool btrfs_can_overcommit(const struct btrfs_space_info *space_info, u64 bytes,
enum btrfs_reserve_flush_enum flush);
static inline void btrfs_space_info_free_bytes_may_use(
struct btrfs_space_info *space_info,
u64 num_bytes)
{
spin_lock(&space_info->lock);
btrfs_space_info_update_bytes_may_use(space_info, -num_bytes);
btrfs_try_granting_tickets(space_info);
spin_unlock(&space_info->lock);
}
int btrfs_reserve_data_bytes(struct btrfs_space_info *space_info, u64 bytes,
enum btrfs_reserve_flush_enum flush);
void btrfs_dump_space_info_for_trans_abort(struct btrfs_fs_info *fs_info);
void btrfs_init_async_reclaim_work(struct btrfs_fs_info *fs_info);
u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo);
void btrfs_space_info_update_reclaimable(struct btrfs_space_info *space_info, s64 bytes);
void btrfs_set_periodic_reclaim_ready(struct btrfs_space_info *space_info, bool ready);
int btrfs_calc_reclaim_threshold(const struct btrfs_space_info *space_info);
void btrfs_reclaim_sweep(const struct btrfs_fs_info *fs_info);
void btrfs_return_free_space(struct btrfs_space_info *space_info, u64 len);
static inline const char *btrfs_space_info_type_str(const struct btrfs_space_info *space_info)
{
switch (space_info->flags) {
case BTRFS_BLOCK_GROUP_SYSTEM:
return "SYSTEM";
case BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA:
return "DATA+METADATA";
case BTRFS_BLOCK_GROUP_DATA:
return "DATA";
case BTRFS_BLOCK_GROUP_METADATA:
return "METADATA";
default:
return "UNKNOWN";
}
}
#endif