#include <linux/dm-bufio.h>
#include <linux/device-mapper.h>
#include <linux/dm-io.h>
#include <linux/slab.h>
#include <linux/sched/mm.h>
#include <linux/jiffies.h>
#include <linux/vmalloc.h>
#include <linux/shrinker.h>
#include <linux/module.h>
#include <linux/rbtree.h>
#include <linux/stacktrace.h>
#include <linux/jump_label.h>
#include "dm.h"
#define DM_MSG_PREFIX …
#define DM_BUFIO_MIN_BUFFERS …
#define DM_BUFIO_MEMORY_PERCENT …
#define DM_BUFIO_VMALLOC_PERCENT …
#define DM_BUFIO_WRITEBACK_RATIO …
#define DM_BUFIO_LOW_WATERMARK_RATIO …
#define DM_BUFIO_WORK_TIMER_SECS …
#define DM_BUFIO_DEFAULT_AGE_SECS …
#define DM_BUFIO_DEFAULT_RETAIN_BYTES …
#define DM_BUFIO_WRITE_ALIGN …
#define LIST_CLEAN …
#define LIST_DIRTY …
#define LIST_SIZE …
struct lru_entry { … };
struct lru_iter { … };
struct lru { … };
static void lru_init(struct lru *lru)
{ … }
static void lru_destroy(struct lru *lru)
{ … }
static void lru_insert(struct lru *lru, struct lru_entry *le)
{ … }
static inline struct lru_entry *to_le(struct list_head *l)
{ … }
static void lru_iter_begin(struct lru *lru, struct lru_iter *it)
{ … }
static inline void lru_iter_end(struct lru_iter *it)
{ … }
iter_predicate;
static struct lru_entry *lru_iter_next(struct lru_iter *it,
iter_predicate pred, void *context)
{ … }
static void lru_iter_invalidate(struct lru *lru, struct lru_entry *e)
{ … }
static void lru_remove(struct lru *lru, struct lru_entry *le)
{ … }
static inline void lru_reference(struct lru_entry *le)
{ … }
enum evict_result { … };
le_predicate;
static struct lru_entry *lru_evict(struct lru *lru, le_predicate pred, void *context, bool no_sleep)
{ … }
#define B_READING …
#define B_WRITING …
#define B_DIRTY …
enum data_mode { … };
struct dm_buffer { … };
struct buffer_tree { … } ____cacheline_aligned_in_smp;
struct dm_buffer_cache { … };
static DEFINE_STATIC_KEY_FALSE(no_sleep_enabled);
static inline unsigned int cache_index(sector_t block, unsigned int num_locks)
{ … }
static inline void cache_read_lock(struct dm_buffer_cache *bc, sector_t block)
{ … }
static inline void cache_read_unlock(struct dm_buffer_cache *bc, sector_t block)
{ … }
static inline void cache_write_lock(struct dm_buffer_cache *bc, sector_t block)
{ … }
static inline void cache_write_unlock(struct dm_buffer_cache *bc, sector_t block)
{ … }
struct lock_history { … };
static void lh_init(struct lock_history *lh, struct dm_buffer_cache *cache, bool write)
{ … }
static void __lh_lock(struct lock_history *lh, unsigned int index)
{ … }
static void __lh_unlock(struct lock_history *lh, unsigned int index)
{ … }
static void lh_exit(struct lock_history *lh)
{ … }
static void lh_next(struct lock_history *lh, sector_t b)
{ … }
static inline struct dm_buffer *le_to_buffer(struct lru_entry *le)
{ … }
static struct dm_buffer *list_to_buffer(struct list_head *l)
{ … }
static void cache_init(struct dm_buffer_cache *bc, unsigned int num_locks, bool no_sleep)
{ … }
static void cache_destroy(struct dm_buffer_cache *bc)
{ … }
static inline unsigned long cache_count(struct dm_buffer_cache *bc, int list_mode)
{ … }
static inline unsigned long cache_total(struct dm_buffer_cache *bc)
{ … }
static struct dm_buffer *__cache_get(const struct rb_root *root, sector_t block)
{ … }
static void __cache_inc_buffer(struct dm_buffer *b)
{ … }
static struct dm_buffer *cache_get(struct dm_buffer_cache *bc, sector_t block)
{ … }
static bool cache_put(struct dm_buffer_cache *bc, struct dm_buffer *b)
{ … }
b_predicate;
struct evict_wrapper { … };
static enum evict_result __evict_pred(struct lru_entry *le, void *context)
{ … }
static struct dm_buffer *__cache_evict(struct dm_buffer_cache *bc, int list_mode,
b_predicate pred, void *context,
struct lock_history *lh)
{ … }
static struct dm_buffer *cache_evict(struct dm_buffer_cache *bc, int list_mode,
b_predicate pred, void *context)
{ … }
static void cache_mark(struct dm_buffer_cache *bc, struct dm_buffer *b, int list_mode)
{ … }
static void __cache_mark_many(struct dm_buffer_cache *bc, int old_mode, int new_mode,
b_predicate pred, void *context, struct lock_history *lh)
{ … }
static void cache_mark_many(struct dm_buffer_cache *bc, int old_mode, int new_mode,
b_predicate pred, void *context)
{ … }
enum it_action { … };
iter_fn;
static void __cache_iterate(struct dm_buffer_cache *bc, int list_mode,
iter_fn fn, void *context, struct lock_history *lh)
{ … }
static void cache_iterate(struct dm_buffer_cache *bc, int list_mode,
iter_fn fn, void *context)
{ … }
static bool __cache_insert(struct rb_root *root, struct dm_buffer *b)
{ … }
static bool cache_insert(struct dm_buffer_cache *bc, struct dm_buffer *b)
{ … }
static bool cache_remove(struct dm_buffer_cache *bc, struct dm_buffer *b)
{ … }
b_release;
static struct dm_buffer *__find_next(struct rb_root *root, sector_t block)
{ … }
static void __remove_range(struct dm_buffer_cache *bc,
struct rb_root *root,
sector_t begin, sector_t end,
b_predicate pred, b_release release)
{ … }
static void cache_remove_range(struct dm_buffer_cache *bc,
sector_t begin, sector_t end,
b_predicate pred, b_release release)
{ … }
struct dm_bufio_client { … };
#define dm_bufio_in_request() …
static void dm_bufio_lock(struct dm_bufio_client *c)
{ … }
static void dm_bufio_unlock(struct dm_bufio_client *c)
{ … }
static unsigned long dm_bufio_default_cache_size;
static unsigned long dm_bufio_cache_size;
static unsigned long dm_bufio_cache_size_latch;
static DEFINE_SPINLOCK(global_spinlock);
static unsigned int dm_bufio_max_age = …;
static unsigned long dm_bufio_retain_bytes = …;
static unsigned long dm_bufio_peak_allocated;
static unsigned long dm_bufio_allocated_kmem_cache;
static unsigned long dm_bufio_allocated_get_free_pages;
static unsigned long dm_bufio_allocated_vmalloc;
static unsigned long dm_bufio_current_allocated;
static int dm_bufio_client_count;
static LIST_HEAD(dm_bufio_all_clients);
static DEFINE_MUTEX(dm_bufio_clients_lock);
static struct workqueue_struct *dm_bufio_wq;
static struct delayed_work dm_bufio_cleanup_old_work;
static struct work_struct dm_bufio_replacement_work;
#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
static void buffer_record_stack(struct dm_buffer *b)
{ … }
#endif
static void adjust_total_allocated(struct dm_buffer *b, bool unlink)
{ … }
static void __cache_size_refresh(void)
{ … }
static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
unsigned char *data_mode)
{ … }
static void free_buffer_data(struct dm_bufio_client *c,
void *data, unsigned char data_mode)
{ … }
static struct dm_buffer *alloc_buffer(struct dm_bufio_client *c, gfp_t gfp_mask)
{ … }
static void free_buffer(struct dm_buffer *b)
{ … }
static void dmio_complete(unsigned long error, void *context)
{ … }
static void use_dmio(struct dm_buffer *b, enum req_op op, sector_t sector,
unsigned int n_sectors, unsigned int offset,
unsigned short ioprio)
{ … }
static void bio_complete(struct bio *bio)
{ … }
static void use_bio(struct dm_buffer *b, enum req_op op, sector_t sector,
unsigned int n_sectors, unsigned int offset,
unsigned short ioprio)
{ … }
static inline sector_t block_to_sector(struct dm_bufio_client *c, sector_t block)
{ … }
static void submit_io(struct dm_buffer *b, enum req_op op, unsigned short ioprio,
void (*end_io)(struct dm_buffer *, blk_status_t))
{ … }
static void write_endio(struct dm_buffer *b, blk_status_t status)
{ … }
static void __write_dirty_buffer(struct dm_buffer *b,
struct list_head *write_list)
{ … }
static void __flush_write_list(struct list_head *write_list)
{ … }
static void __make_buffer_clean(struct dm_buffer *b)
{ … }
static enum evict_result is_clean(struct dm_buffer *b, void *context)
{ … }
static enum evict_result is_dirty(struct dm_buffer *b, void *context)
{ … }
static struct dm_buffer *__get_unclaimed_buffer(struct dm_bufio_client *c)
{ … }
static void __wait_for_free_buffer(struct dm_bufio_client *c)
{ … }
enum new_flag { … };
static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c, enum new_flag nf)
{ … }
static struct dm_buffer *__alloc_buffer_wait(struct dm_bufio_client *c, enum new_flag nf)
{ … }
static void __free_buffer_wake(struct dm_buffer *b)
{ … }
static enum evict_result cleaned(struct dm_buffer *b, void *context)
{ … }
static void __move_clean_buffers(struct dm_bufio_client *c)
{ … }
struct write_context { … };
static enum it_action write_one(struct dm_buffer *b, void *context)
{ … }
static void __write_dirty_buffers_async(struct dm_bufio_client *c, int no_wait,
struct list_head *write_list)
{ … }
static void __check_watermark(struct dm_bufio_client *c,
struct list_head *write_list)
{ … }
static void cache_put_and_wake(struct dm_bufio_client *c, struct dm_buffer *b)
{ … }
static struct dm_buffer *__bufio_new(struct dm_bufio_client *c, sector_t block,
enum new_flag nf, int *need_submit,
struct list_head *write_list)
{ … }
static void read_endio(struct dm_buffer *b, blk_status_t status)
{ … }
static void *new_read(struct dm_bufio_client *c, sector_t block,
enum new_flag nf, struct dm_buffer **bp,
unsigned short ioprio)
{ … }
void *dm_bufio_get(struct dm_bufio_client *c, sector_t block,
struct dm_buffer **bp)
{ … }
EXPORT_SYMBOL_GPL(…);
static void *__dm_bufio_read(struct dm_bufio_client *c, sector_t block,
struct dm_buffer **bp, unsigned short ioprio)
{ … }
void *dm_bufio_read(struct dm_bufio_client *c, sector_t block,
struct dm_buffer **bp)
{ … }
EXPORT_SYMBOL_GPL(…);
void *dm_bufio_read_with_ioprio(struct dm_bufio_client *c, sector_t block,
struct dm_buffer **bp, unsigned short ioprio)
{ … }
EXPORT_SYMBOL_GPL(…);
void *dm_bufio_new(struct dm_bufio_client *c, sector_t block,
struct dm_buffer **bp)
{ … }
EXPORT_SYMBOL_GPL(…);
static void __dm_bufio_prefetch(struct dm_bufio_client *c,
sector_t block, unsigned int n_blocks,
unsigned short ioprio)
{ … }
void dm_bufio_prefetch(struct dm_bufio_client *c, sector_t block, unsigned int n_blocks)
{ … }
EXPORT_SYMBOL_GPL(…);
void dm_bufio_prefetch_with_ioprio(struct dm_bufio_client *c, sector_t block,
unsigned int n_blocks, unsigned short ioprio)
{ … }
EXPORT_SYMBOL_GPL(…);
void dm_bufio_release(struct dm_buffer *b)
{ … }
EXPORT_SYMBOL_GPL(…);
void dm_bufio_mark_partial_buffer_dirty(struct dm_buffer *b,
unsigned int start, unsigned int end)
{ … }
EXPORT_SYMBOL_GPL(…);
void dm_bufio_mark_buffer_dirty(struct dm_buffer *b)
{ … }
EXPORT_SYMBOL_GPL(…);
void dm_bufio_write_dirty_buffers_async(struct dm_bufio_client *c)
{ … }
EXPORT_SYMBOL_GPL(…);
static bool is_writing(struct lru_entry *e, void *context)
{ … }
int dm_bufio_write_dirty_buffers(struct dm_bufio_client *c)
{ … }
EXPORT_SYMBOL_GPL(…);
int dm_bufio_issue_flush(struct dm_bufio_client *c)
{ … }
EXPORT_SYMBOL_GPL(…);
int dm_bufio_issue_discard(struct dm_bufio_client *c, sector_t block, sector_t count)
{ … }
EXPORT_SYMBOL_GPL(…);
static bool forget_buffer(struct dm_bufio_client *c, sector_t block)
{ … }
void dm_bufio_forget(struct dm_bufio_client *c, sector_t block)
{ … }
EXPORT_SYMBOL_GPL(…);
static enum evict_result idle(struct dm_buffer *b, void *context)
{ … }
void dm_bufio_forget_buffers(struct dm_bufio_client *c, sector_t block, sector_t n_blocks)
{ … }
EXPORT_SYMBOL_GPL(…);
void dm_bufio_set_minimum_buffers(struct dm_bufio_client *c, unsigned int n)
{ … }
EXPORT_SYMBOL_GPL(…);
unsigned int dm_bufio_get_block_size(struct dm_bufio_client *c)
{ … }
EXPORT_SYMBOL_GPL(…);
sector_t dm_bufio_get_device_size(struct dm_bufio_client *c)
{ … }
EXPORT_SYMBOL_GPL(…);
struct dm_io_client *dm_bufio_get_dm_io_client(struct dm_bufio_client *c)
{ … }
EXPORT_SYMBOL_GPL(…);
sector_t dm_bufio_get_block_number(struct dm_buffer *b)
{ … }
EXPORT_SYMBOL_GPL(…);
void *dm_bufio_get_block_data(struct dm_buffer *b)
{ … }
EXPORT_SYMBOL_GPL(…);
void *dm_bufio_get_aux_data(struct dm_buffer *b)
{ … }
EXPORT_SYMBOL_GPL(…);
struct dm_bufio_client *dm_bufio_get_client(struct dm_buffer *b)
{ … }
EXPORT_SYMBOL_GPL(…);
static enum it_action warn_leak(struct dm_buffer *b, void *context)
{ … }
static void drop_buffers(struct dm_bufio_client *c)
{ … }
static unsigned long get_retain_buffers(struct dm_bufio_client *c)
{ … }
static void __scan(struct dm_bufio_client *c)
{ … }
static void shrink_work(struct work_struct *w)
{ … }
static unsigned long dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
{ … }
static unsigned long dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
{ … }
struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsigned int block_size,
unsigned int reserved_buffers, unsigned int aux_size,
void (*alloc_callback)(struct dm_buffer *),
void (*write_callback)(struct dm_buffer *),
unsigned int flags)
{ … }
EXPORT_SYMBOL_GPL(…);
void dm_bufio_client_destroy(struct dm_bufio_client *c)
{ … }
EXPORT_SYMBOL_GPL(…);
void dm_bufio_client_reset(struct dm_bufio_client *c)
{ … }
EXPORT_SYMBOL_GPL(…);
void dm_bufio_set_sector_offset(struct dm_bufio_client *c, sector_t start)
{ … }
EXPORT_SYMBOL_GPL(…);
static unsigned int get_max_age_hz(void)
{ … }
static bool older_than(struct dm_buffer *b, unsigned long age_hz)
{ … }
struct evict_params { … };
static enum evict_result select_for_evict(struct dm_buffer *b, void *context)
{ … }
static unsigned long __evict_many(struct dm_bufio_client *c,
struct evict_params *params,
int list_mode, unsigned long max_count)
{ … }
static void evict_old_buffers(struct dm_bufio_client *c, unsigned long age_hz)
{ … }
static void cleanup_old_buffers(void)
{ … }
static void work_fn(struct work_struct *w)
{ … }
static struct dm_bufio_client *__pop_client(void)
{ … }
static void __insert_client(struct dm_bufio_client *new_client)
{ … }
static unsigned long __evict_a_few(unsigned long nr_buffers)
{ … }
static void check_watermarks(void)
{ … }
static void evict_old(void)
{ … }
static void do_global_cleanup(struct work_struct *w)
{ … }
static int __init dm_bufio_init(void)
{ … }
static void __exit dm_bufio_exit(void)
{ … }
module_init(…) …
module_exit(…)
module_param_named(max_cache_size_bytes, dm_bufio_cache_size, ulong, 0644);
MODULE_PARM_DESC(…) …;
module_param_named(max_age_seconds, dm_bufio_max_age, uint, 0644);
MODULE_PARM_DESC(…) …;
module_param_named(retain_bytes, dm_bufio_retain_bytes, ulong, 0644);
MODULE_PARM_DESC(…) …;
module_param_named(peak_allocated_bytes, dm_bufio_peak_allocated, ulong, 0644);
MODULE_PARM_DESC(…) …;
module_param_named(allocated_kmem_cache_bytes, dm_bufio_allocated_kmem_cache, ulong, 0444);
MODULE_PARM_DESC(…) …;
module_param_named(allocated_get_free_pages_bytes, dm_bufio_allocated_get_free_pages, ulong, 0444);
MODULE_PARM_DESC(…) …;
module_param_named(allocated_vmalloc_bytes, dm_bufio_allocated_vmalloc, ulong, 0444);
MODULE_PARM_DESC(…) …;
module_param_named(current_allocated_bytes, dm_bufio_current_allocated, ulong, 0444);
MODULE_PARM_DESC(…) …;
MODULE_AUTHOR(…) …;
MODULE_DESCRIPTION(…) …;
MODULE_LICENSE(…) …;