xref: /openbmc/linux/drivers/md/dm-cache-policy-smq.c (revision 7dd85bb0e98836bd61a619b59dcfc0f2ad3f5172)
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