166a63635SJoe Thornber /* 266a63635SJoe Thornber * Copyright (C) 2015 Red Hat. All rights reserved. 366a63635SJoe Thornber * 466a63635SJoe Thornber * This file is released under the GPL. 566a63635SJoe Thornber */ 666a63635SJoe Thornber 7b29d4986SJoe Thornber #include "dm-cache-background-tracker.h" 866a63635SJoe Thornber #include "dm-cache-policy-internal.h" 9b29d4986SJoe Thornber #include "dm-cache-policy.h" 1066a63635SJoe Thornber #include "dm.h" 1166a63635SJoe Thornber 1266a63635SJoe Thornber #include <linux/hash.h> 1366a63635SJoe Thornber #include <linux/jiffies.h> 1466a63635SJoe Thornber #include <linux/module.h> 1566a63635SJoe Thornber #include <linux/mutex.h> 1666a63635SJoe Thornber #include <linux/vmalloc.h> 1766a63635SJoe Thornber #include <linux/math64.h> 1866a63635SJoe Thornber 1966a63635SJoe Thornber #define DM_MSG_PREFIX "cache-policy-smq" 2066a63635SJoe Thornber 2166a63635SJoe Thornber /*----------------------------------------------------------------*/ 2266a63635SJoe Thornber 2366a63635SJoe Thornber /* 2466a63635SJoe Thornber * Safe division functions that return zero on divide by zero. 2566a63635SJoe Thornber */ 2666a63635SJoe Thornber static unsigned safe_div(unsigned n, unsigned d) 2766a63635SJoe Thornber { 2866a63635SJoe Thornber return d ? n / d : 0u; 2966a63635SJoe Thornber } 3066a63635SJoe Thornber 3166a63635SJoe Thornber static unsigned safe_mod(unsigned n, unsigned d) 3266a63635SJoe Thornber { 3366a63635SJoe Thornber return d ? n % d : 0u; 3466a63635SJoe Thornber } 3566a63635SJoe Thornber 3666a63635SJoe Thornber /*----------------------------------------------------------------*/ 3766a63635SJoe Thornber 3866a63635SJoe Thornber struct entry { 3966a63635SJoe Thornber unsigned hash_next:28; 4066a63635SJoe Thornber unsigned prev:28; 4166a63635SJoe Thornber unsigned next:28; 42b29d4986SJoe Thornber unsigned level:6; 4366a63635SJoe Thornber bool dirty:1; 4466a63635SJoe Thornber bool allocated:1; 4566a63635SJoe Thornber bool sentinel:1; 46b29d4986SJoe Thornber bool pending_work:1; 4766a63635SJoe Thornber 4866a63635SJoe Thornber dm_oblock_t oblock; 4966a63635SJoe Thornber }; 5066a63635SJoe Thornber 5166a63635SJoe Thornber /*----------------------------------------------------------------*/ 5266a63635SJoe Thornber 5366a63635SJoe Thornber #define INDEXER_NULL ((1u << 28u) - 1u) 5466a63635SJoe Thornber 5566a63635SJoe Thornber /* 5666a63635SJoe Thornber * An entry_space manages a set of entries that we use for the queues. 5766a63635SJoe Thornber * The clean and dirty queues share entries, so this object is separate 5866a63635SJoe Thornber * from the queue itself. 5966a63635SJoe Thornber */ 6066a63635SJoe Thornber struct entry_space { 6166a63635SJoe Thornber struct entry *begin; 6266a63635SJoe Thornber struct entry *end; 6366a63635SJoe Thornber }; 6466a63635SJoe Thornber 6566a63635SJoe Thornber static int space_init(struct entry_space *es, unsigned nr_entries) 6666a63635SJoe Thornber { 6766a63635SJoe Thornber if (!nr_entries) { 6866a63635SJoe Thornber es->begin = es->end = NULL; 6966a63635SJoe Thornber return 0; 7066a63635SJoe Thornber } 7166a63635SJoe Thornber 7266a63635SJoe Thornber es->begin = vzalloc(sizeof(struct entry) * nr_entries); 7366a63635SJoe Thornber if (!es->begin) 7466a63635SJoe Thornber return -ENOMEM; 7566a63635SJoe Thornber 7666a63635SJoe Thornber es->end = es->begin + nr_entries; 7766a63635SJoe Thornber return 0; 7866a63635SJoe Thornber } 7966a63635SJoe Thornber 8066a63635SJoe Thornber static void space_exit(struct entry_space *es) 8166a63635SJoe Thornber { 8266a63635SJoe Thornber vfree(es->begin); 8366a63635SJoe Thornber } 8466a63635SJoe Thornber 8566a63635SJoe Thornber static struct entry *__get_entry(struct entry_space *es, unsigned block) 8666a63635SJoe Thornber { 8766a63635SJoe Thornber struct entry *e; 8866a63635SJoe Thornber 8966a63635SJoe Thornber e = es->begin + block; 9066a63635SJoe Thornber BUG_ON(e >= es->end); 9166a63635SJoe Thornber 9266a63635SJoe Thornber return e; 9366a63635SJoe Thornber } 9466a63635SJoe Thornber 9566a63635SJoe Thornber static unsigned to_index(struct entry_space *es, struct entry *e) 9666a63635SJoe Thornber { 9766a63635SJoe Thornber BUG_ON(e < es->begin || e >= es->end); 9866a63635SJoe Thornber return e - es->begin; 9966a63635SJoe Thornber } 10066a63635SJoe Thornber 10166a63635SJoe Thornber static struct entry *to_entry(struct entry_space *es, unsigned block) 10266a63635SJoe Thornber { 10366a63635SJoe Thornber if (block == INDEXER_NULL) 10466a63635SJoe Thornber return NULL; 10566a63635SJoe Thornber 10666a63635SJoe Thornber return __get_entry(es, block); 10766a63635SJoe Thornber } 10866a63635SJoe Thornber 10966a63635SJoe Thornber /*----------------------------------------------------------------*/ 11066a63635SJoe Thornber 11166a63635SJoe Thornber struct ilist { 11266a63635SJoe Thornber unsigned nr_elts; /* excluding sentinel entries */ 11366a63635SJoe Thornber unsigned head, tail; 11466a63635SJoe Thornber }; 11566a63635SJoe Thornber 11666a63635SJoe Thornber static void l_init(struct ilist *l) 11766a63635SJoe Thornber { 11866a63635SJoe Thornber l->nr_elts = 0; 11966a63635SJoe Thornber l->head = l->tail = INDEXER_NULL; 12066a63635SJoe Thornber } 12166a63635SJoe Thornber 12266a63635SJoe Thornber static struct entry *l_head(struct entry_space *es, struct ilist *l) 12366a63635SJoe Thornber { 12466a63635SJoe Thornber return to_entry(es, l->head); 12566a63635SJoe Thornber } 12666a63635SJoe Thornber 12766a63635SJoe Thornber static struct entry *l_tail(struct entry_space *es, struct ilist *l) 12866a63635SJoe Thornber { 12966a63635SJoe Thornber return to_entry(es, l->tail); 13066a63635SJoe Thornber } 13166a63635SJoe Thornber 13266a63635SJoe Thornber static struct entry *l_next(struct entry_space *es, struct entry *e) 13366a63635SJoe Thornber { 13466a63635SJoe Thornber return to_entry(es, e->next); 13566a63635SJoe Thornber } 13666a63635SJoe Thornber 13766a63635SJoe Thornber static struct entry *l_prev(struct entry_space *es, struct entry *e) 13866a63635SJoe Thornber { 13966a63635SJoe Thornber return to_entry(es, e->prev); 14066a63635SJoe Thornber } 14166a63635SJoe Thornber 14266a63635SJoe Thornber static bool l_empty(struct ilist *l) 14366a63635SJoe Thornber { 14466a63635SJoe Thornber return l->head == INDEXER_NULL; 14566a63635SJoe Thornber } 14666a63635SJoe Thornber 14766a63635SJoe Thornber static void l_add_head(struct entry_space *es, struct ilist *l, struct entry *e) 14866a63635SJoe Thornber { 14966a63635SJoe Thornber struct entry *head = l_head(es, l); 15066a63635SJoe Thornber 15166a63635SJoe Thornber e->next = l->head; 15266a63635SJoe Thornber e->prev = INDEXER_NULL; 15366a63635SJoe Thornber 15466a63635SJoe Thornber if (head) 15566a63635SJoe Thornber head->prev = l->head = to_index(es, e); 15666a63635SJoe Thornber else 15766a63635SJoe Thornber l->head = l->tail = to_index(es, e); 15866a63635SJoe Thornber 15966a63635SJoe Thornber if (!e->sentinel) 16066a63635SJoe Thornber l->nr_elts++; 16166a63635SJoe Thornber } 16266a63635SJoe Thornber 16366a63635SJoe Thornber static void l_add_tail(struct entry_space *es, struct ilist *l, struct entry *e) 16466a63635SJoe Thornber { 16566a63635SJoe Thornber struct entry *tail = l_tail(es, l); 16666a63635SJoe Thornber 16766a63635SJoe Thornber e->next = INDEXER_NULL; 16866a63635SJoe Thornber e->prev = l->tail; 16966a63635SJoe Thornber 17066a63635SJoe Thornber if (tail) 17166a63635SJoe Thornber tail->next = l->tail = to_index(es, e); 17266a63635SJoe Thornber else 17366a63635SJoe Thornber l->head = l->tail = to_index(es, e); 17466a63635SJoe Thornber 17566a63635SJoe Thornber if (!e->sentinel) 17666a63635SJoe Thornber l->nr_elts++; 17766a63635SJoe Thornber } 17866a63635SJoe Thornber 17966a63635SJoe Thornber static void l_add_before(struct entry_space *es, struct ilist *l, 18066a63635SJoe Thornber struct entry *old, struct entry *e) 18166a63635SJoe Thornber { 18266a63635SJoe Thornber struct entry *prev = l_prev(es, old); 18366a63635SJoe Thornber 18466a63635SJoe Thornber if (!prev) 18566a63635SJoe Thornber l_add_head(es, l, e); 18666a63635SJoe Thornber 18766a63635SJoe Thornber else { 18866a63635SJoe Thornber e->prev = old->prev; 18966a63635SJoe Thornber e->next = to_index(es, old); 19066a63635SJoe Thornber prev->next = old->prev = to_index(es, e); 19166a63635SJoe Thornber 19266a63635SJoe Thornber if (!e->sentinel) 19366a63635SJoe Thornber l->nr_elts++; 19466a63635SJoe Thornber } 19566a63635SJoe Thornber } 19666a63635SJoe Thornber 19766a63635SJoe Thornber static void l_del(struct entry_space *es, struct ilist *l, struct entry *e) 19866a63635SJoe Thornber { 19966a63635SJoe Thornber struct entry *prev = l_prev(es, e); 20066a63635SJoe Thornber struct entry *next = l_next(es, e); 20166a63635SJoe Thornber 20266a63635SJoe Thornber if (prev) 20366a63635SJoe Thornber prev->next = e->next; 20466a63635SJoe Thornber else 20566a63635SJoe Thornber l->head = e->next; 20666a63635SJoe Thornber 20766a63635SJoe Thornber if (next) 20866a63635SJoe Thornber next->prev = e->prev; 20966a63635SJoe Thornber else 21066a63635SJoe Thornber l->tail = e->prev; 21166a63635SJoe Thornber 21266a63635SJoe Thornber if (!e->sentinel) 21366a63635SJoe Thornber l->nr_elts--; 21466a63635SJoe Thornber } 21566a63635SJoe Thornber 2169768a10dSJoe Thornber static struct entry *l_pop_head(struct entry_space *es, struct ilist *l) 2179768a10dSJoe Thornber { 2189768a10dSJoe Thornber struct entry *e; 2199768a10dSJoe Thornber 2209768a10dSJoe Thornber for (e = l_head(es, l); e; e = l_next(es, e)) 2219768a10dSJoe Thornber if (!e->sentinel) { 2229768a10dSJoe Thornber l_del(es, l, e); 2239768a10dSJoe Thornber return e; 2249768a10dSJoe Thornber } 2259768a10dSJoe Thornber 2269768a10dSJoe Thornber return NULL; 2279768a10dSJoe Thornber } 2289768a10dSJoe Thornber 22966a63635SJoe Thornber static struct entry *l_pop_tail(struct entry_space *es, struct ilist *l) 23066a63635SJoe Thornber { 23166a63635SJoe Thornber struct entry *e; 23266a63635SJoe Thornber 23366a63635SJoe Thornber for (e = l_tail(es, l); e; e = l_prev(es, e)) 23466a63635SJoe Thornber if (!e->sentinel) { 23566a63635SJoe Thornber l_del(es, l, e); 23666a63635SJoe Thornber return e; 23766a63635SJoe Thornber } 23866a63635SJoe Thornber 23966a63635SJoe Thornber return NULL; 24066a63635SJoe Thornber } 24166a63635SJoe Thornber 24266a63635SJoe Thornber /*----------------------------------------------------------------*/ 24366a63635SJoe Thornber 24466a63635SJoe Thornber /* 24566a63635SJoe Thornber * The stochastic-multi-queue is a set of lru lists stacked into levels. 24666a63635SJoe Thornber * Entries are moved up levels when they are used, which loosely orders the 24766a63635SJoe Thornber * most accessed entries in the top levels and least in the bottom. This 24866a63635SJoe Thornber * structure is *much* better than a single lru list. 24966a63635SJoe Thornber */ 25066a63635SJoe Thornber #define MAX_LEVELS 64u 25166a63635SJoe Thornber 25266a63635SJoe Thornber struct queue { 25366a63635SJoe Thornber struct entry_space *es; 25466a63635SJoe Thornber 25566a63635SJoe Thornber unsigned nr_elts; 25666a63635SJoe Thornber unsigned nr_levels; 25766a63635SJoe Thornber struct ilist qs[MAX_LEVELS]; 25866a63635SJoe Thornber 25966a63635SJoe Thornber /* 26066a63635SJoe Thornber * We maintain a count of the number of entries we would like in each 26166a63635SJoe Thornber * level. 26266a63635SJoe Thornber */ 26366a63635SJoe Thornber unsigned last_target_nr_elts; 26466a63635SJoe Thornber unsigned nr_top_levels; 26566a63635SJoe Thornber unsigned nr_in_top_levels; 26666a63635SJoe Thornber unsigned target_count[MAX_LEVELS]; 26766a63635SJoe Thornber }; 26866a63635SJoe Thornber 26966a63635SJoe Thornber static void q_init(struct queue *q, struct entry_space *es, unsigned nr_levels) 27066a63635SJoe Thornber { 27166a63635SJoe Thornber unsigned i; 27266a63635SJoe Thornber 27366a63635SJoe Thornber q->es = es; 27466a63635SJoe Thornber q->nr_elts = 0; 27566a63635SJoe Thornber q->nr_levels = nr_levels; 27666a63635SJoe Thornber 27766a63635SJoe Thornber for (i = 0; i < q->nr_levels; i++) { 27866a63635SJoe Thornber l_init(q->qs + i); 27966a63635SJoe Thornber q->target_count[i] = 0u; 28066a63635SJoe Thornber } 28166a63635SJoe Thornber 28266a63635SJoe Thornber q->last_target_nr_elts = 0u; 28366a63635SJoe Thornber q->nr_top_levels = 0u; 28466a63635SJoe Thornber q->nr_in_top_levels = 0u; 28566a63635SJoe Thornber } 28666a63635SJoe Thornber 28766a63635SJoe Thornber static unsigned q_size(struct queue *q) 28866a63635SJoe Thornber { 28966a63635SJoe Thornber return q->nr_elts; 29066a63635SJoe Thornber } 29166a63635SJoe Thornber 29266a63635SJoe Thornber /* 29366a63635SJoe Thornber * Insert an entry to the back of the given level. 29466a63635SJoe Thornber */ 29566a63635SJoe Thornber static void q_push(struct queue *q, struct entry *e) 29666a63635SJoe Thornber { 297b29d4986SJoe Thornber BUG_ON(e->pending_work); 298b29d4986SJoe Thornber 29966a63635SJoe Thornber if (!e->sentinel) 30066a63635SJoe Thornber q->nr_elts++; 30166a63635SJoe Thornber 30266a63635SJoe Thornber l_add_tail(q->es, q->qs + e->level, e); 30366a63635SJoe Thornber } 30466a63635SJoe Thornber 305b29d4986SJoe Thornber static void q_push_front(struct queue *q, struct entry *e) 306b29d4986SJoe Thornber { 307b29d4986SJoe Thornber BUG_ON(e->pending_work); 308b29d4986SJoe Thornber 309b29d4986SJoe Thornber if (!e->sentinel) 310b29d4986SJoe Thornber q->nr_elts++; 311b29d4986SJoe Thornber 312b29d4986SJoe Thornber l_add_head(q->es, q->qs + e->level, e); 313b29d4986SJoe Thornber } 314b29d4986SJoe Thornber 31566a63635SJoe Thornber static void q_push_before(struct queue *q, struct entry *old, struct entry *e) 31666a63635SJoe Thornber { 317b29d4986SJoe Thornber BUG_ON(e->pending_work); 318b29d4986SJoe Thornber 31966a63635SJoe Thornber if (!e->sentinel) 32066a63635SJoe Thornber q->nr_elts++; 32166a63635SJoe Thornber 32266a63635SJoe Thornber l_add_before(q->es, q->qs + e->level, old, e); 32366a63635SJoe Thornber } 32466a63635SJoe Thornber 32566a63635SJoe Thornber static void q_del(struct queue *q, struct entry *e) 32666a63635SJoe Thornber { 32766a63635SJoe Thornber l_del(q->es, q->qs + e->level, e); 32866a63635SJoe Thornber if (!e->sentinel) 32966a63635SJoe Thornber q->nr_elts--; 33066a63635SJoe Thornber } 33166a63635SJoe Thornber 33266a63635SJoe Thornber /* 33366a63635SJoe Thornber * Return the oldest entry of the lowest populated level. 33466a63635SJoe Thornber */ 33566a63635SJoe Thornber static struct entry *q_peek(struct queue *q, unsigned max_level, bool can_cross_sentinel) 33666a63635SJoe Thornber { 33766a63635SJoe Thornber unsigned level; 33866a63635SJoe Thornber struct entry *e; 33966a63635SJoe Thornber 34066a63635SJoe Thornber max_level = min(max_level, q->nr_levels); 34166a63635SJoe Thornber 34266a63635SJoe Thornber for (level = 0; level < max_level; level++) 34366a63635SJoe Thornber for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e)) { 34466a63635SJoe Thornber if (e->sentinel) { 34566a63635SJoe Thornber if (can_cross_sentinel) 34666a63635SJoe Thornber continue; 34766a63635SJoe Thornber else 34866a63635SJoe Thornber break; 34966a63635SJoe Thornber } 35066a63635SJoe Thornber 35166a63635SJoe Thornber return e; 35266a63635SJoe Thornber } 35366a63635SJoe Thornber 35466a63635SJoe Thornber return NULL; 35566a63635SJoe Thornber } 35666a63635SJoe Thornber 35766a63635SJoe Thornber static struct entry *q_pop(struct queue *q) 35866a63635SJoe Thornber { 35966a63635SJoe Thornber struct entry *e = q_peek(q, q->nr_levels, true); 36066a63635SJoe Thornber 36166a63635SJoe Thornber if (e) 36266a63635SJoe Thornber q_del(q, e); 36366a63635SJoe Thornber 36466a63635SJoe Thornber return e; 36566a63635SJoe Thornber } 36666a63635SJoe Thornber 36766a63635SJoe Thornber /* 36866a63635SJoe Thornber * This function assumes there is a non-sentinel entry to pop. It's only 36966a63635SJoe Thornber * used by redistribute, so we know this is true. It also doesn't adjust 37066a63635SJoe Thornber * the q->nr_elts count. 37166a63635SJoe Thornber */ 37266a63635SJoe Thornber static struct entry *__redist_pop_from(struct queue *q, unsigned level) 37366a63635SJoe Thornber { 37466a63635SJoe Thornber struct entry *e; 37566a63635SJoe Thornber 37666a63635SJoe Thornber for (; level < q->nr_levels; level++) 37766a63635SJoe Thornber for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e)) 37866a63635SJoe Thornber if (!e->sentinel) { 37966a63635SJoe Thornber l_del(q->es, q->qs + e->level, e); 38066a63635SJoe Thornber return e; 38166a63635SJoe Thornber } 38266a63635SJoe Thornber 38366a63635SJoe Thornber return NULL; 38466a63635SJoe Thornber } 38566a63635SJoe Thornber 38666a63635SJoe Thornber static void q_set_targets_subrange_(struct queue *q, unsigned nr_elts, unsigned lbegin, unsigned lend) 38766a63635SJoe Thornber { 38866a63635SJoe Thornber unsigned level, nr_levels, entries_per_level, remainder; 38966a63635SJoe Thornber 39066a63635SJoe Thornber BUG_ON(lbegin > lend); 39166a63635SJoe Thornber BUG_ON(lend > q->nr_levels); 39266a63635SJoe Thornber nr_levels = lend - lbegin; 39366a63635SJoe Thornber entries_per_level = safe_div(nr_elts, nr_levels); 39466a63635SJoe Thornber remainder = safe_mod(nr_elts, nr_levels); 39566a63635SJoe Thornber 39666a63635SJoe Thornber for (level = lbegin; level < lend; level++) 39766a63635SJoe Thornber q->target_count[level] = 39866a63635SJoe Thornber (level < (lbegin + remainder)) ? entries_per_level + 1u : entries_per_level; 39966a63635SJoe Thornber } 40066a63635SJoe Thornber 40166a63635SJoe Thornber /* 40266a63635SJoe Thornber * Typically we have fewer elements in the top few levels which allows us 40366a63635SJoe Thornber * to adjust the promote threshold nicely. 40466a63635SJoe Thornber */ 40566a63635SJoe Thornber static void q_set_targets(struct queue *q) 40666a63635SJoe Thornber { 40766a63635SJoe Thornber if (q->last_target_nr_elts == q->nr_elts) 40866a63635SJoe Thornber return; 40966a63635SJoe Thornber 41066a63635SJoe Thornber q->last_target_nr_elts = q->nr_elts; 41166a63635SJoe Thornber 41266a63635SJoe Thornber if (q->nr_top_levels > q->nr_levels) 41366a63635SJoe Thornber q_set_targets_subrange_(q, q->nr_elts, 0, q->nr_levels); 41466a63635SJoe Thornber 41566a63635SJoe Thornber else { 41666a63635SJoe Thornber q_set_targets_subrange_(q, q->nr_in_top_levels, 41766a63635SJoe Thornber q->nr_levels - q->nr_top_levels, q->nr_levels); 41866a63635SJoe Thornber 41966a63635SJoe Thornber if (q->nr_in_top_levels < q->nr_elts) 42066a63635SJoe Thornber q_set_targets_subrange_(q, q->nr_elts - q->nr_in_top_levels, 42166a63635SJoe Thornber 0, q->nr_levels - q->nr_top_levels); 42266a63635SJoe Thornber else 42366a63635SJoe Thornber q_set_targets_subrange_(q, 0, 0, q->nr_levels - q->nr_top_levels); 42466a63635SJoe Thornber } 42566a63635SJoe Thornber } 42666a63635SJoe Thornber 42766a63635SJoe Thornber static void q_redistribute(struct queue *q) 42866a63635SJoe Thornber { 42966a63635SJoe Thornber unsigned target, level; 43066a63635SJoe Thornber struct ilist *l, *l_above; 43166a63635SJoe Thornber struct entry *e; 43266a63635SJoe Thornber 43366a63635SJoe Thornber q_set_targets(q); 43466a63635SJoe Thornber 43566a63635SJoe Thornber for (level = 0u; level < q->nr_levels - 1u; level++) { 43666a63635SJoe Thornber l = q->qs + level; 43766a63635SJoe Thornber target = q->target_count[level]; 43866a63635SJoe Thornber 43966a63635SJoe Thornber /* 44066a63635SJoe Thornber * Pull down some entries from the level above. 44166a63635SJoe Thornber */ 44266a63635SJoe Thornber while (l->nr_elts < target) { 44366a63635SJoe Thornber e = __redist_pop_from(q, level + 1u); 44466a63635SJoe Thornber if (!e) { 44566a63635SJoe Thornber /* bug in nr_elts */ 44666a63635SJoe Thornber break; 44766a63635SJoe Thornber } 44866a63635SJoe Thornber 44966a63635SJoe Thornber e->level = level; 45066a63635SJoe Thornber l_add_tail(q->es, l, e); 45166a63635SJoe Thornber } 45266a63635SJoe Thornber 45366a63635SJoe Thornber /* 45466a63635SJoe Thornber * Push some entries up. 45566a63635SJoe Thornber */ 45666a63635SJoe Thornber l_above = q->qs + level + 1u; 45766a63635SJoe Thornber while (l->nr_elts > target) { 45866a63635SJoe Thornber e = l_pop_tail(q->es, l); 45966a63635SJoe Thornber 46066a63635SJoe Thornber if (!e) 46166a63635SJoe Thornber /* bug in nr_elts */ 46266a63635SJoe Thornber break; 46366a63635SJoe Thornber 46466a63635SJoe Thornber e->level = level + 1u; 465b29d4986SJoe Thornber l_add_tail(q->es, l_above, e); 46666a63635SJoe Thornber } 46766a63635SJoe Thornber } 46866a63635SJoe Thornber } 46966a63635SJoe Thornber 470b29d4986SJoe Thornber static void q_requeue(struct queue *q, struct entry *e, unsigned extra_levels, 471b29d4986SJoe Thornber struct entry *s1, struct entry *s2) 47266a63635SJoe Thornber { 47366a63635SJoe Thornber struct entry *de; 474b29d4986SJoe Thornber unsigned sentinels_passed = 0; 475b29d4986SJoe Thornber unsigned new_level = min(q->nr_levels - 1u, e->level + extra_levels); 47666a63635SJoe Thornber 477b29d4986SJoe Thornber /* try and find an entry to swap with */ 47866a63635SJoe Thornber if (extra_levels && (e->level < q->nr_levels - 1u)) { 479b29d4986SJoe Thornber for (de = l_head(q->es, q->qs + new_level); de && de->sentinel; de = l_next(q->es, de)) 480b29d4986SJoe Thornber sentinels_passed++; 48166a63635SJoe Thornber 482b29d4986SJoe Thornber if (de) { 48366a63635SJoe Thornber q_del(q, de); 48466a63635SJoe Thornber de->level = e->level; 485b29d4986SJoe Thornber if (s1) { 486b29d4986SJoe Thornber switch (sentinels_passed) { 487b29d4986SJoe Thornber case 0: 488b29d4986SJoe Thornber q_push_before(q, s1, de); 48966a63635SJoe Thornber break; 490b29d4986SJoe Thornber 491b29d4986SJoe Thornber case 1: 492b29d4986SJoe Thornber q_push_before(q, s2, de); 493b29d4986SJoe Thornber break; 494b29d4986SJoe Thornber 495b29d4986SJoe Thornber default: 496b29d4986SJoe Thornber q_push(q, de); 497b29d4986SJoe Thornber } 498b29d4986SJoe Thornber } else 499b29d4986SJoe Thornber q_push(q, de); 500b29d4986SJoe Thornber } 50166a63635SJoe Thornber } 50266a63635SJoe Thornber 503b29d4986SJoe Thornber q_del(q, e); 50466a63635SJoe Thornber e->level = new_level; 50566a63635SJoe Thornber q_push(q, e); 50666a63635SJoe Thornber } 50766a63635SJoe Thornber 50866a63635SJoe Thornber /*----------------------------------------------------------------*/ 50966a63635SJoe Thornber 51066a63635SJoe Thornber #define FP_SHIFT 8 51166a63635SJoe Thornber #define SIXTEENTH (1u << (FP_SHIFT - 4u)) 51266a63635SJoe Thornber #define EIGHTH (1u << (FP_SHIFT - 3u)) 51366a63635SJoe Thornber 51466a63635SJoe Thornber struct stats { 51566a63635SJoe Thornber unsigned hit_threshold; 51666a63635SJoe Thornber unsigned hits; 51766a63635SJoe Thornber unsigned misses; 51866a63635SJoe Thornber }; 51966a63635SJoe Thornber 52066a63635SJoe Thornber enum performance { 52166a63635SJoe Thornber Q_POOR, 52266a63635SJoe Thornber Q_FAIR, 52366a63635SJoe Thornber Q_WELL 52466a63635SJoe Thornber }; 52566a63635SJoe Thornber 52666a63635SJoe Thornber static void stats_init(struct stats *s, unsigned nr_levels) 52766a63635SJoe Thornber { 52866a63635SJoe Thornber s->hit_threshold = (nr_levels * 3u) / 4u; 52966a63635SJoe Thornber s->hits = 0u; 53066a63635SJoe Thornber s->misses = 0u; 53166a63635SJoe Thornber } 53266a63635SJoe Thornber 53366a63635SJoe Thornber static void stats_reset(struct stats *s) 53466a63635SJoe Thornber { 53566a63635SJoe Thornber s->hits = s->misses = 0u; 53666a63635SJoe Thornber } 53766a63635SJoe Thornber 53866a63635SJoe Thornber static void stats_level_accessed(struct stats *s, unsigned level) 53966a63635SJoe Thornber { 54066a63635SJoe Thornber if (level >= s->hit_threshold) 54166a63635SJoe Thornber s->hits++; 54266a63635SJoe Thornber else 54366a63635SJoe Thornber s->misses++; 54466a63635SJoe Thornber } 54566a63635SJoe Thornber 54666a63635SJoe Thornber static void stats_miss(struct stats *s) 54766a63635SJoe Thornber { 54866a63635SJoe Thornber s->misses++; 54966a63635SJoe Thornber } 55066a63635SJoe Thornber 55166a63635SJoe Thornber /* 55266a63635SJoe Thornber * There are times when we don't have any confidence in the hotspot queue. 55366a63635SJoe Thornber * Such as when a fresh cache is created and the blocks have been spread 55466a63635SJoe Thornber * out across the levels, or if an io load changes. We detect this by 55566a63635SJoe Thornber * seeing how often a lookup is in the top levels of the hotspot queue. 55666a63635SJoe Thornber */ 55766a63635SJoe Thornber static enum performance stats_assess(struct stats *s) 55866a63635SJoe Thornber { 55966a63635SJoe Thornber unsigned confidence = safe_div(s->hits << FP_SHIFT, s->hits + s->misses); 56066a63635SJoe Thornber 56166a63635SJoe Thornber if (confidence < SIXTEENTH) 56266a63635SJoe Thornber return Q_POOR; 56366a63635SJoe Thornber 56466a63635SJoe Thornber else if (confidence < EIGHTH) 56566a63635SJoe Thornber return Q_FAIR; 56666a63635SJoe Thornber 56766a63635SJoe Thornber else 56866a63635SJoe Thornber return Q_WELL; 56966a63635SJoe Thornber } 57066a63635SJoe Thornber 57166a63635SJoe Thornber /*----------------------------------------------------------------*/ 57266a63635SJoe Thornber 573b29d4986SJoe Thornber struct smq_hash_table { 57466a63635SJoe Thornber struct entry_space *es; 57566a63635SJoe Thornber unsigned long long hash_bits; 57666a63635SJoe Thornber unsigned *buckets; 57766a63635SJoe Thornber }; 57866a63635SJoe Thornber 57966a63635SJoe Thornber /* 58066a63635SJoe Thornber * All cache entries are stored in a chained hash table. To save space we 58166a63635SJoe Thornber * use indexing again, and only store indexes to the next entry. 58266a63635SJoe Thornber */ 583b29d4986SJoe Thornber static int h_init(struct smq_hash_table *ht, struct entry_space *es, unsigned nr_entries) 58466a63635SJoe Thornber { 58566a63635SJoe Thornber unsigned i, nr_buckets; 58666a63635SJoe Thornber 58766a63635SJoe Thornber ht->es = es; 58866a63635SJoe Thornber nr_buckets = roundup_pow_of_two(max(nr_entries / 4u, 16u)); 589a3d939aeSMikulas Patocka ht->hash_bits = __ffs(nr_buckets); 59066a63635SJoe Thornber 591*42bc47b3SKees Cook ht->buckets = vmalloc(array_size(nr_buckets, sizeof(*ht->buckets))); 59266a63635SJoe Thornber if (!ht->buckets) 59366a63635SJoe Thornber return -ENOMEM; 59466a63635SJoe Thornber 59566a63635SJoe Thornber for (i = 0; i < nr_buckets; i++) 59666a63635SJoe Thornber ht->buckets[i] = INDEXER_NULL; 59766a63635SJoe Thornber 59866a63635SJoe Thornber return 0; 59966a63635SJoe Thornber } 60066a63635SJoe Thornber 601b29d4986SJoe Thornber static void h_exit(struct smq_hash_table *ht) 60266a63635SJoe Thornber { 60366a63635SJoe Thornber vfree(ht->buckets); 60466a63635SJoe Thornber } 60566a63635SJoe Thornber 606b29d4986SJoe Thornber static struct entry *h_head(struct smq_hash_table *ht, unsigned bucket) 60766a63635SJoe Thornber { 60866a63635SJoe Thornber return to_entry(ht->es, ht->buckets[bucket]); 60966a63635SJoe Thornber } 61066a63635SJoe Thornber 611b29d4986SJoe Thornber static struct entry *h_next(struct smq_hash_table *ht, struct entry *e) 61266a63635SJoe Thornber { 61366a63635SJoe Thornber return to_entry(ht->es, e->hash_next); 61466a63635SJoe Thornber } 61566a63635SJoe Thornber 616b29d4986SJoe Thornber static void __h_insert(struct smq_hash_table *ht, unsigned bucket, struct entry *e) 61766a63635SJoe Thornber { 61866a63635SJoe Thornber e->hash_next = ht->buckets[bucket]; 61966a63635SJoe Thornber ht->buckets[bucket] = to_index(ht->es, e); 62066a63635SJoe Thornber } 62166a63635SJoe Thornber 622b29d4986SJoe Thornber static void h_insert(struct smq_hash_table *ht, struct entry *e) 62366a63635SJoe Thornber { 62466a63635SJoe Thornber unsigned h = hash_64(from_oblock(e->oblock), ht->hash_bits); 62566a63635SJoe Thornber __h_insert(ht, h, e); 62666a63635SJoe Thornber } 62766a63635SJoe Thornber 628b29d4986SJoe Thornber static struct entry *__h_lookup(struct smq_hash_table *ht, unsigned h, dm_oblock_t oblock, 62966a63635SJoe Thornber struct entry **prev) 63066a63635SJoe Thornber { 63166a63635SJoe Thornber struct entry *e; 63266a63635SJoe Thornber 63366a63635SJoe Thornber *prev = NULL; 63466a63635SJoe Thornber for (e = h_head(ht, h); e; e = h_next(ht, e)) { 63566a63635SJoe Thornber if (e->oblock == oblock) 63666a63635SJoe Thornber return e; 63766a63635SJoe Thornber 63866a63635SJoe Thornber *prev = e; 63966a63635SJoe Thornber } 64066a63635SJoe Thornber 64166a63635SJoe Thornber return NULL; 64266a63635SJoe Thornber } 64366a63635SJoe Thornber 644b29d4986SJoe Thornber static void __h_unlink(struct smq_hash_table *ht, unsigned h, 64566a63635SJoe Thornber struct entry *e, struct entry *prev) 64666a63635SJoe Thornber { 64766a63635SJoe Thornber if (prev) 64866a63635SJoe Thornber prev->hash_next = e->hash_next; 64966a63635SJoe Thornber else 65066a63635SJoe Thornber ht->buckets[h] = e->hash_next; 65166a63635SJoe Thornber } 65266a63635SJoe Thornber 65366a63635SJoe Thornber /* 65466a63635SJoe Thornber * Also moves each entry to the front of the bucket. 65566a63635SJoe Thornber */ 656b29d4986SJoe Thornber static struct entry *h_lookup(struct smq_hash_table *ht, dm_oblock_t oblock) 65766a63635SJoe Thornber { 65866a63635SJoe Thornber struct entry *e, *prev; 65966a63635SJoe Thornber unsigned h = hash_64(from_oblock(oblock), ht->hash_bits); 66066a63635SJoe Thornber 66166a63635SJoe Thornber e = __h_lookup(ht, h, oblock, &prev); 66266a63635SJoe Thornber if (e && prev) { 66366a63635SJoe Thornber /* 66466a63635SJoe Thornber * Move to the front because this entry is likely 66566a63635SJoe Thornber * to be hit again. 66666a63635SJoe Thornber */ 66766a63635SJoe Thornber __h_unlink(ht, h, e, prev); 66866a63635SJoe Thornber __h_insert(ht, h, e); 66966a63635SJoe Thornber } 67066a63635SJoe Thornber 67166a63635SJoe Thornber return e; 67266a63635SJoe Thornber } 67366a63635SJoe Thornber 674b29d4986SJoe Thornber static void h_remove(struct smq_hash_table *ht, struct entry *e) 67566a63635SJoe Thornber { 67666a63635SJoe Thornber unsigned h = hash_64(from_oblock(e->oblock), ht->hash_bits); 67766a63635SJoe Thornber struct entry *prev; 67866a63635SJoe Thornber 67966a63635SJoe Thornber /* 68066a63635SJoe Thornber * The down side of using a singly linked list is we have to 68166a63635SJoe Thornber * iterate the bucket to remove an item. 68266a63635SJoe Thornber */ 68366a63635SJoe Thornber e = __h_lookup(ht, h, e->oblock, &prev); 68466a63635SJoe Thornber if (e) 68566a63635SJoe Thornber __h_unlink(ht, h, e, prev); 68666a63635SJoe Thornber } 68766a63635SJoe Thornber 68866a63635SJoe Thornber /*----------------------------------------------------------------*/ 68966a63635SJoe Thornber 69066a63635SJoe Thornber struct entry_alloc { 69166a63635SJoe Thornber struct entry_space *es; 69266a63635SJoe Thornber unsigned begin; 69366a63635SJoe Thornber 69466a63635SJoe Thornber unsigned nr_allocated; 69566a63635SJoe Thornber struct ilist free; 69666a63635SJoe Thornber }; 69766a63635SJoe Thornber 69866a63635SJoe Thornber static void init_allocator(struct entry_alloc *ea, struct entry_space *es, 69966a63635SJoe Thornber unsigned begin, unsigned end) 70066a63635SJoe Thornber { 70166a63635SJoe Thornber unsigned i; 70266a63635SJoe Thornber 70366a63635SJoe Thornber ea->es = es; 70466a63635SJoe Thornber ea->nr_allocated = 0u; 70566a63635SJoe Thornber ea->begin = begin; 70666a63635SJoe Thornber 70766a63635SJoe Thornber l_init(&ea->free); 70866a63635SJoe Thornber for (i = begin; i != end; i++) 70966a63635SJoe Thornber l_add_tail(ea->es, &ea->free, __get_entry(ea->es, i)); 71066a63635SJoe Thornber } 71166a63635SJoe Thornber 71266a63635SJoe Thornber static void init_entry(struct entry *e) 71366a63635SJoe Thornber { 71466a63635SJoe Thornber /* 71566a63635SJoe Thornber * We can't memset because that would clear the hotspot and 71666a63635SJoe Thornber * sentinel bits which remain constant. 71766a63635SJoe Thornber */ 71866a63635SJoe Thornber e->hash_next = INDEXER_NULL; 71966a63635SJoe Thornber e->next = INDEXER_NULL; 72066a63635SJoe Thornber e->prev = INDEXER_NULL; 72166a63635SJoe Thornber e->level = 0u; 722b29d4986SJoe Thornber e->dirty = true; /* FIXME: audit */ 72366a63635SJoe Thornber e->allocated = true; 724b29d4986SJoe Thornber e->sentinel = false; 725b29d4986SJoe Thornber e->pending_work = false; 72666a63635SJoe Thornber } 72766a63635SJoe Thornber 72866a63635SJoe Thornber static struct entry *alloc_entry(struct entry_alloc *ea) 72966a63635SJoe Thornber { 73066a63635SJoe Thornber struct entry *e; 73166a63635SJoe Thornber 73266a63635SJoe Thornber if (l_empty(&ea->free)) 73366a63635SJoe Thornber return NULL; 73466a63635SJoe Thornber 7359768a10dSJoe Thornber e = l_pop_head(ea->es, &ea->free); 73666a63635SJoe Thornber init_entry(e); 73766a63635SJoe Thornber ea->nr_allocated++; 73866a63635SJoe Thornber 73966a63635SJoe Thornber return e; 74066a63635SJoe Thornber } 74166a63635SJoe Thornber 74266a63635SJoe Thornber /* 74366a63635SJoe Thornber * This assumes the cblock hasn't already been allocated. 74466a63635SJoe Thornber */ 74566a63635SJoe Thornber static struct entry *alloc_particular_entry(struct entry_alloc *ea, unsigned i) 74666a63635SJoe Thornber { 74766a63635SJoe Thornber struct entry *e = __get_entry(ea->es, ea->begin + i); 74866a63635SJoe Thornber 74966a63635SJoe Thornber BUG_ON(e->allocated); 75066a63635SJoe Thornber 75166a63635SJoe Thornber l_del(ea->es, &ea->free, e); 75266a63635SJoe Thornber init_entry(e); 75366a63635SJoe Thornber ea->nr_allocated++; 75466a63635SJoe Thornber 75566a63635SJoe Thornber return e; 75666a63635SJoe Thornber } 75766a63635SJoe Thornber 75866a63635SJoe Thornber static void free_entry(struct entry_alloc *ea, struct entry *e) 75966a63635SJoe Thornber { 76066a63635SJoe Thornber BUG_ON(!ea->nr_allocated); 76166a63635SJoe Thornber BUG_ON(!e->allocated); 76266a63635SJoe Thornber 76366a63635SJoe Thornber ea->nr_allocated--; 76466a63635SJoe Thornber e->allocated = false; 76566a63635SJoe Thornber l_add_tail(ea->es, &ea->free, e); 76666a63635SJoe Thornber } 76766a63635SJoe Thornber 76866a63635SJoe Thornber static bool allocator_empty(struct entry_alloc *ea) 76966a63635SJoe Thornber { 77066a63635SJoe Thornber return l_empty(&ea->free); 77166a63635SJoe Thornber } 77266a63635SJoe Thornber 77366a63635SJoe Thornber static unsigned get_index(struct entry_alloc *ea, struct entry *e) 77466a63635SJoe Thornber { 77566a63635SJoe Thornber return to_index(ea->es, e) - ea->begin; 77666a63635SJoe Thornber } 77766a63635SJoe Thornber 77866a63635SJoe Thornber static struct entry *get_entry(struct entry_alloc *ea, unsigned index) 77966a63635SJoe Thornber { 78066a63635SJoe Thornber return __get_entry(ea->es, ea->begin + index); 78166a63635SJoe Thornber } 78266a63635SJoe Thornber 78366a63635SJoe Thornber /*----------------------------------------------------------------*/ 78466a63635SJoe Thornber 78566a63635SJoe Thornber #define NR_HOTSPOT_LEVELS 64u 78666a63635SJoe Thornber #define NR_CACHE_LEVELS 64u 78766a63635SJoe Thornber 788b29d4986SJoe Thornber #define WRITEBACK_PERIOD (10ul * HZ) 789b29d4986SJoe Thornber #define DEMOTE_PERIOD (60ul * HZ) 79066a63635SJoe Thornber 79166a63635SJoe Thornber #define HOTSPOT_UPDATE_PERIOD (HZ) 792b29d4986SJoe Thornber #define CACHE_UPDATE_PERIOD (60ul * HZ) 79366a63635SJoe Thornber 79466a63635SJoe Thornber struct smq_policy { 79566a63635SJoe Thornber struct dm_cache_policy policy; 79666a63635SJoe Thornber 79766a63635SJoe Thornber /* protects everything */ 7984051aab7SJoe Thornber spinlock_t lock; 79966a63635SJoe Thornber dm_cblock_t cache_size; 80066a63635SJoe Thornber sector_t cache_block_size; 80166a63635SJoe Thornber 80266a63635SJoe Thornber sector_t hotspot_block_size; 80366a63635SJoe Thornber unsigned nr_hotspot_blocks; 80466a63635SJoe Thornber unsigned cache_blocks_per_hotspot_block; 80566a63635SJoe Thornber unsigned hotspot_level_jump; 80666a63635SJoe Thornber 80766a63635SJoe Thornber struct entry_space es; 80866a63635SJoe Thornber struct entry_alloc writeback_sentinel_alloc; 80966a63635SJoe Thornber struct entry_alloc demote_sentinel_alloc; 81066a63635SJoe Thornber struct entry_alloc hotspot_alloc; 81166a63635SJoe Thornber struct entry_alloc cache_alloc; 81266a63635SJoe Thornber 81366a63635SJoe Thornber unsigned long *hotspot_hit_bits; 81466a63635SJoe Thornber unsigned long *cache_hit_bits; 81566a63635SJoe Thornber 81666a63635SJoe Thornber /* 81766a63635SJoe Thornber * We maintain three queues of entries. The cache proper, 81866a63635SJoe Thornber * consisting of a clean and dirty queue, containing the currently 81966a63635SJoe Thornber * active mappings. The hotspot queue uses a larger block size to 82066a63635SJoe Thornber * track blocks that are being hit frequently and potential 82166a63635SJoe Thornber * candidates for promotion to the cache. 82266a63635SJoe Thornber */ 82366a63635SJoe Thornber struct queue hotspot; 82466a63635SJoe Thornber struct queue clean; 82566a63635SJoe Thornber struct queue dirty; 82666a63635SJoe Thornber 82766a63635SJoe Thornber struct stats hotspot_stats; 82866a63635SJoe Thornber struct stats cache_stats; 82966a63635SJoe Thornber 83066a63635SJoe Thornber /* 83166a63635SJoe Thornber * Keeps track of time, incremented by the core. We use this to 83266a63635SJoe Thornber * avoid attributing multiple hits within the same tick. 83366a63635SJoe Thornber */ 83466a63635SJoe Thornber unsigned tick; 83566a63635SJoe Thornber 83666a63635SJoe Thornber /* 83766a63635SJoe Thornber * The hash tables allows us to quickly find an entry by origin 83866a63635SJoe Thornber * block. 83966a63635SJoe Thornber */ 840b29d4986SJoe Thornber struct smq_hash_table table; 841b29d4986SJoe Thornber struct smq_hash_table hotspot_table; 84266a63635SJoe Thornber 84366a63635SJoe Thornber bool current_writeback_sentinels; 84466a63635SJoe Thornber unsigned long next_writeback_period; 84566a63635SJoe Thornber 84666a63635SJoe Thornber bool current_demote_sentinels; 84766a63635SJoe Thornber unsigned long next_demote_period; 84866a63635SJoe Thornber 84966a63635SJoe Thornber unsigned write_promote_level; 85066a63635SJoe Thornber unsigned read_promote_level; 85166a63635SJoe Thornber 85266a63635SJoe Thornber unsigned long next_hotspot_period; 85366a63635SJoe Thornber unsigned long next_cache_period; 854b29d4986SJoe Thornber 855b29d4986SJoe Thornber struct background_tracker *bg_work; 856b29d4986SJoe Thornber 857b29d4986SJoe Thornber bool migrations_allowed; 85866a63635SJoe Thornber }; 85966a63635SJoe Thornber 86066a63635SJoe Thornber /*----------------------------------------------------------------*/ 86166a63635SJoe Thornber 86266a63635SJoe Thornber static struct entry *get_sentinel(struct entry_alloc *ea, unsigned level, bool which) 86366a63635SJoe Thornber { 86466a63635SJoe Thornber return get_entry(ea, which ? level : NR_CACHE_LEVELS + level); 86566a63635SJoe Thornber } 86666a63635SJoe Thornber 86766a63635SJoe Thornber static struct entry *writeback_sentinel(struct smq_policy *mq, unsigned level) 86866a63635SJoe Thornber { 86966a63635SJoe Thornber return get_sentinel(&mq->writeback_sentinel_alloc, level, mq->current_writeback_sentinels); 87066a63635SJoe Thornber } 87166a63635SJoe Thornber 87266a63635SJoe Thornber static struct entry *demote_sentinel(struct smq_policy *mq, unsigned level) 87366a63635SJoe Thornber { 87466a63635SJoe Thornber return get_sentinel(&mq->demote_sentinel_alloc, level, mq->current_demote_sentinels); 87566a63635SJoe Thornber } 87666a63635SJoe Thornber 87766a63635SJoe Thornber static void __update_writeback_sentinels(struct smq_policy *mq) 87866a63635SJoe Thornber { 87966a63635SJoe Thornber unsigned level; 88066a63635SJoe Thornber struct queue *q = &mq->dirty; 88166a63635SJoe Thornber struct entry *sentinel; 88266a63635SJoe Thornber 88366a63635SJoe Thornber for (level = 0; level < q->nr_levels; level++) { 88466a63635SJoe Thornber sentinel = writeback_sentinel(mq, level); 88566a63635SJoe Thornber q_del(q, sentinel); 88666a63635SJoe Thornber q_push(q, sentinel); 88766a63635SJoe Thornber } 88866a63635SJoe Thornber } 88966a63635SJoe Thornber 89066a63635SJoe Thornber static void __update_demote_sentinels(struct smq_policy *mq) 89166a63635SJoe Thornber { 89266a63635SJoe Thornber unsigned level; 89366a63635SJoe Thornber struct queue *q = &mq->clean; 89466a63635SJoe Thornber struct entry *sentinel; 89566a63635SJoe Thornber 89666a63635SJoe Thornber for (level = 0; level < q->nr_levels; level++) { 89766a63635SJoe Thornber sentinel = demote_sentinel(mq, level); 89866a63635SJoe Thornber q_del(q, sentinel); 89966a63635SJoe Thornber q_push(q, sentinel); 90066a63635SJoe Thornber } 90166a63635SJoe Thornber } 90266a63635SJoe Thornber 90366a63635SJoe Thornber static void update_sentinels(struct smq_policy *mq) 90466a63635SJoe Thornber { 90566a63635SJoe Thornber if (time_after(jiffies, mq->next_writeback_period)) { 90666a63635SJoe Thornber mq->next_writeback_period = jiffies + WRITEBACK_PERIOD; 90766a63635SJoe Thornber mq->current_writeback_sentinels = !mq->current_writeback_sentinels; 908b29d4986SJoe Thornber __update_writeback_sentinels(mq); 90966a63635SJoe Thornber } 91066a63635SJoe Thornber 91166a63635SJoe Thornber if (time_after(jiffies, mq->next_demote_period)) { 91266a63635SJoe Thornber mq->next_demote_period = jiffies + DEMOTE_PERIOD; 91366a63635SJoe Thornber mq->current_demote_sentinels = !mq->current_demote_sentinels; 914b29d4986SJoe Thornber __update_demote_sentinels(mq); 91566a63635SJoe Thornber } 91666a63635SJoe Thornber } 91766a63635SJoe Thornber 91866a63635SJoe Thornber static void __sentinels_init(struct smq_policy *mq) 91966a63635SJoe Thornber { 92066a63635SJoe Thornber unsigned level; 92166a63635SJoe Thornber struct entry *sentinel; 92266a63635SJoe Thornber 92366a63635SJoe Thornber for (level = 0; level < NR_CACHE_LEVELS; level++) { 92466a63635SJoe Thornber sentinel = writeback_sentinel(mq, level); 92566a63635SJoe Thornber sentinel->level = level; 92666a63635SJoe Thornber q_push(&mq->dirty, sentinel); 92766a63635SJoe Thornber 92866a63635SJoe Thornber sentinel = demote_sentinel(mq, level); 92966a63635SJoe Thornber sentinel->level = level; 93066a63635SJoe Thornber q_push(&mq->clean, sentinel); 93166a63635SJoe Thornber } 93266a63635SJoe Thornber } 93366a63635SJoe Thornber 93466a63635SJoe Thornber static void sentinels_init(struct smq_policy *mq) 93566a63635SJoe Thornber { 93666a63635SJoe Thornber mq->next_writeback_period = jiffies + WRITEBACK_PERIOD; 93766a63635SJoe Thornber mq->next_demote_period = jiffies + DEMOTE_PERIOD; 93866a63635SJoe Thornber 93966a63635SJoe Thornber mq->current_writeback_sentinels = false; 94066a63635SJoe Thornber mq->current_demote_sentinels = false; 94166a63635SJoe Thornber __sentinels_init(mq); 94266a63635SJoe Thornber 94366a63635SJoe Thornber mq->current_writeback_sentinels = !mq->current_writeback_sentinels; 94466a63635SJoe Thornber mq->current_demote_sentinels = !mq->current_demote_sentinels; 94566a63635SJoe Thornber __sentinels_init(mq); 94666a63635SJoe Thornber } 94766a63635SJoe Thornber 94866a63635SJoe Thornber /*----------------------------------------------------------------*/ 94966a63635SJoe Thornber 950b29d4986SJoe Thornber static void del_queue(struct smq_policy *mq, struct entry *e) 95166a63635SJoe Thornber { 952b29d4986SJoe Thornber q_del(e->dirty ? &mq->dirty : &mq->clean, e); 95366a63635SJoe Thornber } 95466a63635SJoe Thornber 955b29d4986SJoe Thornber static void push_queue(struct smq_policy *mq, struct entry *e) 956b29d4986SJoe Thornber { 957b29d4986SJoe Thornber if (e->dirty) 958b29d4986SJoe Thornber q_push(&mq->dirty, e); 959b29d4986SJoe Thornber else 960b29d4986SJoe Thornber q_push(&mq->clean, e); 961b29d4986SJoe Thornber } 962b29d4986SJoe Thornber 963b29d4986SJoe Thornber // !h, !q, a -> h, q, a 96466a63635SJoe Thornber static void push(struct smq_policy *mq, struct entry *e) 96566a63635SJoe Thornber { 96666a63635SJoe Thornber h_insert(&mq->table, e); 967b29d4986SJoe Thornber if (!e->pending_work) 968b29d4986SJoe Thornber push_queue(mq, e); 96966a63635SJoe Thornber } 97066a63635SJoe Thornber 971b29d4986SJoe Thornber static void push_queue_front(struct smq_policy *mq, struct entry *e) 97266a63635SJoe Thornber { 973b29d4986SJoe Thornber if (e->dirty) 974b29d4986SJoe Thornber q_push_front(&mq->dirty, e); 975b29d4986SJoe Thornber else 976b29d4986SJoe Thornber q_push_front(&mq->clean, e); 97766a63635SJoe Thornber } 97866a63635SJoe Thornber 979b29d4986SJoe Thornber static void push_front(struct smq_policy *mq, struct entry *e) 98066a63635SJoe Thornber { 981b29d4986SJoe Thornber h_insert(&mq->table, e); 982b29d4986SJoe Thornber if (!e->pending_work) 983b29d4986SJoe Thornber push_queue_front(mq, e); 98466a63635SJoe Thornber } 98566a63635SJoe Thornber 98666a63635SJoe Thornber static dm_cblock_t infer_cblock(struct smq_policy *mq, struct entry *e) 98766a63635SJoe Thornber { 98866a63635SJoe Thornber return to_cblock(get_index(&mq->cache_alloc, e)); 98966a63635SJoe Thornber } 99066a63635SJoe Thornber 99166a63635SJoe Thornber static void requeue(struct smq_policy *mq, struct entry *e) 99266a63635SJoe Thornber { 993b29d4986SJoe Thornber /* 994b29d4986SJoe Thornber * Pending work has temporarily been taken out of the queues. 995b29d4986SJoe Thornber */ 996b29d4986SJoe Thornber if (e->pending_work) 997b29d4986SJoe Thornber return; 99866a63635SJoe Thornber 99966a63635SJoe Thornber if (!test_and_set_bit(from_cblock(infer_cblock(mq, e)), mq->cache_hit_bits)) { 1000b29d4986SJoe Thornber if (!e->dirty) { 1001b29d4986SJoe Thornber q_requeue(&mq->clean, e, 1u, NULL, NULL); 1002b29d4986SJoe Thornber return; 100366a63635SJoe Thornber } 1004b29d4986SJoe Thornber 1005b29d4986SJoe Thornber q_requeue(&mq->dirty, e, 1u, 1006b29d4986SJoe Thornber get_sentinel(&mq->writeback_sentinel_alloc, e->level, !mq->current_writeback_sentinels), 1007b29d4986SJoe Thornber get_sentinel(&mq->writeback_sentinel_alloc, e->level, mq->current_writeback_sentinels)); 100866a63635SJoe Thornber } 100966a63635SJoe Thornber } 101066a63635SJoe Thornber 101166a63635SJoe Thornber static unsigned default_promote_level(struct smq_policy *mq) 101266a63635SJoe Thornber { 101366a63635SJoe Thornber /* 101466a63635SJoe Thornber * The promote level depends on the current performance of the 101566a63635SJoe Thornber * cache. 101666a63635SJoe Thornber * 101766a63635SJoe Thornber * If the cache is performing badly, then we can't afford 101866a63635SJoe Thornber * to promote much without causing performance to drop below that 101966a63635SJoe Thornber * of the origin device. 102066a63635SJoe Thornber * 102166a63635SJoe Thornber * If the cache is performing well, then we don't need to promote 102266a63635SJoe Thornber * much. If it isn't broken, don't fix it. 102366a63635SJoe Thornber * 102466a63635SJoe Thornber * If the cache is middling then we promote more. 102566a63635SJoe Thornber * 102666a63635SJoe Thornber * This scheme reminds me of a graph of entropy vs probability of a 102766a63635SJoe Thornber * binary variable. 102866a63635SJoe Thornber */ 102966a63635SJoe Thornber static unsigned table[] = {1, 1, 1, 2, 4, 6, 7, 8, 7, 6, 4, 4, 3, 3, 2, 2, 1}; 103066a63635SJoe Thornber 103166a63635SJoe Thornber unsigned hits = mq->cache_stats.hits; 103266a63635SJoe Thornber unsigned misses = mq->cache_stats.misses; 103366a63635SJoe Thornber unsigned index = safe_div(hits << 4u, hits + misses); 103466a63635SJoe Thornber return table[index]; 103566a63635SJoe Thornber } 103666a63635SJoe Thornber 103766a63635SJoe Thornber static void update_promote_levels(struct smq_policy *mq) 103866a63635SJoe Thornber { 103966a63635SJoe Thornber /* 104066a63635SJoe Thornber * If there are unused cache entries then we want to be really 104166a63635SJoe Thornber * eager to promote. 104266a63635SJoe Thornber */ 104366a63635SJoe Thornber unsigned threshold_level = allocator_empty(&mq->cache_alloc) ? 104466a63635SJoe Thornber default_promote_level(mq) : (NR_HOTSPOT_LEVELS / 2u); 104566a63635SJoe Thornber 1046b29d4986SJoe Thornber threshold_level = max(threshold_level, NR_HOTSPOT_LEVELS); 1047b29d4986SJoe Thornber 104866a63635SJoe Thornber /* 104966a63635SJoe Thornber * If the hotspot queue is performing badly then we have little 105066a63635SJoe Thornber * confidence that we know which blocks to promote. So we cut down 105166a63635SJoe Thornber * the amount of promotions. 105266a63635SJoe Thornber */ 105366a63635SJoe Thornber switch (stats_assess(&mq->hotspot_stats)) { 105466a63635SJoe Thornber case Q_POOR: 105566a63635SJoe Thornber threshold_level /= 4u; 105666a63635SJoe Thornber break; 105766a63635SJoe Thornber 105866a63635SJoe Thornber case Q_FAIR: 105966a63635SJoe Thornber threshold_level /= 2u; 106066a63635SJoe Thornber break; 106166a63635SJoe Thornber 106266a63635SJoe Thornber case Q_WELL: 106366a63635SJoe Thornber break; 106466a63635SJoe Thornber } 106566a63635SJoe Thornber 106666a63635SJoe Thornber mq->read_promote_level = NR_HOTSPOT_LEVELS - threshold_level; 1067b29d4986SJoe Thornber mq->write_promote_level = (NR_HOTSPOT_LEVELS - threshold_level); 106866a63635SJoe Thornber } 106966a63635SJoe Thornber 107066a63635SJoe Thornber /* 107166a63635SJoe Thornber * If the hotspot queue is performing badly, then we try and move entries 107266a63635SJoe Thornber * around more quickly. 107366a63635SJoe Thornber */ 107466a63635SJoe Thornber static void update_level_jump(struct smq_policy *mq) 107566a63635SJoe Thornber { 107666a63635SJoe Thornber switch (stats_assess(&mq->hotspot_stats)) { 107766a63635SJoe Thornber case Q_POOR: 107866a63635SJoe Thornber mq->hotspot_level_jump = 4u; 107966a63635SJoe Thornber break; 108066a63635SJoe Thornber 108166a63635SJoe Thornber case Q_FAIR: 108266a63635SJoe Thornber mq->hotspot_level_jump = 2u; 108366a63635SJoe Thornber break; 108466a63635SJoe Thornber 108566a63635SJoe Thornber case Q_WELL: 108666a63635SJoe Thornber mq->hotspot_level_jump = 1u; 108766a63635SJoe Thornber break; 108866a63635SJoe Thornber } 108966a63635SJoe Thornber } 109066a63635SJoe Thornber 109166a63635SJoe Thornber static void end_hotspot_period(struct smq_policy *mq) 109266a63635SJoe Thornber { 109366a63635SJoe Thornber clear_bitset(mq->hotspot_hit_bits, mq->nr_hotspot_blocks); 109466a63635SJoe Thornber update_promote_levels(mq); 109566a63635SJoe Thornber 109666a63635SJoe Thornber if (time_after(jiffies, mq->next_hotspot_period)) { 109766a63635SJoe Thornber update_level_jump(mq); 109866a63635SJoe Thornber q_redistribute(&mq->hotspot); 109966a63635SJoe Thornber stats_reset(&mq->hotspot_stats); 110066a63635SJoe Thornber mq->next_hotspot_period = jiffies + HOTSPOT_UPDATE_PERIOD; 110166a63635SJoe Thornber } 110266a63635SJoe Thornber } 110366a63635SJoe Thornber 110466a63635SJoe Thornber static void end_cache_period(struct smq_policy *mq) 110566a63635SJoe Thornber { 110666a63635SJoe Thornber if (time_after(jiffies, mq->next_cache_period)) { 110766a63635SJoe Thornber clear_bitset(mq->cache_hit_bits, from_cblock(mq->cache_size)); 110866a63635SJoe Thornber 110966a63635SJoe Thornber q_redistribute(&mq->dirty); 111066a63635SJoe Thornber q_redistribute(&mq->clean); 111166a63635SJoe Thornber stats_reset(&mq->cache_stats); 111266a63635SJoe Thornber 111366a63635SJoe Thornber mq->next_cache_period = jiffies + CACHE_UPDATE_PERIOD; 111466a63635SJoe Thornber } 111566a63635SJoe Thornber } 111666a63635SJoe Thornber 1117b29d4986SJoe Thornber /*----------------------------------------------------------------*/ 1118b29d4986SJoe Thornber 1119b29d4986SJoe Thornber /* 1120b29d4986SJoe Thornber * Targets are given as a percentage. 1121b29d4986SJoe Thornber */ 1122b29d4986SJoe Thornber #define CLEAN_TARGET 25u 1123b29d4986SJoe Thornber #define FREE_TARGET 25u 1124b29d4986SJoe Thornber 1125b29d4986SJoe Thornber static unsigned percent_to_target(struct smq_policy *mq, unsigned p) 112666a63635SJoe Thornber { 1127b29d4986SJoe Thornber return from_cblock(mq->cache_size) * p / 100u; 112866a63635SJoe Thornber } 112966a63635SJoe Thornber 1130b29d4986SJoe Thornber static bool clean_target_met(struct smq_policy *mq, bool idle) 1131b29d4986SJoe Thornber { 1132b29d4986SJoe Thornber /* 1133b29d4986SJoe Thornber * Cache entries may not be populated. So we cannot rely on the 1134b29d4986SJoe Thornber * size of the clean queue. 1135b29d4986SJoe Thornber */ 113697dfb203SMike Snitzer if (idle) { 1137b29d4986SJoe Thornber /* 1138b29d4986SJoe Thornber * We'd like to clean everything. 1139b29d4986SJoe Thornber */ 1140b29d4986SJoe Thornber return q_size(&mq->dirty) == 0u; 114197dfb203SMike Snitzer } 114297dfb203SMike Snitzer 11432e633095SJoe Thornber /* 11442e633095SJoe Thornber * If we're busy we don't worry about cleaning at all. 11452e633095SJoe Thornber */ 11462e633095SJoe Thornber return true; 1147b29d4986SJoe Thornber } 1148b29d4986SJoe Thornber 11496cf4cc8fSJoe Thornber static bool free_target_met(struct smq_policy *mq) 1150b29d4986SJoe Thornber { 115197dfb203SMike Snitzer unsigned nr_free; 1152b29d4986SJoe Thornber 115397dfb203SMike Snitzer nr_free = from_cblock(mq->cache_size) - mq->cache_alloc.nr_allocated; 1154b29d4986SJoe Thornber return (nr_free + btracker_nr_demotions_queued(mq->bg_work)) >= 1155b29d4986SJoe Thornber percent_to_target(mq, FREE_TARGET); 1156b29d4986SJoe Thornber } 1157b29d4986SJoe Thornber 1158b29d4986SJoe Thornber /*----------------------------------------------------------------*/ 1159b29d4986SJoe Thornber 1160b29d4986SJoe Thornber static void mark_pending(struct smq_policy *mq, struct entry *e) 1161b29d4986SJoe Thornber { 1162b29d4986SJoe Thornber BUG_ON(e->sentinel); 1163b29d4986SJoe Thornber BUG_ON(!e->allocated); 1164b29d4986SJoe Thornber BUG_ON(e->pending_work); 1165b29d4986SJoe Thornber e->pending_work = true; 1166b29d4986SJoe Thornber } 1167b29d4986SJoe Thornber 1168b29d4986SJoe Thornber static void clear_pending(struct smq_policy *mq, struct entry *e) 1169b29d4986SJoe Thornber { 1170b29d4986SJoe Thornber BUG_ON(!e->pending_work); 1171b29d4986SJoe Thornber e->pending_work = false; 1172b29d4986SJoe Thornber } 1173b29d4986SJoe Thornber 1174deb71918SJoe Thornber static void queue_writeback(struct smq_policy *mq, bool idle) 1175b29d4986SJoe Thornber { 1176b29d4986SJoe Thornber int r; 1177b29d4986SJoe Thornber struct policy_work work; 1178b29d4986SJoe Thornber struct entry *e; 1179b29d4986SJoe Thornber 1180deb71918SJoe Thornber e = q_peek(&mq->dirty, mq->dirty.nr_levels, idle); 1181b29d4986SJoe Thornber if (e) { 1182b29d4986SJoe Thornber mark_pending(mq, e); 1183b29d4986SJoe Thornber q_del(&mq->dirty, e); 1184b29d4986SJoe Thornber 1185b29d4986SJoe Thornber work.op = POLICY_WRITEBACK; 1186b29d4986SJoe Thornber work.oblock = e->oblock; 1187b29d4986SJoe Thornber work.cblock = infer_cblock(mq, e); 1188b29d4986SJoe Thornber 1189b29d4986SJoe Thornber r = btracker_queue(mq->bg_work, &work, NULL); 11901e72a8e8SJoe Thornber if (r) { 11911e72a8e8SJoe Thornber clear_pending(mq, e); 11921e72a8e8SJoe Thornber q_push_front(&mq->dirty, e); 11931e72a8e8SJoe Thornber } 1194b29d4986SJoe Thornber } 1195b29d4986SJoe Thornber } 1196b29d4986SJoe Thornber 1197b29d4986SJoe Thornber static void queue_demotion(struct smq_policy *mq) 1198b29d4986SJoe Thornber { 11991e72a8e8SJoe Thornber int r; 1200b29d4986SJoe Thornber struct policy_work work; 1201b29d4986SJoe Thornber struct entry *e; 1202b29d4986SJoe Thornber 1203b29d4986SJoe Thornber if (unlikely(WARN_ON_ONCE(!mq->migrations_allowed))) 1204b29d4986SJoe Thornber return; 1205b29d4986SJoe Thornber 1206a8cd1ebaSJoe Thornber e = q_peek(&mq->clean, mq->clean.nr_levels / 2, true); 1207b29d4986SJoe Thornber if (!e) { 120878c45607SJoe Thornber if (!clean_target_met(mq, true)) 1209deb71918SJoe Thornber queue_writeback(mq, false); 1210b29d4986SJoe Thornber return; 1211b29d4986SJoe Thornber } 1212b29d4986SJoe Thornber 1213b29d4986SJoe Thornber mark_pending(mq, e); 1214b29d4986SJoe Thornber q_del(&mq->clean, e); 1215b29d4986SJoe Thornber 1216b29d4986SJoe Thornber work.op = POLICY_DEMOTE; 1217b29d4986SJoe Thornber work.oblock = e->oblock; 1218b29d4986SJoe Thornber work.cblock = infer_cblock(mq, e); 12191e72a8e8SJoe Thornber r = btracker_queue(mq->bg_work, &work, NULL); 12201e72a8e8SJoe Thornber if (r) { 12211e72a8e8SJoe Thornber clear_pending(mq, e); 12221e72a8e8SJoe Thornber q_push_front(&mq->clean, e); 12231e72a8e8SJoe Thornber } 1224b29d4986SJoe Thornber } 1225b29d4986SJoe Thornber 1226b29d4986SJoe Thornber static void queue_promotion(struct smq_policy *mq, dm_oblock_t oblock, 1227b29d4986SJoe Thornber struct policy_work **workp) 1228b29d4986SJoe Thornber { 12291e72a8e8SJoe Thornber int r; 1230b29d4986SJoe Thornber struct entry *e; 1231b29d4986SJoe Thornber struct policy_work work; 1232b29d4986SJoe Thornber 1233b29d4986SJoe Thornber if (!mq->migrations_allowed) 1234b29d4986SJoe Thornber return; 1235b29d4986SJoe Thornber 1236b29d4986SJoe Thornber if (allocator_empty(&mq->cache_alloc)) { 1237ce1d64e8SJoe Thornber /* 1238ce1d64e8SJoe Thornber * We always claim to be 'idle' to ensure some demotions happen 1239ce1d64e8SJoe Thornber * with continuous loads. 1240ce1d64e8SJoe Thornber */ 12416cf4cc8fSJoe Thornber if (!free_target_met(mq)) 1242b29d4986SJoe Thornber queue_demotion(mq); 1243b29d4986SJoe Thornber return; 1244b29d4986SJoe Thornber } 1245b29d4986SJoe Thornber 1246b29d4986SJoe Thornber if (btracker_promotion_already_present(mq->bg_work, oblock)) 1247b29d4986SJoe Thornber return; 1248b29d4986SJoe Thornber 1249b29d4986SJoe Thornber /* 1250b29d4986SJoe Thornber * We allocate the entry now to reserve the cblock. If the 1251b29d4986SJoe Thornber * background work is aborted we must remember to free it. 1252b29d4986SJoe Thornber */ 1253b29d4986SJoe Thornber e = alloc_entry(&mq->cache_alloc); 1254b29d4986SJoe Thornber BUG_ON(!e); 1255b29d4986SJoe Thornber e->pending_work = true; 1256b29d4986SJoe Thornber work.op = POLICY_PROMOTE; 1257b29d4986SJoe Thornber work.oblock = oblock; 1258b29d4986SJoe Thornber work.cblock = infer_cblock(mq, e); 12591e72a8e8SJoe Thornber r = btracker_queue(mq->bg_work, &work, workp); 12601e72a8e8SJoe Thornber if (r) 12611e72a8e8SJoe Thornber free_entry(&mq->cache_alloc, e); 1262b29d4986SJoe Thornber } 1263b29d4986SJoe Thornber 1264b29d4986SJoe Thornber /*----------------------------------------------------------------*/ 1265b29d4986SJoe Thornber 126666a63635SJoe Thornber enum promote_result { 126766a63635SJoe Thornber PROMOTE_NOT, 126866a63635SJoe Thornber PROMOTE_TEMPORARY, 126966a63635SJoe Thornber PROMOTE_PERMANENT 127066a63635SJoe Thornber }; 127166a63635SJoe Thornber 127266a63635SJoe Thornber /* 127366a63635SJoe Thornber * Converts a boolean into a promote result. 127466a63635SJoe Thornber */ 127566a63635SJoe Thornber static enum promote_result maybe_promote(bool promote) 127666a63635SJoe Thornber { 127766a63635SJoe Thornber return promote ? PROMOTE_PERMANENT : PROMOTE_NOT; 127866a63635SJoe Thornber } 127966a63635SJoe Thornber 1280b29d4986SJoe Thornber static enum promote_result should_promote(struct smq_policy *mq, struct entry *hs_e, 1281b29d4986SJoe Thornber int data_dir, bool fast_promote) 128266a63635SJoe Thornber { 1283b29d4986SJoe Thornber if (data_dir == WRITE) { 128466a63635SJoe Thornber if (!allocator_empty(&mq->cache_alloc) && fast_promote) 128566a63635SJoe Thornber return PROMOTE_TEMPORARY; 128666a63635SJoe Thornber 128766a63635SJoe Thornber return maybe_promote(hs_e->level >= mq->write_promote_level); 128866a63635SJoe Thornber } else 128966a63635SJoe Thornber return maybe_promote(hs_e->level >= mq->read_promote_level); 129066a63635SJoe Thornber } 129166a63635SJoe Thornber 129266a63635SJoe Thornber static dm_oblock_t to_hblock(struct smq_policy *mq, dm_oblock_t b) 129366a63635SJoe Thornber { 129466a63635SJoe Thornber sector_t r = from_oblock(b); 129566a63635SJoe Thornber (void) sector_div(r, mq->cache_blocks_per_hotspot_block); 129666a63635SJoe Thornber return to_oblock(r); 129766a63635SJoe Thornber } 129866a63635SJoe Thornber 1299b29d4986SJoe Thornber static struct entry *update_hotspot_queue(struct smq_policy *mq, dm_oblock_t b) 130066a63635SJoe Thornber { 130166a63635SJoe Thornber unsigned hi; 130266a63635SJoe Thornber dm_oblock_t hb = to_hblock(mq, b); 130366a63635SJoe Thornber struct entry *e = h_lookup(&mq->hotspot_table, hb); 130466a63635SJoe Thornber 130566a63635SJoe Thornber if (e) { 130666a63635SJoe Thornber stats_level_accessed(&mq->hotspot_stats, e->level); 130766a63635SJoe Thornber 130866a63635SJoe Thornber hi = get_index(&mq->hotspot_alloc, e); 130966a63635SJoe Thornber q_requeue(&mq->hotspot, e, 131066a63635SJoe Thornber test_and_set_bit(hi, mq->hotspot_hit_bits) ? 1311b29d4986SJoe Thornber 0u : mq->hotspot_level_jump, 1312b29d4986SJoe Thornber NULL, NULL); 131366a63635SJoe Thornber 131466a63635SJoe Thornber } else { 131566a63635SJoe Thornber stats_miss(&mq->hotspot_stats); 131666a63635SJoe Thornber 131766a63635SJoe Thornber e = alloc_entry(&mq->hotspot_alloc); 131866a63635SJoe Thornber if (!e) { 131966a63635SJoe Thornber e = q_pop(&mq->hotspot); 132066a63635SJoe Thornber if (e) { 132166a63635SJoe Thornber h_remove(&mq->hotspot_table, e); 132266a63635SJoe Thornber hi = get_index(&mq->hotspot_alloc, e); 132366a63635SJoe Thornber clear_bit(hi, mq->hotspot_hit_bits); 132466a63635SJoe Thornber } 132566a63635SJoe Thornber 132666a63635SJoe Thornber } 132766a63635SJoe Thornber 132866a63635SJoe Thornber if (e) { 132966a63635SJoe Thornber e->oblock = hb; 133066a63635SJoe Thornber q_push(&mq->hotspot, e); 133166a63635SJoe Thornber h_insert(&mq->hotspot_table, e); 133266a63635SJoe Thornber } 133366a63635SJoe Thornber } 133466a63635SJoe Thornber 133566a63635SJoe Thornber return e; 133666a63635SJoe Thornber } 133766a63635SJoe Thornber 133866a63635SJoe Thornber /*----------------------------------------------------------------*/ 133966a63635SJoe Thornber 134066a63635SJoe Thornber /* 134166a63635SJoe Thornber * Public interface, via the policy struct. See dm-cache-policy.h for a 134266a63635SJoe Thornber * description of these. 134366a63635SJoe Thornber */ 134466a63635SJoe Thornber 134566a63635SJoe Thornber static struct smq_policy *to_smq_policy(struct dm_cache_policy *p) 134666a63635SJoe Thornber { 134766a63635SJoe Thornber return container_of(p, struct smq_policy, policy); 134866a63635SJoe Thornber } 134966a63635SJoe Thornber 135066a63635SJoe Thornber static void smq_destroy(struct dm_cache_policy *p) 135166a63635SJoe Thornber { 135266a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 135366a63635SJoe Thornber 1354b29d4986SJoe Thornber btracker_destroy(mq->bg_work); 135566a63635SJoe Thornber h_exit(&mq->hotspot_table); 135666a63635SJoe Thornber h_exit(&mq->table); 135766a63635SJoe Thornber free_bitset(mq->hotspot_hit_bits); 135866a63635SJoe Thornber free_bitset(mq->cache_hit_bits); 135966a63635SJoe Thornber space_exit(&mq->es); 136066a63635SJoe Thornber kfree(mq); 136166a63635SJoe Thornber } 136266a63635SJoe Thornber 1363b29d4986SJoe Thornber /*----------------------------------------------------------------*/ 1364b29d4986SJoe Thornber 1365b29d4986SJoe Thornber static int __lookup(struct smq_policy *mq, dm_oblock_t oblock, dm_cblock_t *cblock, 1366b29d4986SJoe Thornber int data_dir, bool fast_copy, 1367b29d4986SJoe Thornber struct policy_work **work, bool *background_work) 136866a63635SJoe Thornber { 1369b29d4986SJoe Thornber struct entry *e, *hs_e; 1370b29d4986SJoe Thornber enum promote_result pr; 137166a63635SJoe Thornber 1372b29d4986SJoe Thornber *background_work = false; 137366a63635SJoe Thornber 137466a63635SJoe Thornber e = h_lookup(&mq->table, oblock); 137566a63635SJoe Thornber if (e) { 1376b29d4986SJoe Thornber stats_level_accessed(&mq->cache_stats, e->level); 1377b29d4986SJoe Thornber 1378b29d4986SJoe Thornber requeue(mq, e); 137966a63635SJoe Thornber *cblock = infer_cblock(mq, e); 1380b29d4986SJoe Thornber return 0; 1381b29d4986SJoe Thornber 1382b29d4986SJoe Thornber } else { 1383b29d4986SJoe Thornber stats_miss(&mq->cache_stats); 1384b29d4986SJoe Thornber 1385b29d4986SJoe Thornber /* 1386b29d4986SJoe Thornber * The hotspot queue only gets updated with misses. 1387b29d4986SJoe Thornber */ 1388b29d4986SJoe Thornber hs_e = update_hotspot_queue(mq, oblock); 1389b29d4986SJoe Thornber 1390b29d4986SJoe Thornber pr = should_promote(mq, hs_e, data_dir, fast_copy); 1391b29d4986SJoe Thornber if (pr != PROMOTE_NOT) { 1392b29d4986SJoe Thornber queue_promotion(mq, oblock, work); 1393b29d4986SJoe Thornber *background_work = true; 1394b29d4986SJoe Thornber } 1395b29d4986SJoe Thornber 1396b29d4986SJoe Thornber return -ENOENT; 1397b29d4986SJoe Thornber } 1398b29d4986SJoe Thornber } 1399b29d4986SJoe Thornber 1400b29d4986SJoe Thornber static int smq_lookup(struct dm_cache_policy *p, dm_oblock_t oblock, dm_cblock_t *cblock, 1401b29d4986SJoe Thornber int data_dir, bool fast_copy, 1402b29d4986SJoe Thornber bool *background_work) 1403b29d4986SJoe Thornber { 1404b29d4986SJoe Thornber int r; 1405b29d4986SJoe Thornber unsigned long flags; 1406b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 1407b29d4986SJoe Thornber 1408b29d4986SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1409b29d4986SJoe Thornber r = __lookup(mq, oblock, cblock, 1410b29d4986SJoe Thornber data_dir, fast_copy, 1411b29d4986SJoe Thornber NULL, background_work); 14124051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 141366a63635SJoe Thornber 141466a63635SJoe Thornber return r; 141566a63635SJoe Thornber } 141666a63635SJoe Thornber 1417b29d4986SJoe Thornber static int smq_lookup_with_work(struct dm_cache_policy *p, 1418b29d4986SJoe Thornber dm_oblock_t oblock, dm_cblock_t *cblock, 1419b29d4986SJoe Thornber int data_dir, bool fast_copy, 1420b29d4986SJoe Thornber struct policy_work **work) 142166a63635SJoe Thornber { 1422b29d4986SJoe Thornber int r; 1423b29d4986SJoe Thornber bool background_queued; 1424b29d4986SJoe Thornber unsigned long flags; 1425b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 142666a63635SJoe Thornber 1427b29d4986SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1428b29d4986SJoe Thornber r = __lookup(mq, oblock, cblock, data_dir, fast_copy, work, &background_queued); 1429b29d4986SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 143066a63635SJoe Thornber 1431b29d4986SJoe Thornber return r; 143266a63635SJoe Thornber } 143366a63635SJoe Thornber 1434b29d4986SJoe Thornber static int smq_get_background_work(struct dm_cache_policy *p, bool idle, 1435b29d4986SJoe Thornber struct policy_work **result) 1436b29d4986SJoe Thornber { 1437b29d4986SJoe Thornber int r; 1438b29d4986SJoe Thornber unsigned long flags; 1439b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 1440b29d4986SJoe Thornber 1441b29d4986SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1442b29d4986SJoe Thornber r = btracker_issue(mq->bg_work, result); 1443b29d4986SJoe Thornber if (r == -ENODATA) { 14446cf4cc8fSJoe Thornber if (!clean_target_met(mq, idle)) { 1445deb71918SJoe Thornber queue_writeback(mq, idle); 1446b29d4986SJoe Thornber r = btracker_issue(mq->bg_work, result); 1447b29d4986SJoe Thornber } 14486cf4cc8fSJoe Thornber } 1449b29d4986SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 1450b29d4986SJoe Thornber 1451b29d4986SJoe Thornber return r; 1452b29d4986SJoe Thornber } 1453b29d4986SJoe Thornber 1454b29d4986SJoe Thornber /* 1455b29d4986SJoe Thornber * We need to clear any pending work flags that have been set, and in the 1456b29d4986SJoe Thornber * case of promotion free the entry for the destination cblock. 1457b29d4986SJoe Thornber */ 1458b29d4986SJoe Thornber static void __complete_background_work(struct smq_policy *mq, 1459b29d4986SJoe Thornber struct policy_work *work, 1460b29d4986SJoe Thornber bool success) 1461b29d4986SJoe Thornber { 1462b29d4986SJoe Thornber struct entry *e = get_entry(&mq->cache_alloc, 1463b29d4986SJoe Thornber from_cblock(work->cblock)); 1464b29d4986SJoe Thornber 1465b29d4986SJoe Thornber switch (work->op) { 1466b29d4986SJoe Thornber case POLICY_PROMOTE: 1467b29d4986SJoe Thornber // !h, !q, a 1468b29d4986SJoe Thornber clear_pending(mq, e); 1469b29d4986SJoe Thornber if (success) { 1470b29d4986SJoe Thornber e->oblock = work->oblock; 14714d44ec5aSJoe Thornber e->level = NR_CACHE_LEVELS - 1; 1472b29d4986SJoe Thornber push(mq, e); 1473b29d4986SJoe Thornber // h, q, a 1474b29d4986SJoe Thornber } else { 1475b29d4986SJoe Thornber free_entry(&mq->cache_alloc, e); 1476b29d4986SJoe Thornber // !h, !q, !a 1477b29d4986SJoe Thornber } 1478b29d4986SJoe Thornber break; 1479b29d4986SJoe Thornber 1480b29d4986SJoe Thornber case POLICY_DEMOTE: 1481b29d4986SJoe Thornber // h, !q, a 1482b29d4986SJoe Thornber if (success) { 1483b29d4986SJoe Thornber h_remove(&mq->table, e); 1484b29d4986SJoe Thornber free_entry(&mq->cache_alloc, e); 1485b29d4986SJoe Thornber // !h, !q, !a 1486b29d4986SJoe Thornber } else { 1487b29d4986SJoe Thornber clear_pending(mq, e); 1488b29d4986SJoe Thornber push_queue(mq, e); 1489b29d4986SJoe Thornber // h, q, a 1490b29d4986SJoe Thornber } 1491b29d4986SJoe Thornber break; 1492b29d4986SJoe Thornber 1493b29d4986SJoe Thornber case POLICY_WRITEBACK: 1494b29d4986SJoe Thornber // h, !q, a 1495b29d4986SJoe Thornber clear_pending(mq, e); 1496b29d4986SJoe Thornber push_queue(mq, e); 1497b29d4986SJoe Thornber // h, q, a 1498b29d4986SJoe Thornber break; 1499b29d4986SJoe Thornber } 1500b29d4986SJoe Thornber 1501b29d4986SJoe Thornber btracker_complete(mq->bg_work, work); 1502b29d4986SJoe Thornber } 1503b29d4986SJoe Thornber 1504b29d4986SJoe Thornber static void smq_complete_background_work(struct dm_cache_policy *p, 1505b29d4986SJoe Thornber struct policy_work *work, 1506b29d4986SJoe Thornber bool success) 150766a63635SJoe Thornber { 15084051aab7SJoe Thornber unsigned long flags; 150966a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 151066a63635SJoe Thornber 15114051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1512b29d4986SJoe Thornber __complete_background_work(mq, work, success); 15134051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 151466a63635SJoe Thornber } 151566a63635SJoe Thornber 1516b29d4986SJoe Thornber // in_hash(oblock) -> in_hash(oblock) 1517b29d4986SJoe Thornber static void __smq_set_clear_dirty(struct smq_policy *mq, dm_cblock_t cblock, bool set) 1518b29d4986SJoe Thornber { 1519b29d4986SJoe Thornber struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); 1520b29d4986SJoe Thornber 1521b29d4986SJoe Thornber if (e->pending_work) 1522b29d4986SJoe Thornber e->dirty = set; 1523b29d4986SJoe Thornber else { 1524b29d4986SJoe Thornber del_queue(mq, e); 1525b29d4986SJoe Thornber e->dirty = set; 1526b29d4986SJoe Thornber push_queue(mq, e); 1527b29d4986SJoe Thornber } 1528b29d4986SJoe Thornber } 1529b29d4986SJoe Thornber 1530b29d4986SJoe Thornber static void smq_set_dirty(struct dm_cache_policy *p, dm_cblock_t cblock) 1531b29d4986SJoe Thornber { 1532b29d4986SJoe Thornber unsigned long flags; 1533b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 1534b29d4986SJoe Thornber 1535b29d4986SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1536b29d4986SJoe Thornber __smq_set_clear_dirty(mq, cblock, true); 1537b29d4986SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 1538b29d4986SJoe Thornber } 1539b29d4986SJoe Thornber 1540b29d4986SJoe Thornber static void smq_clear_dirty(struct dm_cache_policy *p, dm_cblock_t cblock) 154166a63635SJoe Thornber { 154266a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 15434051aab7SJoe Thornber unsigned long flags; 154466a63635SJoe Thornber 15454051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1546b29d4986SJoe Thornber __smq_set_clear_dirty(mq, cblock, false); 15474051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 154866a63635SJoe Thornber } 154966a63635SJoe Thornber 15509d1b404cSJoe Thornber static unsigned random_level(dm_cblock_t cblock) 15519d1b404cSJoe Thornber { 1552e99dda8fSMike Snitzer return hash_32(from_cblock(cblock), 9) & (NR_CACHE_LEVELS - 1); 15539d1b404cSJoe Thornber } 15549d1b404cSJoe Thornber 155566a63635SJoe Thornber static int smq_load_mapping(struct dm_cache_policy *p, 155666a63635SJoe Thornber dm_oblock_t oblock, dm_cblock_t cblock, 1557b29d4986SJoe Thornber bool dirty, uint32_t hint, bool hint_valid) 155866a63635SJoe Thornber { 155966a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 156066a63635SJoe Thornber struct entry *e; 156166a63635SJoe Thornber 156266a63635SJoe Thornber e = alloc_particular_entry(&mq->cache_alloc, from_cblock(cblock)); 156366a63635SJoe Thornber e->oblock = oblock; 1564b29d4986SJoe Thornber e->dirty = dirty; 15659d1b404cSJoe Thornber e->level = hint_valid ? min(hint, NR_CACHE_LEVELS - 1) : random_level(cblock); 1566b29d4986SJoe Thornber e->pending_work = false; 156766a63635SJoe Thornber 1568b29d4986SJoe Thornber /* 1569b29d4986SJoe Thornber * When we load mappings we push ahead of both sentinels in order to 1570b29d4986SJoe Thornber * allow demotions and cleaning to occur immediately. 1571b29d4986SJoe Thornber */ 1572b29d4986SJoe Thornber push_front(mq, e); 1573b29d4986SJoe Thornber 1574b29d4986SJoe Thornber return 0; 1575b29d4986SJoe Thornber } 1576b29d4986SJoe Thornber 1577b29d4986SJoe Thornber static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) 1578b29d4986SJoe Thornber { 1579b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 1580b29d4986SJoe Thornber struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); 1581b29d4986SJoe Thornber 1582b29d4986SJoe Thornber if (!e->allocated) 1583b29d4986SJoe Thornber return -ENODATA; 1584b29d4986SJoe Thornber 1585b29d4986SJoe Thornber // FIXME: what if this block has pending background work? 1586b29d4986SJoe Thornber del_queue(mq, e); 1587b29d4986SJoe Thornber h_remove(&mq->table, e); 1588b29d4986SJoe Thornber free_entry(&mq->cache_alloc, e); 158966a63635SJoe Thornber return 0; 159066a63635SJoe Thornber } 159166a63635SJoe Thornber 15924e781b49SJoe Thornber static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock) 159366a63635SJoe Thornber { 159466a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 15954e781b49SJoe Thornber struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); 159666a63635SJoe Thornber 15974e781b49SJoe Thornber if (!e->allocated) 15984e781b49SJoe Thornber return 0; 159966a63635SJoe Thornber 16004e781b49SJoe Thornber return e->level; 160166a63635SJoe Thornber } 160266a63635SJoe Thornber 160366a63635SJoe Thornber static dm_cblock_t smq_residency(struct dm_cache_policy *p) 160466a63635SJoe Thornber { 160566a63635SJoe Thornber dm_cblock_t r; 16064051aab7SJoe Thornber unsigned long flags; 160766a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 160866a63635SJoe Thornber 16094051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 161066a63635SJoe Thornber r = to_cblock(mq->cache_alloc.nr_allocated); 16114051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 161266a63635SJoe Thornber 161366a63635SJoe Thornber return r; 161466a63635SJoe Thornber } 161566a63635SJoe Thornber 1616fba10109SJoe Thornber static void smq_tick(struct dm_cache_policy *p, bool can_block) 161766a63635SJoe Thornber { 161866a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 161966a63635SJoe Thornber unsigned long flags; 162066a63635SJoe Thornber 16214051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 16224051aab7SJoe Thornber mq->tick++; 16234051aab7SJoe Thornber update_sentinels(mq); 16244051aab7SJoe Thornber end_hotspot_period(mq); 16254051aab7SJoe Thornber end_cache_period(mq); 16264051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 162766a63635SJoe Thornber } 162866a63635SJoe Thornber 1629b29d4986SJoe Thornber static void smq_allow_migrations(struct dm_cache_policy *p, bool allow) 1630b29d4986SJoe Thornber { 1631b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 1632b29d4986SJoe Thornber mq->migrations_allowed = allow; 1633b29d4986SJoe Thornber } 1634b29d4986SJoe Thornber 16359ed84698SJoe Thornber /* 16369ed84698SJoe Thornber * smq has no config values, but the old mq policy did. To avoid breaking 16379ed84698SJoe Thornber * software we continue to accept these configurables for the mq policy, 16389ed84698SJoe Thornber * but they have no effect. 16399ed84698SJoe Thornber */ 16409ed84698SJoe Thornber static int mq_set_config_value(struct dm_cache_policy *p, 16419ed84698SJoe Thornber const char *key, const char *value) 16429ed84698SJoe Thornber { 16439ed84698SJoe Thornber unsigned long tmp; 16449ed84698SJoe Thornber 16459ed84698SJoe Thornber if (kstrtoul(value, 10, &tmp)) 16469ed84698SJoe Thornber return -EINVAL; 16479ed84698SJoe Thornber 16489ed84698SJoe Thornber if (!strcasecmp(key, "random_threshold") || 16499ed84698SJoe Thornber !strcasecmp(key, "sequential_threshold") || 16509ed84698SJoe Thornber !strcasecmp(key, "discard_promote_adjustment") || 16519ed84698SJoe Thornber !strcasecmp(key, "read_promote_adjustment") || 16529ed84698SJoe Thornber !strcasecmp(key, "write_promote_adjustment")) { 16539ed84698SJoe Thornber DMWARN("tunable '%s' no longer has any effect, mq policy is now an alias for smq", key); 16549ed84698SJoe Thornber return 0; 16559ed84698SJoe Thornber } 16569ed84698SJoe Thornber 16579ed84698SJoe Thornber return -EINVAL; 16589ed84698SJoe Thornber } 16599ed84698SJoe Thornber 16609ed84698SJoe Thornber static int mq_emit_config_values(struct dm_cache_policy *p, char *result, 16619ed84698SJoe Thornber unsigned maxlen, ssize_t *sz_ptr) 16629ed84698SJoe Thornber { 16639ed84698SJoe Thornber ssize_t sz = *sz_ptr; 16649ed84698SJoe Thornber 16659ed84698SJoe Thornber DMEMIT("10 random_threshold 0 " 16669ed84698SJoe Thornber "sequential_threshold 0 " 16679ed84698SJoe Thornber "discard_promote_adjustment 0 " 16689ed84698SJoe Thornber "read_promote_adjustment 0 " 16699ed84698SJoe Thornber "write_promote_adjustment 0 "); 16709ed84698SJoe Thornber 16719ed84698SJoe Thornber *sz_ptr = sz; 16729ed84698SJoe Thornber return 0; 16739ed84698SJoe Thornber } 16749ed84698SJoe Thornber 167566a63635SJoe Thornber /* Init the policy plugin interface function pointers. */ 16769ed84698SJoe Thornber static void init_policy_functions(struct smq_policy *mq, bool mimic_mq) 167766a63635SJoe Thornber { 167866a63635SJoe Thornber mq->policy.destroy = smq_destroy; 167966a63635SJoe Thornber mq->policy.lookup = smq_lookup; 1680b29d4986SJoe Thornber mq->policy.lookup_with_work = smq_lookup_with_work; 1681b29d4986SJoe Thornber mq->policy.get_background_work = smq_get_background_work; 1682b29d4986SJoe Thornber mq->policy.complete_background_work = smq_complete_background_work; 168366a63635SJoe Thornber mq->policy.set_dirty = smq_set_dirty; 168466a63635SJoe Thornber mq->policy.clear_dirty = smq_clear_dirty; 168566a63635SJoe Thornber mq->policy.load_mapping = smq_load_mapping; 1686b29d4986SJoe Thornber mq->policy.invalidate_mapping = smq_invalidate_mapping; 16874e781b49SJoe Thornber mq->policy.get_hint = smq_get_hint; 168866a63635SJoe Thornber mq->policy.residency = smq_residency; 168966a63635SJoe Thornber mq->policy.tick = smq_tick; 1690b29d4986SJoe Thornber mq->policy.allow_migrations = smq_allow_migrations; 16919ed84698SJoe Thornber 16929ed84698SJoe Thornber if (mimic_mq) { 16939ed84698SJoe Thornber mq->policy.set_config_value = mq_set_config_value; 16949ed84698SJoe Thornber mq->policy.emit_config_values = mq_emit_config_values; 16959ed84698SJoe Thornber } 169666a63635SJoe Thornber } 169766a63635SJoe Thornber 169866a63635SJoe Thornber static bool too_many_hotspot_blocks(sector_t origin_size, 169966a63635SJoe Thornber sector_t hotspot_block_size, 170066a63635SJoe Thornber unsigned nr_hotspot_blocks) 170166a63635SJoe Thornber { 170266a63635SJoe Thornber return (hotspot_block_size * nr_hotspot_blocks) > origin_size; 170366a63635SJoe Thornber } 170466a63635SJoe Thornber 170566a63635SJoe Thornber static void calc_hotspot_params(sector_t origin_size, 170666a63635SJoe Thornber sector_t cache_block_size, 170766a63635SJoe Thornber unsigned nr_cache_blocks, 170866a63635SJoe Thornber sector_t *hotspot_block_size, 170966a63635SJoe Thornber unsigned *nr_hotspot_blocks) 171066a63635SJoe Thornber { 171166a63635SJoe Thornber *hotspot_block_size = cache_block_size * 16u; 171266a63635SJoe Thornber *nr_hotspot_blocks = max(nr_cache_blocks / 4u, 1024u); 171366a63635SJoe Thornber 171466a63635SJoe Thornber while ((*hotspot_block_size > cache_block_size) && 171566a63635SJoe Thornber too_many_hotspot_blocks(origin_size, *hotspot_block_size, *nr_hotspot_blocks)) 171666a63635SJoe Thornber *hotspot_block_size /= 2u; 171766a63635SJoe Thornber } 171866a63635SJoe Thornber 17199ed84698SJoe Thornber static struct dm_cache_policy *__smq_create(dm_cblock_t cache_size, 172066a63635SJoe Thornber sector_t origin_size, 17219ed84698SJoe Thornber sector_t cache_block_size, 1722b29d4986SJoe Thornber bool mimic_mq, 1723b29d4986SJoe Thornber bool migrations_allowed) 172466a63635SJoe Thornber { 172566a63635SJoe Thornber unsigned i; 172666a63635SJoe Thornber unsigned nr_sentinels_per_queue = 2u * NR_CACHE_LEVELS; 172766a63635SJoe Thornber unsigned total_sentinels = 2u * nr_sentinels_per_queue; 172866a63635SJoe Thornber struct smq_policy *mq = kzalloc(sizeof(*mq), GFP_KERNEL); 172966a63635SJoe Thornber 173066a63635SJoe Thornber if (!mq) 173166a63635SJoe Thornber return NULL; 173266a63635SJoe Thornber 17339ed84698SJoe Thornber init_policy_functions(mq, mimic_mq); 173466a63635SJoe Thornber mq->cache_size = cache_size; 173566a63635SJoe Thornber mq->cache_block_size = cache_block_size; 173666a63635SJoe Thornber 173766a63635SJoe Thornber calc_hotspot_params(origin_size, cache_block_size, from_cblock(cache_size), 173866a63635SJoe Thornber &mq->hotspot_block_size, &mq->nr_hotspot_blocks); 173966a63635SJoe Thornber 174066a63635SJoe Thornber mq->cache_blocks_per_hotspot_block = div64_u64(mq->hotspot_block_size, mq->cache_block_size); 174166a63635SJoe Thornber mq->hotspot_level_jump = 1u; 174266a63635SJoe Thornber if (space_init(&mq->es, total_sentinels + mq->nr_hotspot_blocks + from_cblock(cache_size))) { 174366a63635SJoe Thornber DMERR("couldn't initialize entry space"); 174466a63635SJoe Thornber goto bad_pool_init; 174566a63635SJoe Thornber } 174666a63635SJoe Thornber 174766a63635SJoe Thornber init_allocator(&mq->writeback_sentinel_alloc, &mq->es, 0, nr_sentinels_per_queue); 174866a63635SJoe Thornber for (i = 0; i < nr_sentinels_per_queue; i++) 174966a63635SJoe Thornber get_entry(&mq->writeback_sentinel_alloc, i)->sentinel = true; 175066a63635SJoe Thornber 175166a63635SJoe Thornber init_allocator(&mq->demote_sentinel_alloc, &mq->es, nr_sentinels_per_queue, total_sentinels); 175266a63635SJoe Thornber for (i = 0; i < nr_sentinels_per_queue; i++) 175366a63635SJoe Thornber get_entry(&mq->demote_sentinel_alloc, i)->sentinel = true; 175466a63635SJoe Thornber 175566a63635SJoe Thornber init_allocator(&mq->hotspot_alloc, &mq->es, total_sentinels, 175666a63635SJoe Thornber total_sentinels + mq->nr_hotspot_blocks); 175766a63635SJoe Thornber 175866a63635SJoe Thornber init_allocator(&mq->cache_alloc, &mq->es, 175966a63635SJoe Thornber total_sentinels + mq->nr_hotspot_blocks, 176066a63635SJoe Thornber total_sentinels + mq->nr_hotspot_blocks + from_cblock(cache_size)); 176166a63635SJoe Thornber 176266a63635SJoe Thornber mq->hotspot_hit_bits = alloc_bitset(mq->nr_hotspot_blocks); 176366a63635SJoe Thornber if (!mq->hotspot_hit_bits) { 176466a63635SJoe Thornber DMERR("couldn't allocate hotspot hit bitset"); 176566a63635SJoe Thornber goto bad_hotspot_hit_bits; 176666a63635SJoe Thornber } 176766a63635SJoe Thornber clear_bitset(mq->hotspot_hit_bits, mq->nr_hotspot_blocks); 176866a63635SJoe Thornber 176966a63635SJoe Thornber if (from_cblock(cache_size)) { 177066a63635SJoe Thornber mq->cache_hit_bits = alloc_bitset(from_cblock(cache_size)); 1771134bf30cSColin Ian King if (!mq->cache_hit_bits) { 177266a63635SJoe Thornber DMERR("couldn't allocate cache hit bitset"); 177366a63635SJoe Thornber goto bad_cache_hit_bits; 177466a63635SJoe Thornber } 177566a63635SJoe Thornber clear_bitset(mq->cache_hit_bits, from_cblock(mq->cache_size)); 177666a63635SJoe Thornber } else 177766a63635SJoe Thornber mq->cache_hit_bits = NULL; 177866a63635SJoe Thornber 177966a63635SJoe Thornber mq->tick = 0; 17804051aab7SJoe Thornber spin_lock_init(&mq->lock); 178166a63635SJoe Thornber 178266a63635SJoe Thornber q_init(&mq->hotspot, &mq->es, NR_HOTSPOT_LEVELS); 178366a63635SJoe Thornber mq->hotspot.nr_top_levels = 8; 178466a63635SJoe Thornber mq->hotspot.nr_in_top_levels = min(mq->nr_hotspot_blocks / NR_HOTSPOT_LEVELS, 178566a63635SJoe Thornber from_cblock(mq->cache_size) / mq->cache_blocks_per_hotspot_block); 178666a63635SJoe Thornber 178766a63635SJoe Thornber q_init(&mq->clean, &mq->es, NR_CACHE_LEVELS); 178866a63635SJoe Thornber q_init(&mq->dirty, &mq->es, NR_CACHE_LEVELS); 178966a63635SJoe Thornber 179066a63635SJoe Thornber stats_init(&mq->hotspot_stats, NR_HOTSPOT_LEVELS); 179166a63635SJoe Thornber stats_init(&mq->cache_stats, NR_CACHE_LEVELS); 179266a63635SJoe Thornber 179366a63635SJoe Thornber if (h_init(&mq->table, &mq->es, from_cblock(cache_size))) 179466a63635SJoe Thornber goto bad_alloc_table; 179566a63635SJoe Thornber 179666a63635SJoe Thornber if (h_init(&mq->hotspot_table, &mq->es, mq->nr_hotspot_blocks)) 179766a63635SJoe Thornber goto bad_alloc_hotspot_table; 179866a63635SJoe Thornber 179966a63635SJoe Thornber sentinels_init(mq); 180066a63635SJoe Thornber mq->write_promote_level = mq->read_promote_level = NR_HOTSPOT_LEVELS; 180166a63635SJoe Thornber 180266a63635SJoe Thornber mq->next_hotspot_period = jiffies; 180366a63635SJoe Thornber mq->next_cache_period = jiffies; 180466a63635SJoe Thornber 18058ee18edeSJoe Thornber mq->bg_work = btracker_create(4096); /* FIXME: hard coded value */ 1806b29d4986SJoe Thornber if (!mq->bg_work) 1807b29d4986SJoe Thornber goto bad_btracker; 1808b29d4986SJoe Thornber 1809b29d4986SJoe Thornber mq->migrations_allowed = migrations_allowed; 1810b29d4986SJoe Thornber 181166a63635SJoe Thornber return &mq->policy; 181266a63635SJoe Thornber 1813b29d4986SJoe Thornber bad_btracker: 1814b29d4986SJoe Thornber h_exit(&mq->hotspot_table); 181566a63635SJoe Thornber bad_alloc_hotspot_table: 181666a63635SJoe Thornber h_exit(&mq->table); 181766a63635SJoe Thornber bad_alloc_table: 181866a63635SJoe Thornber free_bitset(mq->cache_hit_bits); 181966a63635SJoe Thornber bad_cache_hit_bits: 182066a63635SJoe Thornber free_bitset(mq->hotspot_hit_bits); 182166a63635SJoe Thornber bad_hotspot_hit_bits: 182266a63635SJoe Thornber space_exit(&mq->es); 182366a63635SJoe Thornber bad_pool_init: 182466a63635SJoe Thornber kfree(mq); 182566a63635SJoe Thornber 182666a63635SJoe Thornber return NULL; 182766a63635SJoe Thornber } 182866a63635SJoe Thornber 18299ed84698SJoe Thornber static struct dm_cache_policy *smq_create(dm_cblock_t cache_size, 18309ed84698SJoe Thornber sector_t origin_size, 18319ed84698SJoe Thornber sector_t cache_block_size) 18329ed84698SJoe Thornber { 1833b29d4986SJoe Thornber return __smq_create(cache_size, origin_size, cache_block_size, false, true); 18349ed84698SJoe Thornber } 18359ed84698SJoe Thornber 18369ed84698SJoe Thornber static struct dm_cache_policy *mq_create(dm_cblock_t cache_size, 18379ed84698SJoe Thornber sector_t origin_size, 18389ed84698SJoe Thornber sector_t cache_block_size) 18399ed84698SJoe Thornber { 1840b29d4986SJoe Thornber return __smq_create(cache_size, origin_size, cache_block_size, true, true); 1841b29d4986SJoe Thornber } 1842b29d4986SJoe Thornber 1843b29d4986SJoe Thornber static struct dm_cache_policy *cleaner_create(dm_cblock_t cache_size, 1844b29d4986SJoe Thornber sector_t origin_size, 1845b29d4986SJoe Thornber sector_t cache_block_size) 1846b29d4986SJoe Thornber { 1847b29d4986SJoe Thornber return __smq_create(cache_size, origin_size, cache_block_size, false, false); 18489ed84698SJoe Thornber } 18499ed84698SJoe Thornber 185066a63635SJoe Thornber /*----------------------------------------------------------------*/ 185166a63635SJoe Thornber 185266a63635SJoe Thornber static struct dm_cache_policy_type smq_policy_type = { 185366a63635SJoe Thornber .name = "smq", 1854b29d4986SJoe Thornber .version = {2, 0, 0}, 185566a63635SJoe Thornber .hint_size = 4, 185666a63635SJoe Thornber .owner = THIS_MODULE, 185766a63635SJoe Thornber .create = smq_create 185866a63635SJoe Thornber }; 185966a63635SJoe Thornber 18609ed84698SJoe Thornber static struct dm_cache_policy_type mq_policy_type = { 18619ed84698SJoe Thornber .name = "mq", 1862b29d4986SJoe Thornber .version = {2, 0, 0}, 18639ed84698SJoe Thornber .hint_size = 4, 18649ed84698SJoe Thornber .owner = THIS_MODULE, 18659ed84698SJoe Thornber .create = mq_create, 18669ed84698SJoe Thornber }; 18679ed84698SJoe Thornber 1868b29d4986SJoe Thornber static struct dm_cache_policy_type cleaner_policy_type = { 1869b29d4986SJoe Thornber .name = "cleaner", 1870b29d4986SJoe Thornber .version = {2, 0, 0}, 1871b29d4986SJoe Thornber .hint_size = 4, 1872b29d4986SJoe Thornber .owner = THIS_MODULE, 1873b29d4986SJoe Thornber .create = cleaner_create, 1874b29d4986SJoe Thornber }; 1875b29d4986SJoe Thornber 1876bccab6a0SMike Snitzer static struct dm_cache_policy_type default_policy_type = { 1877bccab6a0SMike Snitzer .name = "default", 1878b29d4986SJoe Thornber .version = {2, 0, 0}, 1879bccab6a0SMike Snitzer .hint_size = 4, 1880bccab6a0SMike Snitzer .owner = THIS_MODULE, 1881bccab6a0SMike Snitzer .create = smq_create, 1882bccab6a0SMike Snitzer .real = &smq_policy_type 1883bccab6a0SMike Snitzer }; 1884bccab6a0SMike Snitzer 188566a63635SJoe Thornber static int __init smq_init(void) 188666a63635SJoe Thornber { 188766a63635SJoe Thornber int r; 188866a63635SJoe Thornber 188966a63635SJoe Thornber r = dm_cache_policy_register(&smq_policy_type); 189066a63635SJoe Thornber if (r) { 189166a63635SJoe Thornber DMERR("register failed %d", r); 189266a63635SJoe Thornber return -ENOMEM; 189366a63635SJoe Thornber } 189466a63635SJoe Thornber 18959ed84698SJoe Thornber r = dm_cache_policy_register(&mq_policy_type); 18969ed84698SJoe Thornber if (r) { 18977dd85bb0SMike Snitzer DMERR("register failed (as mq) %d", r); 1898b29d4986SJoe Thornber goto out_mq; 1899b29d4986SJoe Thornber } 1900b29d4986SJoe Thornber 1901b29d4986SJoe Thornber r = dm_cache_policy_register(&cleaner_policy_type); 1902b29d4986SJoe Thornber if (r) { 1903b29d4986SJoe Thornber DMERR("register failed (as cleaner) %d", r); 1904b29d4986SJoe Thornber goto out_cleaner; 19059ed84698SJoe Thornber } 19069ed84698SJoe Thornber 1907bccab6a0SMike Snitzer r = dm_cache_policy_register(&default_policy_type); 1908bccab6a0SMike Snitzer if (r) { 1909bccab6a0SMike Snitzer DMERR("register failed (as default) %d", r); 1910b29d4986SJoe Thornber goto out_default; 1911bccab6a0SMike Snitzer } 1912bccab6a0SMike Snitzer 191366a63635SJoe Thornber return 0; 1914b29d4986SJoe Thornber 1915b29d4986SJoe Thornber out_default: 1916b29d4986SJoe Thornber dm_cache_policy_unregister(&cleaner_policy_type); 1917b29d4986SJoe Thornber out_cleaner: 1918b29d4986SJoe Thornber dm_cache_policy_unregister(&mq_policy_type); 1919b29d4986SJoe Thornber out_mq: 1920b29d4986SJoe Thornber dm_cache_policy_unregister(&smq_policy_type); 1921b29d4986SJoe Thornber 1922b29d4986SJoe Thornber return -ENOMEM; 192366a63635SJoe Thornber } 192466a63635SJoe Thornber 192566a63635SJoe Thornber static void __exit smq_exit(void) 192666a63635SJoe Thornber { 1927b29d4986SJoe Thornber dm_cache_policy_unregister(&cleaner_policy_type); 192866a63635SJoe Thornber dm_cache_policy_unregister(&smq_policy_type); 19299ed84698SJoe Thornber dm_cache_policy_unregister(&mq_policy_type); 1930bccab6a0SMike Snitzer dm_cache_policy_unregister(&default_policy_type); 193166a63635SJoe Thornber } 193266a63635SJoe Thornber 193366a63635SJoe Thornber module_init(smq_init); 193466a63635SJoe Thornber module_exit(smq_exit); 193566a63635SJoe Thornber 193666a63635SJoe Thornber MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>"); 193766a63635SJoe Thornber MODULE_LICENSE("GPL"); 193866a63635SJoe Thornber MODULE_DESCRIPTION("smq cache policy"); 193934dd0517SYi Zhang 194034dd0517SYi Zhang MODULE_ALIAS("dm-cache-default"); 19419ed84698SJoe Thornber MODULE_ALIAS("dm-cache-mq"); 1942b29d4986SJoe Thornber MODULE_ALIAS("dm-cache-cleaner"); 1943