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 766a63635SJoe Thornber #include "dm-cache-policy.h" 866a63635SJoe Thornber #include "dm-cache-policy-internal.h" 966a63635SJoe Thornber #include "dm.h" 1066a63635SJoe Thornber 1166a63635SJoe Thornber #include <linux/hash.h> 1266a63635SJoe Thornber #include <linux/jiffies.h> 1366a63635SJoe Thornber #include <linux/module.h> 1466a63635SJoe Thornber #include <linux/mutex.h> 1566a63635SJoe Thornber #include <linux/vmalloc.h> 1666a63635SJoe Thornber #include <linux/math64.h> 1766a63635SJoe Thornber 1866a63635SJoe Thornber #define DM_MSG_PREFIX "cache-policy-smq" 1966a63635SJoe Thornber 2066a63635SJoe Thornber /*----------------------------------------------------------------*/ 2166a63635SJoe Thornber 2266a63635SJoe Thornber /* 2366a63635SJoe Thornber * Safe division functions that return zero on divide by zero. 2466a63635SJoe Thornber */ 2566a63635SJoe Thornber static unsigned safe_div(unsigned n, unsigned d) 2666a63635SJoe Thornber { 2766a63635SJoe Thornber return d ? n / d : 0u; 2866a63635SJoe Thornber } 2966a63635SJoe Thornber 3066a63635SJoe Thornber static unsigned safe_mod(unsigned n, unsigned d) 3166a63635SJoe Thornber { 3266a63635SJoe Thornber return d ? n % d : 0u; 3366a63635SJoe Thornber } 3466a63635SJoe Thornber 3566a63635SJoe Thornber /*----------------------------------------------------------------*/ 3666a63635SJoe Thornber 3766a63635SJoe Thornber struct entry { 3866a63635SJoe Thornber unsigned hash_next:28; 3966a63635SJoe Thornber unsigned prev:28; 4066a63635SJoe Thornber unsigned next:28; 4166a63635SJoe Thornber unsigned level:7; 4266a63635SJoe Thornber bool dirty:1; 4366a63635SJoe Thornber bool allocated:1; 4466a63635SJoe Thornber bool sentinel:1; 4566a63635SJoe Thornber 4666a63635SJoe Thornber dm_oblock_t oblock; 4766a63635SJoe Thornber }; 4866a63635SJoe Thornber 4966a63635SJoe Thornber /*----------------------------------------------------------------*/ 5066a63635SJoe Thornber 5166a63635SJoe Thornber #define INDEXER_NULL ((1u << 28u) - 1u) 5266a63635SJoe Thornber 5366a63635SJoe Thornber /* 5466a63635SJoe Thornber * An entry_space manages a set of entries that we use for the queues. 5566a63635SJoe Thornber * The clean and dirty queues share entries, so this object is separate 5666a63635SJoe Thornber * from the queue itself. 5766a63635SJoe Thornber */ 5866a63635SJoe Thornber struct entry_space { 5966a63635SJoe Thornber struct entry *begin; 6066a63635SJoe Thornber struct entry *end; 6166a63635SJoe Thornber }; 6266a63635SJoe Thornber 6366a63635SJoe Thornber static int space_init(struct entry_space *es, unsigned nr_entries) 6466a63635SJoe Thornber { 6566a63635SJoe Thornber if (!nr_entries) { 6666a63635SJoe Thornber es->begin = es->end = NULL; 6766a63635SJoe Thornber return 0; 6866a63635SJoe Thornber } 6966a63635SJoe Thornber 7066a63635SJoe Thornber es->begin = vzalloc(sizeof(struct entry) * nr_entries); 7166a63635SJoe Thornber if (!es->begin) 7266a63635SJoe Thornber return -ENOMEM; 7366a63635SJoe Thornber 7466a63635SJoe Thornber es->end = es->begin + nr_entries; 7566a63635SJoe Thornber return 0; 7666a63635SJoe Thornber } 7766a63635SJoe Thornber 7866a63635SJoe Thornber static void space_exit(struct entry_space *es) 7966a63635SJoe Thornber { 8066a63635SJoe Thornber vfree(es->begin); 8166a63635SJoe Thornber } 8266a63635SJoe Thornber 8366a63635SJoe Thornber static struct entry *__get_entry(struct entry_space *es, unsigned block) 8466a63635SJoe Thornber { 8566a63635SJoe Thornber struct entry *e; 8666a63635SJoe Thornber 8766a63635SJoe Thornber e = es->begin + block; 8866a63635SJoe Thornber BUG_ON(e >= es->end); 8966a63635SJoe Thornber 9066a63635SJoe Thornber return e; 9166a63635SJoe Thornber } 9266a63635SJoe Thornber 9366a63635SJoe Thornber static unsigned to_index(struct entry_space *es, struct entry *e) 9466a63635SJoe Thornber { 9566a63635SJoe Thornber BUG_ON(e < es->begin || e >= es->end); 9666a63635SJoe Thornber return e - es->begin; 9766a63635SJoe Thornber } 9866a63635SJoe Thornber 9966a63635SJoe Thornber static struct entry *to_entry(struct entry_space *es, unsigned block) 10066a63635SJoe Thornber { 10166a63635SJoe Thornber if (block == INDEXER_NULL) 10266a63635SJoe Thornber return NULL; 10366a63635SJoe Thornber 10466a63635SJoe Thornber return __get_entry(es, block); 10566a63635SJoe Thornber } 10666a63635SJoe Thornber 10766a63635SJoe Thornber /*----------------------------------------------------------------*/ 10866a63635SJoe Thornber 10966a63635SJoe Thornber struct ilist { 11066a63635SJoe Thornber unsigned nr_elts; /* excluding sentinel entries */ 11166a63635SJoe Thornber unsigned head, tail; 11266a63635SJoe Thornber }; 11366a63635SJoe Thornber 11466a63635SJoe Thornber static void l_init(struct ilist *l) 11566a63635SJoe Thornber { 11666a63635SJoe Thornber l->nr_elts = 0; 11766a63635SJoe Thornber l->head = l->tail = INDEXER_NULL; 11866a63635SJoe Thornber } 11966a63635SJoe Thornber 12066a63635SJoe Thornber static struct entry *l_head(struct entry_space *es, struct ilist *l) 12166a63635SJoe Thornber { 12266a63635SJoe Thornber return to_entry(es, l->head); 12366a63635SJoe Thornber } 12466a63635SJoe Thornber 12566a63635SJoe Thornber static struct entry *l_tail(struct entry_space *es, struct ilist *l) 12666a63635SJoe Thornber { 12766a63635SJoe Thornber return to_entry(es, l->tail); 12866a63635SJoe Thornber } 12966a63635SJoe Thornber 13066a63635SJoe Thornber static struct entry *l_next(struct entry_space *es, struct entry *e) 13166a63635SJoe Thornber { 13266a63635SJoe Thornber return to_entry(es, e->next); 13366a63635SJoe Thornber } 13466a63635SJoe Thornber 13566a63635SJoe Thornber static struct entry *l_prev(struct entry_space *es, struct entry *e) 13666a63635SJoe Thornber { 13766a63635SJoe Thornber return to_entry(es, e->prev); 13866a63635SJoe Thornber } 13966a63635SJoe Thornber 14066a63635SJoe Thornber static bool l_empty(struct ilist *l) 14166a63635SJoe Thornber { 14266a63635SJoe Thornber return l->head == INDEXER_NULL; 14366a63635SJoe Thornber } 14466a63635SJoe Thornber 14566a63635SJoe Thornber static void l_add_head(struct entry_space *es, struct ilist *l, struct entry *e) 14666a63635SJoe Thornber { 14766a63635SJoe Thornber struct entry *head = l_head(es, l); 14866a63635SJoe Thornber 14966a63635SJoe Thornber e->next = l->head; 15066a63635SJoe Thornber e->prev = INDEXER_NULL; 15166a63635SJoe Thornber 15266a63635SJoe Thornber if (head) 15366a63635SJoe Thornber head->prev = l->head = to_index(es, e); 15466a63635SJoe Thornber else 15566a63635SJoe Thornber l->head = l->tail = to_index(es, e); 15666a63635SJoe Thornber 15766a63635SJoe Thornber if (!e->sentinel) 15866a63635SJoe Thornber l->nr_elts++; 15966a63635SJoe Thornber } 16066a63635SJoe Thornber 16166a63635SJoe Thornber static void l_add_tail(struct entry_space *es, struct ilist *l, struct entry *e) 16266a63635SJoe Thornber { 16366a63635SJoe Thornber struct entry *tail = l_tail(es, l); 16466a63635SJoe Thornber 16566a63635SJoe Thornber e->next = INDEXER_NULL; 16666a63635SJoe Thornber e->prev = l->tail; 16766a63635SJoe Thornber 16866a63635SJoe Thornber if (tail) 16966a63635SJoe Thornber tail->next = l->tail = to_index(es, e); 17066a63635SJoe Thornber else 17166a63635SJoe Thornber l->head = l->tail = to_index(es, e); 17266a63635SJoe Thornber 17366a63635SJoe Thornber if (!e->sentinel) 17466a63635SJoe Thornber l->nr_elts++; 17566a63635SJoe Thornber } 17666a63635SJoe Thornber 17766a63635SJoe Thornber static void l_add_before(struct entry_space *es, struct ilist *l, 17866a63635SJoe Thornber struct entry *old, struct entry *e) 17966a63635SJoe Thornber { 18066a63635SJoe Thornber struct entry *prev = l_prev(es, old); 18166a63635SJoe Thornber 18266a63635SJoe Thornber if (!prev) 18366a63635SJoe Thornber l_add_head(es, l, e); 18466a63635SJoe Thornber 18566a63635SJoe Thornber else { 18666a63635SJoe Thornber e->prev = old->prev; 18766a63635SJoe Thornber e->next = to_index(es, old); 18866a63635SJoe Thornber prev->next = old->prev = to_index(es, e); 18966a63635SJoe Thornber 19066a63635SJoe Thornber if (!e->sentinel) 19166a63635SJoe Thornber l->nr_elts++; 19266a63635SJoe Thornber } 19366a63635SJoe Thornber } 19466a63635SJoe Thornber 19566a63635SJoe Thornber static void l_del(struct entry_space *es, struct ilist *l, struct entry *e) 19666a63635SJoe Thornber { 19766a63635SJoe Thornber struct entry *prev = l_prev(es, e); 19866a63635SJoe Thornber struct entry *next = l_next(es, e); 19966a63635SJoe Thornber 20066a63635SJoe Thornber if (prev) 20166a63635SJoe Thornber prev->next = e->next; 20266a63635SJoe Thornber else 20366a63635SJoe Thornber l->head = e->next; 20466a63635SJoe Thornber 20566a63635SJoe Thornber if (next) 20666a63635SJoe Thornber next->prev = e->prev; 20766a63635SJoe Thornber else 20866a63635SJoe Thornber l->tail = e->prev; 20966a63635SJoe Thornber 21066a63635SJoe Thornber if (!e->sentinel) 21166a63635SJoe Thornber l->nr_elts--; 21266a63635SJoe Thornber } 21366a63635SJoe Thornber 21466a63635SJoe Thornber static struct entry *l_pop_tail(struct entry_space *es, struct ilist *l) 21566a63635SJoe Thornber { 21666a63635SJoe Thornber struct entry *e; 21766a63635SJoe Thornber 21866a63635SJoe Thornber for (e = l_tail(es, l); e; e = l_prev(es, e)) 21966a63635SJoe Thornber if (!e->sentinel) { 22066a63635SJoe Thornber l_del(es, l, e); 22166a63635SJoe Thornber return e; 22266a63635SJoe Thornber } 22366a63635SJoe Thornber 22466a63635SJoe Thornber return NULL; 22566a63635SJoe Thornber } 22666a63635SJoe Thornber 22766a63635SJoe Thornber /*----------------------------------------------------------------*/ 22866a63635SJoe Thornber 22966a63635SJoe Thornber /* 23066a63635SJoe Thornber * The stochastic-multi-queue is a set of lru lists stacked into levels. 23166a63635SJoe Thornber * Entries are moved up levels when they are used, which loosely orders the 23266a63635SJoe Thornber * most accessed entries in the top levels and least in the bottom. This 23366a63635SJoe Thornber * structure is *much* better than a single lru list. 23466a63635SJoe Thornber */ 23566a63635SJoe Thornber #define MAX_LEVELS 64u 23666a63635SJoe Thornber 23766a63635SJoe Thornber struct queue { 23866a63635SJoe Thornber struct entry_space *es; 23966a63635SJoe Thornber 24066a63635SJoe Thornber unsigned nr_elts; 24166a63635SJoe Thornber unsigned nr_levels; 24266a63635SJoe Thornber struct ilist qs[MAX_LEVELS]; 24366a63635SJoe Thornber 24466a63635SJoe Thornber /* 24566a63635SJoe Thornber * We maintain a count of the number of entries we would like in each 24666a63635SJoe Thornber * level. 24766a63635SJoe Thornber */ 24866a63635SJoe Thornber unsigned last_target_nr_elts; 24966a63635SJoe Thornber unsigned nr_top_levels; 25066a63635SJoe Thornber unsigned nr_in_top_levels; 25166a63635SJoe Thornber unsigned target_count[MAX_LEVELS]; 25266a63635SJoe Thornber }; 25366a63635SJoe Thornber 25466a63635SJoe Thornber static void q_init(struct queue *q, struct entry_space *es, unsigned nr_levels) 25566a63635SJoe Thornber { 25666a63635SJoe Thornber unsigned i; 25766a63635SJoe Thornber 25866a63635SJoe Thornber q->es = es; 25966a63635SJoe Thornber q->nr_elts = 0; 26066a63635SJoe Thornber q->nr_levels = nr_levels; 26166a63635SJoe Thornber 26266a63635SJoe Thornber for (i = 0; i < q->nr_levels; i++) { 26366a63635SJoe Thornber l_init(q->qs + i); 26466a63635SJoe Thornber q->target_count[i] = 0u; 26566a63635SJoe Thornber } 26666a63635SJoe Thornber 26766a63635SJoe Thornber q->last_target_nr_elts = 0u; 26866a63635SJoe Thornber q->nr_top_levels = 0u; 26966a63635SJoe Thornber q->nr_in_top_levels = 0u; 27066a63635SJoe Thornber } 27166a63635SJoe Thornber 27266a63635SJoe Thornber static unsigned q_size(struct queue *q) 27366a63635SJoe Thornber { 27466a63635SJoe Thornber return q->nr_elts; 27566a63635SJoe Thornber } 27666a63635SJoe Thornber 27766a63635SJoe Thornber /* 27866a63635SJoe Thornber * Insert an entry to the back of the given level. 27966a63635SJoe Thornber */ 28066a63635SJoe Thornber static void q_push(struct queue *q, struct entry *e) 28166a63635SJoe Thornber { 28266a63635SJoe Thornber if (!e->sentinel) 28366a63635SJoe Thornber q->nr_elts++; 28466a63635SJoe Thornber 28566a63635SJoe Thornber l_add_tail(q->es, q->qs + e->level, e); 28666a63635SJoe Thornber } 28766a63635SJoe Thornber 28866a63635SJoe Thornber static void q_push_before(struct queue *q, struct entry *old, struct entry *e) 28966a63635SJoe Thornber { 29066a63635SJoe Thornber if (!e->sentinel) 29166a63635SJoe Thornber q->nr_elts++; 29266a63635SJoe Thornber 29366a63635SJoe Thornber l_add_before(q->es, q->qs + e->level, old, e); 29466a63635SJoe Thornber } 29566a63635SJoe Thornber 29666a63635SJoe Thornber static void q_del(struct queue *q, struct entry *e) 29766a63635SJoe Thornber { 29866a63635SJoe Thornber l_del(q->es, q->qs + e->level, e); 29966a63635SJoe Thornber if (!e->sentinel) 30066a63635SJoe Thornber q->nr_elts--; 30166a63635SJoe Thornber } 30266a63635SJoe Thornber 30366a63635SJoe Thornber /* 30466a63635SJoe Thornber * Return the oldest entry of the lowest populated level. 30566a63635SJoe Thornber */ 30666a63635SJoe Thornber static struct entry *q_peek(struct queue *q, unsigned max_level, bool can_cross_sentinel) 30766a63635SJoe Thornber { 30866a63635SJoe Thornber unsigned level; 30966a63635SJoe Thornber struct entry *e; 31066a63635SJoe Thornber 31166a63635SJoe Thornber max_level = min(max_level, q->nr_levels); 31266a63635SJoe Thornber 31366a63635SJoe Thornber for (level = 0; level < max_level; level++) 31466a63635SJoe Thornber for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e)) { 31566a63635SJoe Thornber if (e->sentinel) { 31666a63635SJoe Thornber if (can_cross_sentinel) 31766a63635SJoe Thornber continue; 31866a63635SJoe Thornber else 31966a63635SJoe Thornber break; 32066a63635SJoe Thornber } 32166a63635SJoe Thornber 32266a63635SJoe Thornber return e; 32366a63635SJoe Thornber } 32466a63635SJoe Thornber 32566a63635SJoe Thornber return NULL; 32666a63635SJoe Thornber } 32766a63635SJoe Thornber 32866a63635SJoe Thornber static struct entry *q_pop(struct queue *q) 32966a63635SJoe Thornber { 33066a63635SJoe Thornber struct entry *e = q_peek(q, q->nr_levels, true); 33166a63635SJoe Thornber 33266a63635SJoe Thornber if (e) 33366a63635SJoe Thornber q_del(q, e); 33466a63635SJoe Thornber 33566a63635SJoe Thornber return e; 33666a63635SJoe Thornber } 33766a63635SJoe Thornber 33866a63635SJoe Thornber /* 33966a63635SJoe Thornber * Pops an entry from a level that is not past a sentinel. 34066a63635SJoe Thornber */ 34166a63635SJoe Thornber static struct entry *q_pop_old(struct queue *q, unsigned max_level) 34266a63635SJoe Thornber { 34366a63635SJoe Thornber struct entry *e = q_peek(q, max_level, false); 34466a63635SJoe Thornber 34566a63635SJoe Thornber if (e) 34666a63635SJoe Thornber q_del(q, e); 34766a63635SJoe Thornber 34866a63635SJoe Thornber return e; 34966a63635SJoe Thornber } 35066a63635SJoe Thornber 35166a63635SJoe Thornber /* 35266a63635SJoe Thornber * This function assumes there is a non-sentinel entry to pop. It's only 35366a63635SJoe Thornber * used by redistribute, so we know this is true. It also doesn't adjust 35466a63635SJoe Thornber * the q->nr_elts count. 35566a63635SJoe Thornber */ 35666a63635SJoe Thornber static struct entry *__redist_pop_from(struct queue *q, unsigned level) 35766a63635SJoe Thornber { 35866a63635SJoe Thornber struct entry *e; 35966a63635SJoe Thornber 36066a63635SJoe Thornber for (; level < q->nr_levels; level++) 36166a63635SJoe Thornber for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e)) 36266a63635SJoe Thornber if (!e->sentinel) { 36366a63635SJoe Thornber l_del(q->es, q->qs + e->level, e); 36466a63635SJoe Thornber return e; 36566a63635SJoe Thornber } 36666a63635SJoe Thornber 36766a63635SJoe Thornber return NULL; 36866a63635SJoe Thornber } 36966a63635SJoe Thornber 37066a63635SJoe Thornber static void q_set_targets_subrange_(struct queue *q, unsigned nr_elts, unsigned lbegin, unsigned lend) 37166a63635SJoe Thornber { 37266a63635SJoe Thornber unsigned level, nr_levels, entries_per_level, remainder; 37366a63635SJoe Thornber 37466a63635SJoe Thornber BUG_ON(lbegin > lend); 37566a63635SJoe Thornber BUG_ON(lend > q->nr_levels); 37666a63635SJoe Thornber nr_levels = lend - lbegin; 37766a63635SJoe Thornber entries_per_level = safe_div(nr_elts, nr_levels); 37866a63635SJoe Thornber remainder = safe_mod(nr_elts, nr_levels); 37966a63635SJoe Thornber 38066a63635SJoe Thornber for (level = lbegin; level < lend; level++) 38166a63635SJoe Thornber q->target_count[level] = 38266a63635SJoe Thornber (level < (lbegin + remainder)) ? entries_per_level + 1u : entries_per_level; 38366a63635SJoe Thornber } 38466a63635SJoe Thornber 38566a63635SJoe Thornber /* 38666a63635SJoe Thornber * Typically we have fewer elements in the top few levels which allows us 38766a63635SJoe Thornber * to adjust the promote threshold nicely. 38866a63635SJoe Thornber */ 38966a63635SJoe Thornber static void q_set_targets(struct queue *q) 39066a63635SJoe Thornber { 39166a63635SJoe Thornber if (q->last_target_nr_elts == q->nr_elts) 39266a63635SJoe Thornber return; 39366a63635SJoe Thornber 39466a63635SJoe Thornber q->last_target_nr_elts = q->nr_elts; 39566a63635SJoe Thornber 39666a63635SJoe Thornber if (q->nr_top_levels > q->nr_levels) 39766a63635SJoe Thornber q_set_targets_subrange_(q, q->nr_elts, 0, q->nr_levels); 39866a63635SJoe Thornber 39966a63635SJoe Thornber else { 40066a63635SJoe Thornber q_set_targets_subrange_(q, q->nr_in_top_levels, 40166a63635SJoe Thornber q->nr_levels - q->nr_top_levels, q->nr_levels); 40266a63635SJoe Thornber 40366a63635SJoe Thornber if (q->nr_in_top_levels < q->nr_elts) 40466a63635SJoe Thornber q_set_targets_subrange_(q, q->nr_elts - q->nr_in_top_levels, 40566a63635SJoe Thornber 0, q->nr_levels - q->nr_top_levels); 40666a63635SJoe Thornber else 40766a63635SJoe Thornber q_set_targets_subrange_(q, 0, 0, q->nr_levels - q->nr_top_levels); 40866a63635SJoe Thornber } 40966a63635SJoe Thornber } 41066a63635SJoe Thornber 41166a63635SJoe Thornber static void q_redistribute(struct queue *q) 41266a63635SJoe Thornber { 41366a63635SJoe Thornber unsigned target, level; 41466a63635SJoe Thornber struct ilist *l, *l_above; 41566a63635SJoe Thornber struct entry *e; 41666a63635SJoe Thornber 41766a63635SJoe Thornber q_set_targets(q); 41866a63635SJoe Thornber 41966a63635SJoe Thornber for (level = 0u; level < q->nr_levels - 1u; level++) { 42066a63635SJoe Thornber l = q->qs + level; 42166a63635SJoe Thornber target = q->target_count[level]; 42266a63635SJoe Thornber 42366a63635SJoe Thornber /* 42466a63635SJoe Thornber * Pull down some entries from the level above. 42566a63635SJoe Thornber */ 42666a63635SJoe Thornber while (l->nr_elts < target) { 42766a63635SJoe Thornber e = __redist_pop_from(q, level + 1u); 42866a63635SJoe Thornber if (!e) { 42966a63635SJoe Thornber /* bug in nr_elts */ 43066a63635SJoe Thornber break; 43166a63635SJoe Thornber } 43266a63635SJoe Thornber 43366a63635SJoe Thornber e->level = level; 43466a63635SJoe Thornber l_add_tail(q->es, l, e); 43566a63635SJoe Thornber } 43666a63635SJoe Thornber 43766a63635SJoe Thornber /* 43866a63635SJoe Thornber * Push some entries up. 43966a63635SJoe Thornber */ 44066a63635SJoe Thornber l_above = q->qs + level + 1u; 44166a63635SJoe Thornber while (l->nr_elts > target) { 44266a63635SJoe Thornber e = l_pop_tail(q->es, l); 44366a63635SJoe Thornber 44466a63635SJoe Thornber if (!e) 44566a63635SJoe Thornber /* bug in nr_elts */ 44666a63635SJoe Thornber break; 44766a63635SJoe Thornber 44866a63635SJoe Thornber e->level = level + 1u; 44966a63635SJoe Thornber l_add_head(q->es, l_above, e); 45066a63635SJoe Thornber } 45166a63635SJoe Thornber } 45266a63635SJoe Thornber } 45366a63635SJoe Thornber 45466a63635SJoe Thornber static void q_requeue_before(struct queue *q, struct entry *dest, struct entry *e, unsigned extra_levels) 45566a63635SJoe Thornber { 45666a63635SJoe Thornber struct entry *de; 45766a63635SJoe Thornber unsigned new_level; 45866a63635SJoe Thornber 45966a63635SJoe Thornber q_del(q, e); 46066a63635SJoe Thornber 46166a63635SJoe Thornber if (extra_levels && (e->level < q->nr_levels - 1u)) { 46266a63635SJoe Thornber new_level = min(q->nr_levels - 1u, e->level + extra_levels); 46366a63635SJoe Thornber for (de = l_head(q->es, q->qs + new_level); de; de = l_next(q->es, de)) { 46466a63635SJoe Thornber if (de->sentinel) 46566a63635SJoe Thornber continue; 46666a63635SJoe Thornber 46766a63635SJoe Thornber q_del(q, de); 46866a63635SJoe Thornber de->level = e->level; 46966a63635SJoe Thornber 47066a63635SJoe Thornber if (dest) 47166a63635SJoe Thornber q_push_before(q, dest, de); 47266a63635SJoe Thornber else 47366a63635SJoe Thornber q_push(q, de); 47466a63635SJoe Thornber break; 47566a63635SJoe Thornber } 47666a63635SJoe Thornber 47766a63635SJoe Thornber e->level = new_level; 47866a63635SJoe Thornber } 47966a63635SJoe Thornber 48066a63635SJoe Thornber q_push(q, e); 48166a63635SJoe Thornber } 48266a63635SJoe Thornber 48366a63635SJoe Thornber static void q_requeue(struct queue *q, struct entry *e, unsigned extra_levels) 48466a63635SJoe Thornber { 48566a63635SJoe Thornber q_requeue_before(q, NULL, e, extra_levels); 48666a63635SJoe Thornber } 48766a63635SJoe Thornber 48866a63635SJoe Thornber /*----------------------------------------------------------------*/ 48966a63635SJoe Thornber 49066a63635SJoe Thornber #define FP_SHIFT 8 49166a63635SJoe Thornber #define SIXTEENTH (1u << (FP_SHIFT - 4u)) 49266a63635SJoe Thornber #define EIGHTH (1u << (FP_SHIFT - 3u)) 49366a63635SJoe Thornber 49466a63635SJoe Thornber struct stats { 49566a63635SJoe Thornber unsigned hit_threshold; 49666a63635SJoe Thornber unsigned hits; 49766a63635SJoe Thornber unsigned misses; 49866a63635SJoe Thornber }; 49966a63635SJoe Thornber 50066a63635SJoe Thornber enum performance { 50166a63635SJoe Thornber Q_POOR, 50266a63635SJoe Thornber Q_FAIR, 50366a63635SJoe Thornber Q_WELL 50466a63635SJoe Thornber }; 50566a63635SJoe Thornber 50666a63635SJoe Thornber static void stats_init(struct stats *s, unsigned nr_levels) 50766a63635SJoe Thornber { 50866a63635SJoe Thornber s->hit_threshold = (nr_levels * 3u) / 4u; 50966a63635SJoe Thornber s->hits = 0u; 51066a63635SJoe Thornber s->misses = 0u; 51166a63635SJoe Thornber } 51266a63635SJoe Thornber 51366a63635SJoe Thornber static void stats_reset(struct stats *s) 51466a63635SJoe Thornber { 51566a63635SJoe Thornber s->hits = s->misses = 0u; 51666a63635SJoe Thornber } 51766a63635SJoe Thornber 51866a63635SJoe Thornber static void stats_level_accessed(struct stats *s, unsigned level) 51966a63635SJoe Thornber { 52066a63635SJoe Thornber if (level >= s->hit_threshold) 52166a63635SJoe Thornber s->hits++; 52266a63635SJoe Thornber else 52366a63635SJoe Thornber s->misses++; 52466a63635SJoe Thornber } 52566a63635SJoe Thornber 52666a63635SJoe Thornber static void stats_miss(struct stats *s) 52766a63635SJoe Thornber { 52866a63635SJoe Thornber s->misses++; 52966a63635SJoe Thornber } 53066a63635SJoe Thornber 53166a63635SJoe Thornber /* 53266a63635SJoe Thornber * There are times when we don't have any confidence in the hotspot queue. 53366a63635SJoe Thornber * Such as when a fresh cache is created and the blocks have been spread 53466a63635SJoe Thornber * out across the levels, or if an io load changes. We detect this by 53566a63635SJoe Thornber * seeing how often a lookup is in the top levels of the hotspot queue. 53666a63635SJoe Thornber */ 53766a63635SJoe Thornber static enum performance stats_assess(struct stats *s) 53866a63635SJoe Thornber { 53966a63635SJoe Thornber unsigned confidence = safe_div(s->hits << FP_SHIFT, s->hits + s->misses); 54066a63635SJoe Thornber 54166a63635SJoe Thornber if (confidence < SIXTEENTH) 54266a63635SJoe Thornber return Q_POOR; 54366a63635SJoe Thornber 54466a63635SJoe Thornber else if (confidence < EIGHTH) 54566a63635SJoe Thornber return Q_FAIR; 54666a63635SJoe Thornber 54766a63635SJoe Thornber else 54866a63635SJoe Thornber return Q_WELL; 54966a63635SJoe Thornber } 55066a63635SJoe Thornber 55166a63635SJoe Thornber /*----------------------------------------------------------------*/ 55266a63635SJoe Thornber 55366a63635SJoe Thornber struct hash_table { 55466a63635SJoe Thornber struct entry_space *es; 55566a63635SJoe Thornber unsigned long long hash_bits; 55666a63635SJoe Thornber unsigned *buckets; 55766a63635SJoe Thornber }; 55866a63635SJoe Thornber 55966a63635SJoe Thornber /* 56066a63635SJoe Thornber * All cache entries are stored in a chained hash table. To save space we 56166a63635SJoe Thornber * use indexing again, and only store indexes to the next entry. 56266a63635SJoe Thornber */ 56366a63635SJoe Thornber static int h_init(struct hash_table *ht, struct entry_space *es, unsigned nr_entries) 56466a63635SJoe Thornber { 56566a63635SJoe Thornber unsigned i, nr_buckets; 56666a63635SJoe Thornber 56766a63635SJoe Thornber ht->es = es; 56866a63635SJoe Thornber nr_buckets = roundup_pow_of_two(max(nr_entries / 4u, 16u)); 569a3d939aeSMikulas Patocka ht->hash_bits = __ffs(nr_buckets); 57066a63635SJoe Thornber 57166a63635SJoe Thornber ht->buckets = vmalloc(sizeof(*ht->buckets) * nr_buckets); 57266a63635SJoe Thornber if (!ht->buckets) 57366a63635SJoe Thornber return -ENOMEM; 57466a63635SJoe Thornber 57566a63635SJoe Thornber for (i = 0; i < nr_buckets; i++) 57666a63635SJoe Thornber ht->buckets[i] = INDEXER_NULL; 57766a63635SJoe Thornber 57866a63635SJoe Thornber return 0; 57966a63635SJoe Thornber } 58066a63635SJoe Thornber 58166a63635SJoe Thornber static void h_exit(struct hash_table *ht) 58266a63635SJoe Thornber { 58366a63635SJoe Thornber vfree(ht->buckets); 58466a63635SJoe Thornber } 58566a63635SJoe Thornber 58666a63635SJoe Thornber static struct entry *h_head(struct hash_table *ht, unsigned bucket) 58766a63635SJoe Thornber { 58866a63635SJoe Thornber return to_entry(ht->es, ht->buckets[bucket]); 58966a63635SJoe Thornber } 59066a63635SJoe Thornber 59166a63635SJoe Thornber static struct entry *h_next(struct hash_table *ht, struct entry *e) 59266a63635SJoe Thornber { 59366a63635SJoe Thornber return to_entry(ht->es, e->hash_next); 59466a63635SJoe Thornber } 59566a63635SJoe Thornber 59666a63635SJoe Thornber static void __h_insert(struct hash_table *ht, unsigned bucket, struct entry *e) 59766a63635SJoe Thornber { 59866a63635SJoe Thornber e->hash_next = ht->buckets[bucket]; 59966a63635SJoe Thornber ht->buckets[bucket] = to_index(ht->es, e); 60066a63635SJoe Thornber } 60166a63635SJoe Thornber 60266a63635SJoe Thornber static void h_insert(struct hash_table *ht, struct entry *e) 60366a63635SJoe Thornber { 60466a63635SJoe Thornber unsigned h = hash_64(from_oblock(e->oblock), ht->hash_bits); 60566a63635SJoe Thornber __h_insert(ht, h, e); 60666a63635SJoe Thornber } 60766a63635SJoe Thornber 60866a63635SJoe Thornber static struct entry *__h_lookup(struct hash_table *ht, unsigned h, dm_oblock_t oblock, 60966a63635SJoe Thornber struct entry **prev) 61066a63635SJoe Thornber { 61166a63635SJoe Thornber struct entry *e; 61266a63635SJoe Thornber 61366a63635SJoe Thornber *prev = NULL; 61466a63635SJoe Thornber for (e = h_head(ht, h); e; e = h_next(ht, e)) { 61566a63635SJoe Thornber if (e->oblock == oblock) 61666a63635SJoe Thornber return e; 61766a63635SJoe Thornber 61866a63635SJoe Thornber *prev = e; 61966a63635SJoe Thornber } 62066a63635SJoe Thornber 62166a63635SJoe Thornber return NULL; 62266a63635SJoe Thornber } 62366a63635SJoe Thornber 62466a63635SJoe Thornber static void __h_unlink(struct hash_table *ht, unsigned h, 62566a63635SJoe Thornber struct entry *e, struct entry *prev) 62666a63635SJoe Thornber { 62766a63635SJoe Thornber if (prev) 62866a63635SJoe Thornber prev->hash_next = e->hash_next; 62966a63635SJoe Thornber else 63066a63635SJoe Thornber ht->buckets[h] = e->hash_next; 63166a63635SJoe Thornber } 63266a63635SJoe Thornber 63366a63635SJoe Thornber /* 63466a63635SJoe Thornber * Also moves each entry to the front of the bucket. 63566a63635SJoe Thornber */ 63666a63635SJoe Thornber static struct entry *h_lookup(struct hash_table *ht, dm_oblock_t oblock) 63766a63635SJoe Thornber { 63866a63635SJoe Thornber struct entry *e, *prev; 63966a63635SJoe Thornber unsigned h = hash_64(from_oblock(oblock), ht->hash_bits); 64066a63635SJoe Thornber 64166a63635SJoe Thornber e = __h_lookup(ht, h, oblock, &prev); 64266a63635SJoe Thornber if (e && prev) { 64366a63635SJoe Thornber /* 64466a63635SJoe Thornber * Move to the front because this entry is likely 64566a63635SJoe Thornber * to be hit again. 64666a63635SJoe Thornber */ 64766a63635SJoe Thornber __h_unlink(ht, h, e, prev); 64866a63635SJoe Thornber __h_insert(ht, h, e); 64966a63635SJoe Thornber } 65066a63635SJoe Thornber 65166a63635SJoe Thornber return e; 65266a63635SJoe Thornber } 65366a63635SJoe Thornber 65466a63635SJoe Thornber static void h_remove(struct hash_table *ht, struct entry *e) 65566a63635SJoe Thornber { 65666a63635SJoe Thornber unsigned h = hash_64(from_oblock(e->oblock), ht->hash_bits); 65766a63635SJoe Thornber struct entry *prev; 65866a63635SJoe Thornber 65966a63635SJoe Thornber /* 66066a63635SJoe Thornber * The down side of using a singly linked list is we have to 66166a63635SJoe Thornber * iterate the bucket to remove an item. 66266a63635SJoe Thornber */ 66366a63635SJoe Thornber e = __h_lookup(ht, h, e->oblock, &prev); 66466a63635SJoe Thornber if (e) 66566a63635SJoe Thornber __h_unlink(ht, h, e, prev); 66666a63635SJoe Thornber } 66766a63635SJoe Thornber 66866a63635SJoe Thornber /*----------------------------------------------------------------*/ 66966a63635SJoe Thornber 67066a63635SJoe Thornber struct entry_alloc { 67166a63635SJoe Thornber struct entry_space *es; 67266a63635SJoe Thornber unsigned begin; 67366a63635SJoe Thornber 67466a63635SJoe Thornber unsigned nr_allocated; 67566a63635SJoe Thornber struct ilist free; 67666a63635SJoe Thornber }; 67766a63635SJoe Thornber 67866a63635SJoe Thornber static void init_allocator(struct entry_alloc *ea, struct entry_space *es, 67966a63635SJoe Thornber unsigned begin, unsigned end) 68066a63635SJoe Thornber { 68166a63635SJoe Thornber unsigned i; 68266a63635SJoe Thornber 68366a63635SJoe Thornber ea->es = es; 68466a63635SJoe Thornber ea->nr_allocated = 0u; 68566a63635SJoe Thornber ea->begin = begin; 68666a63635SJoe Thornber 68766a63635SJoe Thornber l_init(&ea->free); 68866a63635SJoe Thornber for (i = begin; i != end; i++) 68966a63635SJoe Thornber l_add_tail(ea->es, &ea->free, __get_entry(ea->es, i)); 69066a63635SJoe Thornber } 69166a63635SJoe Thornber 69266a63635SJoe Thornber static void init_entry(struct entry *e) 69366a63635SJoe Thornber { 69466a63635SJoe Thornber /* 69566a63635SJoe Thornber * We can't memset because that would clear the hotspot and 69666a63635SJoe Thornber * sentinel bits which remain constant. 69766a63635SJoe Thornber */ 69866a63635SJoe Thornber e->hash_next = INDEXER_NULL; 69966a63635SJoe Thornber e->next = INDEXER_NULL; 70066a63635SJoe Thornber e->prev = INDEXER_NULL; 70166a63635SJoe Thornber e->level = 0u; 70266a63635SJoe Thornber e->allocated = true; 70366a63635SJoe Thornber } 70466a63635SJoe Thornber 70566a63635SJoe Thornber static struct entry *alloc_entry(struct entry_alloc *ea) 70666a63635SJoe Thornber { 70766a63635SJoe Thornber struct entry *e; 70866a63635SJoe Thornber 70966a63635SJoe Thornber if (l_empty(&ea->free)) 71066a63635SJoe Thornber return NULL; 71166a63635SJoe Thornber 71266a63635SJoe Thornber e = l_pop_tail(ea->es, &ea->free); 71366a63635SJoe Thornber init_entry(e); 71466a63635SJoe Thornber ea->nr_allocated++; 71566a63635SJoe Thornber 71666a63635SJoe Thornber return e; 71766a63635SJoe Thornber } 71866a63635SJoe Thornber 71966a63635SJoe Thornber /* 72066a63635SJoe Thornber * This assumes the cblock hasn't already been allocated. 72166a63635SJoe Thornber */ 72266a63635SJoe Thornber static struct entry *alloc_particular_entry(struct entry_alloc *ea, unsigned i) 72366a63635SJoe Thornber { 72466a63635SJoe Thornber struct entry *e = __get_entry(ea->es, ea->begin + i); 72566a63635SJoe Thornber 72666a63635SJoe Thornber BUG_ON(e->allocated); 72766a63635SJoe Thornber 72866a63635SJoe Thornber l_del(ea->es, &ea->free, e); 72966a63635SJoe Thornber init_entry(e); 73066a63635SJoe Thornber ea->nr_allocated++; 73166a63635SJoe Thornber 73266a63635SJoe Thornber return e; 73366a63635SJoe Thornber } 73466a63635SJoe Thornber 73566a63635SJoe Thornber static void free_entry(struct entry_alloc *ea, struct entry *e) 73666a63635SJoe Thornber { 73766a63635SJoe Thornber BUG_ON(!ea->nr_allocated); 73866a63635SJoe Thornber BUG_ON(!e->allocated); 73966a63635SJoe Thornber 74066a63635SJoe Thornber ea->nr_allocated--; 74166a63635SJoe Thornber e->allocated = false; 74266a63635SJoe Thornber l_add_tail(ea->es, &ea->free, e); 74366a63635SJoe Thornber } 74466a63635SJoe Thornber 74566a63635SJoe Thornber static bool allocator_empty(struct entry_alloc *ea) 74666a63635SJoe Thornber { 74766a63635SJoe Thornber return l_empty(&ea->free); 74866a63635SJoe Thornber } 74966a63635SJoe Thornber 75066a63635SJoe Thornber static unsigned get_index(struct entry_alloc *ea, struct entry *e) 75166a63635SJoe Thornber { 75266a63635SJoe Thornber return to_index(ea->es, e) - ea->begin; 75366a63635SJoe Thornber } 75466a63635SJoe Thornber 75566a63635SJoe Thornber static struct entry *get_entry(struct entry_alloc *ea, unsigned index) 75666a63635SJoe Thornber { 75766a63635SJoe Thornber return __get_entry(ea->es, ea->begin + index); 75866a63635SJoe Thornber } 75966a63635SJoe Thornber 76066a63635SJoe Thornber /*----------------------------------------------------------------*/ 76166a63635SJoe Thornber 76266a63635SJoe Thornber #define NR_HOTSPOT_LEVELS 64u 76366a63635SJoe Thornber #define NR_CACHE_LEVELS 64u 76466a63635SJoe Thornber 76566a63635SJoe Thornber #define WRITEBACK_PERIOD (10 * HZ) 76666a63635SJoe Thornber #define DEMOTE_PERIOD (60 * HZ) 76766a63635SJoe Thornber 76866a63635SJoe Thornber #define HOTSPOT_UPDATE_PERIOD (HZ) 76966a63635SJoe Thornber #define CACHE_UPDATE_PERIOD (10u * HZ) 77066a63635SJoe Thornber 77166a63635SJoe Thornber struct smq_policy { 77266a63635SJoe Thornber struct dm_cache_policy policy; 77366a63635SJoe Thornber 77466a63635SJoe Thornber /* protects everything */ 7754051aab7SJoe Thornber spinlock_t lock; 77666a63635SJoe Thornber dm_cblock_t cache_size; 77766a63635SJoe Thornber sector_t cache_block_size; 77866a63635SJoe Thornber 77966a63635SJoe Thornber sector_t hotspot_block_size; 78066a63635SJoe Thornber unsigned nr_hotspot_blocks; 78166a63635SJoe Thornber unsigned cache_blocks_per_hotspot_block; 78266a63635SJoe Thornber unsigned hotspot_level_jump; 78366a63635SJoe Thornber 78466a63635SJoe Thornber struct entry_space es; 78566a63635SJoe Thornber struct entry_alloc writeback_sentinel_alloc; 78666a63635SJoe Thornber struct entry_alloc demote_sentinel_alloc; 78766a63635SJoe Thornber struct entry_alloc hotspot_alloc; 78866a63635SJoe Thornber struct entry_alloc cache_alloc; 78966a63635SJoe Thornber 79066a63635SJoe Thornber unsigned long *hotspot_hit_bits; 79166a63635SJoe Thornber unsigned long *cache_hit_bits; 79266a63635SJoe Thornber 79366a63635SJoe Thornber /* 79466a63635SJoe Thornber * We maintain three queues of entries. The cache proper, 79566a63635SJoe Thornber * consisting of a clean and dirty queue, containing the currently 79666a63635SJoe Thornber * active mappings. The hotspot queue uses a larger block size to 79766a63635SJoe Thornber * track blocks that are being hit frequently and potential 79866a63635SJoe Thornber * candidates for promotion to the cache. 79966a63635SJoe Thornber */ 80066a63635SJoe Thornber struct queue hotspot; 80166a63635SJoe Thornber struct queue clean; 80266a63635SJoe Thornber struct queue dirty; 80366a63635SJoe Thornber 80466a63635SJoe Thornber struct stats hotspot_stats; 80566a63635SJoe Thornber struct stats cache_stats; 80666a63635SJoe Thornber 80766a63635SJoe Thornber /* 80866a63635SJoe Thornber * Keeps track of time, incremented by the core. We use this to 80966a63635SJoe Thornber * avoid attributing multiple hits within the same tick. 81066a63635SJoe Thornber */ 81166a63635SJoe Thornber unsigned tick; 81266a63635SJoe Thornber 81366a63635SJoe Thornber /* 81466a63635SJoe Thornber * The hash tables allows us to quickly find an entry by origin 81566a63635SJoe Thornber * block. 81666a63635SJoe Thornber */ 81766a63635SJoe Thornber struct hash_table table; 81866a63635SJoe Thornber struct hash_table hotspot_table; 81966a63635SJoe Thornber 82066a63635SJoe Thornber bool current_writeback_sentinels; 82166a63635SJoe Thornber unsigned long next_writeback_period; 82266a63635SJoe Thornber 82366a63635SJoe Thornber bool current_demote_sentinels; 82466a63635SJoe Thornber unsigned long next_demote_period; 82566a63635SJoe Thornber 82666a63635SJoe Thornber unsigned write_promote_level; 82766a63635SJoe Thornber unsigned read_promote_level; 82866a63635SJoe Thornber 82966a63635SJoe Thornber unsigned long next_hotspot_period; 83066a63635SJoe Thornber unsigned long next_cache_period; 83166a63635SJoe Thornber }; 83266a63635SJoe Thornber 83366a63635SJoe Thornber /*----------------------------------------------------------------*/ 83466a63635SJoe Thornber 83566a63635SJoe Thornber static struct entry *get_sentinel(struct entry_alloc *ea, unsigned level, bool which) 83666a63635SJoe Thornber { 83766a63635SJoe Thornber return get_entry(ea, which ? level : NR_CACHE_LEVELS + level); 83866a63635SJoe Thornber } 83966a63635SJoe Thornber 84066a63635SJoe Thornber static struct entry *writeback_sentinel(struct smq_policy *mq, unsigned level) 84166a63635SJoe Thornber { 84266a63635SJoe Thornber return get_sentinel(&mq->writeback_sentinel_alloc, level, mq->current_writeback_sentinels); 84366a63635SJoe Thornber } 84466a63635SJoe Thornber 84566a63635SJoe Thornber static struct entry *demote_sentinel(struct smq_policy *mq, unsigned level) 84666a63635SJoe Thornber { 84766a63635SJoe Thornber return get_sentinel(&mq->demote_sentinel_alloc, level, mq->current_demote_sentinels); 84866a63635SJoe Thornber } 84966a63635SJoe Thornber 85066a63635SJoe Thornber static void __update_writeback_sentinels(struct smq_policy *mq) 85166a63635SJoe Thornber { 85266a63635SJoe Thornber unsigned level; 85366a63635SJoe Thornber struct queue *q = &mq->dirty; 85466a63635SJoe Thornber struct entry *sentinel; 85566a63635SJoe Thornber 85666a63635SJoe Thornber for (level = 0; level < q->nr_levels; level++) { 85766a63635SJoe Thornber sentinel = writeback_sentinel(mq, level); 85866a63635SJoe Thornber q_del(q, sentinel); 85966a63635SJoe Thornber q_push(q, sentinel); 86066a63635SJoe Thornber } 86166a63635SJoe Thornber } 86266a63635SJoe Thornber 86366a63635SJoe Thornber static void __update_demote_sentinels(struct smq_policy *mq) 86466a63635SJoe Thornber { 86566a63635SJoe Thornber unsigned level; 86666a63635SJoe Thornber struct queue *q = &mq->clean; 86766a63635SJoe Thornber struct entry *sentinel; 86866a63635SJoe Thornber 86966a63635SJoe Thornber for (level = 0; level < q->nr_levels; level++) { 87066a63635SJoe Thornber sentinel = demote_sentinel(mq, level); 87166a63635SJoe Thornber q_del(q, sentinel); 87266a63635SJoe Thornber q_push(q, sentinel); 87366a63635SJoe Thornber } 87466a63635SJoe Thornber } 87566a63635SJoe Thornber 87666a63635SJoe Thornber static void update_sentinels(struct smq_policy *mq) 87766a63635SJoe Thornber { 87866a63635SJoe Thornber if (time_after(jiffies, mq->next_writeback_period)) { 87966a63635SJoe Thornber __update_writeback_sentinels(mq); 88066a63635SJoe Thornber mq->next_writeback_period = jiffies + WRITEBACK_PERIOD; 88166a63635SJoe Thornber mq->current_writeback_sentinels = !mq->current_writeback_sentinels; 88266a63635SJoe Thornber } 88366a63635SJoe Thornber 88466a63635SJoe Thornber if (time_after(jiffies, mq->next_demote_period)) { 88566a63635SJoe Thornber __update_demote_sentinels(mq); 88666a63635SJoe Thornber mq->next_demote_period = jiffies + DEMOTE_PERIOD; 88766a63635SJoe Thornber mq->current_demote_sentinels = !mq->current_demote_sentinels; 88866a63635SJoe Thornber } 88966a63635SJoe Thornber } 89066a63635SJoe Thornber 89166a63635SJoe Thornber static void __sentinels_init(struct smq_policy *mq) 89266a63635SJoe Thornber { 89366a63635SJoe Thornber unsigned level; 89466a63635SJoe Thornber struct entry *sentinel; 89566a63635SJoe Thornber 89666a63635SJoe Thornber for (level = 0; level < NR_CACHE_LEVELS; level++) { 89766a63635SJoe Thornber sentinel = writeback_sentinel(mq, level); 89866a63635SJoe Thornber sentinel->level = level; 89966a63635SJoe Thornber q_push(&mq->dirty, sentinel); 90066a63635SJoe Thornber 90166a63635SJoe Thornber sentinel = demote_sentinel(mq, level); 90266a63635SJoe Thornber sentinel->level = level; 90366a63635SJoe Thornber q_push(&mq->clean, sentinel); 90466a63635SJoe Thornber } 90566a63635SJoe Thornber } 90666a63635SJoe Thornber 90766a63635SJoe Thornber static void sentinels_init(struct smq_policy *mq) 90866a63635SJoe Thornber { 90966a63635SJoe Thornber mq->next_writeback_period = jiffies + WRITEBACK_PERIOD; 91066a63635SJoe Thornber mq->next_demote_period = jiffies + DEMOTE_PERIOD; 91166a63635SJoe Thornber 91266a63635SJoe Thornber mq->current_writeback_sentinels = false; 91366a63635SJoe Thornber mq->current_demote_sentinels = false; 91466a63635SJoe Thornber __sentinels_init(mq); 91566a63635SJoe Thornber 91666a63635SJoe Thornber mq->current_writeback_sentinels = !mq->current_writeback_sentinels; 91766a63635SJoe Thornber mq->current_demote_sentinels = !mq->current_demote_sentinels; 91866a63635SJoe Thornber __sentinels_init(mq); 91966a63635SJoe Thornber } 92066a63635SJoe Thornber 92166a63635SJoe Thornber /*----------------------------------------------------------------*/ 92266a63635SJoe Thornber 92366a63635SJoe Thornber /* 92466a63635SJoe Thornber * These methods tie together the dirty queue, clean queue and hash table. 92566a63635SJoe Thornber */ 92666a63635SJoe Thornber static void push_new(struct smq_policy *mq, struct entry *e) 92766a63635SJoe Thornber { 92866a63635SJoe Thornber struct queue *q = e->dirty ? &mq->dirty : &mq->clean; 92966a63635SJoe Thornber h_insert(&mq->table, e); 93066a63635SJoe Thornber q_push(q, e); 93166a63635SJoe Thornber } 93266a63635SJoe Thornber 93366a63635SJoe Thornber static void push(struct smq_policy *mq, struct entry *e) 93466a63635SJoe Thornber { 93566a63635SJoe Thornber struct entry *sentinel; 93666a63635SJoe Thornber 93766a63635SJoe Thornber h_insert(&mq->table, e); 93866a63635SJoe Thornber 93966a63635SJoe Thornber /* 94066a63635SJoe Thornber * Punch this into the queue just in front of the sentinel, to 94166a63635SJoe Thornber * ensure it's cleaned straight away. 94266a63635SJoe Thornber */ 94366a63635SJoe Thornber if (e->dirty) { 94466a63635SJoe Thornber sentinel = writeback_sentinel(mq, e->level); 94566a63635SJoe Thornber q_push_before(&mq->dirty, sentinel, e); 94666a63635SJoe Thornber } else { 94766a63635SJoe Thornber sentinel = demote_sentinel(mq, e->level); 94866a63635SJoe Thornber q_push_before(&mq->clean, sentinel, e); 94966a63635SJoe Thornber } 95066a63635SJoe Thornber } 95166a63635SJoe Thornber 95266a63635SJoe Thornber /* 95366a63635SJoe Thornber * Removes an entry from cache. Removes from the hash table. 95466a63635SJoe Thornber */ 95566a63635SJoe Thornber static void __del(struct smq_policy *mq, struct queue *q, struct entry *e) 95666a63635SJoe Thornber { 95766a63635SJoe Thornber q_del(q, e); 95866a63635SJoe Thornber h_remove(&mq->table, e); 95966a63635SJoe Thornber } 96066a63635SJoe Thornber 96166a63635SJoe Thornber static void del(struct smq_policy *mq, struct entry *e) 96266a63635SJoe Thornber { 96366a63635SJoe Thornber __del(mq, e->dirty ? &mq->dirty : &mq->clean, e); 96466a63635SJoe Thornber } 96566a63635SJoe Thornber 96666a63635SJoe Thornber static struct entry *pop_old(struct smq_policy *mq, struct queue *q, unsigned max_level) 96766a63635SJoe Thornber { 96866a63635SJoe Thornber struct entry *e = q_pop_old(q, max_level); 96966a63635SJoe Thornber if (e) 97066a63635SJoe Thornber h_remove(&mq->table, e); 97166a63635SJoe Thornber return e; 97266a63635SJoe Thornber } 97366a63635SJoe Thornber 97466a63635SJoe Thornber static dm_cblock_t infer_cblock(struct smq_policy *mq, struct entry *e) 97566a63635SJoe Thornber { 97666a63635SJoe Thornber return to_cblock(get_index(&mq->cache_alloc, e)); 97766a63635SJoe Thornber } 97866a63635SJoe Thornber 97966a63635SJoe Thornber static void requeue(struct smq_policy *mq, struct entry *e) 98066a63635SJoe Thornber { 98166a63635SJoe Thornber struct entry *sentinel; 98266a63635SJoe Thornber 98366a63635SJoe Thornber if (!test_and_set_bit(from_cblock(infer_cblock(mq, e)), mq->cache_hit_bits)) { 98466a63635SJoe Thornber if (e->dirty) { 98566a63635SJoe Thornber sentinel = writeback_sentinel(mq, e->level); 98666a63635SJoe Thornber q_requeue_before(&mq->dirty, sentinel, e, 1u); 98766a63635SJoe Thornber } else { 98866a63635SJoe Thornber sentinel = demote_sentinel(mq, e->level); 98966a63635SJoe Thornber q_requeue_before(&mq->clean, sentinel, e, 1u); 99066a63635SJoe Thornber } 99166a63635SJoe Thornber } 99266a63635SJoe Thornber } 99366a63635SJoe Thornber 99466a63635SJoe Thornber static unsigned default_promote_level(struct smq_policy *mq) 99566a63635SJoe Thornber { 99666a63635SJoe Thornber /* 99766a63635SJoe Thornber * The promote level depends on the current performance of the 99866a63635SJoe Thornber * cache. 99966a63635SJoe Thornber * 100066a63635SJoe Thornber * If the cache is performing badly, then we can't afford 100166a63635SJoe Thornber * to promote much without causing performance to drop below that 100266a63635SJoe Thornber * of the origin device. 100366a63635SJoe Thornber * 100466a63635SJoe Thornber * If the cache is performing well, then we don't need to promote 100566a63635SJoe Thornber * much. If it isn't broken, don't fix it. 100666a63635SJoe Thornber * 100766a63635SJoe Thornber * If the cache is middling then we promote more. 100866a63635SJoe Thornber * 100966a63635SJoe Thornber * This scheme reminds me of a graph of entropy vs probability of a 101066a63635SJoe Thornber * binary variable. 101166a63635SJoe Thornber */ 101266a63635SJoe Thornber static unsigned table[] = {1, 1, 1, 2, 4, 6, 7, 8, 7, 6, 4, 4, 3, 3, 2, 2, 1}; 101366a63635SJoe Thornber 101466a63635SJoe Thornber unsigned hits = mq->cache_stats.hits; 101566a63635SJoe Thornber unsigned misses = mq->cache_stats.misses; 101666a63635SJoe Thornber unsigned index = safe_div(hits << 4u, hits + misses); 101766a63635SJoe Thornber return table[index]; 101866a63635SJoe Thornber } 101966a63635SJoe Thornber 102066a63635SJoe Thornber static void update_promote_levels(struct smq_policy *mq) 102166a63635SJoe Thornber { 102266a63635SJoe Thornber /* 102366a63635SJoe Thornber * If there are unused cache entries then we want to be really 102466a63635SJoe Thornber * eager to promote. 102566a63635SJoe Thornber */ 102666a63635SJoe Thornber unsigned threshold_level = allocator_empty(&mq->cache_alloc) ? 102766a63635SJoe Thornber default_promote_level(mq) : (NR_HOTSPOT_LEVELS / 2u); 102866a63635SJoe Thornber 102966a63635SJoe Thornber /* 103066a63635SJoe Thornber * If the hotspot queue is performing badly then we have little 103166a63635SJoe Thornber * confidence that we know which blocks to promote. So we cut down 103266a63635SJoe Thornber * the amount of promotions. 103366a63635SJoe Thornber */ 103466a63635SJoe Thornber switch (stats_assess(&mq->hotspot_stats)) { 103566a63635SJoe Thornber case Q_POOR: 103666a63635SJoe Thornber threshold_level /= 4u; 103766a63635SJoe Thornber break; 103866a63635SJoe Thornber 103966a63635SJoe Thornber case Q_FAIR: 104066a63635SJoe Thornber threshold_level /= 2u; 104166a63635SJoe Thornber break; 104266a63635SJoe Thornber 104366a63635SJoe Thornber case Q_WELL: 104466a63635SJoe Thornber break; 104566a63635SJoe Thornber } 104666a63635SJoe Thornber 104766a63635SJoe Thornber mq->read_promote_level = NR_HOTSPOT_LEVELS - threshold_level; 104866a63635SJoe Thornber mq->write_promote_level = (NR_HOTSPOT_LEVELS - threshold_level) + 2u; 104966a63635SJoe Thornber } 105066a63635SJoe Thornber 105166a63635SJoe Thornber /* 105266a63635SJoe Thornber * If the hotspot queue is performing badly, then we try and move entries 105366a63635SJoe Thornber * around more quickly. 105466a63635SJoe Thornber */ 105566a63635SJoe Thornber static void update_level_jump(struct smq_policy *mq) 105666a63635SJoe Thornber { 105766a63635SJoe Thornber switch (stats_assess(&mq->hotspot_stats)) { 105866a63635SJoe Thornber case Q_POOR: 105966a63635SJoe Thornber mq->hotspot_level_jump = 4u; 106066a63635SJoe Thornber break; 106166a63635SJoe Thornber 106266a63635SJoe Thornber case Q_FAIR: 106366a63635SJoe Thornber mq->hotspot_level_jump = 2u; 106466a63635SJoe Thornber break; 106566a63635SJoe Thornber 106666a63635SJoe Thornber case Q_WELL: 106766a63635SJoe Thornber mq->hotspot_level_jump = 1u; 106866a63635SJoe Thornber break; 106966a63635SJoe Thornber } 107066a63635SJoe Thornber } 107166a63635SJoe Thornber 107266a63635SJoe Thornber static void end_hotspot_period(struct smq_policy *mq) 107366a63635SJoe Thornber { 107466a63635SJoe Thornber clear_bitset(mq->hotspot_hit_bits, mq->nr_hotspot_blocks); 107566a63635SJoe Thornber update_promote_levels(mq); 107666a63635SJoe Thornber 107766a63635SJoe Thornber if (time_after(jiffies, mq->next_hotspot_period)) { 107866a63635SJoe Thornber update_level_jump(mq); 107966a63635SJoe Thornber q_redistribute(&mq->hotspot); 108066a63635SJoe Thornber stats_reset(&mq->hotspot_stats); 108166a63635SJoe Thornber mq->next_hotspot_period = jiffies + HOTSPOT_UPDATE_PERIOD; 108266a63635SJoe Thornber } 108366a63635SJoe Thornber } 108466a63635SJoe Thornber 108566a63635SJoe Thornber static void end_cache_period(struct smq_policy *mq) 108666a63635SJoe Thornber { 108766a63635SJoe Thornber if (time_after(jiffies, mq->next_cache_period)) { 108866a63635SJoe Thornber clear_bitset(mq->cache_hit_bits, from_cblock(mq->cache_size)); 108966a63635SJoe Thornber 109066a63635SJoe Thornber q_redistribute(&mq->dirty); 109166a63635SJoe Thornber q_redistribute(&mq->clean); 109266a63635SJoe Thornber stats_reset(&mq->cache_stats); 109366a63635SJoe Thornber 109466a63635SJoe Thornber mq->next_cache_period = jiffies + CACHE_UPDATE_PERIOD; 109566a63635SJoe Thornber } 109666a63635SJoe Thornber } 109766a63635SJoe Thornber 109866a63635SJoe Thornber static int demote_cblock(struct smq_policy *mq, 109966a63635SJoe Thornber struct policy_locker *locker, 110066a63635SJoe Thornber dm_oblock_t *oblock) 110166a63635SJoe Thornber { 110266a63635SJoe Thornber struct entry *demoted = q_peek(&mq->clean, mq->clean.nr_levels, false); 110366a63635SJoe Thornber if (!demoted) 110466a63635SJoe Thornber /* 110566a63635SJoe Thornber * We could get a block from mq->dirty, but that 110666a63635SJoe Thornber * would add extra latency to the triggering bio as it 110766a63635SJoe Thornber * waits for the writeback. Better to not promote this 110866a63635SJoe Thornber * time and hope there's a clean block next time this block 110966a63635SJoe Thornber * is hit. 111066a63635SJoe Thornber */ 111166a63635SJoe Thornber return -ENOSPC; 111266a63635SJoe Thornber 111366a63635SJoe Thornber if (locker->fn(locker, demoted->oblock)) 111466a63635SJoe Thornber /* 111566a63635SJoe Thornber * We couldn't lock this block. 111666a63635SJoe Thornber */ 111766a63635SJoe Thornber return -EBUSY; 111866a63635SJoe Thornber 111966a63635SJoe Thornber del(mq, demoted); 112066a63635SJoe Thornber *oblock = demoted->oblock; 112166a63635SJoe Thornber free_entry(&mq->cache_alloc, demoted); 112266a63635SJoe Thornber 112366a63635SJoe Thornber return 0; 112466a63635SJoe Thornber } 112566a63635SJoe Thornber 112666a63635SJoe Thornber enum promote_result { 112766a63635SJoe Thornber PROMOTE_NOT, 112866a63635SJoe Thornber PROMOTE_TEMPORARY, 112966a63635SJoe Thornber PROMOTE_PERMANENT 113066a63635SJoe Thornber }; 113166a63635SJoe Thornber 113266a63635SJoe Thornber /* 113366a63635SJoe Thornber * Converts a boolean into a promote result. 113466a63635SJoe Thornber */ 113566a63635SJoe Thornber static enum promote_result maybe_promote(bool promote) 113666a63635SJoe Thornber { 113766a63635SJoe Thornber return promote ? PROMOTE_PERMANENT : PROMOTE_NOT; 113866a63635SJoe Thornber } 113966a63635SJoe Thornber 114066a63635SJoe Thornber static enum promote_result should_promote(struct smq_policy *mq, struct entry *hs_e, struct bio *bio, 114166a63635SJoe Thornber bool fast_promote) 114266a63635SJoe Thornber { 114366a63635SJoe Thornber if (bio_data_dir(bio) == WRITE) { 114466a63635SJoe Thornber if (!allocator_empty(&mq->cache_alloc) && fast_promote) 114566a63635SJoe Thornber return PROMOTE_TEMPORARY; 114666a63635SJoe Thornber 114766a63635SJoe Thornber else 114866a63635SJoe Thornber return maybe_promote(hs_e->level >= mq->write_promote_level); 114966a63635SJoe Thornber } else 115066a63635SJoe Thornber return maybe_promote(hs_e->level >= mq->read_promote_level); 115166a63635SJoe Thornber } 115266a63635SJoe Thornber 115366a63635SJoe Thornber static void insert_in_cache(struct smq_policy *mq, dm_oblock_t oblock, 115466a63635SJoe Thornber struct policy_locker *locker, 115566a63635SJoe Thornber struct policy_result *result, enum promote_result pr) 115666a63635SJoe Thornber { 115766a63635SJoe Thornber int r; 115866a63635SJoe Thornber struct entry *e; 115966a63635SJoe Thornber 116066a63635SJoe Thornber if (allocator_empty(&mq->cache_alloc)) { 116166a63635SJoe Thornber result->op = POLICY_REPLACE; 116266a63635SJoe Thornber r = demote_cblock(mq, locker, &result->old_oblock); 116366a63635SJoe Thornber if (r) { 116466a63635SJoe Thornber result->op = POLICY_MISS; 116566a63635SJoe Thornber return; 116666a63635SJoe Thornber } 116766a63635SJoe Thornber 116866a63635SJoe Thornber } else 116966a63635SJoe Thornber result->op = POLICY_NEW; 117066a63635SJoe Thornber 117166a63635SJoe Thornber e = alloc_entry(&mq->cache_alloc); 117266a63635SJoe Thornber BUG_ON(!e); 117366a63635SJoe Thornber e->oblock = oblock; 117466a63635SJoe Thornber 117566a63635SJoe Thornber if (pr == PROMOTE_TEMPORARY) 117666a63635SJoe Thornber push(mq, e); 117766a63635SJoe Thornber else 117866a63635SJoe Thornber push_new(mq, e); 117966a63635SJoe Thornber 118066a63635SJoe Thornber result->cblock = infer_cblock(mq, e); 118166a63635SJoe Thornber } 118266a63635SJoe Thornber 118366a63635SJoe Thornber static dm_oblock_t to_hblock(struct smq_policy *mq, dm_oblock_t b) 118466a63635SJoe Thornber { 118566a63635SJoe Thornber sector_t r = from_oblock(b); 118666a63635SJoe Thornber (void) sector_div(r, mq->cache_blocks_per_hotspot_block); 118766a63635SJoe Thornber return to_oblock(r); 118866a63635SJoe Thornber } 118966a63635SJoe Thornber 119066a63635SJoe Thornber static struct entry *update_hotspot_queue(struct smq_policy *mq, dm_oblock_t b, struct bio *bio) 119166a63635SJoe Thornber { 119266a63635SJoe Thornber unsigned hi; 119366a63635SJoe Thornber dm_oblock_t hb = to_hblock(mq, b); 119466a63635SJoe Thornber struct entry *e = h_lookup(&mq->hotspot_table, hb); 119566a63635SJoe Thornber 119666a63635SJoe Thornber if (e) { 119766a63635SJoe Thornber stats_level_accessed(&mq->hotspot_stats, e->level); 119866a63635SJoe Thornber 119966a63635SJoe Thornber hi = get_index(&mq->hotspot_alloc, e); 120066a63635SJoe Thornber q_requeue(&mq->hotspot, e, 120166a63635SJoe Thornber test_and_set_bit(hi, mq->hotspot_hit_bits) ? 120266a63635SJoe Thornber 0u : mq->hotspot_level_jump); 120366a63635SJoe Thornber 120466a63635SJoe Thornber } else { 120566a63635SJoe Thornber stats_miss(&mq->hotspot_stats); 120666a63635SJoe Thornber 120766a63635SJoe Thornber e = alloc_entry(&mq->hotspot_alloc); 120866a63635SJoe Thornber if (!e) { 120966a63635SJoe Thornber e = q_pop(&mq->hotspot); 121066a63635SJoe Thornber if (e) { 121166a63635SJoe Thornber h_remove(&mq->hotspot_table, e); 121266a63635SJoe Thornber hi = get_index(&mq->hotspot_alloc, e); 121366a63635SJoe Thornber clear_bit(hi, mq->hotspot_hit_bits); 121466a63635SJoe Thornber } 121566a63635SJoe Thornber 121666a63635SJoe Thornber } 121766a63635SJoe Thornber 121866a63635SJoe Thornber if (e) { 121966a63635SJoe Thornber e->oblock = hb; 122066a63635SJoe Thornber q_push(&mq->hotspot, e); 122166a63635SJoe Thornber h_insert(&mq->hotspot_table, e); 122266a63635SJoe Thornber } 122366a63635SJoe Thornber } 122466a63635SJoe Thornber 122566a63635SJoe Thornber return e; 122666a63635SJoe Thornber } 122766a63635SJoe Thornber 122866a63635SJoe Thornber /* 122966a63635SJoe Thornber * Looks the oblock up in the hash table, then decides whether to put in 123066a63635SJoe Thornber * pre_cache, or cache etc. 123166a63635SJoe Thornber */ 123266a63635SJoe Thornber static int map(struct smq_policy *mq, struct bio *bio, dm_oblock_t oblock, 123366a63635SJoe Thornber bool can_migrate, bool fast_promote, 123466a63635SJoe Thornber struct policy_locker *locker, struct policy_result *result) 123566a63635SJoe Thornber { 123666a63635SJoe Thornber struct entry *e, *hs_e; 123766a63635SJoe Thornber enum promote_result pr; 123866a63635SJoe Thornber 123966a63635SJoe Thornber hs_e = update_hotspot_queue(mq, oblock, bio); 124066a63635SJoe Thornber 124166a63635SJoe Thornber e = h_lookup(&mq->table, oblock); 124266a63635SJoe Thornber if (e) { 124366a63635SJoe Thornber stats_level_accessed(&mq->cache_stats, e->level); 124466a63635SJoe Thornber 124566a63635SJoe Thornber requeue(mq, e); 124666a63635SJoe Thornber result->op = POLICY_HIT; 124766a63635SJoe Thornber result->cblock = infer_cblock(mq, e); 124866a63635SJoe Thornber 124966a63635SJoe Thornber } else { 125066a63635SJoe Thornber stats_miss(&mq->cache_stats); 125166a63635SJoe Thornber 125266a63635SJoe Thornber pr = should_promote(mq, hs_e, bio, fast_promote); 125366a63635SJoe Thornber if (pr == PROMOTE_NOT) 125466a63635SJoe Thornber result->op = POLICY_MISS; 125566a63635SJoe Thornber 125666a63635SJoe Thornber else { 125766a63635SJoe Thornber if (!can_migrate) { 125866a63635SJoe Thornber result->op = POLICY_MISS; 125966a63635SJoe Thornber return -EWOULDBLOCK; 126066a63635SJoe Thornber } 126166a63635SJoe Thornber 126266a63635SJoe Thornber insert_in_cache(mq, oblock, locker, result, pr); 126366a63635SJoe Thornber } 126466a63635SJoe Thornber } 126566a63635SJoe Thornber 126666a63635SJoe Thornber return 0; 126766a63635SJoe Thornber } 126866a63635SJoe Thornber 126966a63635SJoe Thornber /*----------------------------------------------------------------*/ 127066a63635SJoe Thornber 127166a63635SJoe Thornber /* 127266a63635SJoe Thornber * Public interface, via the policy struct. See dm-cache-policy.h for a 127366a63635SJoe Thornber * description of these. 127466a63635SJoe Thornber */ 127566a63635SJoe Thornber 127666a63635SJoe Thornber static struct smq_policy *to_smq_policy(struct dm_cache_policy *p) 127766a63635SJoe Thornber { 127866a63635SJoe Thornber return container_of(p, struct smq_policy, policy); 127966a63635SJoe Thornber } 128066a63635SJoe Thornber 128166a63635SJoe Thornber static void smq_destroy(struct dm_cache_policy *p) 128266a63635SJoe Thornber { 128366a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 128466a63635SJoe Thornber 128566a63635SJoe Thornber h_exit(&mq->hotspot_table); 128666a63635SJoe Thornber h_exit(&mq->table); 128766a63635SJoe Thornber free_bitset(mq->hotspot_hit_bits); 128866a63635SJoe Thornber free_bitset(mq->cache_hit_bits); 128966a63635SJoe Thornber space_exit(&mq->es); 129066a63635SJoe Thornber kfree(mq); 129166a63635SJoe Thornber } 129266a63635SJoe Thornber 129366a63635SJoe Thornber static int smq_map(struct dm_cache_policy *p, dm_oblock_t oblock, 129466a63635SJoe Thornber bool can_block, bool can_migrate, bool fast_promote, 129566a63635SJoe Thornber struct bio *bio, struct policy_locker *locker, 129666a63635SJoe Thornber struct policy_result *result) 129766a63635SJoe Thornber { 129866a63635SJoe Thornber int r; 12994051aab7SJoe Thornber unsigned long flags; 130066a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 130166a63635SJoe Thornber 130266a63635SJoe Thornber result->op = POLICY_MISS; 130366a63635SJoe Thornber 13044051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 130566a63635SJoe Thornber r = map(mq, bio, oblock, can_migrate, fast_promote, locker, result); 13064051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 130766a63635SJoe Thornber 130866a63635SJoe Thornber return r; 130966a63635SJoe Thornber } 131066a63635SJoe Thornber 131166a63635SJoe Thornber static int smq_lookup(struct dm_cache_policy *p, dm_oblock_t oblock, dm_cblock_t *cblock) 131266a63635SJoe Thornber { 131366a63635SJoe Thornber int r; 13144051aab7SJoe Thornber unsigned long flags; 131566a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 131666a63635SJoe Thornber struct entry *e; 131766a63635SJoe Thornber 13184051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 131966a63635SJoe Thornber e = h_lookup(&mq->table, oblock); 132066a63635SJoe Thornber if (e) { 132166a63635SJoe Thornber *cblock = infer_cblock(mq, e); 132266a63635SJoe Thornber r = 0; 132366a63635SJoe Thornber } else 132466a63635SJoe Thornber r = -ENOENT; 13254051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 132666a63635SJoe Thornber 132766a63635SJoe Thornber return r; 132866a63635SJoe Thornber } 132966a63635SJoe Thornber 133066a63635SJoe Thornber static void __smq_set_clear_dirty(struct smq_policy *mq, dm_oblock_t oblock, bool set) 133166a63635SJoe Thornber { 133266a63635SJoe Thornber struct entry *e; 133366a63635SJoe Thornber 133466a63635SJoe Thornber e = h_lookup(&mq->table, oblock); 133566a63635SJoe Thornber BUG_ON(!e); 133666a63635SJoe Thornber 133766a63635SJoe Thornber del(mq, e); 133866a63635SJoe Thornber e->dirty = set; 133966a63635SJoe Thornber push(mq, e); 134066a63635SJoe Thornber } 134166a63635SJoe Thornber 134266a63635SJoe Thornber static void smq_set_dirty(struct dm_cache_policy *p, dm_oblock_t oblock) 134366a63635SJoe Thornber { 13444051aab7SJoe Thornber unsigned long flags; 134566a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 134666a63635SJoe Thornber 13474051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 134866a63635SJoe Thornber __smq_set_clear_dirty(mq, oblock, true); 13494051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 135066a63635SJoe Thornber } 135166a63635SJoe Thornber 135266a63635SJoe Thornber static void smq_clear_dirty(struct dm_cache_policy *p, dm_oblock_t oblock) 135366a63635SJoe Thornber { 135466a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 13554051aab7SJoe Thornber unsigned long flags; 135666a63635SJoe Thornber 13574051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 135866a63635SJoe Thornber __smq_set_clear_dirty(mq, oblock, false); 13594051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 136066a63635SJoe Thornber } 136166a63635SJoe Thornber 136266a63635SJoe Thornber static int smq_load_mapping(struct dm_cache_policy *p, 136366a63635SJoe Thornber dm_oblock_t oblock, dm_cblock_t cblock, 136466a63635SJoe Thornber uint32_t hint, bool hint_valid) 136566a63635SJoe Thornber { 136666a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 136766a63635SJoe Thornber struct entry *e; 136866a63635SJoe Thornber 136966a63635SJoe Thornber e = alloc_particular_entry(&mq->cache_alloc, from_cblock(cblock)); 137066a63635SJoe Thornber e->oblock = oblock; 137166a63635SJoe Thornber e->dirty = false; /* this gets corrected in a minute */ 137266a63635SJoe Thornber e->level = hint_valid ? min(hint, NR_CACHE_LEVELS - 1) : 1; 137366a63635SJoe Thornber push(mq, e); 137466a63635SJoe Thornber 137566a63635SJoe Thornber return 0; 137666a63635SJoe Thornber } 137766a63635SJoe Thornber 137866a63635SJoe Thornber static int smq_save_hints(struct smq_policy *mq, struct queue *q, 137966a63635SJoe Thornber policy_walk_fn fn, void *context) 138066a63635SJoe Thornber { 138166a63635SJoe Thornber int r; 138266a63635SJoe Thornber unsigned level; 138366a63635SJoe Thornber struct entry *e; 138466a63635SJoe Thornber 138566a63635SJoe Thornber for (level = 0; level < q->nr_levels; level++) 138666a63635SJoe Thornber for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e)) { 138766a63635SJoe Thornber if (!e->sentinel) { 138866a63635SJoe Thornber r = fn(context, infer_cblock(mq, e), 138966a63635SJoe Thornber e->oblock, e->level); 139066a63635SJoe Thornber if (r) 139166a63635SJoe Thornber return r; 139266a63635SJoe Thornber } 139366a63635SJoe Thornber } 139466a63635SJoe Thornber 139566a63635SJoe Thornber return 0; 139666a63635SJoe Thornber } 139766a63635SJoe Thornber 139866a63635SJoe Thornber static int smq_walk_mappings(struct dm_cache_policy *p, policy_walk_fn fn, 139966a63635SJoe Thornber void *context) 140066a63635SJoe Thornber { 140166a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 140266a63635SJoe Thornber int r = 0; 140366a63635SJoe Thornber 14044051aab7SJoe Thornber /* 14054051aab7SJoe Thornber * We don't need to lock here since this method is only called once 14064051aab7SJoe Thornber * the IO has stopped. 14074051aab7SJoe Thornber */ 140866a63635SJoe Thornber r = smq_save_hints(mq, &mq->clean, fn, context); 140966a63635SJoe Thornber if (!r) 141066a63635SJoe Thornber r = smq_save_hints(mq, &mq->dirty, fn, context); 141166a63635SJoe Thornber 141266a63635SJoe Thornber return r; 141366a63635SJoe Thornber } 141466a63635SJoe Thornber 141566a63635SJoe Thornber static void __remove_mapping(struct smq_policy *mq, dm_oblock_t oblock) 141666a63635SJoe Thornber { 141766a63635SJoe Thornber struct entry *e; 141866a63635SJoe Thornber 141966a63635SJoe Thornber e = h_lookup(&mq->table, oblock); 142066a63635SJoe Thornber BUG_ON(!e); 142166a63635SJoe Thornber 142266a63635SJoe Thornber del(mq, e); 142366a63635SJoe Thornber free_entry(&mq->cache_alloc, e); 142466a63635SJoe Thornber } 142566a63635SJoe Thornber 142666a63635SJoe Thornber static void smq_remove_mapping(struct dm_cache_policy *p, dm_oblock_t oblock) 142766a63635SJoe Thornber { 142866a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 14294051aab7SJoe Thornber unsigned long flags; 143066a63635SJoe Thornber 14314051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 143266a63635SJoe Thornber __remove_mapping(mq, oblock); 14334051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 143466a63635SJoe Thornber } 143566a63635SJoe Thornber 143666a63635SJoe Thornber static int __remove_cblock(struct smq_policy *mq, dm_cblock_t cblock) 143766a63635SJoe Thornber { 143866a63635SJoe Thornber struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock)); 143966a63635SJoe Thornber 144066a63635SJoe Thornber if (!e || !e->allocated) 144166a63635SJoe Thornber return -ENODATA; 144266a63635SJoe Thornber 144366a63635SJoe Thornber del(mq, e); 144466a63635SJoe Thornber free_entry(&mq->cache_alloc, e); 144566a63635SJoe Thornber 144666a63635SJoe Thornber return 0; 144766a63635SJoe Thornber } 144866a63635SJoe Thornber 144966a63635SJoe Thornber static int smq_remove_cblock(struct dm_cache_policy *p, dm_cblock_t cblock) 145066a63635SJoe Thornber { 145166a63635SJoe Thornber int r; 14524051aab7SJoe Thornber unsigned long flags; 145366a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 145466a63635SJoe Thornber 14554051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 145666a63635SJoe Thornber r = __remove_cblock(mq, cblock); 14574051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 145866a63635SJoe Thornber 145966a63635SJoe Thornber return r; 146066a63635SJoe Thornber } 146166a63635SJoe Thornber 146266a63635SJoe Thornber 146366a63635SJoe Thornber #define CLEAN_TARGET_CRITICAL 5u /* percent */ 146466a63635SJoe Thornber 146566a63635SJoe Thornber static bool clean_target_met(struct smq_policy *mq, bool critical) 146666a63635SJoe Thornber { 146766a63635SJoe Thornber if (critical) { 146866a63635SJoe Thornber /* 146966a63635SJoe Thornber * Cache entries may not be populated. So we're cannot rely on the 147066a63635SJoe Thornber * size of the clean queue. 147166a63635SJoe Thornber */ 147266a63635SJoe Thornber unsigned nr_clean = from_cblock(mq->cache_size) - q_size(&mq->dirty); 147366a63635SJoe Thornber unsigned target = from_cblock(mq->cache_size) * CLEAN_TARGET_CRITICAL / 100u; 147466a63635SJoe Thornber 147566a63635SJoe Thornber return nr_clean >= target; 147666a63635SJoe Thornber } else 147766a63635SJoe Thornber return !q_size(&mq->dirty); 147866a63635SJoe Thornber } 147966a63635SJoe Thornber 148066a63635SJoe Thornber static int __smq_writeback_work(struct smq_policy *mq, dm_oblock_t *oblock, 148166a63635SJoe Thornber dm_cblock_t *cblock, bool critical_only) 148266a63635SJoe Thornber { 148366a63635SJoe Thornber struct entry *e = NULL; 148466a63635SJoe Thornber bool target_met = clean_target_met(mq, critical_only); 148566a63635SJoe Thornber 148666a63635SJoe Thornber if (critical_only) 148766a63635SJoe Thornber /* 148866a63635SJoe Thornber * Always try and keep the bottom level clean. 148966a63635SJoe Thornber */ 149066a63635SJoe Thornber e = pop_old(mq, &mq->dirty, target_met ? 1u : mq->dirty.nr_levels); 149166a63635SJoe Thornber 149266a63635SJoe Thornber else 149366a63635SJoe Thornber e = pop_old(mq, &mq->dirty, mq->dirty.nr_levels); 149466a63635SJoe Thornber 149566a63635SJoe Thornber if (!e) 149666a63635SJoe Thornber return -ENODATA; 149766a63635SJoe Thornber 149866a63635SJoe Thornber *oblock = e->oblock; 149966a63635SJoe Thornber *cblock = infer_cblock(mq, e); 150066a63635SJoe Thornber e->dirty = false; 150166a63635SJoe Thornber push_new(mq, e); 150266a63635SJoe Thornber 150366a63635SJoe Thornber return 0; 150466a63635SJoe Thornber } 150566a63635SJoe Thornber 150666a63635SJoe Thornber static int smq_writeback_work(struct dm_cache_policy *p, dm_oblock_t *oblock, 150766a63635SJoe Thornber dm_cblock_t *cblock, bool critical_only) 150866a63635SJoe Thornber { 150966a63635SJoe Thornber int r; 15104051aab7SJoe Thornber unsigned long flags; 151166a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 151266a63635SJoe Thornber 15134051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 151466a63635SJoe Thornber r = __smq_writeback_work(mq, oblock, cblock, critical_only); 15154051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 151666a63635SJoe Thornber 151766a63635SJoe Thornber return r; 151866a63635SJoe Thornber } 151966a63635SJoe Thornber 152066a63635SJoe Thornber static void __force_mapping(struct smq_policy *mq, 152166a63635SJoe Thornber dm_oblock_t current_oblock, dm_oblock_t new_oblock) 152266a63635SJoe Thornber { 152366a63635SJoe Thornber struct entry *e = h_lookup(&mq->table, current_oblock); 152466a63635SJoe Thornber 152566a63635SJoe Thornber if (e) { 152666a63635SJoe Thornber del(mq, e); 152766a63635SJoe Thornber e->oblock = new_oblock; 152866a63635SJoe Thornber e->dirty = true; 152966a63635SJoe Thornber push(mq, e); 153066a63635SJoe Thornber } 153166a63635SJoe Thornber } 153266a63635SJoe Thornber 153366a63635SJoe Thornber static void smq_force_mapping(struct dm_cache_policy *p, 153466a63635SJoe Thornber dm_oblock_t current_oblock, dm_oblock_t new_oblock) 153566a63635SJoe Thornber { 15364051aab7SJoe Thornber unsigned long flags; 153766a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 153866a63635SJoe Thornber 15394051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 154066a63635SJoe Thornber __force_mapping(mq, current_oblock, new_oblock); 15414051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 154266a63635SJoe Thornber } 154366a63635SJoe Thornber 154466a63635SJoe Thornber static dm_cblock_t smq_residency(struct dm_cache_policy *p) 154566a63635SJoe Thornber { 154666a63635SJoe Thornber dm_cblock_t r; 15474051aab7SJoe Thornber unsigned long flags; 154866a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 154966a63635SJoe Thornber 15504051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 155166a63635SJoe Thornber r = to_cblock(mq->cache_alloc.nr_allocated); 15524051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 155366a63635SJoe Thornber 155466a63635SJoe Thornber return r; 155566a63635SJoe Thornber } 155666a63635SJoe Thornber 1557fba10109SJoe Thornber static void smq_tick(struct dm_cache_policy *p, bool can_block) 155866a63635SJoe Thornber { 155966a63635SJoe Thornber struct smq_policy *mq = to_smq_policy(p); 156066a63635SJoe Thornber unsigned long flags; 156166a63635SJoe Thornber 15624051aab7SJoe Thornber spin_lock_irqsave(&mq->lock, flags); 15634051aab7SJoe Thornber mq->tick++; 15644051aab7SJoe Thornber update_sentinels(mq); 15654051aab7SJoe Thornber end_hotspot_period(mq); 15664051aab7SJoe Thornber end_cache_period(mq); 15674051aab7SJoe Thornber spin_unlock_irqrestore(&mq->lock, flags); 156866a63635SJoe Thornber } 156966a63635SJoe Thornber 15709ed84698SJoe Thornber /* 15719ed84698SJoe Thornber * smq has no config values, but the old mq policy did. To avoid breaking 15729ed84698SJoe Thornber * software we continue to accept these configurables for the mq policy, 15739ed84698SJoe Thornber * but they have no effect. 15749ed84698SJoe Thornber */ 15759ed84698SJoe Thornber static int mq_set_config_value(struct dm_cache_policy *p, 15769ed84698SJoe Thornber const char *key, const char *value) 15779ed84698SJoe Thornber { 15789ed84698SJoe Thornber unsigned long tmp; 15799ed84698SJoe Thornber 15809ed84698SJoe Thornber if (kstrtoul(value, 10, &tmp)) 15819ed84698SJoe Thornber return -EINVAL; 15829ed84698SJoe Thornber 15839ed84698SJoe Thornber if (!strcasecmp(key, "random_threshold") || 15849ed84698SJoe Thornber !strcasecmp(key, "sequential_threshold") || 15859ed84698SJoe Thornber !strcasecmp(key, "discard_promote_adjustment") || 15869ed84698SJoe Thornber !strcasecmp(key, "read_promote_adjustment") || 15879ed84698SJoe Thornber !strcasecmp(key, "write_promote_adjustment")) { 15889ed84698SJoe Thornber DMWARN("tunable '%s' no longer has any effect, mq policy is now an alias for smq", key); 15899ed84698SJoe Thornber return 0; 15909ed84698SJoe Thornber } 15919ed84698SJoe Thornber 15929ed84698SJoe Thornber return -EINVAL; 15939ed84698SJoe Thornber } 15949ed84698SJoe Thornber 15959ed84698SJoe Thornber static int mq_emit_config_values(struct dm_cache_policy *p, char *result, 15969ed84698SJoe Thornber unsigned maxlen, ssize_t *sz_ptr) 15979ed84698SJoe Thornber { 15989ed84698SJoe Thornber ssize_t sz = *sz_ptr; 15999ed84698SJoe Thornber 16009ed84698SJoe Thornber DMEMIT("10 random_threshold 0 " 16019ed84698SJoe Thornber "sequential_threshold 0 " 16029ed84698SJoe Thornber "discard_promote_adjustment 0 " 16039ed84698SJoe Thornber "read_promote_adjustment 0 " 16049ed84698SJoe Thornber "write_promote_adjustment 0 "); 16059ed84698SJoe Thornber 16069ed84698SJoe Thornber *sz_ptr = sz; 16079ed84698SJoe Thornber return 0; 16089ed84698SJoe Thornber } 16099ed84698SJoe Thornber 161066a63635SJoe Thornber /* Init the policy plugin interface function pointers. */ 16119ed84698SJoe Thornber static void init_policy_functions(struct smq_policy *mq, bool mimic_mq) 161266a63635SJoe Thornber { 161366a63635SJoe Thornber mq->policy.destroy = smq_destroy; 161466a63635SJoe Thornber mq->policy.map = smq_map; 161566a63635SJoe Thornber mq->policy.lookup = smq_lookup; 161666a63635SJoe Thornber mq->policy.set_dirty = smq_set_dirty; 161766a63635SJoe Thornber mq->policy.clear_dirty = smq_clear_dirty; 161866a63635SJoe Thornber mq->policy.load_mapping = smq_load_mapping; 161966a63635SJoe Thornber mq->policy.walk_mappings = smq_walk_mappings; 162066a63635SJoe Thornber mq->policy.remove_mapping = smq_remove_mapping; 162166a63635SJoe Thornber mq->policy.remove_cblock = smq_remove_cblock; 162266a63635SJoe Thornber mq->policy.writeback_work = smq_writeback_work; 162366a63635SJoe Thornber mq->policy.force_mapping = smq_force_mapping; 162466a63635SJoe Thornber mq->policy.residency = smq_residency; 162566a63635SJoe Thornber mq->policy.tick = smq_tick; 16269ed84698SJoe Thornber 16279ed84698SJoe Thornber if (mimic_mq) { 16289ed84698SJoe Thornber mq->policy.set_config_value = mq_set_config_value; 16299ed84698SJoe Thornber mq->policy.emit_config_values = mq_emit_config_values; 16309ed84698SJoe Thornber } 163166a63635SJoe Thornber } 163266a63635SJoe Thornber 163366a63635SJoe Thornber static bool too_many_hotspot_blocks(sector_t origin_size, 163466a63635SJoe Thornber sector_t hotspot_block_size, 163566a63635SJoe Thornber unsigned nr_hotspot_blocks) 163666a63635SJoe Thornber { 163766a63635SJoe Thornber return (hotspot_block_size * nr_hotspot_blocks) > origin_size; 163866a63635SJoe Thornber } 163966a63635SJoe Thornber 164066a63635SJoe Thornber static void calc_hotspot_params(sector_t origin_size, 164166a63635SJoe Thornber sector_t cache_block_size, 164266a63635SJoe Thornber unsigned nr_cache_blocks, 164366a63635SJoe Thornber sector_t *hotspot_block_size, 164466a63635SJoe Thornber unsigned *nr_hotspot_blocks) 164566a63635SJoe Thornber { 164666a63635SJoe Thornber *hotspot_block_size = cache_block_size * 16u; 164766a63635SJoe Thornber *nr_hotspot_blocks = max(nr_cache_blocks / 4u, 1024u); 164866a63635SJoe Thornber 164966a63635SJoe Thornber while ((*hotspot_block_size > cache_block_size) && 165066a63635SJoe Thornber too_many_hotspot_blocks(origin_size, *hotspot_block_size, *nr_hotspot_blocks)) 165166a63635SJoe Thornber *hotspot_block_size /= 2u; 165266a63635SJoe Thornber } 165366a63635SJoe Thornber 16549ed84698SJoe Thornber static struct dm_cache_policy *__smq_create(dm_cblock_t cache_size, 165566a63635SJoe Thornber sector_t origin_size, 16569ed84698SJoe Thornber sector_t cache_block_size, 16579ed84698SJoe Thornber bool mimic_mq) 165866a63635SJoe Thornber { 165966a63635SJoe Thornber unsigned i; 166066a63635SJoe Thornber unsigned nr_sentinels_per_queue = 2u * NR_CACHE_LEVELS; 166166a63635SJoe Thornber unsigned total_sentinels = 2u * nr_sentinels_per_queue; 166266a63635SJoe Thornber struct smq_policy *mq = kzalloc(sizeof(*mq), GFP_KERNEL); 166366a63635SJoe Thornber 166466a63635SJoe Thornber if (!mq) 166566a63635SJoe Thornber return NULL; 166666a63635SJoe Thornber 16679ed84698SJoe Thornber init_policy_functions(mq, mimic_mq); 166866a63635SJoe Thornber mq->cache_size = cache_size; 166966a63635SJoe Thornber mq->cache_block_size = cache_block_size; 167066a63635SJoe Thornber 167166a63635SJoe Thornber calc_hotspot_params(origin_size, cache_block_size, from_cblock(cache_size), 167266a63635SJoe Thornber &mq->hotspot_block_size, &mq->nr_hotspot_blocks); 167366a63635SJoe Thornber 167466a63635SJoe Thornber mq->cache_blocks_per_hotspot_block = div64_u64(mq->hotspot_block_size, mq->cache_block_size); 167566a63635SJoe Thornber mq->hotspot_level_jump = 1u; 167666a63635SJoe Thornber if (space_init(&mq->es, total_sentinels + mq->nr_hotspot_blocks + from_cblock(cache_size))) { 167766a63635SJoe Thornber DMERR("couldn't initialize entry space"); 167866a63635SJoe Thornber goto bad_pool_init; 167966a63635SJoe Thornber } 168066a63635SJoe Thornber 168166a63635SJoe Thornber init_allocator(&mq->writeback_sentinel_alloc, &mq->es, 0, nr_sentinels_per_queue); 168266a63635SJoe Thornber for (i = 0; i < nr_sentinels_per_queue; i++) 168366a63635SJoe Thornber get_entry(&mq->writeback_sentinel_alloc, i)->sentinel = true; 168466a63635SJoe Thornber 168566a63635SJoe Thornber init_allocator(&mq->demote_sentinel_alloc, &mq->es, nr_sentinels_per_queue, total_sentinels); 168666a63635SJoe Thornber for (i = 0; i < nr_sentinels_per_queue; i++) 168766a63635SJoe Thornber get_entry(&mq->demote_sentinel_alloc, i)->sentinel = true; 168866a63635SJoe Thornber 168966a63635SJoe Thornber init_allocator(&mq->hotspot_alloc, &mq->es, total_sentinels, 169066a63635SJoe Thornber total_sentinels + mq->nr_hotspot_blocks); 169166a63635SJoe Thornber 169266a63635SJoe Thornber init_allocator(&mq->cache_alloc, &mq->es, 169366a63635SJoe Thornber total_sentinels + mq->nr_hotspot_blocks, 169466a63635SJoe Thornber total_sentinels + mq->nr_hotspot_blocks + from_cblock(cache_size)); 169566a63635SJoe Thornber 169666a63635SJoe Thornber mq->hotspot_hit_bits = alloc_bitset(mq->nr_hotspot_blocks); 169766a63635SJoe Thornber if (!mq->hotspot_hit_bits) { 169866a63635SJoe Thornber DMERR("couldn't allocate hotspot hit bitset"); 169966a63635SJoe Thornber goto bad_hotspot_hit_bits; 170066a63635SJoe Thornber } 170166a63635SJoe Thornber clear_bitset(mq->hotspot_hit_bits, mq->nr_hotspot_blocks); 170266a63635SJoe Thornber 170366a63635SJoe Thornber if (from_cblock(cache_size)) { 170466a63635SJoe Thornber mq->cache_hit_bits = alloc_bitset(from_cblock(cache_size)); 1705134bf30cSColin Ian King if (!mq->cache_hit_bits) { 170666a63635SJoe Thornber DMERR("couldn't allocate cache hit bitset"); 170766a63635SJoe Thornber goto bad_cache_hit_bits; 170866a63635SJoe Thornber } 170966a63635SJoe Thornber clear_bitset(mq->cache_hit_bits, from_cblock(mq->cache_size)); 171066a63635SJoe Thornber } else 171166a63635SJoe Thornber mq->cache_hit_bits = NULL; 171266a63635SJoe Thornber 171366a63635SJoe Thornber mq->tick = 0; 17144051aab7SJoe Thornber spin_lock_init(&mq->lock); 171566a63635SJoe Thornber 171666a63635SJoe Thornber q_init(&mq->hotspot, &mq->es, NR_HOTSPOT_LEVELS); 171766a63635SJoe Thornber mq->hotspot.nr_top_levels = 8; 171866a63635SJoe Thornber mq->hotspot.nr_in_top_levels = min(mq->nr_hotspot_blocks / NR_HOTSPOT_LEVELS, 171966a63635SJoe Thornber from_cblock(mq->cache_size) / mq->cache_blocks_per_hotspot_block); 172066a63635SJoe Thornber 172166a63635SJoe Thornber q_init(&mq->clean, &mq->es, NR_CACHE_LEVELS); 172266a63635SJoe Thornber q_init(&mq->dirty, &mq->es, NR_CACHE_LEVELS); 172366a63635SJoe Thornber 172466a63635SJoe Thornber stats_init(&mq->hotspot_stats, NR_HOTSPOT_LEVELS); 172566a63635SJoe Thornber stats_init(&mq->cache_stats, NR_CACHE_LEVELS); 172666a63635SJoe Thornber 172766a63635SJoe Thornber if (h_init(&mq->table, &mq->es, from_cblock(cache_size))) 172866a63635SJoe Thornber goto bad_alloc_table; 172966a63635SJoe Thornber 173066a63635SJoe Thornber if (h_init(&mq->hotspot_table, &mq->es, mq->nr_hotspot_blocks)) 173166a63635SJoe Thornber goto bad_alloc_hotspot_table; 173266a63635SJoe Thornber 173366a63635SJoe Thornber sentinels_init(mq); 173466a63635SJoe Thornber mq->write_promote_level = mq->read_promote_level = NR_HOTSPOT_LEVELS; 173566a63635SJoe Thornber 173666a63635SJoe Thornber mq->next_hotspot_period = jiffies; 173766a63635SJoe Thornber mq->next_cache_period = jiffies; 173866a63635SJoe Thornber 173966a63635SJoe Thornber return &mq->policy; 174066a63635SJoe Thornber 174166a63635SJoe Thornber bad_alloc_hotspot_table: 174266a63635SJoe Thornber h_exit(&mq->table); 174366a63635SJoe Thornber bad_alloc_table: 174466a63635SJoe Thornber free_bitset(mq->cache_hit_bits); 174566a63635SJoe Thornber bad_cache_hit_bits: 174666a63635SJoe Thornber free_bitset(mq->hotspot_hit_bits); 174766a63635SJoe Thornber bad_hotspot_hit_bits: 174866a63635SJoe Thornber space_exit(&mq->es); 174966a63635SJoe Thornber bad_pool_init: 175066a63635SJoe Thornber kfree(mq); 175166a63635SJoe Thornber 175266a63635SJoe Thornber return NULL; 175366a63635SJoe Thornber } 175466a63635SJoe Thornber 17559ed84698SJoe Thornber static struct dm_cache_policy *smq_create(dm_cblock_t cache_size, 17569ed84698SJoe Thornber sector_t origin_size, 17579ed84698SJoe Thornber sector_t cache_block_size) 17589ed84698SJoe Thornber { 17599ed84698SJoe Thornber return __smq_create(cache_size, origin_size, cache_block_size, false); 17609ed84698SJoe Thornber } 17619ed84698SJoe Thornber 17629ed84698SJoe Thornber static struct dm_cache_policy *mq_create(dm_cblock_t cache_size, 17639ed84698SJoe Thornber sector_t origin_size, 17649ed84698SJoe Thornber sector_t cache_block_size) 17659ed84698SJoe Thornber { 17669ed84698SJoe Thornber return __smq_create(cache_size, origin_size, cache_block_size, true); 17679ed84698SJoe Thornber } 17689ed84698SJoe Thornber 176966a63635SJoe Thornber /*----------------------------------------------------------------*/ 177066a63635SJoe Thornber 177166a63635SJoe Thornber static struct dm_cache_policy_type smq_policy_type = { 177266a63635SJoe Thornber .name = "smq", 17739ed84698SJoe Thornber .version = {1, 5, 0}, 177466a63635SJoe Thornber .hint_size = 4, 177566a63635SJoe Thornber .owner = THIS_MODULE, 177666a63635SJoe Thornber .create = smq_create 177766a63635SJoe Thornber }; 177866a63635SJoe Thornber 17799ed84698SJoe Thornber static struct dm_cache_policy_type mq_policy_type = { 17809ed84698SJoe Thornber .name = "mq", 17819ed84698SJoe Thornber .version = {1, 5, 0}, 17829ed84698SJoe Thornber .hint_size = 4, 17839ed84698SJoe Thornber .owner = THIS_MODULE, 17849ed84698SJoe Thornber .create = mq_create, 17859ed84698SJoe Thornber }; 17869ed84698SJoe Thornber 1787bccab6a0SMike Snitzer static struct dm_cache_policy_type default_policy_type = { 1788bccab6a0SMike Snitzer .name = "default", 17899ed84698SJoe Thornber .version = {1, 5, 0}, 1790bccab6a0SMike Snitzer .hint_size = 4, 1791bccab6a0SMike Snitzer .owner = THIS_MODULE, 1792bccab6a0SMike Snitzer .create = smq_create, 1793bccab6a0SMike Snitzer .real = &smq_policy_type 1794bccab6a0SMike Snitzer }; 1795bccab6a0SMike Snitzer 179666a63635SJoe Thornber static int __init smq_init(void) 179766a63635SJoe Thornber { 179866a63635SJoe Thornber int r; 179966a63635SJoe Thornber 180066a63635SJoe Thornber r = dm_cache_policy_register(&smq_policy_type); 180166a63635SJoe Thornber if (r) { 180266a63635SJoe Thornber DMERR("register failed %d", r); 180366a63635SJoe Thornber return -ENOMEM; 180466a63635SJoe Thornber } 180566a63635SJoe Thornber 18069ed84698SJoe Thornber r = dm_cache_policy_register(&mq_policy_type); 18079ed84698SJoe Thornber if (r) { 1808*7dd85bb0SMike Snitzer DMERR("register failed (as mq) %d", r); 18099ed84698SJoe Thornber dm_cache_policy_unregister(&smq_policy_type); 18109ed84698SJoe Thornber return -ENOMEM; 18119ed84698SJoe Thornber } 18129ed84698SJoe Thornber 1813bccab6a0SMike Snitzer r = dm_cache_policy_register(&default_policy_type); 1814bccab6a0SMike Snitzer if (r) { 1815bccab6a0SMike Snitzer DMERR("register failed (as default) %d", r); 18169ed84698SJoe Thornber dm_cache_policy_unregister(&mq_policy_type); 1817bccab6a0SMike Snitzer dm_cache_policy_unregister(&smq_policy_type); 1818bccab6a0SMike Snitzer return -ENOMEM; 1819bccab6a0SMike Snitzer } 1820bccab6a0SMike Snitzer 182166a63635SJoe Thornber return 0; 182266a63635SJoe Thornber } 182366a63635SJoe Thornber 182466a63635SJoe Thornber static void __exit smq_exit(void) 182566a63635SJoe Thornber { 182666a63635SJoe Thornber dm_cache_policy_unregister(&smq_policy_type); 18279ed84698SJoe Thornber dm_cache_policy_unregister(&mq_policy_type); 1828bccab6a0SMike Snitzer dm_cache_policy_unregister(&default_policy_type); 182966a63635SJoe Thornber } 183066a63635SJoe Thornber 183166a63635SJoe Thornber module_init(smq_init); 183266a63635SJoe Thornber module_exit(smq_exit); 183366a63635SJoe Thornber 183466a63635SJoe Thornber MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>"); 183566a63635SJoe Thornber MODULE_LICENSE("GPL"); 183666a63635SJoe Thornber MODULE_DESCRIPTION("smq cache policy"); 183734dd0517SYi Zhang 183834dd0517SYi Zhang MODULE_ALIAS("dm-cache-default"); 18399ed84698SJoe Thornber MODULE_ALIAS("dm-cache-mq"); 1840