xref: /openbmc/linux/drivers/md/dm-cache-policy-smq.c (revision bccab6a01afc26f53d91762d78153513cad10b29)
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));
56966a63635SJoe Thornber 	ht->hash_bits = ffs(nr_buckets) - 1;
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 */
77566a63635SJoe Thornber 	struct mutex 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 	 * Access to tick_protected should be done with the spin lock held.
81266a63635SJoe Thornber 	 * It's copied to tick at the start of the map function (within the
81366a63635SJoe Thornber 	 * mutex).
81466a63635SJoe Thornber 	 */
81566a63635SJoe Thornber 	spinlock_t tick_lock;
81666a63635SJoe Thornber 	unsigned tick_protected;
81766a63635SJoe Thornber 	unsigned tick;
81866a63635SJoe Thornber 
81966a63635SJoe Thornber 	/*
82066a63635SJoe Thornber 	 * The hash tables allows us to quickly find an entry by origin
82166a63635SJoe Thornber 	 * block.
82266a63635SJoe Thornber 	 */
82366a63635SJoe Thornber 	struct hash_table table;
82466a63635SJoe Thornber 	struct hash_table hotspot_table;
82566a63635SJoe Thornber 
82666a63635SJoe Thornber 	bool current_writeback_sentinels;
82766a63635SJoe Thornber 	unsigned long next_writeback_period;
82866a63635SJoe Thornber 
82966a63635SJoe Thornber 	bool current_demote_sentinels;
83066a63635SJoe Thornber 	unsigned long next_demote_period;
83166a63635SJoe Thornber 
83266a63635SJoe Thornber 	unsigned write_promote_level;
83366a63635SJoe Thornber 	unsigned read_promote_level;
83466a63635SJoe Thornber 
83566a63635SJoe Thornber 	unsigned long next_hotspot_period;
83666a63635SJoe Thornber 	unsigned long next_cache_period;
83766a63635SJoe Thornber };
83866a63635SJoe Thornber 
83966a63635SJoe Thornber /*----------------------------------------------------------------*/
84066a63635SJoe Thornber 
84166a63635SJoe Thornber static struct entry *get_sentinel(struct entry_alloc *ea, unsigned level, bool which)
84266a63635SJoe Thornber {
84366a63635SJoe Thornber 	return get_entry(ea, which ? level : NR_CACHE_LEVELS + level);
84466a63635SJoe Thornber }
84566a63635SJoe Thornber 
84666a63635SJoe Thornber static struct entry *writeback_sentinel(struct smq_policy *mq, unsigned level)
84766a63635SJoe Thornber {
84866a63635SJoe Thornber 	return get_sentinel(&mq->writeback_sentinel_alloc, level, mq->current_writeback_sentinels);
84966a63635SJoe Thornber }
85066a63635SJoe Thornber 
85166a63635SJoe Thornber static struct entry *demote_sentinel(struct smq_policy *mq, unsigned level)
85266a63635SJoe Thornber {
85366a63635SJoe Thornber 	return get_sentinel(&mq->demote_sentinel_alloc, level, mq->current_demote_sentinels);
85466a63635SJoe Thornber }
85566a63635SJoe Thornber 
85666a63635SJoe Thornber static void __update_writeback_sentinels(struct smq_policy *mq)
85766a63635SJoe Thornber {
85866a63635SJoe Thornber 	unsigned level;
85966a63635SJoe Thornber 	struct queue *q = &mq->dirty;
86066a63635SJoe Thornber 	struct entry *sentinel;
86166a63635SJoe Thornber 
86266a63635SJoe Thornber 	for (level = 0; level < q->nr_levels; level++) {
86366a63635SJoe Thornber 		sentinel = writeback_sentinel(mq, level);
86466a63635SJoe Thornber 		q_del(q, sentinel);
86566a63635SJoe Thornber 		q_push(q, sentinel);
86666a63635SJoe Thornber 	}
86766a63635SJoe Thornber }
86866a63635SJoe Thornber 
86966a63635SJoe Thornber static void __update_demote_sentinels(struct smq_policy *mq)
87066a63635SJoe Thornber {
87166a63635SJoe Thornber 	unsigned level;
87266a63635SJoe Thornber 	struct queue *q = &mq->clean;
87366a63635SJoe Thornber 	struct entry *sentinel;
87466a63635SJoe Thornber 
87566a63635SJoe Thornber 	for (level = 0; level < q->nr_levels; level++) {
87666a63635SJoe Thornber 		sentinel = demote_sentinel(mq, level);
87766a63635SJoe Thornber 		q_del(q, sentinel);
87866a63635SJoe Thornber 		q_push(q, sentinel);
87966a63635SJoe Thornber 	}
88066a63635SJoe Thornber }
88166a63635SJoe Thornber 
88266a63635SJoe Thornber static void update_sentinels(struct smq_policy *mq)
88366a63635SJoe Thornber {
88466a63635SJoe Thornber 	if (time_after(jiffies, mq->next_writeback_period)) {
88566a63635SJoe Thornber 		__update_writeback_sentinels(mq);
88666a63635SJoe Thornber 		mq->next_writeback_period = jiffies + WRITEBACK_PERIOD;
88766a63635SJoe Thornber 		mq->current_writeback_sentinels = !mq->current_writeback_sentinels;
88866a63635SJoe Thornber 	}
88966a63635SJoe Thornber 
89066a63635SJoe Thornber 	if (time_after(jiffies, mq->next_demote_period)) {
89166a63635SJoe Thornber 		__update_demote_sentinels(mq);
89266a63635SJoe Thornber 		mq->next_demote_period = jiffies + DEMOTE_PERIOD;
89366a63635SJoe Thornber 		mq->current_demote_sentinels = !mq->current_demote_sentinels;
89466a63635SJoe Thornber 	}
89566a63635SJoe Thornber }
89666a63635SJoe Thornber 
89766a63635SJoe Thornber static void __sentinels_init(struct smq_policy *mq)
89866a63635SJoe Thornber {
89966a63635SJoe Thornber 	unsigned level;
90066a63635SJoe Thornber 	struct entry *sentinel;
90166a63635SJoe Thornber 
90266a63635SJoe Thornber 	for (level = 0; level < NR_CACHE_LEVELS; level++) {
90366a63635SJoe Thornber 		sentinel = writeback_sentinel(mq, level);
90466a63635SJoe Thornber 		sentinel->level = level;
90566a63635SJoe Thornber 		q_push(&mq->dirty, sentinel);
90666a63635SJoe Thornber 
90766a63635SJoe Thornber 		sentinel = demote_sentinel(mq, level);
90866a63635SJoe Thornber 		sentinel->level = level;
90966a63635SJoe Thornber 		q_push(&mq->clean, sentinel);
91066a63635SJoe Thornber 	}
91166a63635SJoe Thornber }
91266a63635SJoe Thornber 
91366a63635SJoe Thornber static void sentinels_init(struct smq_policy *mq)
91466a63635SJoe Thornber {
91566a63635SJoe Thornber 	mq->next_writeback_period = jiffies + WRITEBACK_PERIOD;
91666a63635SJoe Thornber 	mq->next_demote_period = jiffies + DEMOTE_PERIOD;
91766a63635SJoe Thornber 
91866a63635SJoe Thornber 	mq->current_writeback_sentinels = false;
91966a63635SJoe Thornber 	mq->current_demote_sentinels = false;
92066a63635SJoe Thornber 	__sentinels_init(mq);
92166a63635SJoe Thornber 
92266a63635SJoe Thornber 	mq->current_writeback_sentinels = !mq->current_writeback_sentinels;
92366a63635SJoe Thornber 	mq->current_demote_sentinels = !mq->current_demote_sentinels;
92466a63635SJoe Thornber 	__sentinels_init(mq);
92566a63635SJoe Thornber }
92666a63635SJoe Thornber 
92766a63635SJoe Thornber /*----------------------------------------------------------------*/
92866a63635SJoe Thornber 
92966a63635SJoe Thornber /*
93066a63635SJoe Thornber  * These methods tie together the dirty queue, clean queue and hash table.
93166a63635SJoe Thornber  */
93266a63635SJoe Thornber static void push_new(struct smq_policy *mq, struct entry *e)
93366a63635SJoe Thornber {
93466a63635SJoe Thornber 	struct queue *q = e->dirty ? &mq->dirty : &mq->clean;
93566a63635SJoe Thornber 	h_insert(&mq->table, e);
93666a63635SJoe Thornber 	q_push(q, e);
93766a63635SJoe Thornber }
93866a63635SJoe Thornber 
93966a63635SJoe Thornber static void push(struct smq_policy *mq, struct entry *e)
94066a63635SJoe Thornber {
94166a63635SJoe Thornber 	struct entry *sentinel;
94266a63635SJoe Thornber 
94366a63635SJoe Thornber 	h_insert(&mq->table, e);
94466a63635SJoe Thornber 
94566a63635SJoe Thornber 	/*
94666a63635SJoe Thornber 	 * Punch this into the queue just in front of the sentinel, to
94766a63635SJoe Thornber 	 * ensure it's cleaned straight away.
94866a63635SJoe Thornber 	 */
94966a63635SJoe Thornber 	if (e->dirty) {
95066a63635SJoe Thornber 		sentinel = writeback_sentinel(mq, e->level);
95166a63635SJoe Thornber 		q_push_before(&mq->dirty, sentinel, e);
95266a63635SJoe Thornber 	} else {
95366a63635SJoe Thornber 		sentinel = demote_sentinel(mq, e->level);
95466a63635SJoe Thornber 		q_push_before(&mq->clean, sentinel, e);
95566a63635SJoe Thornber 	}
95666a63635SJoe Thornber }
95766a63635SJoe Thornber 
95866a63635SJoe Thornber /*
95966a63635SJoe Thornber  * Removes an entry from cache.  Removes from the hash table.
96066a63635SJoe Thornber  */
96166a63635SJoe Thornber static void __del(struct smq_policy *mq, struct queue *q, struct entry *e)
96266a63635SJoe Thornber {
96366a63635SJoe Thornber 	q_del(q, e);
96466a63635SJoe Thornber 	h_remove(&mq->table, e);
96566a63635SJoe Thornber }
96666a63635SJoe Thornber 
96766a63635SJoe Thornber static void del(struct smq_policy *mq, struct entry *e)
96866a63635SJoe Thornber {
96966a63635SJoe Thornber 	__del(mq, e->dirty ? &mq->dirty : &mq->clean, e);
97066a63635SJoe Thornber }
97166a63635SJoe Thornber 
97266a63635SJoe Thornber static struct entry *pop_old(struct smq_policy *mq, struct queue *q, unsigned max_level)
97366a63635SJoe Thornber {
97466a63635SJoe Thornber 	struct entry *e = q_pop_old(q, max_level);
97566a63635SJoe Thornber 	if (e)
97666a63635SJoe Thornber 		h_remove(&mq->table, e);
97766a63635SJoe Thornber 	return e;
97866a63635SJoe Thornber }
97966a63635SJoe Thornber 
98066a63635SJoe Thornber static dm_cblock_t infer_cblock(struct smq_policy *mq, struct entry *e)
98166a63635SJoe Thornber {
98266a63635SJoe Thornber 	return to_cblock(get_index(&mq->cache_alloc, e));
98366a63635SJoe Thornber }
98466a63635SJoe Thornber 
98566a63635SJoe Thornber static void requeue(struct smq_policy *mq, struct entry *e)
98666a63635SJoe Thornber {
98766a63635SJoe Thornber 	struct entry *sentinel;
98866a63635SJoe Thornber 
98966a63635SJoe Thornber 	if (!test_and_set_bit(from_cblock(infer_cblock(mq, e)), mq->cache_hit_bits)) {
99066a63635SJoe Thornber 		if (e->dirty) {
99166a63635SJoe Thornber 			sentinel = writeback_sentinel(mq, e->level);
99266a63635SJoe Thornber 			q_requeue_before(&mq->dirty, sentinel, e, 1u);
99366a63635SJoe Thornber 		} else {
99466a63635SJoe Thornber 			sentinel = demote_sentinel(mq, e->level);
99566a63635SJoe Thornber 			q_requeue_before(&mq->clean, sentinel, e, 1u);
99666a63635SJoe Thornber 		}
99766a63635SJoe Thornber 	}
99866a63635SJoe Thornber }
99966a63635SJoe Thornber 
100066a63635SJoe Thornber static unsigned default_promote_level(struct smq_policy *mq)
100166a63635SJoe Thornber {
100266a63635SJoe Thornber 	/*
100366a63635SJoe Thornber 	 * The promote level depends on the current performance of the
100466a63635SJoe Thornber 	 * cache.
100566a63635SJoe Thornber 	 *
100666a63635SJoe Thornber 	 * If the cache is performing badly, then we can't afford
100766a63635SJoe Thornber 	 * to promote much without causing performance to drop below that
100866a63635SJoe Thornber 	 * of the origin device.
100966a63635SJoe Thornber 	 *
101066a63635SJoe Thornber 	 * If the cache is performing well, then we don't need to promote
101166a63635SJoe Thornber 	 * much.  If it isn't broken, don't fix it.
101266a63635SJoe Thornber 	 *
101366a63635SJoe Thornber 	 * If the cache is middling then we promote more.
101466a63635SJoe Thornber 	 *
101566a63635SJoe Thornber 	 * This scheme reminds me of a graph of entropy vs probability of a
101666a63635SJoe Thornber 	 * binary variable.
101766a63635SJoe Thornber 	 */
101866a63635SJoe Thornber 	static unsigned table[] = {1, 1, 1, 2, 4, 6, 7, 8, 7, 6, 4, 4, 3, 3, 2, 2, 1};
101966a63635SJoe Thornber 
102066a63635SJoe Thornber 	unsigned hits = mq->cache_stats.hits;
102166a63635SJoe Thornber 	unsigned misses = mq->cache_stats.misses;
102266a63635SJoe Thornber 	unsigned index = safe_div(hits << 4u, hits + misses);
102366a63635SJoe Thornber 	return table[index];
102466a63635SJoe Thornber }
102566a63635SJoe Thornber 
102666a63635SJoe Thornber static void update_promote_levels(struct smq_policy *mq)
102766a63635SJoe Thornber {
102866a63635SJoe Thornber 	/*
102966a63635SJoe Thornber 	 * If there are unused cache entries then we want to be really
103066a63635SJoe Thornber 	 * eager to promote.
103166a63635SJoe Thornber 	 */
103266a63635SJoe Thornber 	unsigned threshold_level = allocator_empty(&mq->cache_alloc) ?
103366a63635SJoe Thornber 		default_promote_level(mq) : (NR_HOTSPOT_LEVELS / 2u);
103466a63635SJoe Thornber 
103566a63635SJoe Thornber 	/*
103666a63635SJoe Thornber 	 * If the hotspot queue is performing badly then we have little
103766a63635SJoe Thornber 	 * confidence that we know which blocks to promote.  So we cut down
103866a63635SJoe Thornber 	 * the amount of promotions.
103966a63635SJoe Thornber 	 */
104066a63635SJoe Thornber 	switch (stats_assess(&mq->hotspot_stats)) {
104166a63635SJoe Thornber 	case Q_POOR:
104266a63635SJoe Thornber 		threshold_level /= 4u;
104366a63635SJoe Thornber 		break;
104466a63635SJoe Thornber 
104566a63635SJoe Thornber 	case Q_FAIR:
104666a63635SJoe Thornber 		threshold_level /= 2u;
104766a63635SJoe Thornber 		break;
104866a63635SJoe Thornber 
104966a63635SJoe Thornber 	case Q_WELL:
105066a63635SJoe Thornber 		break;
105166a63635SJoe Thornber 	}
105266a63635SJoe Thornber 
105366a63635SJoe Thornber 	mq->read_promote_level = NR_HOTSPOT_LEVELS - threshold_level;
105466a63635SJoe Thornber 	mq->write_promote_level = (NR_HOTSPOT_LEVELS - threshold_level) + 2u;
105566a63635SJoe Thornber }
105666a63635SJoe Thornber 
105766a63635SJoe Thornber /*
105866a63635SJoe Thornber  * If the hotspot queue is performing badly, then we try and move entries
105966a63635SJoe Thornber  * around more quickly.
106066a63635SJoe Thornber  */
106166a63635SJoe Thornber static void update_level_jump(struct smq_policy *mq)
106266a63635SJoe Thornber {
106366a63635SJoe Thornber 	switch (stats_assess(&mq->hotspot_stats)) {
106466a63635SJoe Thornber 	case Q_POOR:
106566a63635SJoe Thornber 		mq->hotspot_level_jump = 4u;
106666a63635SJoe Thornber 		break;
106766a63635SJoe Thornber 
106866a63635SJoe Thornber 	case Q_FAIR:
106966a63635SJoe Thornber 		mq->hotspot_level_jump = 2u;
107066a63635SJoe Thornber 		break;
107166a63635SJoe Thornber 
107266a63635SJoe Thornber 	case Q_WELL:
107366a63635SJoe Thornber 		mq->hotspot_level_jump = 1u;
107466a63635SJoe Thornber 		break;
107566a63635SJoe Thornber 	}
107666a63635SJoe Thornber }
107766a63635SJoe Thornber 
107866a63635SJoe Thornber static void end_hotspot_period(struct smq_policy *mq)
107966a63635SJoe Thornber {
108066a63635SJoe Thornber 	clear_bitset(mq->hotspot_hit_bits, mq->nr_hotspot_blocks);
108166a63635SJoe Thornber 	update_promote_levels(mq);
108266a63635SJoe Thornber 
108366a63635SJoe Thornber 	if (time_after(jiffies, mq->next_hotspot_period)) {
108466a63635SJoe Thornber 		update_level_jump(mq);
108566a63635SJoe Thornber 		q_redistribute(&mq->hotspot);
108666a63635SJoe Thornber 		stats_reset(&mq->hotspot_stats);
108766a63635SJoe Thornber 		mq->next_hotspot_period = jiffies + HOTSPOT_UPDATE_PERIOD;
108866a63635SJoe Thornber 	}
108966a63635SJoe Thornber }
109066a63635SJoe Thornber 
109166a63635SJoe Thornber static void end_cache_period(struct smq_policy *mq)
109266a63635SJoe Thornber {
109366a63635SJoe Thornber 	if (time_after(jiffies, mq->next_cache_period)) {
109466a63635SJoe Thornber 		clear_bitset(mq->cache_hit_bits, from_cblock(mq->cache_size));
109566a63635SJoe Thornber 
109666a63635SJoe Thornber 		q_redistribute(&mq->dirty);
109766a63635SJoe Thornber 		q_redistribute(&mq->clean);
109866a63635SJoe Thornber 		stats_reset(&mq->cache_stats);
109966a63635SJoe Thornber 
110066a63635SJoe Thornber 		mq->next_cache_period = jiffies + CACHE_UPDATE_PERIOD;
110166a63635SJoe Thornber 	}
110266a63635SJoe Thornber }
110366a63635SJoe Thornber 
110466a63635SJoe Thornber static int demote_cblock(struct smq_policy *mq,
110566a63635SJoe Thornber 			 struct policy_locker *locker,
110666a63635SJoe Thornber 			 dm_oblock_t *oblock)
110766a63635SJoe Thornber {
110866a63635SJoe Thornber 	struct entry *demoted = q_peek(&mq->clean, mq->clean.nr_levels, false);
110966a63635SJoe Thornber 	if (!demoted)
111066a63635SJoe Thornber 		/*
111166a63635SJoe Thornber 		 * We could get a block from mq->dirty, but that
111266a63635SJoe Thornber 		 * would add extra latency to the triggering bio as it
111366a63635SJoe Thornber 		 * waits for the writeback.  Better to not promote this
111466a63635SJoe Thornber 		 * time and hope there's a clean block next time this block
111566a63635SJoe Thornber 		 * is hit.
111666a63635SJoe Thornber 		 */
111766a63635SJoe Thornber 		return -ENOSPC;
111866a63635SJoe Thornber 
111966a63635SJoe Thornber 	if (locker->fn(locker, demoted->oblock))
112066a63635SJoe Thornber 		/*
112166a63635SJoe Thornber 		 * We couldn't lock this block.
112266a63635SJoe Thornber 		 */
112366a63635SJoe Thornber 		return -EBUSY;
112466a63635SJoe Thornber 
112566a63635SJoe Thornber 	del(mq, demoted);
112666a63635SJoe Thornber 	*oblock = demoted->oblock;
112766a63635SJoe Thornber 	free_entry(&mq->cache_alloc, demoted);
112866a63635SJoe Thornber 
112966a63635SJoe Thornber 	return 0;
113066a63635SJoe Thornber }
113166a63635SJoe Thornber 
113266a63635SJoe Thornber enum promote_result {
113366a63635SJoe Thornber 	PROMOTE_NOT,
113466a63635SJoe Thornber 	PROMOTE_TEMPORARY,
113566a63635SJoe Thornber 	PROMOTE_PERMANENT
113666a63635SJoe Thornber };
113766a63635SJoe Thornber 
113866a63635SJoe Thornber /*
113966a63635SJoe Thornber  * Converts a boolean into a promote result.
114066a63635SJoe Thornber  */
114166a63635SJoe Thornber static enum promote_result maybe_promote(bool promote)
114266a63635SJoe Thornber {
114366a63635SJoe Thornber 	return promote ? PROMOTE_PERMANENT : PROMOTE_NOT;
114466a63635SJoe Thornber }
114566a63635SJoe Thornber 
114666a63635SJoe Thornber static enum promote_result should_promote(struct smq_policy *mq, struct entry *hs_e, struct bio *bio,
114766a63635SJoe Thornber 					  bool fast_promote)
114866a63635SJoe Thornber {
114966a63635SJoe Thornber 	if (bio_data_dir(bio) == WRITE) {
115066a63635SJoe Thornber 		if (!allocator_empty(&mq->cache_alloc) && fast_promote)
115166a63635SJoe Thornber 			return PROMOTE_TEMPORARY;
115266a63635SJoe Thornber 
115366a63635SJoe Thornber 		else
115466a63635SJoe Thornber 			return maybe_promote(hs_e->level >= mq->write_promote_level);
115566a63635SJoe Thornber 	} else
115666a63635SJoe Thornber 		return maybe_promote(hs_e->level >= mq->read_promote_level);
115766a63635SJoe Thornber }
115866a63635SJoe Thornber 
115966a63635SJoe Thornber static void insert_in_cache(struct smq_policy *mq, dm_oblock_t oblock,
116066a63635SJoe Thornber 			    struct policy_locker *locker,
116166a63635SJoe Thornber 			    struct policy_result *result, enum promote_result pr)
116266a63635SJoe Thornber {
116366a63635SJoe Thornber 	int r;
116466a63635SJoe Thornber 	struct entry *e;
116566a63635SJoe Thornber 
116666a63635SJoe Thornber 	if (allocator_empty(&mq->cache_alloc)) {
116766a63635SJoe Thornber 		result->op = POLICY_REPLACE;
116866a63635SJoe Thornber 		r = demote_cblock(mq, locker, &result->old_oblock);
116966a63635SJoe Thornber 		if (r) {
117066a63635SJoe Thornber 			result->op = POLICY_MISS;
117166a63635SJoe Thornber 			return;
117266a63635SJoe Thornber 		}
117366a63635SJoe Thornber 
117466a63635SJoe Thornber 	} else
117566a63635SJoe Thornber 		result->op = POLICY_NEW;
117666a63635SJoe Thornber 
117766a63635SJoe Thornber 	e = alloc_entry(&mq->cache_alloc);
117866a63635SJoe Thornber 	BUG_ON(!e);
117966a63635SJoe Thornber 	e->oblock = oblock;
118066a63635SJoe Thornber 
118166a63635SJoe Thornber 	if (pr == PROMOTE_TEMPORARY)
118266a63635SJoe Thornber 		push(mq, e);
118366a63635SJoe Thornber 	else
118466a63635SJoe Thornber 		push_new(mq, e);
118566a63635SJoe Thornber 
118666a63635SJoe Thornber 	result->cblock = infer_cblock(mq, e);
118766a63635SJoe Thornber }
118866a63635SJoe Thornber 
118966a63635SJoe Thornber static dm_oblock_t to_hblock(struct smq_policy *mq, dm_oblock_t b)
119066a63635SJoe Thornber {
119166a63635SJoe Thornber 	sector_t r = from_oblock(b);
119266a63635SJoe Thornber 	(void) sector_div(r, mq->cache_blocks_per_hotspot_block);
119366a63635SJoe Thornber 	return to_oblock(r);
119466a63635SJoe Thornber }
119566a63635SJoe Thornber 
119666a63635SJoe Thornber static struct entry *update_hotspot_queue(struct smq_policy *mq, dm_oblock_t b, struct bio *bio)
119766a63635SJoe Thornber {
119866a63635SJoe Thornber 	unsigned hi;
119966a63635SJoe Thornber 	dm_oblock_t hb = to_hblock(mq, b);
120066a63635SJoe Thornber 	struct entry *e = h_lookup(&mq->hotspot_table, hb);
120166a63635SJoe Thornber 
120266a63635SJoe Thornber 	if (e) {
120366a63635SJoe Thornber 		stats_level_accessed(&mq->hotspot_stats, e->level);
120466a63635SJoe Thornber 
120566a63635SJoe Thornber 		hi = get_index(&mq->hotspot_alloc, e);
120666a63635SJoe Thornber 		q_requeue(&mq->hotspot, e,
120766a63635SJoe Thornber 			  test_and_set_bit(hi, mq->hotspot_hit_bits) ?
120866a63635SJoe Thornber 			  0u : mq->hotspot_level_jump);
120966a63635SJoe Thornber 
121066a63635SJoe Thornber 	} else {
121166a63635SJoe Thornber 		stats_miss(&mq->hotspot_stats);
121266a63635SJoe Thornber 
121366a63635SJoe Thornber 		e = alloc_entry(&mq->hotspot_alloc);
121466a63635SJoe Thornber 		if (!e) {
121566a63635SJoe Thornber 			e = q_pop(&mq->hotspot);
121666a63635SJoe Thornber 			if (e) {
121766a63635SJoe Thornber 				h_remove(&mq->hotspot_table, e);
121866a63635SJoe Thornber 				hi = get_index(&mq->hotspot_alloc, e);
121966a63635SJoe Thornber 				clear_bit(hi, mq->hotspot_hit_bits);
122066a63635SJoe Thornber 			}
122166a63635SJoe Thornber 
122266a63635SJoe Thornber 		}
122366a63635SJoe Thornber 
122466a63635SJoe Thornber 		if (e) {
122566a63635SJoe Thornber 			e->oblock = hb;
122666a63635SJoe Thornber 			q_push(&mq->hotspot, e);
122766a63635SJoe Thornber 			h_insert(&mq->hotspot_table, e);
122866a63635SJoe Thornber 		}
122966a63635SJoe Thornber 	}
123066a63635SJoe Thornber 
123166a63635SJoe Thornber 	return e;
123266a63635SJoe Thornber }
123366a63635SJoe Thornber 
123466a63635SJoe Thornber /*
123566a63635SJoe Thornber  * Looks the oblock up in the hash table, then decides whether to put in
123666a63635SJoe Thornber  * pre_cache, or cache etc.
123766a63635SJoe Thornber  */
123866a63635SJoe Thornber static int map(struct smq_policy *mq, struct bio *bio, dm_oblock_t oblock,
123966a63635SJoe Thornber 	       bool can_migrate, bool fast_promote,
124066a63635SJoe Thornber 	       struct policy_locker *locker, struct policy_result *result)
124166a63635SJoe Thornber {
124266a63635SJoe Thornber 	struct entry *e, *hs_e;
124366a63635SJoe Thornber 	enum promote_result pr;
124466a63635SJoe Thornber 
124566a63635SJoe Thornber 	hs_e = update_hotspot_queue(mq, oblock, bio);
124666a63635SJoe Thornber 
124766a63635SJoe Thornber 	e = h_lookup(&mq->table, oblock);
124866a63635SJoe Thornber 	if (e) {
124966a63635SJoe Thornber 		stats_level_accessed(&mq->cache_stats, e->level);
125066a63635SJoe Thornber 
125166a63635SJoe Thornber 		requeue(mq, e);
125266a63635SJoe Thornber 		result->op = POLICY_HIT;
125366a63635SJoe Thornber 		result->cblock = infer_cblock(mq, e);
125466a63635SJoe Thornber 
125566a63635SJoe Thornber 	} else {
125666a63635SJoe Thornber 		stats_miss(&mq->cache_stats);
125766a63635SJoe Thornber 
125866a63635SJoe Thornber 		pr = should_promote(mq, hs_e, bio, fast_promote);
125966a63635SJoe Thornber 		if (pr == PROMOTE_NOT)
126066a63635SJoe Thornber 			result->op = POLICY_MISS;
126166a63635SJoe Thornber 
126266a63635SJoe Thornber 		else {
126366a63635SJoe Thornber 			if (!can_migrate) {
126466a63635SJoe Thornber 				result->op = POLICY_MISS;
126566a63635SJoe Thornber 				return -EWOULDBLOCK;
126666a63635SJoe Thornber 			}
126766a63635SJoe Thornber 
126866a63635SJoe Thornber 			insert_in_cache(mq, oblock, locker, result, pr);
126966a63635SJoe Thornber 		}
127066a63635SJoe Thornber 	}
127166a63635SJoe Thornber 
127266a63635SJoe Thornber 	return 0;
127366a63635SJoe Thornber }
127466a63635SJoe Thornber 
127566a63635SJoe Thornber /*----------------------------------------------------------------*/
127666a63635SJoe Thornber 
127766a63635SJoe Thornber /*
127866a63635SJoe Thornber  * Public interface, via the policy struct.  See dm-cache-policy.h for a
127966a63635SJoe Thornber  * description of these.
128066a63635SJoe Thornber  */
128166a63635SJoe Thornber 
128266a63635SJoe Thornber static struct smq_policy *to_smq_policy(struct dm_cache_policy *p)
128366a63635SJoe Thornber {
128466a63635SJoe Thornber 	return container_of(p, struct smq_policy, policy);
128566a63635SJoe Thornber }
128666a63635SJoe Thornber 
128766a63635SJoe Thornber static void smq_destroy(struct dm_cache_policy *p)
128866a63635SJoe Thornber {
128966a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
129066a63635SJoe Thornber 
129166a63635SJoe Thornber 	h_exit(&mq->hotspot_table);
129266a63635SJoe Thornber 	h_exit(&mq->table);
129366a63635SJoe Thornber 	free_bitset(mq->hotspot_hit_bits);
129466a63635SJoe Thornber 	free_bitset(mq->cache_hit_bits);
129566a63635SJoe Thornber 	space_exit(&mq->es);
129666a63635SJoe Thornber 	kfree(mq);
129766a63635SJoe Thornber }
129866a63635SJoe Thornber 
129966a63635SJoe Thornber static void copy_tick(struct smq_policy *mq)
130066a63635SJoe Thornber {
130166a63635SJoe Thornber 	unsigned long flags, tick;
130266a63635SJoe Thornber 
130366a63635SJoe Thornber 	spin_lock_irqsave(&mq->tick_lock, flags);
130466a63635SJoe Thornber 	tick = mq->tick_protected;
130566a63635SJoe Thornber 	if (tick != mq->tick) {
130666a63635SJoe Thornber 		update_sentinels(mq);
130766a63635SJoe Thornber 		end_hotspot_period(mq);
130866a63635SJoe Thornber 		end_cache_period(mq);
130966a63635SJoe Thornber 		mq->tick = tick;
131066a63635SJoe Thornber 	}
131166a63635SJoe Thornber 	spin_unlock_irqrestore(&mq->tick_lock, flags);
131266a63635SJoe Thornber }
131366a63635SJoe Thornber 
131466a63635SJoe Thornber static bool maybe_lock(struct smq_policy *mq, bool can_block)
131566a63635SJoe Thornber {
131666a63635SJoe Thornber 	if (can_block) {
131766a63635SJoe Thornber 		mutex_lock(&mq->lock);
131866a63635SJoe Thornber 		return true;
131966a63635SJoe Thornber 	} else
132066a63635SJoe Thornber 		return mutex_trylock(&mq->lock);
132166a63635SJoe Thornber }
132266a63635SJoe Thornber 
132366a63635SJoe Thornber static int smq_map(struct dm_cache_policy *p, dm_oblock_t oblock,
132466a63635SJoe Thornber 		   bool can_block, bool can_migrate, bool fast_promote,
132566a63635SJoe Thornber 		   struct bio *bio, struct policy_locker *locker,
132666a63635SJoe Thornber 		   struct policy_result *result)
132766a63635SJoe Thornber {
132866a63635SJoe Thornber 	int r;
132966a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
133066a63635SJoe Thornber 
133166a63635SJoe Thornber 	result->op = POLICY_MISS;
133266a63635SJoe Thornber 
133366a63635SJoe Thornber 	if (!maybe_lock(mq, can_block))
133466a63635SJoe Thornber 		return -EWOULDBLOCK;
133566a63635SJoe Thornber 
133666a63635SJoe Thornber 	copy_tick(mq);
133766a63635SJoe Thornber 	r = map(mq, bio, oblock, can_migrate, fast_promote, locker, result);
133866a63635SJoe Thornber 	mutex_unlock(&mq->lock);
133966a63635SJoe Thornber 
134066a63635SJoe Thornber 	return r;
134166a63635SJoe Thornber }
134266a63635SJoe Thornber 
134366a63635SJoe Thornber static int smq_lookup(struct dm_cache_policy *p, dm_oblock_t oblock, dm_cblock_t *cblock)
134466a63635SJoe Thornber {
134566a63635SJoe Thornber 	int r;
134666a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
134766a63635SJoe Thornber 	struct entry *e;
134866a63635SJoe Thornber 
134966a63635SJoe Thornber 	if (!mutex_trylock(&mq->lock))
135066a63635SJoe Thornber 		return -EWOULDBLOCK;
135166a63635SJoe Thornber 
135266a63635SJoe Thornber 	e = h_lookup(&mq->table, oblock);
135366a63635SJoe Thornber 	if (e) {
135466a63635SJoe Thornber 		*cblock = infer_cblock(mq, e);
135566a63635SJoe Thornber 		r = 0;
135666a63635SJoe Thornber 	} else
135766a63635SJoe Thornber 		r = -ENOENT;
135866a63635SJoe Thornber 
135966a63635SJoe Thornber 	mutex_unlock(&mq->lock);
136066a63635SJoe Thornber 
136166a63635SJoe Thornber 	return r;
136266a63635SJoe Thornber }
136366a63635SJoe Thornber 
136466a63635SJoe Thornber static void __smq_set_clear_dirty(struct smq_policy *mq, dm_oblock_t oblock, bool set)
136566a63635SJoe Thornber {
136666a63635SJoe Thornber 	struct entry *e;
136766a63635SJoe Thornber 
136866a63635SJoe Thornber 	e = h_lookup(&mq->table, oblock);
136966a63635SJoe Thornber 	BUG_ON(!e);
137066a63635SJoe Thornber 
137166a63635SJoe Thornber 	del(mq, e);
137266a63635SJoe Thornber 	e->dirty = set;
137366a63635SJoe Thornber 	push(mq, e);
137466a63635SJoe Thornber }
137566a63635SJoe Thornber 
137666a63635SJoe Thornber static void smq_set_dirty(struct dm_cache_policy *p, dm_oblock_t oblock)
137766a63635SJoe Thornber {
137866a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
137966a63635SJoe Thornber 
138066a63635SJoe Thornber 	mutex_lock(&mq->lock);
138166a63635SJoe Thornber 	__smq_set_clear_dirty(mq, oblock, true);
138266a63635SJoe Thornber 	mutex_unlock(&mq->lock);
138366a63635SJoe Thornber }
138466a63635SJoe Thornber 
138566a63635SJoe Thornber static void smq_clear_dirty(struct dm_cache_policy *p, dm_oblock_t oblock)
138666a63635SJoe Thornber {
138766a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
138866a63635SJoe Thornber 
138966a63635SJoe Thornber 	mutex_lock(&mq->lock);
139066a63635SJoe Thornber 	__smq_set_clear_dirty(mq, oblock, false);
139166a63635SJoe Thornber 	mutex_unlock(&mq->lock);
139266a63635SJoe Thornber }
139366a63635SJoe Thornber 
139466a63635SJoe Thornber static int smq_load_mapping(struct dm_cache_policy *p,
139566a63635SJoe Thornber 			    dm_oblock_t oblock, dm_cblock_t cblock,
139666a63635SJoe Thornber 			    uint32_t hint, bool hint_valid)
139766a63635SJoe Thornber {
139866a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
139966a63635SJoe Thornber 	struct entry *e;
140066a63635SJoe Thornber 
140166a63635SJoe Thornber 	e = alloc_particular_entry(&mq->cache_alloc, from_cblock(cblock));
140266a63635SJoe Thornber 	e->oblock = oblock;
140366a63635SJoe Thornber 	e->dirty = false;	/* this gets corrected in a minute */
140466a63635SJoe Thornber 	e->level = hint_valid ? min(hint, NR_CACHE_LEVELS - 1) : 1;
140566a63635SJoe Thornber 	push(mq, e);
140666a63635SJoe Thornber 
140766a63635SJoe Thornber 	return 0;
140866a63635SJoe Thornber }
140966a63635SJoe Thornber 
141066a63635SJoe Thornber static int smq_save_hints(struct smq_policy *mq, struct queue *q,
141166a63635SJoe Thornber 			  policy_walk_fn fn, void *context)
141266a63635SJoe Thornber {
141366a63635SJoe Thornber 	int r;
141466a63635SJoe Thornber 	unsigned level;
141566a63635SJoe Thornber 	struct entry *e;
141666a63635SJoe Thornber 
141766a63635SJoe Thornber 	for (level = 0; level < q->nr_levels; level++)
141866a63635SJoe Thornber 		for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e)) {
141966a63635SJoe Thornber 			if (!e->sentinel) {
142066a63635SJoe Thornber 				r = fn(context, infer_cblock(mq, e),
142166a63635SJoe Thornber 				       e->oblock, e->level);
142266a63635SJoe Thornber 				if (r)
142366a63635SJoe Thornber 					return r;
142466a63635SJoe Thornber 			}
142566a63635SJoe Thornber 		}
142666a63635SJoe Thornber 
142766a63635SJoe Thornber 	return 0;
142866a63635SJoe Thornber }
142966a63635SJoe Thornber 
143066a63635SJoe Thornber static int smq_walk_mappings(struct dm_cache_policy *p, policy_walk_fn fn,
143166a63635SJoe Thornber 			     void *context)
143266a63635SJoe Thornber {
143366a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
143466a63635SJoe Thornber 	int r = 0;
143566a63635SJoe Thornber 
143666a63635SJoe Thornber 	mutex_lock(&mq->lock);
143766a63635SJoe Thornber 
143866a63635SJoe Thornber 	r = smq_save_hints(mq, &mq->clean, fn, context);
143966a63635SJoe Thornber 	if (!r)
144066a63635SJoe Thornber 		r = smq_save_hints(mq, &mq->dirty, fn, context);
144166a63635SJoe Thornber 
144266a63635SJoe Thornber 	mutex_unlock(&mq->lock);
144366a63635SJoe Thornber 
144466a63635SJoe Thornber 	return r;
144566a63635SJoe Thornber }
144666a63635SJoe Thornber 
144766a63635SJoe Thornber static void __remove_mapping(struct smq_policy *mq, dm_oblock_t oblock)
144866a63635SJoe Thornber {
144966a63635SJoe Thornber 	struct entry *e;
145066a63635SJoe Thornber 
145166a63635SJoe Thornber 	e = h_lookup(&mq->table, oblock);
145266a63635SJoe Thornber 	BUG_ON(!e);
145366a63635SJoe Thornber 
145466a63635SJoe Thornber 	del(mq, e);
145566a63635SJoe Thornber 	free_entry(&mq->cache_alloc, e);
145666a63635SJoe Thornber }
145766a63635SJoe Thornber 
145866a63635SJoe Thornber static void smq_remove_mapping(struct dm_cache_policy *p, dm_oblock_t oblock)
145966a63635SJoe Thornber {
146066a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
146166a63635SJoe Thornber 
146266a63635SJoe Thornber 	mutex_lock(&mq->lock);
146366a63635SJoe Thornber 	__remove_mapping(mq, oblock);
146466a63635SJoe Thornber 	mutex_unlock(&mq->lock);
146566a63635SJoe Thornber }
146666a63635SJoe Thornber 
146766a63635SJoe Thornber static int __remove_cblock(struct smq_policy *mq, dm_cblock_t cblock)
146866a63635SJoe Thornber {
146966a63635SJoe Thornber 	struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock));
147066a63635SJoe Thornber 
147166a63635SJoe Thornber 	if (!e || !e->allocated)
147266a63635SJoe Thornber 		return -ENODATA;
147366a63635SJoe Thornber 
147466a63635SJoe Thornber 	del(mq, e);
147566a63635SJoe Thornber 	free_entry(&mq->cache_alloc, e);
147666a63635SJoe Thornber 
147766a63635SJoe Thornber 	return 0;
147866a63635SJoe Thornber }
147966a63635SJoe Thornber 
148066a63635SJoe Thornber static int smq_remove_cblock(struct dm_cache_policy *p, dm_cblock_t cblock)
148166a63635SJoe Thornber {
148266a63635SJoe Thornber 	int r;
148366a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
148466a63635SJoe Thornber 
148566a63635SJoe Thornber 	mutex_lock(&mq->lock);
148666a63635SJoe Thornber 	r = __remove_cblock(mq, cblock);
148766a63635SJoe Thornber 	mutex_unlock(&mq->lock);
148866a63635SJoe Thornber 
148966a63635SJoe Thornber 	return r;
149066a63635SJoe Thornber }
149166a63635SJoe Thornber 
149266a63635SJoe Thornber 
149366a63635SJoe Thornber #define CLEAN_TARGET_CRITICAL 5u /* percent */
149466a63635SJoe Thornber 
149566a63635SJoe Thornber static bool clean_target_met(struct smq_policy *mq, bool critical)
149666a63635SJoe Thornber {
149766a63635SJoe Thornber 	if (critical) {
149866a63635SJoe Thornber 		/*
149966a63635SJoe Thornber 		 * Cache entries may not be populated.  So we're cannot rely on the
150066a63635SJoe Thornber 		 * size of the clean queue.
150166a63635SJoe Thornber 		 */
150266a63635SJoe Thornber 		unsigned nr_clean = from_cblock(mq->cache_size) - q_size(&mq->dirty);
150366a63635SJoe Thornber 		unsigned target = from_cblock(mq->cache_size) * CLEAN_TARGET_CRITICAL / 100u;
150466a63635SJoe Thornber 
150566a63635SJoe Thornber 		return nr_clean >= target;
150666a63635SJoe Thornber 	} else
150766a63635SJoe Thornber 		return !q_size(&mq->dirty);
150866a63635SJoe Thornber }
150966a63635SJoe Thornber 
151066a63635SJoe Thornber static int __smq_writeback_work(struct smq_policy *mq, dm_oblock_t *oblock,
151166a63635SJoe Thornber 				dm_cblock_t *cblock, bool critical_only)
151266a63635SJoe Thornber {
151366a63635SJoe Thornber 	struct entry *e = NULL;
151466a63635SJoe Thornber 	bool target_met = clean_target_met(mq, critical_only);
151566a63635SJoe Thornber 
151666a63635SJoe Thornber 	if (critical_only)
151766a63635SJoe Thornber 		/*
151866a63635SJoe Thornber 		 * Always try and keep the bottom level clean.
151966a63635SJoe Thornber 		 */
152066a63635SJoe Thornber 		e = pop_old(mq, &mq->dirty, target_met ? 1u : mq->dirty.nr_levels);
152166a63635SJoe Thornber 
152266a63635SJoe Thornber 	else
152366a63635SJoe Thornber 		e = pop_old(mq, &mq->dirty, mq->dirty.nr_levels);
152466a63635SJoe Thornber 
152566a63635SJoe Thornber 	if (!e)
152666a63635SJoe Thornber 		return -ENODATA;
152766a63635SJoe Thornber 
152866a63635SJoe Thornber 	*oblock = e->oblock;
152966a63635SJoe Thornber 	*cblock = infer_cblock(mq, e);
153066a63635SJoe Thornber 	e->dirty = false;
153166a63635SJoe Thornber 	push_new(mq, e);
153266a63635SJoe Thornber 
153366a63635SJoe Thornber 	return 0;
153466a63635SJoe Thornber }
153566a63635SJoe Thornber 
153666a63635SJoe Thornber static int smq_writeback_work(struct dm_cache_policy *p, dm_oblock_t *oblock,
153766a63635SJoe Thornber 			      dm_cblock_t *cblock, bool critical_only)
153866a63635SJoe Thornber {
153966a63635SJoe Thornber 	int r;
154066a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
154166a63635SJoe Thornber 
154266a63635SJoe Thornber 	mutex_lock(&mq->lock);
154366a63635SJoe Thornber 	r = __smq_writeback_work(mq, oblock, cblock, critical_only);
154466a63635SJoe Thornber 	mutex_unlock(&mq->lock);
154566a63635SJoe Thornber 
154666a63635SJoe Thornber 	return r;
154766a63635SJoe Thornber }
154866a63635SJoe Thornber 
154966a63635SJoe Thornber static void __force_mapping(struct smq_policy *mq,
155066a63635SJoe Thornber 			    dm_oblock_t current_oblock, dm_oblock_t new_oblock)
155166a63635SJoe Thornber {
155266a63635SJoe Thornber 	struct entry *e = h_lookup(&mq->table, current_oblock);
155366a63635SJoe Thornber 
155466a63635SJoe Thornber 	if (e) {
155566a63635SJoe Thornber 		del(mq, e);
155666a63635SJoe Thornber 		e->oblock = new_oblock;
155766a63635SJoe Thornber 		e->dirty = true;
155866a63635SJoe Thornber 		push(mq, e);
155966a63635SJoe Thornber 	}
156066a63635SJoe Thornber }
156166a63635SJoe Thornber 
156266a63635SJoe Thornber static void smq_force_mapping(struct dm_cache_policy *p,
156366a63635SJoe Thornber 			      dm_oblock_t current_oblock, dm_oblock_t new_oblock)
156466a63635SJoe Thornber {
156566a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
156666a63635SJoe Thornber 
156766a63635SJoe Thornber 	mutex_lock(&mq->lock);
156866a63635SJoe Thornber 	__force_mapping(mq, current_oblock, new_oblock);
156966a63635SJoe Thornber 	mutex_unlock(&mq->lock);
157066a63635SJoe Thornber }
157166a63635SJoe Thornber 
157266a63635SJoe Thornber static dm_cblock_t smq_residency(struct dm_cache_policy *p)
157366a63635SJoe Thornber {
157466a63635SJoe Thornber 	dm_cblock_t r;
157566a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
157666a63635SJoe Thornber 
157766a63635SJoe Thornber 	mutex_lock(&mq->lock);
157866a63635SJoe Thornber 	r = to_cblock(mq->cache_alloc.nr_allocated);
157966a63635SJoe Thornber 	mutex_unlock(&mq->lock);
158066a63635SJoe Thornber 
158166a63635SJoe Thornber 	return r;
158266a63635SJoe Thornber }
158366a63635SJoe Thornber 
1584fba10109SJoe Thornber static void smq_tick(struct dm_cache_policy *p, bool can_block)
158566a63635SJoe Thornber {
158666a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
158766a63635SJoe Thornber 	unsigned long flags;
158866a63635SJoe Thornber 
158966a63635SJoe Thornber 	spin_lock_irqsave(&mq->tick_lock, flags);
159066a63635SJoe Thornber 	mq->tick_protected++;
159166a63635SJoe Thornber 	spin_unlock_irqrestore(&mq->tick_lock, flags);
1592fba10109SJoe Thornber 
1593fba10109SJoe Thornber 	if (can_block) {
1594fba10109SJoe Thornber 		mutex_lock(&mq->lock);
1595fba10109SJoe Thornber 		copy_tick(mq);
1596fba10109SJoe Thornber 		mutex_unlock(&mq->lock);
1597fba10109SJoe Thornber 	}
159866a63635SJoe Thornber }
159966a63635SJoe Thornber 
160066a63635SJoe Thornber /* Init the policy plugin interface function pointers. */
160166a63635SJoe Thornber static void init_policy_functions(struct smq_policy *mq)
160266a63635SJoe Thornber {
160366a63635SJoe Thornber 	mq->policy.destroy = smq_destroy;
160466a63635SJoe Thornber 	mq->policy.map = smq_map;
160566a63635SJoe Thornber 	mq->policy.lookup = smq_lookup;
160666a63635SJoe Thornber 	mq->policy.set_dirty = smq_set_dirty;
160766a63635SJoe Thornber 	mq->policy.clear_dirty = smq_clear_dirty;
160866a63635SJoe Thornber 	mq->policy.load_mapping = smq_load_mapping;
160966a63635SJoe Thornber 	mq->policy.walk_mappings = smq_walk_mappings;
161066a63635SJoe Thornber 	mq->policy.remove_mapping = smq_remove_mapping;
161166a63635SJoe Thornber 	mq->policy.remove_cblock = smq_remove_cblock;
161266a63635SJoe Thornber 	mq->policy.writeback_work = smq_writeback_work;
161366a63635SJoe Thornber 	mq->policy.force_mapping = smq_force_mapping;
161466a63635SJoe Thornber 	mq->policy.residency = smq_residency;
161566a63635SJoe Thornber 	mq->policy.tick = smq_tick;
161666a63635SJoe Thornber }
161766a63635SJoe Thornber 
161866a63635SJoe Thornber static bool too_many_hotspot_blocks(sector_t origin_size,
161966a63635SJoe Thornber 				    sector_t hotspot_block_size,
162066a63635SJoe Thornber 				    unsigned nr_hotspot_blocks)
162166a63635SJoe Thornber {
162266a63635SJoe Thornber 	return (hotspot_block_size * nr_hotspot_blocks) > origin_size;
162366a63635SJoe Thornber }
162466a63635SJoe Thornber 
162566a63635SJoe Thornber static void calc_hotspot_params(sector_t origin_size,
162666a63635SJoe Thornber 				sector_t cache_block_size,
162766a63635SJoe Thornber 				unsigned nr_cache_blocks,
162866a63635SJoe Thornber 				sector_t *hotspot_block_size,
162966a63635SJoe Thornber 				unsigned *nr_hotspot_blocks)
163066a63635SJoe Thornber {
163166a63635SJoe Thornber 	*hotspot_block_size = cache_block_size * 16u;
163266a63635SJoe Thornber 	*nr_hotspot_blocks = max(nr_cache_blocks / 4u, 1024u);
163366a63635SJoe Thornber 
163466a63635SJoe Thornber 	while ((*hotspot_block_size > cache_block_size) &&
163566a63635SJoe Thornber 	       too_many_hotspot_blocks(origin_size, *hotspot_block_size, *nr_hotspot_blocks))
163666a63635SJoe Thornber 		*hotspot_block_size /= 2u;
163766a63635SJoe Thornber }
163866a63635SJoe Thornber 
163966a63635SJoe Thornber static struct dm_cache_policy *smq_create(dm_cblock_t cache_size,
164066a63635SJoe Thornber 					  sector_t origin_size,
164166a63635SJoe Thornber 					  sector_t cache_block_size)
164266a63635SJoe Thornber {
164366a63635SJoe Thornber 	unsigned i;
164466a63635SJoe Thornber 	unsigned nr_sentinels_per_queue = 2u * NR_CACHE_LEVELS;
164566a63635SJoe Thornber 	unsigned total_sentinels = 2u * nr_sentinels_per_queue;
164666a63635SJoe Thornber 	struct smq_policy *mq = kzalloc(sizeof(*mq), GFP_KERNEL);
164766a63635SJoe Thornber 
164866a63635SJoe Thornber 	if (!mq)
164966a63635SJoe Thornber 		return NULL;
165066a63635SJoe Thornber 
165166a63635SJoe Thornber 	init_policy_functions(mq);
165266a63635SJoe Thornber 	mq->cache_size = cache_size;
165366a63635SJoe Thornber 	mq->cache_block_size = cache_block_size;
165466a63635SJoe Thornber 
165566a63635SJoe Thornber 	calc_hotspot_params(origin_size, cache_block_size, from_cblock(cache_size),
165666a63635SJoe Thornber 			    &mq->hotspot_block_size, &mq->nr_hotspot_blocks);
165766a63635SJoe Thornber 
165866a63635SJoe Thornber 	mq->cache_blocks_per_hotspot_block = div64_u64(mq->hotspot_block_size, mq->cache_block_size);
165966a63635SJoe Thornber 	mq->hotspot_level_jump = 1u;
166066a63635SJoe Thornber 	if (space_init(&mq->es, total_sentinels + mq->nr_hotspot_blocks + from_cblock(cache_size))) {
166166a63635SJoe Thornber 		DMERR("couldn't initialize entry space");
166266a63635SJoe Thornber 		goto bad_pool_init;
166366a63635SJoe Thornber 	}
166466a63635SJoe Thornber 
166566a63635SJoe Thornber 	init_allocator(&mq->writeback_sentinel_alloc, &mq->es, 0, nr_sentinels_per_queue);
166666a63635SJoe Thornber         for (i = 0; i < nr_sentinels_per_queue; i++)
166766a63635SJoe Thornber 		get_entry(&mq->writeback_sentinel_alloc, i)->sentinel = true;
166866a63635SJoe Thornber 
166966a63635SJoe Thornber 	init_allocator(&mq->demote_sentinel_alloc, &mq->es, nr_sentinels_per_queue, total_sentinels);
167066a63635SJoe Thornber         for (i = 0; i < nr_sentinels_per_queue; i++)
167166a63635SJoe Thornber 		get_entry(&mq->demote_sentinel_alloc, i)->sentinel = true;
167266a63635SJoe Thornber 
167366a63635SJoe Thornber 	init_allocator(&mq->hotspot_alloc, &mq->es, total_sentinels,
167466a63635SJoe Thornber 		       total_sentinels + mq->nr_hotspot_blocks);
167566a63635SJoe Thornber 
167666a63635SJoe Thornber 	init_allocator(&mq->cache_alloc, &mq->es,
167766a63635SJoe Thornber 		       total_sentinels + mq->nr_hotspot_blocks,
167866a63635SJoe Thornber 		       total_sentinels + mq->nr_hotspot_blocks + from_cblock(cache_size));
167966a63635SJoe Thornber 
168066a63635SJoe Thornber 	mq->hotspot_hit_bits = alloc_bitset(mq->nr_hotspot_blocks);
168166a63635SJoe Thornber 	if (!mq->hotspot_hit_bits) {
168266a63635SJoe Thornber 		DMERR("couldn't allocate hotspot hit bitset");
168366a63635SJoe Thornber 		goto bad_hotspot_hit_bits;
168466a63635SJoe Thornber 	}
168566a63635SJoe Thornber 	clear_bitset(mq->hotspot_hit_bits, mq->nr_hotspot_blocks);
168666a63635SJoe Thornber 
168766a63635SJoe Thornber 	if (from_cblock(cache_size)) {
168866a63635SJoe Thornber 		mq->cache_hit_bits = alloc_bitset(from_cblock(cache_size));
168966a63635SJoe Thornber 		if (!mq->cache_hit_bits && mq->cache_hit_bits) {
169066a63635SJoe Thornber 			DMERR("couldn't allocate cache hit bitset");
169166a63635SJoe Thornber 			goto bad_cache_hit_bits;
169266a63635SJoe Thornber 		}
169366a63635SJoe Thornber 		clear_bitset(mq->cache_hit_bits, from_cblock(mq->cache_size));
169466a63635SJoe Thornber 	} else
169566a63635SJoe Thornber 		mq->cache_hit_bits = NULL;
169666a63635SJoe Thornber 
169766a63635SJoe Thornber 	mq->tick_protected = 0;
169866a63635SJoe Thornber 	mq->tick = 0;
169966a63635SJoe Thornber 	mutex_init(&mq->lock);
170066a63635SJoe Thornber 	spin_lock_init(&mq->tick_lock);
170166a63635SJoe Thornber 
170266a63635SJoe Thornber 	q_init(&mq->hotspot, &mq->es, NR_HOTSPOT_LEVELS);
170366a63635SJoe Thornber 	mq->hotspot.nr_top_levels = 8;
170466a63635SJoe Thornber 	mq->hotspot.nr_in_top_levels = min(mq->nr_hotspot_blocks / NR_HOTSPOT_LEVELS,
170566a63635SJoe Thornber 					   from_cblock(mq->cache_size) / mq->cache_blocks_per_hotspot_block);
170666a63635SJoe Thornber 
170766a63635SJoe Thornber 	q_init(&mq->clean, &mq->es, NR_CACHE_LEVELS);
170866a63635SJoe Thornber 	q_init(&mq->dirty, &mq->es, NR_CACHE_LEVELS);
170966a63635SJoe Thornber 
171066a63635SJoe Thornber 	stats_init(&mq->hotspot_stats, NR_HOTSPOT_LEVELS);
171166a63635SJoe Thornber 	stats_init(&mq->cache_stats, NR_CACHE_LEVELS);
171266a63635SJoe Thornber 
171366a63635SJoe Thornber 	if (h_init(&mq->table, &mq->es, from_cblock(cache_size)))
171466a63635SJoe Thornber 		goto bad_alloc_table;
171566a63635SJoe Thornber 
171666a63635SJoe Thornber 	if (h_init(&mq->hotspot_table, &mq->es, mq->nr_hotspot_blocks))
171766a63635SJoe Thornber 		goto bad_alloc_hotspot_table;
171866a63635SJoe Thornber 
171966a63635SJoe Thornber 	sentinels_init(mq);
172066a63635SJoe Thornber 	mq->write_promote_level = mq->read_promote_level = NR_HOTSPOT_LEVELS;
172166a63635SJoe Thornber 
172266a63635SJoe Thornber 	mq->next_hotspot_period = jiffies;
172366a63635SJoe Thornber 	mq->next_cache_period = jiffies;
172466a63635SJoe Thornber 
172566a63635SJoe Thornber 	return &mq->policy;
172666a63635SJoe Thornber 
172766a63635SJoe Thornber bad_alloc_hotspot_table:
172866a63635SJoe Thornber 	h_exit(&mq->table);
172966a63635SJoe Thornber bad_alloc_table:
173066a63635SJoe Thornber 	free_bitset(mq->cache_hit_bits);
173166a63635SJoe Thornber bad_cache_hit_bits:
173266a63635SJoe Thornber 	free_bitset(mq->hotspot_hit_bits);
173366a63635SJoe Thornber bad_hotspot_hit_bits:
173466a63635SJoe Thornber 	space_exit(&mq->es);
173566a63635SJoe Thornber bad_pool_init:
173666a63635SJoe Thornber 	kfree(mq);
173766a63635SJoe Thornber 
173866a63635SJoe Thornber 	return NULL;
173966a63635SJoe Thornber }
174066a63635SJoe Thornber 
174166a63635SJoe Thornber /*----------------------------------------------------------------*/
174266a63635SJoe Thornber 
174366a63635SJoe Thornber static struct dm_cache_policy_type smq_policy_type = {
174466a63635SJoe Thornber 	.name = "smq",
174566a63635SJoe Thornber 	.version = {1, 0, 0},
174666a63635SJoe Thornber 	.hint_size = 4,
174766a63635SJoe Thornber 	.owner = THIS_MODULE,
174866a63635SJoe Thornber 	.create = smq_create
174966a63635SJoe Thornber };
175066a63635SJoe Thornber 
1751*bccab6a0SMike Snitzer static struct dm_cache_policy_type default_policy_type = {
1752*bccab6a0SMike Snitzer 	.name = "default",
1753*bccab6a0SMike Snitzer 	.version = {1, 0, 0},
1754*bccab6a0SMike Snitzer 	.hint_size = 4,
1755*bccab6a0SMike Snitzer 	.owner = THIS_MODULE,
1756*bccab6a0SMike Snitzer 	.create = smq_create,
1757*bccab6a0SMike Snitzer 	.real = &smq_policy_type
1758*bccab6a0SMike Snitzer };
1759*bccab6a0SMike Snitzer 
176066a63635SJoe Thornber static int __init smq_init(void)
176166a63635SJoe Thornber {
176266a63635SJoe Thornber 	int r;
176366a63635SJoe Thornber 
176466a63635SJoe Thornber 	r = dm_cache_policy_register(&smq_policy_type);
176566a63635SJoe Thornber 	if (r) {
176666a63635SJoe Thornber 		DMERR("register failed %d", r);
176766a63635SJoe Thornber 		return -ENOMEM;
176866a63635SJoe Thornber 	}
176966a63635SJoe Thornber 
1770*bccab6a0SMike Snitzer 	r = dm_cache_policy_register(&default_policy_type);
1771*bccab6a0SMike Snitzer 	if (r) {
1772*bccab6a0SMike Snitzer 		DMERR("register failed (as default) %d", r);
1773*bccab6a0SMike Snitzer 		dm_cache_policy_unregister(&smq_policy_type);
1774*bccab6a0SMike Snitzer 		return -ENOMEM;
1775*bccab6a0SMike Snitzer 	}
1776*bccab6a0SMike Snitzer 
177766a63635SJoe Thornber 	return 0;
177866a63635SJoe Thornber }
177966a63635SJoe Thornber 
178066a63635SJoe Thornber static void __exit smq_exit(void)
178166a63635SJoe Thornber {
178266a63635SJoe Thornber 	dm_cache_policy_unregister(&smq_policy_type);
1783*bccab6a0SMike Snitzer 	dm_cache_policy_unregister(&default_policy_type);
178466a63635SJoe Thornber }
178566a63635SJoe Thornber 
178666a63635SJoe Thornber module_init(smq_init);
178766a63635SJoe Thornber module_exit(smq_exit);
178866a63635SJoe Thornber 
178966a63635SJoe Thornber MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
179066a63635SJoe Thornber MODULE_LICENSE("GPL");
179166a63635SJoe Thornber MODULE_DESCRIPTION("smq cache policy");
1792