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 21666a63635SJoe Thornber static struct entry *l_pop_tail(struct entry_space *es, struct ilist *l) 21766a63635SJoe Thornber { 21866a63635SJoe Thornber struct entry *e; 21966a63635SJoe Thornber 22066a63635SJoe Thornber for (e = l_tail(es, l); e; e = l_prev(es, e)) 22166a63635SJoe Thornber if (!e->sentinel) { 22266a63635SJoe Thornber l_del(es, l, e); 22366a63635SJoe Thornber return e; 22466a63635SJoe Thornber } 22566a63635SJoe Thornber 22666a63635SJoe Thornber return NULL; 22766a63635SJoe Thornber } 22866a63635SJoe Thornber 22966a63635SJoe Thornber /*----------------------------------------------------------------*/ 23066a63635SJoe Thornber 23166a63635SJoe Thornber /* 23266a63635SJoe Thornber * The stochastic-multi-queue is a set of lru lists stacked into levels. 23366a63635SJoe Thornber * Entries are moved up levels when they are used, which loosely orders the 23466a63635SJoe Thornber * most accessed entries in the top levels and least in the bottom. This 23566a63635SJoe Thornber * structure is *much* better than a single lru list. 23666a63635SJoe Thornber */ 23766a63635SJoe Thornber #define MAX_LEVELS 64u 23866a63635SJoe Thornber 23966a63635SJoe Thornber struct queue { 24066a63635SJoe Thornber struct entry_space *es; 24166a63635SJoe Thornber 24266a63635SJoe Thornber unsigned nr_elts; 24366a63635SJoe Thornber unsigned nr_levels; 24466a63635SJoe Thornber struct ilist qs[MAX_LEVELS]; 24566a63635SJoe Thornber 24666a63635SJoe Thornber /* 24766a63635SJoe Thornber * We maintain a count of the number of entries we would like in each 24866a63635SJoe Thornber * level. 24966a63635SJoe Thornber */ 25066a63635SJoe Thornber unsigned last_target_nr_elts; 25166a63635SJoe Thornber unsigned nr_top_levels; 25266a63635SJoe Thornber unsigned nr_in_top_levels; 25366a63635SJoe Thornber unsigned target_count[MAX_LEVELS]; 25466a63635SJoe Thornber }; 25566a63635SJoe Thornber 25666a63635SJoe Thornber static void q_init(struct queue *q, struct entry_space *es, unsigned nr_levels) 25766a63635SJoe Thornber { 25866a63635SJoe Thornber unsigned i; 25966a63635SJoe Thornber 26066a63635SJoe Thornber q->es = es; 26166a63635SJoe Thornber q->nr_elts = 0; 26266a63635SJoe Thornber q->nr_levels = nr_levels; 26366a63635SJoe Thornber 26466a63635SJoe Thornber for (i = 0; i < q->nr_levels; i++) { 26566a63635SJoe Thornber l_init(q->qs + i); 26666a63635SJoe Thornber q->target_count[i] = 0u; 26766a63635SJoe Thornber } 26866a63635SJoe Thornber 26966a63635SJoe Thornber q->last_target_nr_elts = 0u; 27066a63635SJoe Thornber q->nr_top_levels = 0u; 27166a63635SJoe Thornber q->nr_in_top_levels = 0u; 27266a63635SJoe Thornber } 27366a63635SJoe Thornber 27466a63635SJoe Thornber static unsigned q_size(struct queue *q) 27566a63635SJoe Thornber { 27666a63635SJoe Thornber return q->nr_elts; 27766a63635SJoe Thornber } 27866a63635SJoe Thornber 27966a63635SJoe Thornber /* 28066a63635SJoe Thornber * Insert an entry to the back of the given level. 28166a63635SJoe Thornber */ 28266a63635SJoe Thornber static void q_push(struct queue *q, struct entry *e) 28366a63635SJoe Thornber { 284b29d4986SJoe Thornber BUG_ON(e->pending_work); 285b29d4986SJoe Thornber 28666a63635SJoe Thornber if (!e->sentinel) 28766a63635SJoe Thornber q->nr_elts++; 28866a63635SJoe Thornber 28966a63635SJoe Thornber l_add_tail(q->es, q->qs + e->level, e); 29066a63635SJoe Thornber } 29166a63635SJoe Thornber 292b29d4986SJoe Thornber static void q_push_front(struct queue *q, struct entry *e) 293b29d4986SJoe Thornber { 294b29d4986SJoe Thornber BUG_ON(e->pending_work); 295b29d4986SJoe Thornber 296b29d4986SJoe Thornber if (!e->sentinel) 297b29d4986SJoe Thornber q->nr_elts++; 298b29d4986SJoe Thornber 299b29d4986SJoe Thornber l_add_head(q->es, q->qs + e->level, e); 300b29d4986SJoe Thornber } 301b29d4986SJoe Thornber 30266a63635SJoe Thornber static void q_push_before(struct queue *q, struct entry *old, struct entry *e) 30366a63635SJoe Thornber { 304b29d4986SJoe Thornber BUG_ON(e->pending_work); 305b29d4986SJoe Thornber 30666a63635SJoe Thornber if (!e->sentinel) 30766a63635SJoe Thornber q->nr_elts++; 30866a63635SJoe Thornber 30966a63635SJoe Thornber l_add_before(q->es, q->qs + e->level, old, e); 31066a63635SJoe Thornber } 31166a63635SJoe Thornber 31266a63635SJoe Thornber static void q_del(struct queue *q, struct entry *e) 31366a63635SJoe Thornber { 31466a63635SJoe Thornber l_del(q->es, q->qs + e->level, e); 31566a63635SJoe Thornber if (!e->sentinel) 31666a63635SJoe Thornber q->nr_elts--; 31766a63635SJoe Thornber } 31866a63635SJoe Thornber 31966a63635SJoe Thornber /* 32066a63635SJoe Thornber * Return the oldest entry of the lowest populated level. 32166a63635SJoe Thornber */ 32266a63635SJoe Thornber static struct entry *q_peek(struct queue *q, unsigned max_level, bool can_cross_sentinel) 32366a63635SJoe Thornber { 32466a63635SJoe Thornber unsigned level; 32566a63635SJoe Thornber struct entry *e; 32666a63635SJoe Thornber 32766a63635SJoe Thornber max_level = min(max_level, q->nr_levels); 32866a63635SJoe Thornber 32966a63635SJoe Thornber for (level = 0; level < max_level; level++) 33066a63635SJoe Thornber for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e)) { 33166a63635SJoe Thornber if (e->sentinel) { 33266a63635SJoe Thornber if (can_cross_sentinel) 33366a63635SJoe Thornber continue; 33466a63635SJoe Thornber else 33566a63635SJoe Thornber break; 33666a63635SJoe Thornber } 33766a63635SJoe Thornber 33866a63635SJoe Thornber return e; 33966a63635SJoe Thornber } 34066a63635SJoe Thornber 34166a63635SJoe Thornber return NULL; 34266a63635SJoe Thornber } 34366a63635SJoe Thornber 34466a63635SJoe Thornber static struct entry *q_pop(struct queue *q) 34566a63635SJoe Thornber { 34666a63635SJoe Thornber struct entry *e = q_peek(q, q->nr_levels, true); 34766a63635SJoe Thornber 34866a63635SJoe Thornber if (e) 34966a63635SJoe Thornber q_del(q, e); 35066a63635SJoe Thornber 35166a63635SJoe Thornber return e; 35266a63635SJoe Thornber } 35366a63635SJoe Thornber 35466a63635SJoe Thornber /* 35566a63635SJoe Thornber * This function assumes there is a non-sentinel entry to pop. It's only 35666a63635SJoe Thornber * used by redistribute, so we know this is true. It also doesn't adjust 35766a63635SJoe Thornber * the q->nr_elts count. 35866a63635SJoe Thornber */ 35966a63635SJoe Thornber static struct entry *__redist_pop_from(struct queue *q, unsigned level) 36066a63635SJoe Thornber { 36166a63635SJoe Thornber struct entry *e; 36266a63635SJoe Thornber 36366a63635SJoe Thornber for (; level < q->nr_levels; level++) 36466a63635SJoe Thornber for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e)) 36566a63635SJoe Thornber if (!e->sentinel) { 36666a63635SJoe Thornber l_del(q->es, q->qs + e->level, e); 36766a63635SJoe Thornber return e; 36866a63635SJoe Thornber } 36966a63635SJoe Thornber 37066a63635SJoe Thornber return NULL; 37166a63635SJoe Thornber } 37266a63635SJoe Thornber 37366a63635SJoe Thornber static void q_set_targets_subrange_(struct queue *q, unsigned nr_elts, unsigned lbegin, unsigned lend) 37466a63635SJoe Thornber { 37566a63635SJoe Thornber unsigned level, nr_levels, entries_per_level, remainder; 37666a63635SJoe Thornber 37766a63635SJoe Thornber BUG_ON(lbegin > lend); 37866a63635SJoe Thornber BUG_ON(lend > q->nr_levels); 37966a63635SJoe Thornber nr_levels = lend - lbegin; 38066a63635SJoe Thornber entries_per_level = safe_div(nr_elts, nr_levels); 38166a63635SJoe Thornber remainder = safe_mod(nr_elts, nr_levels); 38266a63635SJoe Thornber 38366a63635SJoe Thornber for (level = lbegin; level < lend; level++) 38466a63635SJoe Thornber q->target_count[level] = 38566a63635SJoe Thornber (level < (lbegin + remainder)) ? entries_per_level + 1u : entries_per_level; 38666a63635SJoe Thornber } 38766a63635SJoe Thornber 38866a63635SJoe Thornber /* 38966a63635SJoe Thornber * Typically we have fewer elements in the top few levels which allows us 39066a63635SJoe Thornber * to adjust the promote threshold nicely. 39166a63635SJoe Thornber */ 39266a63635SJoe Thornber static void q_set_targets(struct queue *q) 39366a63635SJoe Thornber { 39466a63635SJoe Thornber if (q->last_target_nr_elts == q->nr_elts) 39566a63635SJoe Thornber return; 39666a63635SJoe Thornber 39766a63635SJoe Thornber q->last_target_nr_elts = q->nr_elts; 39866a63635SJoe Thornber 39966a63635SJoe Thornber if (q->nr_top_levels > q->nr_levels) 40066a63635SJoe Thornber q_set_targets_subrange_(q, q->nr_elts, 0, q->nr_levels); 40166a63635SJoe Thornber 40266a63635SJoe Thornber else { 40366a63635SJoe Thornber q_set_targets_subrange_(q, q->nr_in_top_levels, 40466a63635SJoe Thornber q->nr_levels - q->nr_top_levels, q->nr_levels); 40566a63635SJoe Thornber 40666a63635SJoe Thornber if (q->nr_in_top_levels < q->nr_elts) 40766a63635SJoe Thornber q_set_targets_subrange_(q, q->nr_elts - q->nr_in_top_levels, 40866a63635SJoe Thornber 0, q->nr_levels - q->nr_top_levels); 40966a63635SJoe Thornber else 41066a63635SJoe Thornber q_set_targets_subrange_(q, 0, 0, q->nr_levels - q->nr_top_levels); 41166a63635SJoe Thornber } 41266a63635SJoe Thornber } 41366a63635SJoe Thornber 41466a63635SJoe Thornber static void q_redistribute(struct queue *q) 41566a63635SJoe Thornber { 41666a63635SJoe Thornber unsigned target, level; 41766a63635SJoe Thornber struct ilist *l, *l_above; 41866a63635SJoe Thornber struct entry *e; 41966a63635SJoe Thornber 42066a63635SJoe Thornber q_set_targets(q); 42166a63635SJoe Thornber 42266a63635SJoe Thornber for (level = 0u; level < q->nr_levels - 1u; level++) { 42366a63635SJoe Thornber l = q->qs + level; 42466a63635SJoe Thornber target = q->target_count[level]; 42566a63635SJoe Thornber 42666a63635SJoe Thornber /* 42766a63635SJoe Thornber * Pull down some entries from the level above. 42866a63635SJoe Thornber */ 42966a63635SJoe Thornber while (l->nr_elts < target) { 43066a63635SJoe Thornber e = __redist_pop_from(q, level + 1u); 43166a63635SJoe Thornber if (!e) { 43266a63635SJoe Thornber /* bug in nr_elts */ 43366a63635SJoe Thornber break; 43466a63635SJoe Thornber } 43566a63635SJoe Thornber 43666a63635SJoe Thornber e->level = level; 43766a63635SJoe Thornber l_add_tail(q->es, l, e); 43866a63635SJoe Thornber } 43966a63635SJoe Thornber 44066a63635SJoe Thornber /* 44166a63635SJoe Thornber * Push some entries up. 44266a63635SJoe Thornber */ 44366a63635SJoe Thornber l_above = q->qs + level + 1u; 44466a63635SJoe Thornber while (l->nr_elts > target) { 44566a63635SJoe Thornber e = l_pop_tail(q->es, l); 44666a63635SJoe Thornber 44766a63635SJoe Thornber if (!e) 44866a63635SJoe Thornber /* bug in nr_elts */ 44966a63635SJoe Thornber break; 45066a63635SJoe Thornber 45166a63635SJoe Thornber e->level = level + 1u; 452b29d4986SJoe Thornber l_add_tail(q->es, l_above, e); 45366a63635SJoe Thornber } 45466a63635SJoe Thornber } 45566a63635SJoe Thornber } 45666a63635SJoe Thornber 457b29d4986SJoe Thornber static void q_requeue(struct queue *q, struct entry *e, unsigned extra_levels, 458b29d4986SJoe Thornber struct entry *s1, struct entry *s2) 45966a63635SJoe Thornber { 46066a63635SJoe Thornber struct entry *de; 461b29d4986SJoe Thornber unsigned sentinels_passed = 0; 462b29d4986SJoe Thornber unsigned new_level = min(q->nr_levels - 1u, e->level + extra_levels); 46366a63635SJoe Thornber 464b29d4986SJoe Thornber /* try and find an entry to swap with */ 46566a63635SJoe Thornber if (extra_levels && (e->level < q->nr_levels - 1u)) { 466b29d4986SJoe Thornber for (de = l_head(q->es, q->qs + new_level); de && de->sentinel; de = l_next(q->es, de)) 467b29d4986SJoe Thornber sentinels_passed++; 46866a63635SJoe Thornber 469b29d4986SJoe Thornber if (de) { 47066a63635SJoe Thornber q_del(q, de); 47166a63635SJoe Thornber de->level = e->level; 472b29d4986SJoe Thornber if (s1) { 473b29d4986SJoe Thornber switch (sentinels_passed) { 474b29d4986SJoe Thornber case 0: 475b29d4986SJoe Thornber q_push_before(q, s1, de); 47666a63635SJoe Thornber break; 477b29d4986SJoe Thornber 478b29d4986SJoe Thornber case 1: 479b29d4986SJoe Thornber q_push_before(q, s2, de); 480b29d4986SJoe Thornber break; 481b29d4986SJoe Thornber 482b29d4986SJoe Thornber default: 483b29d4986SJoe Thornber q_push(q, de); 484b29d4986SJoe Thornber } 485b29d4986SJoe Thornber } else 486b29d4986SJoe Thornber q_push(q, de); 487b29d4986SJoe Thornber } 48866a63635SJoe Thornber } 48966a63635SJoe Thornber 490b29d4986SJoe Thornber q_del(q, e); 49166a63635SJoe Thornber e->level = new_level; 49266a63635SJoe Thornber q_push(q, e); 49366a63635SJoe Thornber } 49466a63635SJoe Thornber 49566a63635SJoe Thornber /*----------------------------------------------------------------*/ 49666a63635SJoe Thornber 49766a63635SJoe Thornber #define FP_SHIFT 8 49866a63635SJoe Thornber #define SIXTEENTH (1u << (FP_SHIFT - 4u)) 49966a63635SJoe Thornber #define EIGHTH (1u << (FP_SHIFT - 3u)) 50066a63635SJoe Thornber 50166a63635SJoe Thornber struct stats { 50266a63635SJoe Thornber unsigned hit_threshold; 50366a63635SJoe Thornber unsigned hits; 50466a63635SJoe Thornber unsigned misses; 50566a63635SJoe Thornber }; 50666a63635SJoe Thornber 50766a63635SJoe Thornber enum performance { 50866a63635SJoe Thornber Q_POOR, 50966a63635SJoe Thornber Q_FAIR, 51066a63635SJoe Thornber Q_WELL 51166a63635SJoe Thornber }; 51266a63635SJoe Thornber 51366a63635SJoe Thornber static void stats_init(struct stats *s, unsigned nr_levels) 51466a63635SJoe Thornber { 51566a63635SJoe Thornber s->hit_threshold = (nr_levels * 3u) / 4u; 51666a63635SJoe Thornber s->hits = 0u; 51766a63635SJoe Thornber s->misses = 0u; 51866a63635SJoe Thornber } 51966a63635SJoe Thornber 52066a63635SJoe Thornber static void stats_reset(struct stats *s) 52166a63635SJoe Thornber { 52266a63635SJoe Thornber s->hits = s->misses = 0u; 52366a63635SJoe Thornber } 52466a63635SJoe Thornber 52566a63635SJoe Thornber static void stats_level_accessed(struct stats *s, unsigned level) 52666a63635SJoe Thornber { 52766a63635SJoe Thornber if (level >= s->hit_threshold) 52866a63635SJoe Thornber s->hits++; 52966a63635SJoe Thornber else 53066a63635SJoe Thornber s->misses++; 53166a63635SJoe Thornber } 53266a63635SJoe Thornber 53366a63635SJoe Thornber static void stats_miss(struct stats *s) 53466a63635SJoe Thornber { 53566a63635SJoe Thornber s->misses++; 53666a63635SJoe Thornber } 53766a63635SJoe Thornber 53866a63635SJoe Thornber /* 53966a63635SJoe Thornber * There are times when we don't have any confidence in the hotspot queue. 54066a63635SJoe Thornber * Such as when a fresh cache is created and the blocks have been spread 54166a63635SJoe Thornber * out across the levels, or if an io load changes. We detect this by 54266a63635SJoe Thornber * seeing how often a lookup is in the top levels of the hotspot queue. 54366a63635SJoe Thornber */ 54466a63635SJoe Thornber static enum performance stats_assess(struct stats *s) 54566a63635SJoe Thornber { 54666a63635SJoe Thornber unsigned confidence = safe_div(s->hits << FP_SHIFT, s->hits + s->misses); 54766a63635SJoe Thornber 54866a63635SJoe Thornber if (confidence < SIXTEENTH) 54966a63635SJoe Thornber return Q_POOR; 55066a63635SJoe Thornber 55166a63635SJoe Thornber else if (confidence < EIGHTH) 55266a63635SJoe Thornber return Q_FAIR; 55366a63635SJoe Thornber 55466a63635SJoe Thornber else 55566a63635SJoe Thornber return Q_WELL; 55666a63635SJoe Thornber } 55766a63635SJoe Thornber 55866a63635SJoe Thornber /*----------------------------------------------------------------*/ 55966a63635SJoe Thornber 560b29d4986SJoe Thornber struct smq_hash_table { 56166a63635SJoe Thornber struct entry_space *es; 56266a63635SJoe Thornber unsigned long long hash_bits; 56366a63635SJoe Thornber unsigned *buckets; 56466a63635SJoe Thornber }; 56566a63635SJoe Thornber 56666a63635SJoe Thornber /* 56766a63635SJoe Thornber * All cache entries are stored in a chained hash table. To save space we 56866a63635SJoe Thornber * use indexing again, and only store indexes to the next entry. 56966a63635SJoe Thornber */ 570b29d4986SJoe Thornber static int h_init(struct smq_hash_table *ht, struct entry_space *es, unsigned nr_entries) 57166a63635SJoe Thornber { 57266a63635SJoe Thornber unsigned i, nr_buckets; 57366a63635SJoe Thornber 57466a63635SJoe Thornber ht->es = es; 57566a63635SJoe Thornber nr_buckets = roundup_pow_of_two(max(nr_entries / 4u, 16u)); 576a3d939aeSMikulas Patocka ht->hash_bits = __ffs(nr_buckets); 57766a63635SJoe Thornber 57866a63635SJoe Thornber ht->buckets = vmalloc(sizeof(*ht->buckets) * nr_buckets); 57966a63635SJoe Thornber if (!ht->buckets) 58066a63635SJoe Thornber return -ENOMEM; 58166a63635SJoe Thornber 58266a63635SJoe Thornber for (i = 0; i < nr_buckets; i++) 58366a63635SJoe Thornber ht->buckets[i] = INDEXER_NULL; 58466a63635SJoe Thornber 58566a63635SJoe Thornber return 0; 58666a63635SJoe Thornber } 58766a63635SJoe Thornber 588b29d4986SJoe Thornber static void h_exit(struct smq_hash_table *ht) 58966a63635SJoe Thornber { 59066a63635SJoe Thornber vfree(ht->buckets); 59166a63635SJoe Thornber } 59266a63635SJoe Thornber 593b29d4986SJoe Thornber static struct entry *h_head(struct smq_hash_table *ht, unsigned bucket) 59466a63635SJoe Thornber { 59566a63635SJoe Thornber return to_entry(ht->es, ht->buckets[bucket]); 59666a63635SJoe Thornber } 59766a63635SJoe Thornber 598b29d4986SJoe Thornber static struct entry *h_next(struct smq_hash_table *ht, struct entry *e) 59966a63635SJoe Thornber { 60066a63635SJoe Thornber return to_entry(ht->es, e->hash_next); 60166a63635SJoe Thornber } 60266a63635SJoe Thornber 603b29d4986SJoe Thornber static void __h_insert(struct smq_hash_table *ht, unsigned bucket, struct entry *e) 60466a63635SJoe Thornber { 60566a63635SJoe Thornber e->hash_next = ht->buckets[bucket]; 60666a63635SJoe Thornber ht->buckets[bucket] = to_index(ht->es, e); 60766a63635SJoe Thornber } 60866a63635SJoe Thornber 609b29d4986SJoe Thornber static void h_insert(struct smq_hash_table *ht, struct entry *e) 61066a63635SJoe Thornber { 61166a63635SJoe Thornber unsigned h = hash_64(from_oblock(e->oblock), ht->hash_bits); 61266a63635SJoe Thornber __h_insert(ht, h, e); 61366a63635SJoe Thornber } 61466a63635SJoe Thornber 615b29d4986SJoe Thornber static struct entry *__h_lookup(struct smq_hash_table *ht, unsigned h, dm_oblock_t oblock, 61666a63635SJoe Thornber struct entry **prev) 61766a63635SJoe Thornber { 61866a63635SJoe Thornber struct entry *e; 61966a63635SJoe Thornber 62066a63635SJoe Thornber *prev = NULL; 62166a63635SJoe Thornber for (e = h_head(ht, h); e; e = h_next(ht, e)) { 62266a63635SJoe Thornber if (e->oblock == oblock) 62366a63635SJoe Thornber return e; 62466a63635SJoe Thornber 62566a63635SJoe Thornber *prev = e; 62666a63635SJoe Thornber } 62766a63635SJoe Thornber 62866a63635SJoe Thornber return NULL; 62966a63635SJoe Thornber } 63066a63635SJoe Thornber 631b29d4986SJoe Thornber static void __h_unlink(struct smq_hash_table *ht, unsigned h, 63266a63635SJoe Thornber struct entry *e, struct entry *prev) 63366a63635SJoe Thornber { 63466a63635SJoe Thornber if (prev) 63566a63635SJoe Thornber prev->hash_next = e->hash_next; 63666a63635SJoe Thornber else 63766a63635SJoe Thornber ht->buckets[h] = e->hash_next; 63866a63635SJoe Thornber } 63966a63635SJoe Thornber 64066a63635SJoe Thornber /* 64166a63635SJoe Thornber * Also moves each entry to the front of the bucket. 64266a63635SJoe Thornber */ 643b29d4986SJoe Thornber static struct entry *h_lookup(struct smq_hash_table *ht, dm_oblock_t oblock) 64466a63635SJoe Thornber { 64566a63635SJoe Thornber struct entry *e, *prev; 64666a63635SJoe Thornber unsigned h = hash_64(from_oblock(oblock), ht->hash_bits); 64766a63635SJoe Thornber 64866a63635SJoe Thornber e = __h_lookup(ht, h, oblock, &prev); 64966a63635SJoe Thornber if (e && prev) { 65066a63635SJoe Thornber /* 65166a63635SJoe Thornber * Move to the front because this entry is likely 65266a63635SJoe Thornber * to be hit again. 65366a63635SJoe Thornber */ 65466a63635SJoe Thornber __h_unlink(ht, h, e, prev); 65566a63635SJoe Thornber __h_insert(ht, h, e); 65666a63635SJoe Thornber } 65766a63635SJoe Thornber 65866a63635SJoe Thornber return e; 65966a63635SJoe Thornber } 66066a63635SJoe Thornber 661b29d4986SJoe Thornber static void h_remove(struct smq_hash_table *ht, struct entry *e) 66266a63635SJoe Thornber { 66366a63635SJoe Thornber unsigned h = hash_64(from_oblock(e->oblock), ht->hash_bits); 66466a63635SJoe Thornber struct entry *prev; 66566a63635SJoe Thornber 66666a63635SJoe Thornber /* 66766a63635SJoe Thornber * The down side of using a singly linked list is we have to 66866a63635SJoe Thornber * iterate the bucket to remove an item. 66966a63635SJoe Thornber */ 67066a63635SJoe Thornber e = __h_lookup(ht, h, e->oblock, &prev); 67166a63635SJoe Thornber if (e) 67266a63635SJoe Thornber __h_unlink(ht, h, e, prev); 67366a63635SJoe Thornber } 67466a63635SJoe Thornber 67566a63635SJoe Thornber /*----------------------------------------------------------------*/ 67666a63635SJoe Thornber 67766a63635SJoe Thornber struct entry_alloc { 67866a63635SJoe Thornber struct entry_space *es; 67966a63635SJoe Thornber unsigned begin; 68066a63635SJoe Thornber 68166a63635SJoe Thornber unsigned nr_allocated; 68266a63635SJoe Thornber struct ilist free; 68366a63635SJoe Thornber }; 68466a63635SJoe Thornber 68566a63635SJoe Thornber static void init_allocator(struct entry_alloc *ea, struct entry_space *es, 68666a63635SJoe Thornber unsigned begin, unsigned end) 68766a63635SJoe Thornber { 68866a63635SJoe Thornber unsigned i; 68966a63635SJoe Thornber 69066a63635SJoe Thornber ea->es = es; 69166a63635SJoe Thornber ea->nr_allocated = 0u; 69266a63635SJoe Thornber ea->begin = begin; 69366a63635SJoe Thornber 69466a63635SJoe Thornber l_init(&ea->free); 69566a63635SJoe Thornber for (i = begin; i != end; i++) 69666a63635SJoe Thornber l_add_tail(ea->es, &ea->free, __get_entry(ea->es, i)); 69766a63635SJoe Thornber } 69866a63635SJoe Thornber 69966a63635SJoe Thornber static void init_entry(struct entry *e) 70066a63635SJoe Thornber { 70166a63635SJoe Thornber /* 70266a63635SJoe Thornber * We can't memset because that would clear the hotspot and 70366a63635SJoe Thornber * sentinel bits which remain constant. 70466a63635SJoe Thornber */ 70566a63635SJoe Thornber e->hash_next = INDEXER_NULL; 70666a63635SJoe Thornber e->next = INDEXER_NULL; 70766a63635SJoe Thornber e->prev = INDEXER_NULL; 70866a63635SJoe Thornber e->level = 0u; 709b29d4986SJoe Thornber e->dirty = true; /* FIXME: audit */ 71066a63635SJoe Thornber e->allocated = true; 711b29d4986SJoe Thornber e->sentinel = false; 712b29d4986SJoe Thornber e->pending_work = false; 71366a63635SJoe Thornber } 71466a63635SJoe Thornber 71566a63635SJoe Thornber static struct entry *alloc_entry(struct entry_alloc *ea) 71666a63635SJoe Thornber { 71766a63635SJoe Thornber struct entry *e; 71866a63635SJoe Thornber 71966a63635SJoe Thornber if (l_empty(&ea->free)) 72066a63635SJoe Thornber return NULL; 72166a63635SJoe Thornber 72266a63635SJoe Thornber e = l_pop_tail(ea->es, &ea->free); 72366a63635SJoe Thornber init_entry(e); 72466a63635SJoe Thornber ea->nr_allocated++; 72566a63635SJoe Thornber 72666a63635SJoe Thornber return e; 72766a63635SJoe Thornber } 72866a63635SJoe Thornber 72966a63635SJoe Thornber /* 73066a63635SJoe Thornber * This assumes the cblock hasn't already been allocated. 73166a63635SJoe Thornber */ 73266a63635SJoe Thornber static struct entry *alloc_particular_entry(struct entry_alloc *ea, unsigned i) 73366a63635SJoe Thornber { 73466a63635SJoe Thornber struct entry *e = __get_entry(ea->es, ea->begin + i); 73566a63635SJoe Thornber 73666a63635SJoe Thornber BUG_ON(e->allocated); 73766a63635SJoe Thornber 73866a63635SJoe Thornber l_del(ea->es, &ea->free, e); 73966a63635SJoe Thornber init_entry(e); 74066a63635SJoe Thornber ea->nr_allocated++; 74166a63635SJoe Thornber 74266a63635SJoe Thornber return e; 74366a63635SJoe Thornber } 74466a63635SJoe Thornber 74566a63635SJoe Thornber static void free_entry(struct entry_alloc *ea, struct entry *e) 74666a63635SJoe Thornber { 74766a63635SJoe Thornber BUG_ON(!ea->nr_allocated); 74866a63635SJoe Thornber BUG_ON(!e->allocated); 74966a63635SJoe Thornber 75066a63635SJoe Thornber ea->nr_allocated--; 75166a63635SJoe Thornber e->allocated = false; 75266a63635SJoe Thornber l_add_tail(ea->es, &ea->free, e); 75366a63635SJoe Thornber } 75466a63635SJoe Thornber 75566a63635SJoe Thornber static bool allocator_empty(struct entry_alloc *ea) 75666a63635SJoe Thornber { 75766a63635SJoe Thornber return l_empty(&ea->free); 75866a63635SJoe Thornber } 75966a63635SJoe Thornber 76066a63635SJoe Thornber static unsigned get_index(struct entry_alloc *ea, struct entry *e) 76166a63635SJoe Thornber { 76266a63635SJoe Thornber return to_index(ea->es, e) - ea->begin; 76366a63635SJoe Thornber } 76466a63635SJoe Thornber 76566a63635SJoe Thornber static struct entry *get_entry(struct entry_alloc *ea, unsigned index) 76666a63635SJoe Thornber { 76766a63635SJoe Thornber return __get_entry(ea->es, ea->begin + index); 76866a63635SJoe Thornber } 76966a63635SJoe Thornber 77066a63635SJoe Thornber /*----------------------------------------------------------------*/ 77166a63635SJoe Thornber 77266a63635SJoe Thornber #define NR_HOTSPOT_LEVELS 64u 77366a63635SJoe Thornber #define NR_CACHE_LEVELS 64u 77466a63635SJoe Thornber 775b29d4986SJoe Thornber #define WRITEBACK_PERIOD (10ul * HZ) 776b29d4986SJoe Thornber #define DEMOTE_PERIOD (60ul * HZ) 77766a63635SJoe Thornber 77866a63635SJoe Thornber #define HOTSPOT_UPDATE_PERIOD (HZ) 779b29d4986SJoe Thornber #define CACHE_UPDATE_PERIOD (60ul * HZ) 78066a63635SJoe Thornber 78166a63635SJoe Thornber struct smq_policy { 78266a63635SJoe Thornber struct dm_cache_policy policy; 78366a63635SJoe Thornber 78466a63635SJoe Thornber /* protects everything */ 7854051aab7SJoe Thornber spinlock_t lock; 78666a63635SJoe Thornber dm_cblock_t cache_size; 78766a63635SJoe Thornber sector_t cache_block_size; 78866a63635SJoe Thornber 78966a63635SJoe Thornber sector_t hotspot_block_size; 79066a63635SJoe Thornber unsigned nr_hotspot_blocks; 79166a63635SJoe Thornber unsigned cache_blocks_per_hotspot_block; 79266a63635SJoe Thornber unsigned hotspot_level_jump; 79366a63635SJoe Thornber 79466a63635SJoe Thornber struct entry_space es; 79566a63635SJoe Thornber struct entry_alloc writeback_sentinel_alloc; 79666a63635SJoe Thornber struct entry_alloc demote_sentinel_alloc; 79766a63635SJoe Thornber struct entry_alloc hotspot_alloc; 79866a63635SJoe Thornber struct entry_alloc cache_alloc; 79966a63635SJoe Thornber 80066a63635SJoe Thornber unsigned long *hotspot_hit_bits; 80166a63635SJoe Thornber unsigned long *cache_hit_bits; 80266a63635SJoe Thornber 80366a63635SJoe Thornber /* 80466a63635SJoe Thornber * We maintain three queues of entries. The cache proper, 80566a63635SJoe Thornber * consisting of a clean and dirty queue, containing the currently 80666a63635SJoe Thornber * active mappings. The hotspot queue uses a larger block size to 80766a63635SJoe Thornber * track blocks that are being hit frequently and potential 80866a63635SJoe Thornber * candidates for promotion to the cache. 80966a63635SJoe Thornber */ 81066a63635SJoe Thornber struct queue hotspot; 81166a63635SJoe Thornber struct queue clean; 81266a63635SJoe Thornber struct queue dirty; 81366a63635SJoe Thornber 81466a63635SJoe Thornber struct stats hotspot_stats; 81566a63635SJoe Thornber struct stats cache_stats; 81666a63635SJoe Thornber 81766a63635SJoe Thornber /* 81866a63635SJoe Thornber * Keeps track of time, incremented by the core. We use this to 81966a63635SJoe Thornber * avoid attributing multiple hits within the same tick. 82066a63635SJoe Thornber */ 82166a63635SJoe Thornber unsigned tick; 82266a63635SJoe Thornber 82366a63635SJoe Thornber /* 82466a63635SJoe Thornber * The hash tables allows us to quickly find an entry by origin 82566a63635SJoe Thornber * block. 82666a63635SJoe Thornber */ 827b29d4986SJoe Thornber struct smq_hash_table table; 828b29d4986SJoe Thornber struct smq_hash_table hotspot_table; 82966a63635SJoe Thornber 83066a63635SJoe Thornber bool current_writeback_sentinels; 83166a63635SJoe Thornber unsigned long next_writeback_period; 83266a63635SJoe Thornber 83366a63635SJoe Thornber bool current_demote_sentinels; 83466a63635SJoe Thornber unsigned long next_demote_period; 83566a63635SJoe Thornber 83666a63635SJoe Thornber unsigned write_promote_level; 83766a63635SJoe Thornber unsigned read_promote_level; 83866a63635SJoe Thornber 83966a63635SJoe Thornber unsigned long next_hotspot_period; 84066a63635SJoe Thornber unsigned long next_cache_period; 841b29d4986SJoe Thornber 842b29d4986SJoe Thornber struct background_tracker *bg_work; 843b29d4986SJoe Thornber 844b29d4986SJoe Thornber bool migrations_allowed; 84566a63635SJoe Thornber }; 84666a63635SJoe Thornber 84766a63635SJoe Thornber /*----------------------------------------------------------------*/ 84866a63635SJoe Thornber 84966a63635SJoe Thornber static struct entry *get_sentinel(struct entry_alloc *ea, unsigned level, bool which) 85066a63635SJoe Thornber { 85166a63635SJoe Thornber return get_entry(ea, which ? level : NR_CACHE_LEVELS + level); 85266a63635SJoe Thornber } 85366a63635SJoe Thornber 85466a63635SJoe Thornber static struct entry *writeback_sentinel(struct smq_policy *mq, unsigned level) 85566a63635SJoe Thornber { 85666a63635SJoe Thornber return get_sentinel(&mq->writeback_sentinel_alloc, level, mq->current_writeback_sentinels); 85766a63635SJoe Thornber } 85866a63635SJoe Thornber 85966a63635SJoe Thornber static struct entry *demote_sentinel(struct smq_policy *mq, unsigned level) 86066a63635SJoe Thornber { 86166a63635SJoe Thornber return get_sentinel(&mq->demote_sentinel_alloc, level, mq->current_demote_sentinels); 86266a63635SJoe Thornber } 86366a63635SJoe Thornber 86466a63635SJoe Thornber static void __update_writeback_sentinels(struct smq_policy *mq) 86566a63635SJoe Thornber { 86666a63635SJoe Thornber unsigned level; 86766a63635SJoe Thornber struct queue *q = &mq->dirty; 86866a63635SJoe Thornber struct entry *sentinel; 86966a63635SJoe Thornber 87066a63635SJoe Thornber for (level = 0; level < q->nr_levels; level++) { 87166a63635SJoe Thornber sentinel = writeback_sentinel(mq, level); 87266a63635SJoe Thornber q_del(q, sentinel); 87366a63635SJoe Thornber q_push(q, sentinel); 87466a63635SJoe Thornber } 87566a63635SJoe Thornber } 87666a63635SJoe Thornber 87766a63635SJoe Thornber static void __update_demote_sentinels(struct smq_policy *mq) 87866a63635SJoe Thornber { 87966a63635SJoe Thornber unsigned level; 88066a63635SJoe Thornber struct queue *q = &mq->clean; 88166a63635SJoe Thornber struct entry *sentinel; 88266a63635SJoe Thornber 88366a63635SJoe Thornber for (level = 0; level < q->nr_levels; level++) { 88466a63635SJoe Thornber sentinel = demote_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_sentinels(struct smq_policy *mq) 89166a63635SJoe Thornber { 89266a63635SJoe Thornber if (time_after(jiffies, mq->next_writeback_period)) { 89366a63635SJoe Thornber mq->next_writeback_period = jiffies + WRITEBACK_PERIOD; 89466a63635SJoe Thornber mq->current_writeback_sentinels = !mq->current_writeback_sentinels; 895b29d4986SJoe Thornber __update_writeback_sentinels(mq); 89666a63635SJoe Thornber } 89766a63635SJoe Thornber 89866a63635SJoe Thornber if (time_after(jiffies, mq->next_demote_period)) { 89966a63635SJoe Thornber mq->next_demote_period = jiffies + DEMOTE_PERIOD; 90066a63635SJoe Thornber mq->current_demote_sentinels = !mq->current_demote_sentinels; 901b29d4986SJoe Thornber __update_demote_sentinels(mq); 90266a63635SJoe Thornber } 90366a63635SJoe Thornber } 90466a63635SJoe Thornber 90566a63635SJoe Thornber static void __sentinels_init(struct smq_policy *mq) 90666a63635SJoe Thornber { 90766a63635SJoe Thornber unsigned level; 90866a63635SJoe Thornber struct entry *sentinel; 90966a63635SJoe Thornber 91066a63635SJoe Thornber for (level = 0; level < NR_CACHE_LEVELS; level++) { 91166a63635SJoe Thornber sentinel = writeback_sentinel(mq, level); 91266a63635SJoe Thornber sentinel->level = level; 91366a63635SJoe Thornber q_push(&mq->dirty, sentinel); 91466a63635SJoe Thornber 91566a63635SJoe Thornber sentinel = demote_sentinel(mq, level); 91666a63635SJoe Thornber sentinel->level = level; 91766a63635SJoe Thornber q_push(&mq->clean, sentinel); 91866a63635SJoe Thornber } 91966a63635SJoe Thornber } 92066a63635SJoe Thornber 92166a63635SJoe Thornber static void sentinels_init(struct smq_policy *mq) 92266a63635SJoe Thornber { 92366a63635SJoe Thornber mq->next_writeback_period = jiffies + WRITEBACK_PERIOD; 92466a63635SJoe Thornber mq->next_demote_period = jiffies + DEMOTE_PERIOD; 92566a63635SJoe Thornber 92666a63635SJoe Thornber mq->current_writeback_sentinels = false; 92766a63635SJoe Thornber mq->current_demote_sentinels = false; 92866a63635SJoe Thornber __sentinels_init(mq); 92966a63635SJoe Thornber 93066a63635SJoe Thornber mq->current_writeback_sentinels = !mq->current_writeback_sentinels; 93166a63635SJoe Thornber mq->current_demote_sentinels = !mq->current_demote_sentinels; 93266a63635SJoe Thornber __sentinels_init(mq); 93366a63635SJoe Thornber } 93466a63635SJoe Thornber 93566a63635SJoe Thornber /*----------------------------------------------------------------*/ 93666a63635SJoe Thornber 937b29d4986SJoe Thornber static void del_queue(struct smq_policy *mq, struct entry *e) 93866a63635SJoe Thornber { 939b29d4986SJoe Thornber q_del(e->dirty ? &mq->dirty : &mq->clean, e); 94066a63635SJoe Thornber } 94166a63635SJoe Thornber 942b29d4986SJoe Thornber static void push_queue(struct smq_policy *mq, struct entry *e) 943b29d4986SJoe Thornber { 944b29d4986SJoe Thornber if (e->dirty) 945b29d4986SJoe Thornber q_push(&mq->dirty, e); 946b29d4986SJoe Thornber else 947b29d4986SJoe Thornber q_push(&mq->clean, e); 948b29d4986SJoe Thornber } 949b29d4986SJoe Thornber 950b29d4986SJoe Thornber // !h, !q, a -> h, q, a 95166a63635SJoe Thornber static void push(struct smq_policy *mq, struct entry *e) 95266a63635SJoe Thornber { 95366a63635SJoe Thornber h_insert(&mq->table, e); 954b29d4986SJoe Thornber if (!e->pending_work) 955b29d4986SJoe Thornber push_queue(mq, e); 95666a63635SJoe Thornber } 95766a63635SJoe Thornber 958b29d4986SJoe Thornber static void push_queue_front(struct smq_policy *mq, struct entry *e) 95966a63635SJoe Thornber { 960b29d4986SJoe Thornber if (e->dirty) 961b29d4986SJoe Thornber q_push_front(&mq->dirty, e); 962b29d4986SJoe Thornber else 963b29d4986SJoe Thornber q_push_front(&mq->clean, e); 96466a63635SJoe Thornber } 96566a63635SJoe Thornber 966b29d4986SJoe Thornber static void push_front(struct smq_policy *mq, struct entry *e) 96766a63635SJoe Thornber { 968b29d4986SJoe Thornber h_insert(&mq->table, e); 969b29d4986SJoe Thornber if (!e->pending_work) 970b29d4986SJoe Thornber push_queue_front(mq, e); 97166a63635SJoe Thornber } 97266a63635SJoe Thornber 97366a63635SJoe Thornber static dm_cblock_t infer_cblock(struct smq_policy *mq, struct entry *e) 97466a63635SJoe Thornber { 97566a63635SJoe Thornber return to_cblock(get_index(&mq->cache_alloc, e)); 97666a63635SJoe Thornber } 97766a63635SJoe Thornber 97866a63635SJoe Thornber static void requeue(struct smq_policy *mq, struct entry *e) 97966a63635SJoe Thornber { 980b29d4986SJoe Thornber /* 981b29d4986SJoe Thornber * Pending work has temporarily been taken out of the queues. 982b29d4986SJoe Thornber */ 983b29d4986SJoe Thornber if (e->pending_work) 984b29d4986SJoe Thornber return; 98566a63635SJoe Thornber 98666a63635SJoe Thornber if (!test_and_set_bit(from_cblock(infer_cblock(mq, e)), mq->cache_hit_bits)) { 987b29d4986SJoe Thornber if (!e->dirty) { 988b29d4986SJoe Thornber q_requeue(&mq->clean, e, 1u, NULL, NULL); 989b29d4986SJoe Thornber return; 99066a63635SJoe Thornber } 991b29d4986SJoe Thornber 992b29d4986SJoe Thornber q_requeue(&mq->dirty, e, 1u, 993b29d4986SJoe Thornber get_sentinel(&mq->writeback_sentinel_alloc, e->level, !mq->current_writeback_sentinels), 994b29d4986SJoe Thornber get_sentinel(&mq->writeback_sentinel_alloc, e->level, mq->current_writeback_sentinels)); 99566a63635SJoe Thornber } 99666a63635SJoe Thornber } 99766a63635SJoe Thornber 99866a63635SJoe Thornber static unsigned default_promote_level(struct smq_policy *mq) 99966a63635SJoe Thornber { 100066a63635SJoe Thornber /* 100166a63635SJoe Thornber * The promote level depends on the current performance of the 100266a63635SJoe Thornber * cache. 100366a63635SJoe Thornber * 100466a63635SJoe Thornber * If the cache is performing badly, then we can't afford 100566a63635SJoe Thornber * to promote much without causing performance to drop below that 100666a63635SJoe Thornber * of the origin device. 100766a63635SJoe Thornber * 100866a63635SJoe Thornber * If the cache is performing well, then we don't need to promote 100966a63635SJoe Thornber * much. If it isn't broken, don't fix it. 101066a63635SJoe Thornber * 101166a63635SJoe Thornber * If the cache is middling then we promote more. 101266a63635SJoe Thornber * 101366a63635SJoe Thornber * This scheme reminds me of a graph of entropy vs probability of a 101466a63635SJoe Thornber * binary variable. 101566a63635SJoe Thornber */ 101666a63635SJoe Thornber static unsigned table[] = {1, 1, 1, 2, 4, 6, 7, 8, 7, 6, 4, 4, 3, 3, 2, 2, 1}; 101766a63635SJoe Thornber 101866a63635SJoe Thornber unsigned hits = mq->cache_stats.hits; 101966a63635SJoe Thornber unsigned misses = mq->cache_stats.misses; 102066a63635SJoe Thornber unsigned index = safe_div(hits << 4u, hits + misses); 102166a63635SJoe Thornber return table[index]; 102266a63635SJoe Thornber } 102366a63635SJoe Thornber 102466a63635SJoe Thornber static void update_promote_levels(struct smq_policy *mq) 102566a63635SJoe Thornber { 102666a63635SJoe Thornber /* 102766a63635SJoe Thornber * If there are unused cache entries then we want to be really 102866a63635SJoe Thornber * eager to promote. 102966a63635SJoe Thornber */ 103066a63635SJoe Thornber unsigned threshold_level = allocator_empty(&mq->cache_alloc) ? 103166a63635SJoe Thornber default_promote_level(mq) : (NR_HOTSPOT_LEVELS / 2u); 103266a63635SJoe Thornber 1033b29d4986SJoe Thornber threshold_level = max(threshold_level, NR_HOTSPOT_LEVELS); 1034b29d4986SJoe Thornber 103566a63635SJoe Thornber /* 103666a63635SJoe Thornber * If the hotspot queue is performing badly then we have little 103766a63635SJoe Thornber * confidence that we know which blocks to promote. So we cut down 103866a63635SJoe Thornber * the amount of promotions. 103966a63635SJoe Thornber */ 104066a63635SJoe Thornber switch (stats_assess(&mq->hotspot_stats)) { 104166a63635SJoe Thornber case Q_POOR: 104266a63635SJoe Thornber threshold_level /= 4u; 104366a63635SJoe Thornber break; 104466a63635SJoe Thornber 104566a63635SJoe Thornber case Q_FAIR: 104666a63635SJoe Thornber threshold_level /= 2u; 104766a63635SJoe Thornber break; 104866a63635SJoe Thornber 104966a63635SJoe Thornber case Q_WELL: 105066a63635SJoe Thornber break; 105166a63635SJoe Thornber } 105266a63635SJoe Thornber 105366a63635SJoe Thornber mq->read_promote_level = NR_HOTSPOT_LEVELS - threshold_level; 1054b29d4986SJoe Thornber mq->write_promote_level = (NR_HOTSPOT_LEVELS - threshold_level); 105566a63635SJoe Thornber } 105666a63635SJoe Thornber 105766a63635SJoe Thornber /* 105866a63635SJoe Thornber * If the hotspot queue is performing badly, then we try and move entries 105966a63635SJoe Thornber * around more quickly. 106066a63635SJoe Thornber */ 106166a63635SJoe Thornber static void update_level_jump(struct smq_policy *mq) 106266a63635SJoe Thornber { 106366a63635SJoe Thornber switch (stats_assess(&mq->hotspot_stats)) { 106466a63635SJoe Thornber case Q_POOR: 106566a63635SJoe Thornber mq->hotspot_level_jump = 4u; 106666a63635SJoe Thornber break; 106766a63635SJoe Thornber 106866a63635SJoe Thornber case Q_FAIR: 106966a63635SJoe Thornber mq->hotspot_level_jump = 2u; 107066a63635SJoe Thornber break; 107166a63635SJoe Thornber 107266a63635SJoe Thornber case Q_WELL: 107366a63635SJoe Thornber mq->hotspot_level_jump = 1u; 107466a63635SJoe Thornber break; 107566a63635SJoe Thornber } 107666a63635SJoe Thornber } 107766a63635SJoe Thornber 107866a63635SJoe Thornber static void end_hotspot_period(struct smq_policy *mq) 107966a63635SJoe Thornber { 108066a63635SJoe Thornber clear_bitset(mq->hotspot_hit_bits, mq->nr_hotspot_blocks); 108166a63635SJoe Thornber update_promote_levels(mq); 108266a63635SJoe Thornber 108366a63635SJoe Thornber if (time_after(jiffies, mq->next_hotspot_period)) { 108466a63635SJoe Thornber update_level_jump(mq); 108566a63635SJoe Thornber q_redistribute(&mq->hotspot); 108666a63635SJoe Thornber stats_reset(&mq->hotspot_stats); 108766a63635SJoe Thornber mq->next_hotspot_period = jiffies + HOTSPOT_UPDATE_PERIOD; 108866a63635SJoe Thornber } 108966a63635SJoe Thornber } 109066a63635SJoe Thornber 109166a63635SJoe Thornber static void end_cache_period(struct smq_policy *mq) 109266a63635SJoe Thornber { 109366a63635SJoe Thornber if (time_after(jiffies, mq->next_cache_period)) { 109466a63635SJoe Thornber clear_bitset(mq->cache_hit_bits, from_cblock(mq->cache_size)); 109566a63635SJoe Thornber 109666a63635SJoe Thornber q_redistribute(&mq->dirty); 109766a63635SJoe Thornber q_redistribute(&mq->clean); 109866a63635SJoe Thornber stats_reset(&mq->cache_stats); 109966a63635SJoe Thornber 110066a63635SJoe Thornber mq->next_cache_period = jiffies + CACHE_UPDATE_PERIOD; 110166a63635SJoe Thornber } 110266a63635SJoe Thornber } 110366a63635SJoe Thornber 1104b29d4986SJoe Thornber /*----------------------------------------------------------------*/ 1105b29d4986SJoe Thornber 1106b29d4986SJoe Thornber /* 1107b29d4986SJoe Thornber * Targets are given as a percentage. 1108b29d4986SJoe Thornber */ 1109b29d4986SJoe Thornber #define CLEAN_TARGET 25u 1110b29d4986SJoe Thornber #define FREE_TARGET 25u 1111b29d4986SJoe Thornber 1112b29d4986SJoe Thornber static unsigned percent_to_target(struct smq_policy *mq, unsigned p) 111366a63635SJoe Thornber { 1114b29d4986SJoe Thornber return from_cblock(mq->cache_size) * p / 100u; 111566a63635SJoe Thornber } 111666a63635SJoe Thornber 1117b29d4986SJoe Thornber static bool clean_target_met(struct smq_policy *mq, bool idle) 1118b29d4986SJoe Thornber { 1119b29d4986SJoe Thornber /* 1120b29d4986SJoe Thornber * Cache entries may not be populated. So we cannot rely on the 1121b29d4986SJoe Thornber * size of the clean queue. 1122b29d4986SJoe Thornber */ 112397dfb203SMike Snitzer unsigned nr_clean; 1124b29d4986SJoe Thornber 112597dfb203SMike Snitzer if (idle) { 1126b29d4986SJoe Thornber /* 1127b29d4986SJoe Thornber * We'd like to clean everything. 1128b29d4986SJoe Thornber */ 1129b29d4986SJoe Thornber return q_size(&mq->dirty) == 0u; 113097dfb203SMike Snitzer } 113197dfb203SMike Snitzer 113297dfb203SMike Snitzer nr_clean = from_cblock(mq->cache_size) - q_size(&mq->dirty); 1133b29d4986SJoe Thornber return (nr_clean + btracker_nr_writebacks_queued(mq->bg_work)) >= 1134b29d4986SJoe Thornber percent_to_target(mq, CLEAN_TARGET); 1135b29d4986SJoe Thornber } 1136b29d4986SJoe Thornber 1137*6cf4cc8fSJoe Thornber static bool free_target_met(struct smq_policy *mq) 1138b29d4986SJoe Thornber { 113997dfb203SMike Snitzer unsigned nr_free; 1140b29d4986SJoe Thornber 114197dfb203SMike Snitzer nr_free = from_cblock(mq->cache_size) - mq->cache_alloc.nr_allocated; 1142b29d4986SJoe Thornber return (nr_free + btracker_nr_demotions_queued(mq->bg_work)) >= 1143b29d4986SJoe Thornber percent_to_target(mq, FREE_TARGET); 1144b29d4986SJoe Thornber } 1145b29d4986SJoe Thornber 1146b29d4986SJoe Thornber /*----------------------------------------------------------------*/ 1147b29d4986SJoe Thornber 1148b29d4986SJoe Thornber static void mark_pending(struct smq_policy *mq, struct entry *e) 1149b29d4986SJoe Thornber { 1150b29d4986SJoe Thornber BUG_ON(e->sentinel); 1151b29d4986SJoe Thornber BUG_ON(!e->allocated); 1152b29d4986SJoe Thornber BUG_ON(e->pending_work); 1153b29d4986SJoe Thornber e->pending_work = true; 1154b29d4986SJoe Thornber } 1155b29d4986SJoe Thornber 1156b29d4986SJoe Thornber static void clear_pending(struct smq_policy *mq, struct entry *e) 1157b29d4986SJoe Thornber { 1158b29d4986SJoe Thornber BUG_ON(!e->pending_work); 1159b29d4986SJoe Thornber e->pending_work = false; 1160b29d4986SJoe Thornber } 1161b29d4986SJoe Thornber 1162b29d4986SJoe Thornber static void queue_writeback(struct smq_policy *mq) 1163b29d4986SJoe Thornber { 1164b29d4986SJoe Thornber int r; 1165b29d4986SJoe Thornber struct policy_work work; 1166b29d4986SJoe Thornber struct entry *e; 1167b29d4986SJoe Thornber 1168cc7e3940SJoe Thornber e = q_peek(&mq->dirty, mq->dirty.nr_levels, !mq->migrations_allowed); 1169b29d4986SJoe Thornber if (e) { 1170b29d4986SJoe Thornber mark_pending(mq, e); 1171b29d4986SJoe Thornber q_del(&mq->dirty, e); 1172b29d4986SJoe Thornber 1173b29d4986SJoe Thornber work.op = POLICY_WRITEBACK; 1174b29d4986SJoe Thornber work.oblock = e->oblock; 1175b29d4986SJoe Thornber work.cblock = infer_cblock(mq, e); 1176b29d4986SJoe Thornber 1177b29d4986SJoe Thornber r = btracker_queue(mq->bg_work, &work, NULL); 1178b29d4986SJoe Thornber WARN_ON_ONCE(r); // FIXME: finish, I think we have to get rid of this race. 1179b29d4986SJoe Thornber } 1180b29d4986SJoe Thornber } 1181b29d4986SJoe Thornber 1182b29d4986SJoe Thornber static void queue_demotion(struct smq_policy *mq) 1183b29d4986SJoe Thornber { 1184b29d4986SJoe Thornber struct policy_work work; 1185b29d4986SJoe Thornber struct entry *e; 1186b29d4986SJoe Thornber 1187b29d4986SJoe Thornber if (unlikely(WARN_ON_ONCE(!mq->migrations_allowed))) 1188b29d4986SJoe Thornber return; 1189b29d4986SJoe Thornber 1190a8cd1ebaSJoe Thornber e = q_peek(&mq->clean, mq->clean.nr_levels / 2, true); 1191b29d4986SJoe Thornber if (!e) { 119278c45607SJoe Thornber if (!clean_target_met(mq, true)) 1193b29d4986SJoe Thornber queue_writeback(mq); 1194b29d4986SJoe Thornber return; 1195b29d4986SJoe Thornber } 1196b29d4986SJoe Thornber 1197b29d4986SJoe Thornber mark_pending(mq, e); 1198b29d4986SJoe Thornber q_del(&mq->clean, e); 1199b29d4986SJoe Thornber 1200b29d4986SJoe Thornber work.op = POLICY_DEMOTE; 1201b29d4986SJoe Thornber work.oblock = e->oblock; 1202b29d4986SJoe Thornber work.cblock = infer_cblock(mq, e); 1203b29d4986SJoe Thornber btracker_queue(mq->bg_work, &work, NULL); 1204b29d4986SJoe Thornber } 1205b29d4986SJoe Thornber 1206b29d4986SJoe Thornber static void queue_promotion(struct smq_policy *mq, dm_oblock_t oblock, 1207b29d4986SJoe Thornber struct policy_work **workp) 1208b29d4986SJoe Thornber { 1209b29d4986SJoe Thornber struct entry *e; 1210b29d4986SJoe Thornber struct policy_work work; 1211b29d4986SJoe Thornber 1212b29d4986SJoe Thornber if (!mq->migrations_allowed) 1213b29d4986SJoe Thornber return; 1214b29d4986SJoe Thornber 1215b29d4986SJoe Thornber if (allocator_empty(&mq->cache_alloc)) { 1216ce1d64e8SJoe Thornber /* 1217ce1d64e8SJoe Thornber * We always claim to be 'idle' to ensure some demotions happen 1218ce1d64e8SJoe Thornber * with continuous loads. 1219ce1d64e8SJoe Thornber */ 1220*6cf4cc8fSJoe Thornber if (!free_target_met(mq)) 1221b29d4986SJoe Thornber queue_demotion(mq); 1222b29d4986SJoe Thornber return; 1223b29d4986SJoe Thornber } 1224b29d4986SJoe Thornber 1225b29d4986SJoe Thornber if (btracker_promotion_already_present(mq->bg_work, oblock)) 1226b29d4986SJoe Thornber return; 1227b29d4986SJoe Thornber 1228b29d4986SJoe Thornber /* 1229b29d4986SJoe Thornber * We allocate the entry now to reserve the cblock. If the 1230b29d4986SJoe Thornber * background work is aborted we must remember to free it. 1231b29d4986SJoe Thornber */ 1232b29d4986SJoe Thornber e = alloc_entry(&mq->cache_alloc); 1233b29d4986SJoe Thornber BUG_ON(!e); 1234b29d4986SJoe Thornber e->pending_work = true; 1235b29d4986SJoe Thornber work.op = POLICY_PROMOTE; 1236b29d4986SJoe Thornber work.oblock = oblock; 1237b29d4986SJoe Thornber work.cblock = infer_cblock(mq, e); 1238b29d4986SJoe Thornber btracker_queue(mq->bg_work, &work, workp); 1239b29d4986SJoe Thornber } 1240b29d4986SJoe Thornber 1241b29d4986SJoe Thornber /*----------------------------------------------------------------*/ 1242b29d4986SJoe Thornber 124366a63635SJoe Thornber enum promote_result { 124466a63635SJoe Thornber PROMOTE_NOT, 124566a63635SJoe Thornber PROMOTE_TEMPORARY, 124666a63635SJoe Thornber PROMOTE_PERMANENT 124766a63635SJoe Thornber }; 124866a63635SJoe Thornber 124966a63635SJoe Thornber /* 125066a63635SJoe Thornber * Converts a boolean into a promote result. 125166a63635SJoe Thornber */ 125266a63635SJoe Thornber static enum promote_result maybe_promote(bool promote) 125366a63635SJoe Thornber { 125466a63635SJoe Thornber return promote ? PROMOTE_PERMANENT : PROMOTE_NOT; 125566a63635SJoe Thornber } 125666a63635SJoe Thornber 1257b29d4986SJoe Thornber static enum promote_result should_promote(struct smq_policy *mq, struct entry *hs_e, 1258b29d4986SJoe Thornber int data_dir, bool fast_promote) 125966a63635SJoe Thornber { 1260b29d4986SJoe Thornber if (data_dir == WRITE) { 126166a63635SJoe Thornber if (!allocator_empty(&mq->cache_alloc) && fast_promote) 126266a63635SJoe Thornber return PROMOTE_TEMPORARY; 126366a63635SJoe Thornber 126466a63635SJoe Thornber return maybe_promote(hs_e->level >= mq->write_promote_level); 126566a63635SJoe Thornber } else 126666a63635SJoe Thornber return maybe_promote(hs_e->level >= mq->read_promote_level); 126766a63635SJoe Thornber } 126866a63635SJoe Thornber 126966a63635SJoe Thornber static dm_oblock_t to_hblock(struct smq_policy *mq, dm_oblock_t b) 127066a63635SJoe Thornber { 127166a63635SJoe Thornber sector_t r = from_oblock(b); 127266a63635SJoe Thornber (void) sector_div(r, mq->cache_blocks_per_hotspot_block); 127366a63635SJoe Thornber return to_oblock(r); 127466a63635SJoe Thornber } 127566a63635SJoe Thornber 1276b29d4986SJoe Thornber static struct entry *update_hotspot_queue(struct smq_policy *mq, dm_oblock_t b) 127766a63635SJoe Thornber { 127866a63635SJoe Thornber unsigned hi; 127966a63635SJoe Thornber dm_oblock_t hb = to_hblock(mq, b); 128066a63635SJoe Thornber struct entry *e = h_lookup(&mq->hotspot_table, hb); 128166a63635SJoe Thornber 128266a63635SJoe Thornber if (e) { 128366a63635SJoe Thornber stats_level_accessed(&mq->hotspot_stats, e->level); 128466a63635SJoe Thornber 128566a63635SJoe Thornber hi = get_index(&mq->hotspot_alloc, e); 128666a63635SJoe Thornber q_requeue(&mq->hotspot, e, 128766a63635SJoe Thornber test_and_set_bit(hi, mq->hotspot_hit_bits) ? 1288b29d4986SJoe Thornber 0u : mq->hotspot_level_jump, 1289b29d4986SJoe Thornber NULL, NULL); 129066a63635SJoe Thornber 129166a63635SJoe Thornber } else { 129266a63635SJoe Thornber stats_miss(&mq->hotspot_stats); 129366a63635SJoe Thornber 129466a63635SJoe Thornber e = alloc_entry(&mq->hotspot_alloc); 129566a63635SJoe Thornber if (!e) { 129666a63635SJoe Thornber e = q_pop(&mq->hotspot); 129766a63635SJoe Thornber if (e) { 129866a63635SJoe Thornber h_remove(&mq->hotspot_table, e); 129966a63635SJoe Thornber hi = get_index(&mq->hotspot_alloc, e); 130066a63635SJoe Thornber clear_bit(hi, mq->hotspot_hit_bits); 130166a63635SJoe Thornber } 130266a63635SJoe Thornber 130366a63635SJoe Thornber } 130466a63635SJoe Thornber 130566a63635SJoe Thornber if (e) { 130666a63635SJoe Thornber e->oblock = hb; 130766a63635SJoe Thornber q_push(&mq->hotspot, e); 130866a63635SJoe Thornber h_insert(&mq->hotspot_table, e); 130966a63635SJoe Thornber } 131066a63635SJoe Thornber } 131166a63635SJoe Thornber 131266a63635SJoe Thornber return e; 131366a63635SJoe Thornber } 131466a63635SJoe Thornber 131566a63635SJoe Thornber /*----------------------------------------------------------------*/ 131666a63635SJoe Thornber 131766a63635SJoe Thornber /* 131866a63635SJoe Thornber * Public interface, via the policy struct. See dm-cache-policy.h for a 131966a63635SJoe Thornber * description of these. 132066a63635SJoe Thornber */ 132166a63635SJoe Thornber 132266a63635SJoe Thornber static struct smq_policy *to_smq_policy(struct dm_cache_policy *p) 132366a63635SJoe Thornber { 132466a63635SJoe Thornber return container_of(p, struct smq_policy, policy); 132566a63635SJoe Thornber } 132666a63635SJoe Thornber 132766a63635SJoe Thornber static void smq_destroy(struct dm_cache_policy *p) 132866a63635SJoe Thornber { 132966a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 133066a63635SJoe Thornber 1331b29d4986SJoe Thornber btracker_destroy(mq->bg_work); 133266a63635SJoe Thornber h_exit(&mq->hotspot_table); 133366a63635SJoe Thornber h_exit(&mq->table); 133466a63635SJoe Thornber free_bitset(mq->hotspot_hit_bits); 133566a63635SJoe Thornber free_bitset(mq->cache_hit_bits); 133666a63635SJoe Thornber space_exit(&mq->es); 133766a63635SJoe Thornber kfree(mq); 133866a63635SJoe Thornber } 133966a63635SJoe Thornber 1340b29d4986SJoe Thornber /*----------------------------------------------------------------*/ 1341b29d4986SJoe Thornber 1342b29d4986SJoe Thornber static int __lookup(struct smq_policy *mq, dm_oblock_t oblock, dm_cblock_t *cblock, 1343b29d4986SJoe Thornber int data_dir, bool fast_copy, 1344b29d4986SJoe Thornber struct policy_work **work, bool *background_work) 134566a63635SJoe Thornber { 1346b29d4986SJoe Thornber struct entry *e, *hs_e; 1347b29d4986SJoe Thornber enum promote_result pr; 134866a63635SJoe Thornber 1349b29d4986SJoe Thornber *background_work = false; 135066a63635SJoe Thornber 135166a63635SJoe Thornber e = h_lookup(&mq->table, oblock); 135266a63635SJoe Thornber if (e) { 1353b29d4986SJoe Thornber stats_level_accessed(&mq->cache_stats, e->level); 1354b29d4986SJoe Thornber 1355b29d4986SJoe Thornber requeue(mq, e); 135666a63635SJoe Thornber *cblock = infer_cblock(mq, e); 1357b29d4986SJoe Thornber return 0; 1358b29d4986SJoe Thornber 1359b29d4986SJoe Thornber } else { 1360b29d4986SJoe Thornber stats_miss(&mq->cache_stats); 1361b29d4986SJoe Thornber 1362b29d4986SJoe Thornber /* 1363b29d4986SJoe Thornber * The hotspot queue only gets updated with misses. 1364b29d4986SJoe Thornber */ 1365b29d4986SJoe Thornber hs_e = update_hotspot_queue(mq, oblock); 1366b29d4986SJoe Thornber 1367b29d4986SJoe Thornber pr = should_promote(mq, hs_e, data_dir, fast_copy); 1368b29d4986SJoe Thornber if (pr != PROMOTE_NOT) { 1369b29d4986SJoe Thornber queue_promotion(mq, oblock, work); 1370b29d4986SJoe Thornber *background_work = true; 1371b29d4986SJoe Thornber } 1372b29d4986SJoe Thornber 1373b29d4986SJoe Thornber return -ENOENT; 1374b29d4986SJoe Thornber } 1375b29d4986SJoe Thornber } 1376b29d4986SJoe Thornber 1377b29d4986SJoe Thornber static int smq_lookup(struct dm_cache_policy *p, dm_oblock_t oblock, dm_cblock_t *cblock, 1378b29d4986SJoe Thornber int data_dir, bool fast_copy, 1379b29d4986SJoe Thornber bool *background_work) 1380b29d4986SJoe Thornber { 1381b29d4986SJoe Thornber int r; 1382b29d4986SJoe Thornber unsigned long flags; 1383b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 1384b29d4986SJoe Thornber 1385b29d4986SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1386b29d4986SJoe Thornber r = __lookup(mq, oblock, cblock, 1387b29d4986SJoe Thornber data_dir, fast_copy, 1388b29d4986SJoe Thornber NULL, background_work); 13894051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 139066a63635SJoe Thornber 139166a63635SJoe Thornber return r; 139266a63635SJoe Thornber } 139366a63635SJoe Thornber 1394b29d4986SJoe Thornber static int smq_lookup_with_work(struct dm_cache_policy *p, 1395b29d4986SJoe Thornber dm_oblock_t oblock, dm_cblock_t *cblock, 1396b29d4986SJoe Thornber int data_dir, bool fast_copy, 1397b29d4986SJoe Thornber struct policy_work **work) 139866a63635SJoe Thornber { 1399b29d4986SJoe Thornber int r; 1400b29d4986SJoe Thornber bool background_queued; 1401b29d4986SJoe Thornber unsigned long flags; 1402b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 140366a63635SJoe Thornber 1404b29d4986SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1405b29d4986SJoe Thornber r = __lookup(mq, oblock, cblock, data_dir, fast_copy, work, &background_queued); 1406b29d4986SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 140766a63635SJoe Thornber 1408b29d4986SJoe Thornber return r; 140966a63635SJoe Thornber } 141066a63635SJoe Thornber 1411b29d4986SJoe Thornber static int smq_get_background_work(struct dm_cache_policy *p, bool idle, 1412b29d4986SJoe Thornber struct policy_work **result) 1413b29d4986SJoe Thornber { 1414b29d4986SJoe Thornber int r; 1415b29d4986SJoe Thornber unsigned long flags; 1416b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 1417b29d4986SJoe Thornber 1418b29d4986SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1419b29d4986SJoe Thornber r = btracker_issue(mq->bg_work, result); 1420b29d4986SJoe Thornber if (r == -ENODATA) { 1421*6cf4cc8fSJoe Thornber if (!clean_target_met(mq, idle)) { 1422b29d4986SJoe Thornber queue_writeback(mq); 1423b29d4986SJoe Thornber r = btracker_issue(mq->bg_work, result); 1424b29d4986SJoe Thornber } 1425*6cf4cc8fSJoe Thornber } 1426b29d4986SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 1427b29d4986SJoe Thornber 1428b29d4986SJoe Thornber return r; 1429b29d4986SJoe Thornber } 1430b29d4986SJoe Thornber 1431b29d4986SJoe Thornber /* 1432b29d4986SJoe Thornber * We need to clear any pending work flags that have been set, and in the 1433b29d4986SJoe Thornber * case of promotion free the entry for the destination cblock. 1434b29d4986SJoe Thornber */ 1435b29d4986SJoe Thornber static void __complete_background_work(struct smq_policy *mq, 1436b29d4986SJoe Thornber struct policy_work *work, 1437b29d4986SJoe Thornber bool success) 1438b29d4986SJoe Thornber { 1439b29d4986SJoe Thornber struct entry *e = get_entry(&mq->cache_alloc, 1440b29d4986SJoe Thornber from_cblock(work->cblock)); 1441b29d4986SJoe Thornber 1442b29d4986SJoe Thornber switch (work->op) { 1443b29d4986SJoe Thornber case POLICY_PROMOTE: 1444b29d4986SJoe Thornber // !h, !q, a 1445b29d4986SJoe Thornber clear_pending(mq, e); 1446b29d4986SJoe Thornber if (success) { 1447b29d4986SJoe Thornber e->oblock = work->oblock; 14484d44ec5aSJoe Thornber e->level = NR_CACHE_LEVELS - 1; 1449b29d4986SJoe Thornber push(mq, e); 1450b29d4986SJoe Thornber // h, q, a 1451b29d4986SJoe Thornber } else { 1452b29d4986SJoe Thornber free_entry(&mq->cache_alloc, e); 1453b29d4986SJoe Thornber // !h, !q, !a 1454b29d4986SJoe Thornber } 1455b29d4986SJoe Thornber break; 1456b29d4986SJoe Thornber 1457b29d4986SJoe Thornber case POLICY_DEMOTE: 1458b29d4986SJoe Thornber // h, !q, a 1459b29d4986SJoe Thornber if (success) { 1460b29d4986SJoe Thornber h_remove(&mq->table, e); 1461b29d4986SJoe Thornber free_entry(&mq->cache_alloc, e); 1462b29d4986SJoe Thornber // !h, !q, !a 1463b29d4986SJoe Thornber } else { 1464b29d4986SJoe Thornber clear_pending(mq, e); 1465b29d4986SJoe Thornber push_queue(mq, e); 1466b29d4986SJoe Thornber // h, q, a 1467b29d4986SJoe Thornber } 1468b29d4986SJoe Thornber break; 1469b29d4986SJoe Thornber 1470b29d4986SJoe Thornber case POLICY_WRITEBACK: 1471b29d4986SJoe Thornber // h, !q, a 1472b29d4986SJoe Thornber clear_pending(mq, e); 1473b29d4986SJoe Thornber push_queue(mq, e); 1474b29d4986SJoe Thornber // h, q, a 1475b29d4986SJoe Thornber break; 1476b29d4986SJoe Thornber } 1477b29d4986SJoe Thornber 1478b29d4986SJoe Thornber btracker_complete(mq->bg_work, work); 1479b29d4986SJoe Thornber } 1480b29d4986SJoe Thornber 1481b29d4986SJoe Thornber static void smq_complete_background_work(struct dm_cache_policy *p, 1482b29d4986SJoe Thornber struct policy_work *work, 1483b29d4986SJoe Thornber bool success) 148466a63635SJoe Thornber { 14854051aab7SJoe Thornber unsigned long flags; 148666a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 148766a63635SJoe Thornber 14884051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1489b29d4986SJoe Thornber __complete_background_work(mq, work, success); 14904051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 149166a63635SJoe Thornber } 149266a63635SJoe Thornber 1493b29d4986SJoe Thornber // in_hash(oblock) -> in_hash(oblock) 1494b29d4986SJoe Thornber static void __smq_set_clear_dirty(struct smq_policy *mq, dm_cblock_t cblock, bool set) 1495b29d4986SJoe Thornber { 1496b29d4986SJoe Thornber struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); 1497b29d4986SJoe Thornber 1498b29d4986SJoe Thornber if (e->pending_work) 1499b29d4986SJoe Thornber e->dirty = set; 1500b29d4986SJoe Thornber else { 1501b29d4986SJoe Thornber del_queue(mq, e); 1502b29d4986SJoe Thornber e->dirty = set; 1503b29d4986SJoe Thornber push_queue(mq, e); 1504b29d4986SJoe Thornber } 1505b29d4986SJoe Thornber } 1506b29d4986SJoe Thornber 1507b29d4986SJoe Thornber static void smq_set_dirty(struct dm_cache_policy *p, dm_cblock_t cblock) 1508b29d4986SJoe Thornber { 1509b29d4986SJoe Thornber unsigned long flags; 1510b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 1511b29d4986SJoe Thornber 1512b29d4986SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1513b29d4986SJoe Thornber __smq_set_clear_dirty(mq, cblock, true); 1514b29d4986SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 1515b29d4986SJoe Thornber } 1516b29d4986SJoe Thornber 1517b29d4986SJoe Thornber static void smq_clear_dirty(struct dm_cache_policy *p, dm_cblock_t cblock) 151866a63635SJoe Thornber { 151966a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 15204051aab7SJoe Thornber unsigned long flags; 152166a63635SJoe Thornber 15224051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 1523b29d4986SJoe Thornber __smq_set_clear_dirty(mq, cblock, false); 15244051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 152566a63635SJoe Thornber } 152666a63635SJoe Thornber 15279d1b404cSJoe Thornber static unsigned random_level(dm_cblock_t cblock) 15289d1b404cSJoe Thornber { 1529e99dda8fSMike Snitzer return hash_32(from_cblock(cblock), 9) & (NR_CACHE_LEVELS - 1); 15309d1b404cSJoe Thornber } 15319d1b404cSJoe Thornber 153266a63635SJoe Thornber static int smq_load_mapping(struct dm_cache_policy *p, 153366a63635SJoe Thornber dm_oblock_t oblock, dm_cblock_t cblock, 1534b29d4986SJoe Thornber bool dirty, uint32_t hint, bool hint_valid) 153566a63635SJoe Thornber { 153666a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 153766a63635SJoe Thornber struct entry *e; 153866a63635SJoe Thornber 153966a63635SJoe Thornber e = alloc_particular_entry(&mq->cache_alloc, from_cblock(cblock)); 154066a63635SJoe Thornber e->oblock = oblock; 1541b29d4986SJoe Thornber e->dirty = dirty; 15429d1b404cSJoe Thornber e->level = hint_valid ? min(hint, NR_CACHE_LEVELS - 1) : random_level(cblock); 1543b29d4986SJoe Thornber e->pending_work = false; 154466a63635SJoe Thornber 1545b29d4986SJoe Thornber /* 1546b29d4986SJoe Thornber * When we load mappings we push ahead of both sentinels in order to 1547b29d4986SJoe Thornber * allow demotions and cleaning to occur immediately. 1548b29d4986SJoe Thornber */ 1549b29d4986SJoe Thornber push_front(mq, e); 1550b29d4986SJoe Thornber 1551b29d4986SJoe Thornber return 0; 1552b29d4986SJoe Thornber } 1553b29d4986SJoe Thornber 1554b29d4986SJoe Thornber static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock) 1555b29d4986SJoe Thornber { 1556b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 1557b29d4986SJoe Thornber struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); 1558b29d4986SJoe Thornber 1559b29d4986SJoe Thornber if (!e->allocated) 1560b29d4986SJoe Thornber return -ENODATA; 1561b29d4986SJoe Thornber 1562b29d4986SJoe Thornber // FIXME: what if this block has pending background work? 1563b29d4986SJoe Thornber del_queue(mq, e); 1564b29d4986SJoe Thornber h_remove(&mq->table, e); 1565b29d4986SJoe Thornber free_entry(&mq->cache_alloc, e); 156666a63635SJoe Thornber return 0; 156766a63635SJoe Thornber } 156866a63635SJoe Thornber 15694e781b49SJoe Thornber static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock) 157066a63635SJoe Thornber { 157166a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 15724e781b49SJoe Thornber struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); 157366a63635SJoe Thornber 15744e781b49SJoe Thornber if (!e->allocated) 15754e781b49SJoe Thornber return 0; 157666a63635SJoe Thornber 15774e781b49SJoe Thornber return e->level; 157866a63635SJoe Thornber } 157966a63635SJoe Thornber 158066a63635SJoe Thornber static dm_cblock_t smq_residency(struct dm_cache_policy *p) 158166a63635SJoe Thornber { 158266a63635SJoe Thornber dm_cblock_t r; 15834051aab7SJoe Thornber unsigned long flags; 158466a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 158566a63635SJoe Thornber 15864051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 158766a63635SJoe Thornber r = to_cblock(mq->cache_alloc.nr_allocated); 15884051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 158966a63635SJoe Thornber 159066a63635SJoe Thornber return r; 159166a63635SJoe Thornber } 159266a63635SJoe Thornber 1593fba10109SJoe Thornber static void smq_tick(struct dm_cache_policy *p, bool can_block) 159466a63635SJoe Thornber { 159566a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 159666a63635SJoe Thornber unsigned long flags; 159766a63635SJoe Thornber 15984051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 15994051aab7SJoe Thornber mq->tick++; 16004051aab7SJoe Thornber update_sentinels(mq); 16014051aab7SJoe Thornber end_hotspot_period(mq); 16024051aab7SJoe Thornber end_cache_period(mq); 16034051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 160466a63635SJoe Thornber } 160566a63635SJoe Thornber 1606b29d4986SJoe Thornber static void smq_allow_migrations(struct dm_cache_policy *p, bool allow) 1607b29d4986SJoe Thornber { 1608b29d4986SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 1609b29d4986SJoe Thornber mq->migrations_allowed = allow; 1610b29d4986SJoe Thornber } 1611b29d4986SJoe Thornber 16129ed84698SJoe Thornber /* 16139ed84698SJoe Thornber * smq has no config values, but the old mq policy did. To avoid breaking 16149ed84698SJoe Thornber * software we continue to accept these configurables for the mq policy, 16159ed84698SJoe Thornber * but they have no effect. 16169ed84698SJoe Thornber */ 16179ed84698SJoe Thornber static int mq_set_config_value(struct dm_cache_policy *p, 16189ed84698SJoe Thornber const char *key, const char *value) 16199ed84698SJoe Thornber { 16209ed84698SJoe Thornber unsigned long tmp; 16219ed84698SJoe Thornber 16229ed84698SJoe Thornber if (kstrtoul(value, 10, &tmp)) 16239ed84698SJoe Thornber return -EINVAL; 16249ed84698SJoe Thornber 16259ed84698SJoe Thornber if (!strcasecmp(key, "random_threshold") || 16269ed84698SJoe Thornber !strcasecmp(key, "sequential_threshold") || 16279ed84698SJoe Thornber !strcasecmp(key, "discard_promote_adjustment") || 16289ed84698SJoe Thornber !strcasecmp(key, "read_promote_adjustment") || 16299ed84698SJoe Thornber !strcasecmp(key, "write_promote_adjustment")) { 16309ed84698SJoe Thornber DMWARN("tunable '%s' no longer has any effect, mq policy is now an alias for smq", key); 16319ed84698SJoe Thornber return 0; 16329ed84698SJoe Thornber } 16339ed84698SJoe Thornber 16349ed84698SJoe Thornber return -EINVAL; 16359ed84698SJoe Thornber } 16369ed84698SJoe Thornber 16379ed84698SJoe Thornber static int mq_emit_config_values(struct dm_cache_policy *p, char *result, 16389ed84698SJoe Thornber unsigned maxlen, ssize_t *sz_ptr) 16399ed84698SJoe Thornber { 16409ed84698SJoe Thornber ssize_t sz = *sz_ptr; 16419ed84698SJoe Thornber 16429ed84698SJoe Thornber DMEMIT("10 random_threshold 0 " 16439ed84698SJoe Thornber "sequential_threshold 0 " 16449ed84698SJoe Thornber "discard_promote_adjustment 0 " 16459ed84698SJoe Thornber "read_promote_adjustment 0 " 16469ed84698SJoe Thornber "write_promote_adjustment 0 "); 16479ed84698SJoe Thornber 16489ed84698SJoe Thornber *sz_ptr = sz; 16499ed84698SJoe Thornber return 0; 16509ed84698SJoe Thornber } 16519ed84698SJoe Thornber 165266a63635SJoe Thornber /* Init the policy plugin interface function pointers. */ 16539ed84698SJoe Thornber static void init_policy_functions(struct smq_policy *mq, bool mimic_mq) 165466a63635SJoe Thornber { 165566a63635SJoe Thornber mq->policy.destroy = smq_destroy; 165666a63635SJoe Thornber mq->policy.lookup = smq_lookup; 1657b29d4986SJoe Thornber mq->policy.lookup_with_work = smq_lookup_with_work; 1658b29d4986SJoe Thornber mq->policy.get_background_work = smq_get_background_work; 1659b29d4986SJoe Thornber mq->policy.complete_background_work = smq_complete_background_work; 166066a63635SJoe Thornber mq->policy.set_dirty = smq_set_dirty; 166166a63635SJoe Thornber mq->policy.clear_dirty = smq_clear_dirty; 166266a63635SJoe Thornber mq->policy.load_mapping = smq_load_mapping; 1663b29d4986SJoe Thornber mq->policy.invalidate_mapping = smq_invalidate_mapping; 16644e781b49SJoe Thornber mq->policy.get_hint = smq_get_hint; 166566a63635SJoe Thornber mq->policy.residency = smq_residency; 166666a63635SJoe Thornber mq->policy.tick = smq_tick; 1667b29d4986SJoe Thornber mq->policy.allow_migrations = smq_allow_migrations; 16689ed84698SJoe Thornber 16699ed84698SJoe Thornber if (mimic_mq) { 16709ed84698SJoe Thornber mq->policy.set_config_value = mq_set_config_value; 16719ed84698SJoe Thornber mq->policy.emit_config_values = mq_emit_config_values; 16729ed84698SJoe Thornber } 167366a63635SJoe Thornber } 167466a63635SJoe Thornber 167566a63635SJoe Thornber static bool too_many_hotspot_blocks(sector_t origin_size, 167666a63635SJoe Thornber sector_t hotspot_block_size, 167766a63635SJoe Thornber unsigned nr_hotspot_blocks) 167866a63635SJoe Thornber { 167966a63635SJoe Thornber return (hotspot_block_size * nr_hotspot_blocks) > origin_size; 168066a63635SJoe Thornber } 168166a63635SJoe Thornber 168266a63635SJoe Thornber static void calc_hotspot_params(sector_t origin_size, 168366a63635SJoe Thornber sector_t cache_block_size, 168466a63635SJoe Thornber unsigned nr_cache_blocks, 168566a63635SJoe Thornber sector_t *hotspot_block_size, 168666a63635SJoe Thornber unsigned *nr_hotspot_blocks) 168766a63635SJoe Thornber { 168866a63635SJoe Thornber *hotspot_block_size = cache_block_size * 16u; 168966a63635SJoe Thornber *nr_hotspot_blocks = max(nr_cache_blocks / 4u, 1024u); 169066a63635SJoe Thornber 169166a63635SJoe Thornber while ((*hotspot_block_size > cache_block_size) && 169266a63635SJoe Thornber too_many_hotspot_blocks(origin_size, *hotspot_block_size, *nr_hotspot_blocks)) 169366a63635SJoe Thornber *hotspot_block_size /= 2u; 169466a63635SJoe Thornber } 169566a63635SJoe Thornber 16969ed84698SJoe Thornber static struct dm_cache_policy *__smq_create(dm_cblock_t cache_size, 169766a63635SJoe Thornber sector_t origin_size, 16989ed84698SJoe Thornber sector_t cache_block_size, 1699b29d4986SJoe Thornber bool mimic_mq, 1700b29d4986SJoe Thornber bool migrations_allowed) 170166a63635SJoe Thornber { 170266a63635SJoe Thornber unsigned i; 170366a63635SJoe Thornber unsigned nr_sentinels_per_queue = 2u * NR_CACHE_LEVELS; 170466a63635SJoe Thornber unsigned total_sentinels = 2u * nr_sentinels_per_queue; 170566a63635SJoe Thornber struct smq_policy *mq = kzalloc(sizeof(*mq), GFP_KERNEL); 170666a63635SJoe Thornber 170766a63635SJoe Thornber if (!mq) 170866a63635SJoe Thornber return NULL; 170966a63635SJoe Thornber 17109ed84698SJoe Thornber init_policy_functions(mq, mimic_mq); 171166a63635SJoe Thornber mq->cache_size = cache_size; 171266a63635SJoe Thornber mq->cache_block_size = cache_block_size; 171366a63635SJoe Thornber 171466a63635SJoe Thornber calc_hotspot_params(origin_size, cache_block_size, from_cblock(cache_size), 171566a63635SJoe Thornber &mq->hotspot_block_size, &mq->nr_hotspot_blocks); 171666a63635SJoe Thornber 171766a63635SJoe Thornber mq->cache_blocks_per_hotspot_block = div64_u64(mq->hotspot_block_size, mq->cache_block_size); 171866a63635SJoe Thornber mq->hotspot_level_jump = 1u; 171966a63635SJoe Thornber if (space_init(&mq->es, total_sentinels + mq->nr_hotspot_blocks + from_cblock(cache_size))) { 172066a63635SJoe Thornber DMERR("couldn't initialize entry space"); 172166a63635SJoe Thornber goto bad_pool_init; 172266a63635SJoe Thornber } 172366a63635SJoe Thornber 172466a63635SJoe Thornber init_allocator(&mq->writeback_sentinel_alloc, &mq->es, 0, nr_sentinels_per_queue); 172566a63635SJoe Thornber for (i = 0; i < nr_sentinels_per_queue; i++) 172666a63635SJoe Thornber get_entry(&mq->writeback_sentinel_alloc, i)->sentinel = true; 172766a63635SJoe Thornber 172866a63635SJoe Thornber init_allocator(&mq->demote_sentinel_alloc, &mq->es, nr_sentinels_per_queue, total_sentinels); 172966a63635SJoe Thornber for (i = 0; i < nr_sentinels_per_queue; i++) 173066a63635SJoe Thornber get_entry(&mq->demote_sentinel_alloc, i)->sentinel = true; 173166a63635SJoe Thornber 173266a63635SJoe Thornber init_allocator(&mq->hotspot_alloc, &mq->es, total_sentinels, 173366a63635SJoe Thornber total_sentinels + mq->nr_hotspot_blocks); 173466a63635SJoe Thornber 173566a63635SJoe Thornber init_allocator(&mq->cache_alloc, &mq->es, 173666a63635SJoe Thornber total_sentinels + mq->nr_hotspot_blocks, 173766a63635SJoe Thornber total_sentinels + mq->nr_hotspot_blocks + from_cblock(cache_size)); 173866a63635SJoe Thornber 173966a63635SJoe Thornber mq->hotspot_hit_bits = alloc_bitset(mq->nr_hotspot_blocks); 174066a63635SJoe Thornber if (!mq->hotspot_hit_bits) { 174166a63635SJoe Thornber DMERR("couldn't allocate hotspot hit bitset"); 174266a63635SJoe Thornber goto bad_hotspot_hit_bits; 174366a63635SJoe Thornber } 174466a63635SJoe Thornber clear_bitset(mq->hotspot_hit_bits, mq->nr_hotspot_blocks); 174566a63635SJoe Thornber 174666a63635SJoe Thornber if (from_cblock(cache_size)) { 174766a63635SJoe Thornber mq->cache_hit_bits = alloc_bitset(from_cblock(cache_size)); 1748134bf30cSColin Ian King if (!mq->cache_hit_bits) { 174966a63635SJoe Thornber DMERR("couldn't allocate cache hit bitset"); 175066a63635SJoe Thornber goto bad_cache_hit_bits; 175166a63635SJoe Thornber } 175266a63635SJoe Thornber clear_bitset(mq->cache_hit_bits, from_cblock(mq->cache_size)); 175366a63635SJoe Thornber } else 175466a63635SJoe Thornber mq->cache_hit_bits = NULL; 175566a63635SJoe Thornber 175666a63635SJoe Thornber mq->tick = 0; 17574051aab7SJoe Thornber spin_lock_init(&mq->lock); 175866a63635SJoe Thornber 175966a63635SJoe Thornber q_init(&mq->hotspot, &mq->es, NR_HOTSPOT_LEVELS); 176066a63635SJoe Thornber mq->hotspot.nr_top_levels = 8; 176166a63635SJoe Thornber mq->hotspot.nr_in_top_levels = min(mq->nr_hotspot_blocks / NR_HOTSPOT_LEVELS, 176266a63635SJoe Thornber from_cblock(mq->cache_size) / mq->cache_blocks_per_hotspot_block); 176366a63635SJoe Thornber 176466a63635SJoe Thornber q_init(&mq->clean, &mq->es, NR_CACHE_LEVELS); 176566a63635SJoe Thornber q_init(&mq->dirty, &mq->es, NR_CACHE_LEVELS); 176666a63635SJoe Thornber 176766a63635SJoe Thornber stats_init(&mq->hotspot_stats, NR_HOTSPOT_LEVELS); 176866a63635SJoe Thornber stats_init(&mq->cache_stats, NR_CACHE_LEVELS); 176966a63635SJoe Thornber 177066a63635SJoe Thornber if (h_init(&mq->table, &mq->es, from_cblock(cache_size))) 177166a63635SJoe Thornber goto bad_alloc_table; 177266a63635SJoe Thornber 177366a63635SJoe Thornber if (h_init(&mq->hotspot_table, &mq->es, mq->nr_hotspot_blocks)) 177466a63635SJoe Thornber goto bad_alloc_hotspot_table; 177566a63635SJoe Thornber 177666a63635SJoe Thornber sentinels_init(mq); 177766a63635SJoe Thornber mq->write_promote_level = mq->read_promote_level = NR_HOTSPOT_LEVELS; 177866a63635SJoe Thornber 177966a63635SJoe Thornber mq->next_hotspot_period = jiffies; 178066a63635SJoe Thornber mq->next_cache_period = jiffies; 178166a63635SJoe Thornber 1782b29d4986SJoe Thornber mq->bg_work = btracker_create(10240); /* FIXME: hard coded value */ 1783b29d4986SJoe Thornber if (!mq->bg_work) 1784b29d4986SJoe Thornber goto bad_btracker; 1785b29d4986SJoe Thornber 1786b29d4986SJoe Thornber mq->migrations_allowed = migrations_allowed; 1787b29d4986SJoe Thornber 178866a63635SJoe Thornber return &mq->policy; 178966a63635SJoe Thornber 1790b29d4986SJoe Thornber bad_btracker: 1791b29d4986SJoe Thornber h_exit(&mq->hotspot_table); 179266a63635SJoe Thornber bad_alloc_hotspot_table: 179366a63635SJoe Thornber h_exit(&mq->table); 179466a63635SJoe Thornber bad_alloc_table: 179566a63635SJoe Thornber free_bitset(mq->cache_hit_bits); 179666a63635SJoe Thornber bad_cache_hit_bits: 179766a63635SJoe Thornber free_bitset(mq->hotspot_hit_bits); 179866a63635SJoe Thornber bad_hotspot_hit_bits: 179966a63635SJoe Thornber space_exit(&mq->es); 180066a63635SJoe Thornber bad_pool_init: 180166a63635SJoe Thornber kfree(mq); 180266a63635SJoe Thornber 180366a63635SJoe Thornber return NULL; 180466a63635SJoe Thornber } 180566a63635SJoe Thornber 18069ed84698SJoe Thornber static struct dm_cache_policy *smq_create(dm_cblock_t cache_size, 18079ed84698SJoe Thornber sector_t origin_size, 18089ed84698SJoe Thornber sector_t cache_block_size) 18099ed84698SJoe Thornber { 1810b29d4986SJoe Thornber return __smq_create(cache_size, origin_size, cache_block_size, false, true); 18119ed84698SJoe Thornber } 18129ed84698SJoe Thornber 18139ed84698SJoe Thornber static struct dm_cache_policy *mq_create(dm_cblock_t cache_size, 18149ed84698SJoe Thornber sector_t origin_size, 18159ed84698SJoe Thornber sector_t cache_block_size) 18169ed84698SJoe Thornber { 1817b29d4986SJoe Thornber return __smq_create(cache_size, origin_size, cache_block_size, true, true); 1818b29d4986SJoe Thornber } 1819b29d4986SJoe Thornber 1820b29d4986SJoe Thornber static struct dm_cache_policy *cleaner_create(dm_cblock_t cache_size, 1821b29d4986SJoe Thornber sector_t origin_size, 1822b29d4986SJoe Thornber sector_t cache_block_size) 1823b29d4986SJoe Thornber { 1824b29d4986SJoe Thornber return __smq_create(cache_size, origin_size, cache_block_size, false, false); 18259ed84698SJoe Thornber } 18269ed84698SJoe Thornber 182766a63635SJoe Thornber /*----------------------------------------------------------------*/ 182866a63635SJoe Thornber 182966a63635SJoe Thornber static struct dm_cache_policy_type smq_policy_type = { 183066a63635SJoe Thornber .name = "smq", 1831b29d4986SJoe Thornber .version = {2, 0, 0}, 183266a63635SJoe Thornber .hint_size = 4, 183366a63635SJoe Thornber .owner = THIS_MODULE, 183466a63635SJoe Thornber .create = smq_create 183566a63635SJoe Thornber }; 183666a63635SJoe Thornber 18379ed84698SJoe Thornber static struct dm_cache_policy_type mq_policy_type = { 18389ed84698SJoe Thornber .name = "mq", 1839b29d4986SJoe Thornber .version = {2, 0, 0}, 18409ed84698SJoe Thornber .hint_size = 4, 18419ed84698SJoe Thornber .owner = THIS_MODULE, 18429ed84698SJoe Thornber .create = mq_create, 18439ed84698SJoe Thornber }; 18449ed84698SJoe Thornber 1845b29d4986SJoe Thornber static struct dm_cache_policy_type cleaner_policy_type = { 1846b29d4986SJoe Thornber .name = "cleaner", 1847b29d4986SJoe Thornber .version = {2, 0, 0}, 1848b29d4986SJoe Thornber .hint_size = 4, 1849b29d4986SJoe Thornber .owner = THIS_MODULE, 1850b29d4986SJoe Thornber .create = cleaner_create, 1851b29d4986SJoe Thornber }; 1852b29d4986SJoe Thornber 1853bccab6a0SMike Snitzer static struct dm_cache_policy_type default_policy_type = { 1854bccab6a0SMike Snitzer .name = "default", 1855b29d4986SJoe Thornber .version = {2, 0, 0}, 1856bccab6a0SMike Snitzer .hint_size = 4, 1857bccab6a0SMike Snitzer .owner = THIS_MODULE, 1858bccab6a0SMike Snitzer .create = smq_create, 1859bccab6a0SMike Snitzer .real = &smq_policy_type 1860bccab6a0SMike Snitzer }; 1861bccab6a0SMike Snitzer 186266a63635SJoe Thornber static int __init smq_init(void) 186366a63635SJoe Thornber { 186466a63635SJoe Thornber int r; 186566a63635SJoe Thornber 186666a63635SJoe Thornber r = dm_cache_policy_register(&smq_policy_type); 186766a63635SJoe Thornber if (r) { 186866a63635SJoe Thornber DMERR("register failed %d", r); 186966a63635SJoe Thornber return -ENOMEM; 187066a63635SJoe Thornber } 187166a63635SJoe Thornber 18729ed84698SJoe Thornber r = dm_cache_policy_register(&mq_policy_type); 18739ed84698SJoe Thornber if (r) { 18747dd85bb0SMike Snitzer DMERR("register failed (as mq) %d", r); 1875b29d4986SJoe Thornber goto out_mq; 1876b29d4986SJoe Thornber } 1877b29d4986SJoe Thornber 1878b29d4986SJoe Thornber r = dm_cache_policy_register(&cleaner_policy_type); 1879b29d4986SJoe Thornber if (r) { 1880b29d4986SJoe Thornber DMERR("register failed (as cleaner) %d", r); 1881b29d4986SJoe Thornber goto out_cleaner; 18829ed84698SJoe Thornber } 18839ed84698SJoe Thornber 1884bccab6a0SMike Snitzer r = dm_cache_policy_register(&default_policy_type); 1885bccab6a0SMike Snitzer if (r) { 1886bccab6a0SMike Snitzer DMERR("register failed (as default) %d", r); 1887b29d4986SJoe Thornber goto out_default; 1888bccab6a0SMike Snitzer } 1889bccab6a0SMike Snitzer 189066a63635SJoe Thornber return 0; 1891b29d4986SJoe Thornber 1892b29d4986SJoe Thornber out_default: 1893b29d4986SJoe Thornber dm_cache_policy_unregister(&cleaner_policy_type); 1894b29d4986SJoe Thornber out_cleaner: 1895b29d4986SJoe Thornber dm_cache_policy_unregister(&mq_policy_type); 1896b29d4986SJoe Thornber out_mq: 1897b29d4986SJoe Thornber dm_cache_policy_unregister(&smq_policy_type); 1898b29d4986SJoe Thornber 1899b29d4986SJoe Thornber return -ENOMEM; 190066a63635SJoe Thornber } 190166a63635SJoe Thornber 190266a63635SJoe Thornber static void __exit smq_exit(void) 190366a63635SJoe Thornber { 1904b29d4986SJoe Thornber dm_cache_policy_unregister(&cleaner_policy_type); 190566a63635SJoe Thornber dm_cache_policy_unregister(&smq_policy_type); 19069ed84698SJoe Thornber dm_cache_policy_unregister(&mq_policy_type); 1907bccab6a0SMike Snitzer dm_cache_policy_unregister(&default_policy_type); 190866a63635SJoe Thornber } 190966a63635SJoe Thornber 191066a63635SJoe Thornber module_init(smq_init); 191166a63635SJoe Thornber module_exit(smq_exit); 191266a63635SJoe Thornber 191366a63635SJoe Thornber MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>"); 191466a63635SJoe Thornber MODULE_LICENSE("GPL"); 191566a63635SJoe Thornber MODULE_DESCRIPTION("smq cache policy"); 191634dd0517SYi Zhang 191734dd0517SYi Zhang MODULE_ALIAS("dm-cache-default"); 19189ed84698SJoe Thornber MODULE_ALIAS("dm-cache-mq"); 1919b29d4986SJoe Thornber MODULE_ALIAS("dm-cache-cleaner"); 1920