#ifndef _EXT4_MBALLOC_H
#define _EXT4_MBALLOC_H
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/namei.h>
#include <linux/quotaops.h>
#include <linux/buffer_head.h>
#include <linux/module.h>
#include <linux/swap.h>
#include <linux/proc_fs.h>
#include <linux/pagemap.h>
#include <linux/seq_file.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
#include "ext4_jbd2.h"
#include "ext4.h"
#ifdef CONFIG_EXT4_DEBUG
#define mb_debug(sb, fmt, ...) \
pr_debug("[%s/%d] EXT4-fs (%s): (%s, %d): %s: " fmt, \
current->comm, task_pid_nr(current), sb->s_id, \
__FILE__, __LINE__, __func__, ##__VA_ARGS__)
#else
#define mb_debug(sb, fmt, ...) no_printk(fmt, ##__VA_ARGS__)
#endif
#define EXT4_MB_HISTORY_ALLOC 1
#define EXT4_MB_HISTORY_PREALLOC 2
#define MB_DEFAULT_MAX_TO_SCAN 200
#define MB_DEFAULT_MIN_TO_SCAN 10
#define MB_DEFAULT_STATS 0
#define MB_DEFAULT_STREAM_THRESHOLD 16
#define MB_DEFAULT_ORDER2_REQS 2
#define MB_DEFAULT_GROUP_PREALLOC 512
#define MB_DEFAULT_LINEAR_LIMIT 4
#define MB_DEFAULT_LINEAR_SCAN_THRESHOLD 16
#define MB_DEFAULT_BEST_AVAIL_TRIM_ORDER 3
#define MB_NUM_ORDERS(sb) ((sb)->s_blocksize_bits + 2)
struct ext4_free_data {
struct list_head efd_list;
struct rb_node efd_node;
ext4_group_t efd_group;
ext4_grpblk_t efd_start_cluster;
ext4_grpblk_t efd_count;
tid_t efd_tid;
};
struct ext4_prealloc_space {
union {
struct rb_node inode_node;
struct list_head lg_list;
} pa_node;
struct list_head pa_group_list;
union {
struct list_head pa_tmp_list;
struct rcu_head pa_rcu;
} u;
spinlock_t pa_lock;
atomic_t pa_count;
unsigned pa_deleted;
ext4_fsblk_t pa_pstart;
ext4_lblk_t pa_lstart;
ext4_grpblk_t pa_len;
ext4_grpblk_t pa_free;
unsigned short pa_type;
union {
rwlock_t *inode_lock;
spinlock_t *lg_lock;
} pa_node_lock;
struct inode *pa_inode;
};
enum {
MB_INODE_PA = 0,
MB_GROUP_PA = 1
};
struct ext4_free_extent {
ext4_lblk_t fe_logical;
ext4_grpblk_t fe_start;
ext4_group_t fe_group;
ext4_grpblk_t fe_len;
};
#define PREALLOC_TB_SIZE 10
struct ext4_locality_group {
struct mutex lg_mutex;
struct list_head lg_prealloc_list[PREALLOC_TB_SIZE];
spinlock_t lg_prealloc_lock;
};
struct ext4_allocation_context {
struct inode *ac_inode;
struct super_block *ac_sb;
struct ext4_free_extent ac_o_ex;
struct ext4_free_extent ac_g_ex;
struct ext4_free_extent ac_b_ex;
struct ext4_free_extent ac_f_ex;
ext4_grpblk_t ac_orig_goal_len;
ext4_group_t ac_prefetch_grp;
unsigned int ac_prefetch_ios;
unsigned int ac_prefetch_nr;
int ac_first_err;
__u32 ac_flags;
__u16 ac_groups_scanned;
__u16 ac_found;
__u16 ac_cX_found[EXT4_MB_NUM_CRS];
__u16 ac_tail;
__u16 ac_buddy;
__u8 ac_status;
__u8 ac_criteria;
__u8 ac_2order;
__u8 ac_op;
struct ext4_buddy *ac_e4b;
struct folio *ac_bitmap_folio;
struct folio *ac_buddy_folio;
struct ext4_prealloc_space *ac_pa;
struct ext4_locality_group *ac_lg;
};
#define AC_STATUS_CONTINUE 1
#define AC_STATUS_FOUND 2
#define AC_STATUS_BREAK 3
struct ext4_buddy {
struct folio *bd_buddy_folio;
void *bd_buddy;
struct folio *bd_bitmap_folio;
void *bd_bitmap;
struct ext4_group_info *bd_info;
struct super_block *bd_sb;
__u16 bd_blkbits;
ext4_group_t bd_group;
};
static inline ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb,
struct ext4_free_extent *fex)
{
return ext4_group_first_block_no(sb, fex->fe_group) +
(fex->fe_start << EXT4_SB(sb)->s_cluster_bits);
}
static inline loff_t extent_logical_end(struct ext4_sb_info *sbi,
struct ext4_free_extent *fex)
{
return (loff_t)fex->fe_logical + EXT4_C2B(sbi, fex->fe_len);
}
static inline loff_t pa_logical_end(struct ext4_sb_info *sbi,
struct ext4_prealloc_space *pa)
{
return (loff_t)pa->pa_lstart + EXT4_C2B(sbi, pa->pa_len);
}
typedef int (*ext4_mballoc_query_range_fn)(
struct super_block *sb,
ext4_group_t agno,
ext4_grpblk_t start,
ext4_grpblk_t len,
void *priv);
int
ext4_mballoc_query_range(
struct super_block *sb,
ext4_group_t agno,
ext4_grpblk_t start,
ext4_grpblk_t end,
ext4_mballoc_query_range_fn meta_formatter,
ext4_mballoc_query_range_fn formatter,
void *priv);
extern int ext4_mb_mark_context(handle_t *handle,
struct super_block *sb, bool state,
ext4_group_t group, ext4_grpblk_t blkoff,
ext4_grpblk_t len, int flags,
ext4_grpblk_t *ret_changed);
#if IS_ENABLED(CONFIG_EXT4_KUNIT_TESTS)
extern void mb_clear_bits_test(void *bm, int cur, int len);
extern ext4_fsblk_t
ext4_mb_new_blocks_simple_test(struct ext4_allocation_request *ar,
int *errp);
extern int mb_find_next_zero_bit_test(void *addr, int max, int start);
extern int mb_find_next_bit_test(void *addr, int max, int start);
extern void mb_clear_bit_test(int bit, void *addr);
extern int mb_test_bit_test(int bit, void *addr);
extern int
ext4_mb_mark_diskspace_used_test(struct ext4_allocation_context *ac,
handle_t *handle);
extern int mb_mark_used_test(struct ext4_buddy *e4b,
struct ext4_free_extent *ex);
extern void ext4_mb_generate_buddy_test(struct super_block *sb,
void *buddy, void *bitmap, ext4_group_t group,
struct ext4_group_info *grp);
extern int ext4_mb_load_buddy_test(struct super_block *sb,
ext4_group_t group, struct ext4_buddy *e4b);
extern void ext4_mb_unload_buddy_test(struct ext4_buddy *e4b);
extern void mb_free_blocks_test(struct inode *inode,
struct ext4_buddy *e4b, int first, int count);
extern void ext4_free_blocks_simple_test(struct inode *inode,
ext4_fsblk_t block, unsigned long count);
#endif
#endif