xref: /openbmc/linux/drivers/md/dm-cache-policy-smq.c (revision 3bd940030752a33ff665eefdd74a1cdb74a4f9b0)
1*3bd94003SHeinz Mauelshagen // SPDX-License-Identifier: GPL-2.0-only
266a63635SJoe Thornber /*
366a63635SJoe Thornber  * Copyright (C) 2015 Red Hat. All rights reserved.
466a63635SJoe Thornber  *
566a63635SJoe Thornber  * This file is released under the GPL.
666a63635SJoe Thornber  */
766a63635SJoe Thornber 
8b29d4986SJoe Thornber #include "dm-cache-background-tracker.h"
966a63635SJoe Thornber #include "dm-cache-policy-internal.h"
10b29d4986SJoe Thornber #include "dm-cache-policy.h"
1166a63635SJoe Thornber #include "dm.h"
1266a63635SJoe Thornber 
1366a63635SJoe Thornber #include <linux/hash.h>
1466a63635SJoe Thornber #include <linux/jiffies.h>
1566a63635SJoe Thornber #include <linux/module.h>
1666a63635SJoe Thornber #include <linux/mutex.h>
1766a63635SJoe Thornber #include <linux/vmalloc.h>
1866a63635SJoe Thornber #include <linux/math64.h>
1966a63635SJoe Thornber 
2066a63635SJoe Thornber #define DM_MSG_PREFIX "cache-policy-smq"
2166a63635SJoe Thornber 
2266a63635SJoe Thornber /*----------------------------------------------------------------*/
2366a63635SJoe Thornber 
2466a63635SJoe Thornber /*
2566a63635SJoe Thornber  * Safe division functions that return zero on divide by zero.
2666a63635SJoe Thornber  */
2766a63635SJoe Thornber static unsigned safe_div(unsigned n, unsigned d)
2866a63635SJoe Thornber {
2966a63635SJoe Thornber 	return d ? n / d : 0u;
3066a63635SJoe Thornber }
3166a63635SJoe Thornber 
3266a63635SJoe Thornber static unsigned safe_mod(unsigned n, unsigned d)
3366a63635SJoe Thornber {
3466a63635SJoe Thornber 	return d ? n % d : 0u;
3566a63635SJoe Thornber }
3666a63635SJoe Thornber 
3766a63635SJoe Thornber /*----------------------------------------------------------------*/
3866a63635SJoe Thornber 
3966a63635SJoe Thornber struct entry {
4066a63635SJoe Thornber 	unsigned hash_next:28;
4166a63635SJoe Thornber 	unsigned prev:28;
4266a63635SJoe Thornber 	unsigned next:28;
43b29d4986SJoe Thornber 	unsigned level:6;
4466a63635SJoe Thornber 	bool dirty:1;
4566a63635SJoe Thornber 	bool allocated:1;
4666a63635SJoe Thornber 	bool sentinel:1;
47b29d4986SJoe Thornber 	bool pending_work:1;
4866a63635SJoe Thornber 
4966a63635SJoe Thornber 	dm_oblock_t oblock;
5066a63635SJoe Thornber };
5166a63635SJoe Thornber 
5266a63635SJoe Thornber /*----------------------------------------------------------------*/
5366a63635SJoe Thornber 
5466a63635SJoe Thornber #define INDEXER_NULL ((1u << 28u) - 1u)
5566a63635SJoe Thornber 
5666a63635SJoe Thornber /*
5766a63635SJoe Thornber  * An entry_space manages a set of entries that we use for the queues.
5866a63635SJoe Thornber  * The clean and dirty queues share entries, so this object is separate
5966a63635SJoe Thornber  * from the queue itself.
6066a63635SJoe Thornber  */
6166a63635SJoe Thornber struct entry_space {
6266a63635SJoe Thornber 	struct entry *begin;
6366a63635SJoe Thornber 	struct entry *end;
6466a63635SJoe Thornber };
6566a63635SJoe Thornber 
6666a63635SJoe Thornber static int space_init(struct entry_space *es, unsigned nr_entries)
6766a63635SJoe Thornber {
6866a63635SJoe Thornber 	if (!nr_entries) {
6966a63635SJoe Thornber 		es->begin = es->end = NULL;
7066a63635SJoe Thornber 		return 0;
7166a63635SJoe Thornber 	}
7266a63635SJoe Thornber 
73fad953ceSKees Cook 	es->begin = vzalloc(array_size(nr_entries, sizeof(struct entry)));
7466a63635SJoe Thornber 	if (!es->begin)
7566a63635SJoe Thornber 		return -ENOMEM;
7666a63635SJoe Thornber 
7766a63635SJoe Thornber 	es->end = es->begin + nr_entries;
7866a63635SJoe Thornber 	return 0;
7966a63635SJoe Thornber }
8066a63635SJoe Thornber 
8166a63635SJoe Thornber static void space_exit(struct entry_space *es)
8266a63635SJoe Thornber {
8366a63635SJoe Thornber 	vfree(es->begin);
8466a63635SJoe Thornber }
8566a63635SJoe Thornber 
8666a63635SJoe Thornber static struct entry *__get_entry(struct entry_space *es, unsigned block)
8766a63635SJoe Thornber {
8866a63635SJoe Thornber 	struct entry *e;
8966a63635SJoe Thornber 
9066a63635SJoe Thornber 	e = es->begin + block;
9166a63635SJoe Thornber 	BUG_ON(e >= es->end);
9266a63635SJoe Thornber 
9366a63635SJoe Thornber 	return e;
9466a63635SJoe Thornber }
9566a63635SJoe Thornber 
9666a63635SJoe Thornber static unsigned to_index(struct entry_space *es, struct entry *e)
9766a63635SJoe Thornber {
9866a63635SJoe Thornber 	BUG_ON(e < es->begin || e >= es->end);
9966a63635SJoe Thornber 	return e - es->begin;
10066a63635SJoe Thornber }
10166a63635SJoe Thornber 
10266a63635SJoe Thornber static struct entry *to_entry(struct entry_space *es, unsigned block)
10366a63635SJoe Thornber {
10466a63635SJoe Thornber 	if (block == INDEXER_NULL)
10566a63635SJoe Thornber 		return NULL;
10666a63635SJoe Thornber 
10766a63635SJoe Thornber 	return __get_entry(es, block);
10866a63635SJoe Thornber }
10966a63635SJoe Thornber 
11066a63635SJoe Thornber /*----------------------------------------------------------------*/
11166a63635SJoe Thornber 
11266a63635SJoe Thornber struct ilist {
11366a63635SJoe Thornber 	unsigned nr_elts;	/* excluding sentinel entries */
11466a63635SJoe Thornber 	unsigned head, tail;
11566a63635SJoe Thornber };
11666a63635SJoe Thornber 
11766a63635SJoe Thornber static void l_init(struct ilist *l)
11866a63635SJoe Thornber {
11966a63635SJoe Thornber 	l->nr_elts = 0;
12066a63635SJoe Thornber 	l->head = l->tail = INDEXER_NULL;
12166a63635SJoe Thornber }
12266a63635SJoe Thornber 
12366a63635SJoe Thornber static struct entry *l_head(struct entry_space *es, struct ilist *l)
12466a63635SJoe Thornber {
12566a63635SJoe Thornber 	return to_entry(es, l->head);
12666a63635SJoe Thornber }
12766a63635SJoe Thornber 
12866a63635SJoe Thornber static struct entry *l_tail(struct entry_space *es, struct ilist *l)
12966a63635SJoe Thornber {
13066a63635SJoe Thornber 	return to_entry(es, l->tail);
13166a63635SJoe Thornber }
13266a63635SJoe Thornber 
13366a63635SJoe Thornber static struct entry *l_next(struct entry_space *es, struct entry *e)
13466a63635SJoe Thornber {
13566a63635SJoe Thornber 	return to_entry(es, e->next);
13666a63635SJoe Thornber }
13766a63635SJoe Thornber 
13866a63635SJoe Thornber static struct entry *l_prev(struct entry_space *es, struct entry *e)
13966a63635SJoe Thornber {
14066a63635SJoe Thornber 	return to_entry(es, e->prev);
14166a63635SJoe Thornber }
14266a63635SJoe Thornber 
14366a63635SJoe Thornber static bool l_empty(struct ilist *l)
14466a63635SJoe Thornber {
14566a63635SJoe Thornber 	return l->head == INDEXER_NULL;
14666a63635SJoe Thornber }
14766a63635SJoe Thornber 
14866a63635SJoe Thornber static void l_add_head(struct entry_space *es, struct ilist *l, struct entry *e)
14966a63635SJoe Thornber {
15066a63635SJoe Thornber 	struct entry *head = l_head(es, l);
15166a63635SJoe Thornber 
15266a63635SJoe Thornber 	e->next = l->head;
15366a63635SJoe Thornber 	e->prev = INDEXER_NULL;
15466a63635SJoe Thornber 
15566a63635SJoe Thornber 	if (head)
15666a63635SJoe Thornber 		head->prev = l->head = to_index(es, e);
15766a63635SJoe Thornber 	else
15866a63635SJoe Thornber 		l->head = l->tail = to_index(es, e);
15966a63635SJoe Thornber 
16066a63635SJoe Thornber 	if (!e->sentinel)
16166a63635SJoe Thornber 		l->nr_elts++;
16266a63635SJoe Thornber }
16366a63635SJoe Thornber 
16466a63635SJoe Thornber static void l_add_tail(struct entry_space *es, struct ilist *l, struct entry *e)
16566a63635SJoe Thornber {
16666a63635SJoe Thornber 	struct entry *tail = l_tail(es, l);
16766a63635SJoe Thornber 
16866a63635SJoe Thornber 	e->next = INDEXER_NULL;
16966a63635SJoe Thornber 	e->prev = l->tail;
17066a63635SJoe Thornber 
17166a63635SJoe Thornber 	if (tail)
17266a63635SJoe Thornber 		tail->next = l->tail = to_index(es, e);
17366a63635SJoe Thornber 	else
17466a63635SJoe Thornber 		l->head = l->tail = to_index(es, e);
17566a63635SJoe Thornber 
17666a63635SJoe Thornber 	if (!e->sentinel)
17766a63635SJoe Thornber 		l->nr_elts++;
17866a63635SJoe Thornber }
17966a63635SJoe Thornber 
18066a63635SJoe Thornber static void l_add_before(struct entry_space *es, struct ilist *l,
18166a63635SJoe Thornber 			 struct entry *old, struct entry *e)
18266a63635SJoe Thornber {
18366a63635SJoe Thornber 	struct entry *prev = l_prev(es, old);
18466a63635SJoe Thornber 
18566a63635SJoe Thornber 	if (!prev)
18666a63635SJoe Thornber 		l_add_head(es, l, e);
18766a63635SJoe Thornber 
18866a63635SJoe Thornber 	else {
18966a63635SJoe Thornber 		e->prev = old->prev;
19066a63635SJoe Thornber 		e->next = to_index(es, old);
19166a63635SJoe Thornber 		prev->next = old->prev = to_index(es, e);
19266a63635SJoe Thornber 
19366a63635SJoe Thornber 		if (!e->sentinel)
19466a63635SJoe Thornber 			l->nr_elts++;
19566a63635SJoe Thornber 	}
19666a63635SJoe Thornber }
19766a63635SJoe Thornber 
19866a63635SJoe Thornber static void l_del(struct entry_space *es, struct ilist *l, struct entry *e)
19966a63635SJoe Thornber {
20066a63635SJoe Thornber 	struct entry *prev = l_prev(es, e);
20166a63635SJoe Thornber 	struct entry *next = l_next(es, e);
20266a63635SJoe Thornber 
20366a63635SJoe Thornber 	if (prev)
20466a63635SJoe Thornber 		prev->next = e->next;
20566a63635SJoe Thornber 	else
20666a63635SJoe Thornber 		l->head = e->next;
20766a63635SJoe Thornber 
20866a63635SJoe Thornber 	if (next)
20966a63635SJoe Thornber 		next->prev = e->prev;
21066a63635SJoe Thornber 	else
21166a63635SJoe Thornber 		l->tail = e->prev;
21266a63635SJoe Thornber 
21366a63635SJoe Thornber 	if (!e->sentinel)
21466a63635SJoe Thornber 		l->nr_elts--;
21566a63635SJoe Thornber }
21666a63635SJoe Thornber 
2179768a10dSJoe Thornber static struct entry *l_pop_head(struct entry_space *es, struct ilist *l)
2189768a10dSJoe Thornber {
2199768a10dSJoe Thornber 	struct entry *e;
2209768a10dSJoe Thornber 
2219768a10dSJoe Thornber 	for (e = l_head(es, l); e; e = l_next(es, e))
2229768a10dSJoe Thornber 		if (!e->sentinel) {
2239768a10dSJoe Thornber 			l_del(es, l, e);
2249768a10dSJoe Thornber 			return e;
2259768a10dSJoe Thornber 		}
2269768a10dSJoe Thornber 
2279768a10dSJoe Thornber 	return NULL;
2289768a10dSJoe Thornber }
2299768a10dSJoe Thornber 
23066a63635SJoe Thornber static struct entry *l_pop_tail(struct entry_space *es, struct ilist *l)
23166a63635SJoe Thornber {
23266a63635SJoe Thornber 	struct entry *e;
23366a63635SJoe Thornber 
23466a63635SJoe Thornber 	for (e = l_tail(es, l); e; e = l_prev(es, e))
23566a63635SJoe Thornber 		if (!e->sentinel) {
23666a63635SJoe Thornber 			l_del(es, l, e);
23766a63635SJoe Thornber 			return e;
23866a63635SJoe Thornber 		}
23966a63635SJoe Thornber 
24066a63635SJoe Thornber 	return NULL;
24166a63635SJoe Thornber }
24266a63635SJoe Thornber 
24366a63635SJoe Thornber /*----------------------------------------------------------------*/
24466a63635SJoe Thornber 
24566a63635SJoe Thornber /*
24666a63635SJoe Thornber  * The stochastic-multi-queue is a set of lru lists stacked into levels.
24766a63635SJoe Thornber  * Entries are moved up levels when they are used, which loosely orders the
24866a63635SJoe Thornber  * most accessed entries in the top levels and least in the bottom.  This
24966a63635SJoe Thornber  * structure is *much* better than a single lru list.
25066a63635SJoe Thornber  */
25166a63635SJoe Thornber #define MAX_LEVELS 64u
25266a63635SJoe Thornber 
25366a63635SJoe Thornber struct queue {
25466a63635SJoe Thornber 	struct entry_space *es;
25566a63635SJoe Thornber 
25666a63635SJoe Thornber 	unsigned nr_elts;
25766a63635SJoe Thornber 	unsigned nr_levels;
25866a63635SJoe Thornber 	struct ilist qs[MAX_LEVELS];
25966a63635SJoe Thornber 
26066a63635SJoe Thornber 	/*
26166a63635SJoe Thornber 	 * We maintain a count of the number of entries we would like in each
26266a63635SJoe Thornber 	 * level.
26366a63635SJoe Thornber 	 */
26466a63635SJoe Thornber 	unsigned last_target_nr_elts;
26566a63635SJoe Thornber 	unsigned nr_top_levels;
26666a63635SJoe Thornber 	unsigned nr_in_top_levels;
26766a63635SJoe Thornber 	unsigned target_count[MAX_LEVELS];
26866a63635SJoe Thornber };
26966a63635SJoe Thornber 
27066a63635SJoe Thornber static void q_init(struct queue *q, struct entry_space *es, unsigned nr_levels)
27166a63635SJoe Thornber {
27266a63635SJoe Thornber 	unsigned i;
27366a63635SJoe Thornber 
27466a63635SJoe Thornber 	q->es = es;
27566a63635SJoe Thornber 	q->nr_elts = 0;
27666a63635SJoe Thornber 	q->nr_levels = nr_levels;
27766a63635SJoe Thornber 
27866a63635SJoe Thornber 	for (i = 0; i < q->nr_levels; i++) {
27966a63635SJoe Thornber 		l_init(q->qs + i);
28066a63635SJoe Thornber 		q->target_count[i] = 0u;
28166a63635SJoe Thornber 	}
28266a63635SJoe Thornber 
28366a63635SJoe Thornber 	q->last_target_nr_elts = 0u;
28466a63635SJoe Thornber 	q->nr_top_levels = 0u;
28566a63635SJoe Thornber 	q->nr_in_top_levels = 0u;
28666a63635SJoe Thornber }
28766a63635SJoe Thornber 
28866a63635SJoe Thornber static unsigned q_size(struct queue *q)
28966a63635SJoe Thornber {
29066a63635SJoe Thornber 	return q->nr_elts;
29166a63635SJoe Thornber }
29266a63635SJoe Thornber 
29366a63635SJoe Thornber /*
29466a63635SJoe Thornber  * Insert an entry to the back of the given level.
29566a63635SJoe Thornber  */
29666a63635SJoe Thornber static void q_push(struct queue *q, struct entry *e)
29766a63635SJoe Thornber {
298b29d4986SJoe Thornber 	BUG_ON(e->pending_work);
299b29d4986SJoe Thornber 
30066a63635SJoe Thornber 	if (!e->sentinel)
30166a63635SJoe Thornber 		q->nr_elts++;
30266a63635SJoe Thornber 
30366a63635SJoe Thornber 	l_add_tail(q->es, q->qs + e->level, e);
30466a63635SJoe Thornber }
30566a63635SJoe Thornber 
306b29d4986SJoe Thornber static void q_push_front(struct queue *q, struct entry *e)
307b29d4986SJoe Thornber {
308b29d4986SJoe Thornber 	BUG_ON(e->pending_work);
309b29d4986SJoe Thornber 
310b29d4986SJoe Thornber 	if (!e->sentinel)
311b29d4986SJoe Thornber 		q->nr_elts++;
312b29d4986SJoe Thornber 
313b29d4986SJoe Thornber 	l_add_head(q->es, q->qs + e->level, e);
314b29d4986SJoe Thornber }
315b29d4986SJoe Thornber 
31666a63635SJoe Thornber static void q_push_before(struct queue *q, struct entry *old, struct entry *e)
31766a63635SJoe Thornber {
318b29d4986SJoe Thornber 	BUG_ON(e->pending_work);
319b29d4986SJoe Thornber 
32066a63635SJoe Thornber 	if (!e->sentinel)
32166a63635SJoe Thornber 		q->nr_elts++;
32266a63635SJoe Thornber 
32366a63635SJoe Thornber 	l_add_before(q->es, q->qs + e->level, old, e);
32466a63635SJoe Thornber }
32566a63635SJoe Thornber 
32666a63635SJoe Thornber static void q_del(struct queue *q, struct entry *e)
32766a63635SJoe Thornber {
32866a63635SJoe Thornber 	l_del(q->es, q->qs + e->level, e);
32966a63635SJoe Thornber 	if (!e->sentinel)
33066a63635SJoe Thornber 		q->nr_elts--;
33166a63635SJoe Thornber }
33266a63635SJoe Thornber 
33366a63635SJoe Thornber /*
33466a63635SJoe Thornber  * Return the oldest entry of the lowest populated level.
33566a63635SJoe Thornber  */
33666a63635SJoe Thornber static struct entry *q_peek(struct queue *q, unsigned max_level, bool can_cross_sentinel)
33766a63635SJoe Thornber {
33866a63635SJoe Thornber 	unsigned level;
33966a63635SJoe Thornber 	struct entry *e;
34066a63635SJoe Thornber 
34166a63635SJoe Thornber 	max_level = min(max_level, q->nr_levels);
34266a63635SJoe Thornber 
34366a63635SJoe Thornber 	for (level = 0; level < max_level; level++)
34466a63635SJoe Thornber 		for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e)) {
34566a63635SJoe Thornber 			if (e->sentinel) {
34666a63635SJoe Thornber 				if (can_cross_sentinel)
34766a63635SJoe Thornber 					continue;
34866a63635SJoe Thornber 				else
34966a63635SJoe Thornber 					break;
35066a63635SJoe Thornber 			}
35166a63635SJoe Thornber 
35266a63635SJoe Thornber 			return e;
35366a63635SJoe Thornber 		}
35466a63635SJoe Thornber 
35566a63635SJoe Thornber 	return NULL;
35666a63635SJoe Thornber }
35766a63635SJoe Thornber 
35866a63635SJoe Thornber static struct entry *q_pop(struct queue *q)
35966a63635SJoe Thornber {
36066a63635SJoe Thornber 	struct entry *e = q_peek(q, q->nr_levels, true);
36166a63635SJoe Thornber 
36266a63635SJoe Thornber 	if (e)
36366a63635SJoe Thornber 		q_del(q, e);
36466a63635SJoe Thornber 
36566a63635SJoe Thornber 	return e;
36666a63635SJoe Thornber }
36766a63635SJoe Thornber 
36866a63635SJoe Thornber /*
36966a63635SJoe Thornber  * This function assumes there is a non-sentinel entry to pop.  It's only
37066a63635SJoe Thornber  * used by redistribute, so we know this is true.  It also doesn't adjust
37166a63635SJoe Thornber  * the q->nr_elts count.
37266a63635SJoe Thornber  */
37366a63635SJoe Thornber static struct entry *__redist_pop_from(struct queue *q, unsigned level)
37466a63635SJoe Thornber {
37566a63635SJoe Thornber 	struct entry *e;
37666a63635SJoe Thornber 
37766a63635SJoe Thornber 	for (; level < q->nr_levels; level++)
37866a63635SJoe Thornber 		for (e = l_head(q->es, q->qs + level); e; e = l_next(q->es, e))
37966a63635SJoe Thornber 			if (!e->sentinel) {
38066a63635SJoe Thornber 				l_del(q->es, q->qs + e->level, e);
38166a63635SJoe Thornber 				return e;
38266a63635SJoe Thornber 			}
38366a63635SJoe Thornber 
38466a63635SJoe Thornber 	return NULL;
38566a63635SJoe Thornber }
38666a63635SJoe Thornber 
38766a63635SJoe Thornber static void q_set_targets_subrange_(struct queue *q, unsigned nr_elts, unsigned lbegin, unsigned lend)
38866a63635SJoe Thornber {
38966a63635SJoe Thornber 	unsigned level, nr_levels, entries_per_level, remainder;
39066a63635SJoe Thornber 
39166a63635SJoe Thornber 	BUG_ON(lbegin > lend);
39266a63635SJoe Thornber 	BUG_ON(lend > q->nr_levels);
39366a63635SJoe Thornber 	nr_levels = lend - lbegin;
39466a63635SJoe Thornber 	entries_per_level = safe_div(nr_elts, nr_levels);
39566a63635SJoe Thornber 	remainder = safe_mod(nr_elts, nr_levels);
39666a63635SJoe Thornber 
39766a63635SJoe Thornber 	for (level = lbegin; level < lend; level++)
39866a63635SJoe Thornber 		q->target_count[level] =
39966a63635SJoe Thornber 			(level < (lbegin + remainder)) ? entries_per_level + 1u : entries_per_level;
40066a63635SJoe Thornber }
40166a63635SJoe Thornber 
40266a63635SJoe Thornber /*
40366a63635SJoe Thornber  * Typically we have fewer elements in the top few levels which allows us
40466a63635SJoe Thornber  * to adjust the promote threshold nicely.
40566a63635SJoe Thornber  */
40666a63635SJoe Thornber static void q_set_targets(struct queue *q)
40766a63635SJoe Thornber {
40866a63635SJoe Thornber 	if (q->last_target_nr_elts == q->nr_elts)
40966a63635SJoe Thornber 		return;
41066a63635SJoe Thornber 
41166a63635SJoe Thornber 	q->last_target_nr_elts = q->nr_elts;
41266a63635SJoe Thornber 
41366a63635SJoe Thornber 	if (q->nr_top_levels > q->nr_levels)
41466a63635SJoe Thornber 		q_set_targets_subrange_(q, q->nr_elts, 0, q->nr_levels);
41566a63635SJoe Thornber 
41666a63635SJoe Thornber 	else {
41766a63635SJoe Thornber 		q_set_targets_subrange_(q, q->nr_in_top_levels,
41866a63635SJoe Thornber 					q->nr_levels - q->nr_top_levels, q->nr_levels);
41966a63635SJoe Thornber 
42066a63635SJoe Thornber 		if (q->nr_in_top_levels < q->nr_elts)
42166a63635SJoe Thornber 			q_set_targets_subrange_(q, q->nr_elts - q->nr_in_top_levels,
42266a63635SJoe Thornber 						0, q->nr_levels - q->nr_top_levels);
42366a63635SJoe Thornber 		else
42466a63635SJoe Thornber 			q_set_targets_subrange_(q, 0, 0, q->nr_levels - q->nr_top_levels);
42566a63635SJoe Thornber 	}
42666a63635SJoe Thornber }
42766a63635SJoe Thornber 
42866a63635SJoe Thornber static void q_redistribute(struct queue *q)
42966a63635SJoe Thornber {
43066a63635SJoe Thornber 	unsigned target, level;
43166a63635SJoe Thornber 	struct ilist *l, *l_above;
43266a63635SJoe Thornber 	struct entry *e;
43366a63635SJoe Thornber 
43466a63635SJoe Thornber 	q_set_targets(q);
43566a63635SJoe Thornber 
43666a63635SJoe Thornber 	for (level = 0u; level < q->nr_levels - 1u; level++) {
43766a63635SJoe Thornber 		l = q->qs + level;
43866a63635SJoe Thornber 		target = q->target_count[level];
43966a63635SJoe Thornber 
44066a63635SJoe Thornber 		/*
44166a63635SJoe Thornber 		 * Pull down some entries from the level above.
44266a63635SJoe Thornber 		 */
44366a63635SJoe Thornber 		while (l->nr_elts < target) {
44466a63635SJoe Thornber 			e = __redist_pop_from(q, level + 1u);
44566a63635SJoe Thornber 			if (!e) {
44666a63635SJoe Thornber 				/* bug in nr_elts */
44766a63635SJoe Thornber 				break;
44866a63635SJoe Thornber 			}
44966a63635SJoe Thornber 
45066a63635SJoe Thornber 			e->level = level;
45166a63635SJoe Thornber 			l_add_tail(q->es, l, e);
45266a63635SJoe Thornber 		}
45366a63635SJoe Thornber 
45466a63635SJoe Thornber 		/*
45566a63635SJoe Thornber 		 * Push some entries up.
45666a63635SJoe Thornber 		 */
45766a63635SJoe Thornber 		l_above = q->qs + level + 1u;
45866a63635SJoe Thornber 		while (l->nr_elts > target) {
45966a63635SJoe Thornber 			e = l_pop_tail(q->es, l);
46066a63635SJoe Thornber 
46166a63635SJoe Thornber 			if (!e)
46266a63635SJoe Thornber 				/* bug in nr_elts */
46366a63635SJoe Thornber 				break;
46466a63635SJoe Thornber 
46566a63635SJoe Thornber 			e->level = level + 1u;
466b29d4986SJoe Thornber 			l_add_tail(q->es, l_above, e);
46766a63635SJoe Thornber 		}
46866a63635SJoe Thornber 	}
46966a63635SJoe Thornber }
47066a63635SJoe Thornber 
471b29d4986SJoe Thornber static void q_requeue(struct queue *q, struct entry *e, unsigned extra_levels,
472b29d4986SJoe Thornber 		      struct entry *s1, struct entry *s2)
47366a63635SJoe Thornber {
47466a63635SJoe Thornber 	struct entry *de;
475b29d4986SJoe Thornber 	unsigned sentinels_passed = 0;
476b29d4986SJoe Thornber 	unsigned new_level = min(q->nr_levels - 1u, e->level + extra_levels);
47766a63635SJoe Thornber 
478b29d4986SJoe Thornber 	/* try and find an entry to swap with */
47966a63635SJoe Thornber 	if (extra_levels && (e->level < q->nr_levels - 1u)) {
480b29d4986SJoe Thornber 		for (de = l_head(q->es, q->qs + new_level); de && de->sentinel; de = l_next(q->es, de))
481b29d4986SJoe Thornber 			sentinels_passed++;
48266a63635SJoe Thornber 
483b29d4986SJoe Thornber 		if (de) {
48466a63635SJoe Thornber 			q_del(q, de);
48566a63635SJoe Thornber 			de->level = e->level;
486b29d4986SJoe Thornber 			if (s1) {
487b29d4986SJoe Thornber 				switch (sentinels_passed) {
488b29d4986SJoe Thornber 				case 0:
489b29d4986SJoe Thornber 					q_push_before(q, s1, de);
49066a63635SJoe Thornber 					break;
491b29d4986SJoe Thornber 
492b29d4986SJoe Thornber 				case 1:
493b29d4986SJoe Thornber 					q_push_before(q, s2, de);
494b29d4986SJoe Thornber 					break;
495b29d4986SJoe Thornber 
496b29d4986SJoe Thornber 				default:
497b29d4986SJoe Thornber 					q_push(q, de);
498b29d4986SJoe Thornber 				}
499b29d4986SJoe Thornber 			} else
500b29d4986SJoe Thornber 				q_push(q, de);
501b29d4986SJoe Thornber 		}
50266a63635SJoe Thornber 	}
50366a63635SJoe Thornber 
504b29d4986SJoe Thornber 	q_del(q, e);
50566a63635SJoe Thornber 	e->level = new_level;
50666a63635SJoe Thornber 	q_push(q, e);
50766a63635SJoe Thornber }
50866a63635SJoe Thornber 
50966a63635SJoe Thornber /*----------------------------------------------------------------*/
51066a63635SJoe Thornber 
51166a63635SJoe Thornber #define FP_SHIFT 8
51266a63635SJoe Thornber #define SIXTEENTH (1u << (FP_SHIFT - 4u))
51366a63635SJoe Thornber #define EIGHTH (1u << (FP_SHIFT - 3u))
51466a63635SJoe Thornber 
51566a63635SJoe Thornber struct stats {
51666a63635SJoe Thornber 	unsigned hit_threshold;
51766a63635SJoe Thornber 	unsigned hits;
51866a63635SJoe Thornber 	unsigned misses;
51966a63635SJoe Thornber };
52066a63635SJoe Thornber 
52166a63635SJoe Thornber enum performance {
52266a63635SJoe Thornber 	Q_POOR,
52366a63635SJoe Thornber 	Q_FAIR,
52466a63635SJoe Thornber 	Q_WELL
52566a63635SJoe Thornber };
52666a63635SJoe Thornber 
52766a63635SJoe Thornber static void stats_init(struct stats *s, unsigned nr_levels)
52866a63635SJoe Thornber {
52966a63635SJoe Thornber 	s->hit_threshold = (nr_levels * 3u) / 4u;
53066a63635SJoe Thornber 	s->hits = 0u;
53166a63635SJoe Thornber 	s->misses = 0u;
53266a63635SJoe Thornber }
53366a63635SJoe Thornber 
53466a63635SJoe Thornber static void stats_reset(struct stats *s)
53566a63635SJoe Thornber {
53666a63635SJoe Thornber 	s->hits = s->misses = 0u;
53766a63635SJoe Thornber }
53866a63635SJoe Thornber 
53966a63635SJoe Thornber static void stats_level_accessed(struct stats *s, unsigned level)
54066a63635SJoe Thornber {
54166a63635SJoe Thornber 	if (level >= s->hit_threshold)
54266a63635SJoe Thornber 		s->hits++;
54366a63635SJoe Thornber 	else
54466a63635SJoe Thornber 		s->misses++;
54566a63635SJoe Thornber }
54666a63635SJoe Thornber 
54766a63635SJoe Thornber static void stats_miss(struct stats *s)
54866a63635SJoe Thornber {
54966a63635SJoe Thornber 	s->misses++;
55066a63635SJoe Thornber }
55166a63635SJoe Thornber 
55266a63635SJoe Thornber /*
55366a63635SJoe Thornber  * There are times when we don't have any confidence in the hotspot queue.
55466a63635SJoe Thornber  * Such as when a fresh cache is created and the blocks have been spread
55566a63635SJoe Thornber  * out across the levels, or if an io load changes.  We detect this by
55666a63635SJoe Thornber  * seeing how often a lookup is in the top levels of the hotspot queue.
55766a63635SJoe Thornber  */
55866a63635SJoe Thornber static enum performance stats_assess(struct stats *s)
55966a63635SJoe Thornber {
56066a63635SJoe Thornber 	unsigned confidence = safe_div(s->hits << FP_SHIFT, s->hits + s->misses);
56166a63635SJoe Thornber 
56266a63635SJoe Thornber 	if (confidence < SIXTEENTH)
56366a63635SJoe Thornber 		return Q_POOR;
56466a63635SJoe Thornber 
56566a63635SJoe Thornber 	else if (confidence < EIGHTH)
56666a63635SJoe Thornber 		return Q_FAIR;
56766a63635SJoe Thornber 
56866a63635SJoe Thornber 	else
56966a63635SJoe Thornber 		return Q_WELL;
57066a63635SJoe Thornber }
57166a63635SJoe Thornber 
57266a63635SJoe Thornber /*----------------------------------------------------------------*/
57366a63635SJoe Thornber 
574b29d4986SJoe Thornber struct smq_hash_table {
57566a63635SJoe Thornber 	struct entry_space *es;
57666a63635SJoe Thornber 	unsigned long long hash_bits;
57766a63635SJoe Thornber 	unsigned *buckets;
57866a63635SJoe Thornber };
57966a63635SJoe Thornber 
58066a63635SJoe Thornber /*
58166a63635SJoe Thornber  * All cache entries are stored in a chained hash table.  To save space we
58266a63635SJoe Thornber  * use indexing again, and only store indexes to the next entry.
58366a63635SJoe Thornber  */
584b29d4986SJoe Thornber static int h_init(struct smq_hash_table *ht, struct entry_space *es, unsigned nr_entries)
58566a63635SJoe Thornber {
58666a63635SJoe Thornber 	unsigned i, nr_buckets;
58766a63635SJoe Thornber 
58866a63635SJoe Thornber 	ht->es = es;
58966a63635SJoe Thornber 	nr_buckets = roundup_pow_of_two(max(nr_entries / 4u, 16u));
590a3d939aeSMikulas Patocka 	ht->hash_bits = __ffs(nr_buckets);
59166a63635SJoe Thornber 
59242bc47b3SKees Cook 	ht->buckets = vmalloc(array_size(nr_buckets, sizeof(*ht->buckets)));
59366a63635SJoe Thornber 	if (!ht->buckets)
59466a63635SJoe Thornber 		return -ENOMEM;
59566a63635SJoe Thornber 
59666a63635SJoe Thornber 	for (i = 0; i < nr_buckets; i++)
59766a63635SJoe Thornber 		ht->buckets[i] = INDEXER_NULL;
59866a63635SJoe Thornber 
59966a63635SJoe Thornber 	return 0;
60066a63635SJoe Thornber }
60166a63635SJoe Thornber 
602b29d4986SJoe Thornber static void h_exit(struct smq_hash_table *ht)
60366a63635SJoe Thornber {
60466a63635SJoe Thornber 	vfree(ht->buckets);
60566a63635SJoe Thornber }
60666a63635SJoe Thornber 
607b29d4986SJoe Thornber static struct entry *h_head(struct smq_hash_table *ht, unsigned bucket)
60866a63635SJoe Thornber {
60966a63635SJoe Thornber 	return to_entry(ht->es, ht->buckets[bucket]);
61066a63635SJoe Thornber }
61166a63635SJoe Thornber 
612b29d4986SJoe Thornber static struct entry *h_next(struct smq_hash_table *ht, struct entry *e)
61366a63635SJoe Thornber {
61466a63635SJoe Thornber 	return to_entry(ht->es, e->hash_next);
61566a63635SJoe Thornber }
61666a63635SJoe Thornber 
617b29d4986SJoe Thornber static void __h_insert(struct smq_hash_table *ht, unsigned bucket, struct entry *e)
61866a63635SJoe Thornber {
61966a63635SJoe Thornber 	e->hash_next = ht->buckets[bucket];
62066a63635SJoe Thornber 	ht->buckets[bucket] = to_index(ht->es, e);
62166a63635SJoe Thornber }
62266a63635SJoe Thornber 
623b29d4986SJoe Thornber static void h_insert(struct smq_hash_table *ht, struct entry *e)
62466a63635SJoe Thornber {
62566a63635SJoe Thornber 	unsigned h = hash_64(from_oblock(e->oblock), ht->hash_bits);
62666a63635SJoe Thornber 	__h_insert(ht, h, e);
62766a63635SJoe Thornber }
62866a63635SJoe Thornber 
629b29d4986SJoe Thornber static struct entry *__h_lookup(struct smq_hash_table *ht, unsigned h, dm_oblock_t oblock,
63066a63635SJoe Thornber 				struct entry **prev)
63166a63635SJoe Thornber {
63266a63635SJoe Thornber 	struct entry *e;
63366a63635SJoe Thornber 
63466a63635SJoe Thornber 	*prev = NULL;
63566a63635SJoe Thornber 	for (e = h_head(ht, h); e; e = h_next(ht, e)) {
63666a63635SJoe Thornber 		if (e->oblock == oblock)
63766a63635SJoe Thornber 			return e;
63866a63635SJoe Thornber 
63966a63635SJoe Thornber 		*prev = e;
64066a63635SJoe Thornber 	}
64166a63635SJoe Thornber 
64266a63635SJoe Thornber 	return NULL;
64366a63635SJoe Thornber }
64466a63635SJoe Thornber 
645b29d4986SJoe Thornber static void __h_unlink(struct smq_hash_table *ht, unsigned h,
64666a63635SJoe Thornber 		       struct entry *e, struct entry *prev)
64766a63635SJoe Thornber {
64866a63635SJoe Thornber 	if (prev)
64966a63635SJoe Thornber 		prev->hash_next = e->hash_next;
65066a63635SJoe Thornber 	else
65166a63635SJoe Thornber 		ht->buckets[h] = e->hash_next;
65266a63635SJoe Thornber }
65366a63635SJoe Thornber 
65466a63635SJoe Thornber /*
65566a63635SJoe Thornber  * Also moves each entry to the front of the bucket.
65666a63635SJoe Thornber  */
657b29d4986SJoe Thornber static struct entry *h_lookup(struct smq_hash_table *ht, dm_oblock_t oblock)
65866a63635SJoe Thornber {
65966a63635SJoe Thornber 	struct entry *e, *prev;
66066a63635SJoe Thornber 	unsigned h = hash_64(from_oblock(oblock), ht->hash_bits);
66166a63635SJoe Thornber 
66266a63635SJoe Thornber 	e = __h_lookup(ht, h, oblock, &prev);
66366a63635SJoe Thornber 	if (e && prev) {
66466a63635SJoe Thornber 		/*
66566a63635SJoe Thornber 		 * Move to the front because this entry is likely
66666a63635SJoe Thornber 		 * to be hit again.
66766a63635SJoe Thornber 		 */
66866a63635SJoe Thornber 		__h_unlink(ht, h, e, prev);
66966a63635SJoe Thornber 		__h_insert(ht, h, e);
67066a63635SJoe Thornber 	}
67166a63635SJoe Thornber 
67266a63635SJoe Thornber 	return e;
67366a63635SJoe Thornber }
67466a63635SJoe Thornber 
675b29d4986SJoe Thornber static void h_remove(struct smq_hash_table *ht, struct entry *e)
67666a63635SJoe Thornber {
67766a63635SJoe Thornber 	unsigned h = hash_64(from_oblock(e->oblock), ht->hash_bits);
67866a63635SJoe Thornber 	struct entry *prev;
67966a63635SJoe Thornber 
68066a63635SJoe Thornber 	/*
68166a63635SJoe Thornber 	 * The down side of using a singly linked list is we have to
68266a63635SJoe Thornber 	 * iterate the bucket to remove an item.
68366a63635SJoe Thornber 	 */
68466a63635SJoe Thornber 	e = __h_lookup(ht, h, e->oblock, &prev);
68566a63635SJoe Thornber 	if (e)
68666a63635SJoe Thornber 		__h_unlink(ht, h, e, prev);
68766a63635SJoe Thornber }
68866a63635SJoe Thornber 
68966a63635SJoe Thornber /*----------------------------------------------------------------*/
69066a63635SJoe Thornber 
69166a63635SJoe Thornber struct entry_alloc {
69266a63635SJoe Thornber 	struct entry_space *es;
69366a63635SJoe Thornber 	unsigned begin;
69466a63635SJoe Thornber 
69566a63635SJoe Thornber 	unsigned nr_allocated;
69666a63635SJoe Thornber 	struct ilist free;
69766a63635SJoe Thornber };
69866a63635SJoe Thornber 
69966a63635SJoe Thornber static void init_allocator(struct entry_alloc *ea, struct entry_space *es,
70066a63635SJoe Thornber 			   unsigned begin, unsigned end)
70166a63635SJoe Thornber {
70266a63635SJoe Thornber 	unsigned i;
70366a63635SJoe Thornber 
70466a63635SJoe Thornber 	ea->es = es;
70566a63635SJoe Thornber 	ea->nr_allocated = 0u;
70666a63635SJoe Thornber 	ea->begin = begin;
70766a63635SJoe Thornber 
70866a63635SJoe Thornber 	l_init(&ea->free);
70966a63635SJoe Thornber 	for (i = begin; i != end; i++)
71066a63635SJoe Thornber 		l_add_tail(ea->es, &ea->free, __get_entry(ea->es, i));
71166a63635SJoe Thornber }
71266a63635SJoe Thornber 
71366a63635SJoe Thornber static void init_entry(struct entry *e)
71466a63635SJoe Thornber {
71566a63635SJoe Thornber 	/*
71666a63635SJoe Thornber 	 * We can't memset because that would clear the hotspot and
71766a63635SJoe Thornber 	 * sentinel bits which remain constant.
71866a63635SJoe Thornber 	 */
71966a63635SJoe Thornber 	e->hash_next = INDEXER_NULL;
72066a63635SJoe Thornber 	e->next = INDEXER_NULL;
72166a63635SJoe Thornber 	e->prev = INDEXER_NULL;
72266a63635SJoe Thornber 	e->level = 0u;
723b29d4986SJoe Thornber 	e->dirty = true;	/* FIXME: audit */
72466a63635SJoe Thornber 	e->allocated = true;
725b29d4986SJoe Thornber 	e->sentinel = false;
726b29d4986SJoe Thornber 	e->pending_work = false;
72766a63635SJoe Thornber }
72866a63635SJoe Thornber 
72966a63635SJoe Thornber static struct entry *alloc_entry(struct entry_alloc *ea)
73066a63635SJoe Thornber {
73166a63635SJoe Thornber 	struct entry *e;
73266a63635SJoe Thornber 
73366a63635SJoe Thornber 	if (l_empty(&ea->free))
73466a63635SJoe Thornber 		return NULL;
73566a63635SJoe Thornber 
7369768a10dSJoe Thornber 	e = l_pop_head(ea->es, &ea->free);
73766a63635SJoe Thornber 	init_entry(e);
73866a63635SJoe Thornber 	ea->nr_allocated++;
73966a63635SJoe Thornber 
74066a63635SJoe Thornber 	return e;
74166a63635SJoe Thornber }
74266a63635SJoe Thornber 
74366a63635SJoe Thornber /*
74466a63635SJoe Thornber  * This assumes the cblock hasn't already been allocated.
74566a63635SJoe Thornber  */
74666a63635SJoe Thornber static struct entry *alloc_particular_entry(struct entry_alloc *ea, unsigned i)
74766a63635SJoe Thornber {
74866a63635SJoe Thornber 	struct entry *e = __get_entry(ea->es, ea->begin + i);
74966a63635SJoe Thornber 
75066a63635SJoe Thornber 	BUG_ON(e->allocated);
75166a63635SJoe Thornber 
75266a63635SJoe Thornber 	l_del(ea->es, &ea->free, e);
75366a63635SJoe Thornber 	init_entry(e);
75466a63635SJoe Thornber 	ea->nr_allocated++;
75566a63635SJoe Thornber 
75666a63635SJoe Thornber 	return e;
75766a63635SJoe Thornber }
75866a63635SJoe Thornber 
75966a63635SJoe Thornber static void free_entry(struct entry_alloc *ea, struct entry *e)
76066a63635SJoe Thornber {
76166a63635SJoe Thornber 	BUG_ON(!ea->nr_allocated);
76266a63635SJoe Thornber 	BUG_ON(!e->allocated);
76366a63635SJoe Thornber 
76466a63635SJoe Thornber 	ea->nr_allocated--;
76566a63635SJoe Thornber 	e->allocated = false;
76666a63635SJoe Thornber 	l_add_tail(ea->es, &ea->free, e);
76766a63635SJoe Thornber }
76866a63635SJoe Thornber 
76966a63635SJoe Thornber static bool allocator_empty(struct entry_alloc *ea)
77066a63635SJoe Thornber {
77166a63635SJoe Thornber 	return l_empty(&ea->free);
77266a63635SJoe Thornber }
77366a63635SJoe Thornber 
77466a63635SJoe Thornber static unsigned get_index(struct entry_alloc *ea, struct entry *e)
77566a63635SJoe Thornber {
77666a63635SJoe Thornber 	return to_index(ea->es, e) - ea->begin;
77766a63635SJoe Thornber }
77866a63635SJoe Thornber 
77966a63635SJoe Thornber static struct entry *get_entry(struct entry_alloc *ea, unsigned index)
78066a63635SJoe Thornber {
78166a63635SJoe Thornber 	return __get_entry(ea->es, ea->begin + index);
78266a63635SJoe Thornber }
78366a63635SJoe Thornber 
78466a63635SJoe Thornber /*----------------------------------------------------------------*/
78566a63635SJoe Thornber 
78666a63635SJoe Thornber #define NR_HOTSPOT_LEVELS 64u
78766a63635SJoe Thornber #define NR_CACHE_LEVELS 64u
78866a63635SJoe Thornber 
789b29d4986SJoe Thornber #define WRITEBACK_PERIOD (10ul * HZ)
790b29d4986SJoe Thornber #define DEMOTE_PERIOD (60ul * HZ)
79166a63635SJoe Thornber 
79266a63635SJoe Thornber #define HOTSPOT_UPDATE_PERIOD (HZ)
793b29d4986SJoe Thornber #define CACHE_UPDATE_PERIOD (60ul * HZ)
79466a63635SJoe Thornber 
79566a63635SJoe Thornber struct smq_policy {
79666a63635SJoe Thornber 	struct dm_cache_policy policy;
79766a63635SJoe Thornber 
79866a63635SJoe Thornber 	/* protects everything */
7994051aab7SJoe Thornber 	spinlock_t lock;
80066a63635SJoe Thornber 	dm_cblock_t cache_size;
80166a63635SJoe Thornber 	sector_t cache_block_size;
80266a63635SJoe Thornber 
80366a63635SJoe Thornber 	sector_t hotspot_block_size;
80466a63635SJoe Thornber 	unsigned nr_hotspot_blocks;
80566a63635SJoe Thornber 	unsigned cache_blocks_per_hotspot_block;
80666a63635SJoe Thornber 	unsigned hotspot_level_jump;
80766a63635SJoe Thornber 
80866a63635SJoe Thornber 	struct entry_space es;
80966a63635SJoe Thornber 	struct entry_alloc writeback_sentinel_alloc;
81066a63635SJoe Thornber 	struct entry_alloc demote_sentinel_alloc;
81166a63635SJoe Thornber 	struct entry_alloc hotspot_alloc;
81266a63635SJoe Thornber 	struct entry_alloc cache_alloc;
81366a63635SJoe Thornber 
81466a63635SJoe Thornber 	unsigned long *hotspot_hit_bits;
81566a63635SJoe Thornber 	unsigned long *cache_hit_bits;
81666a63635SJoe Thornber 
81766a63635SJoe Thornber 	/*
81866a63635SJoe Thornber 	 * We maintain three queues of entries.  The cache proper,
81966a63635SJoe Thornber 	 * consisting of a clean and dirty queue, containing the currently
82066a63635SJoe Thornber 	 * active mappings.  The hotspot queue uses a larger block size to
82166a63635SJoe Thornber 	 * track blocks that are being hit frequently and potential
82266a63635SJoe Thornber 	 * candidates for promotion to the cache.
82366a63635SJoe Thornber 	 */
82466a63635SJoe Thornber 	struct queue hotspot;
82566a63635SJoe Thornber 	struct queue clean;
82666a63635SJoe Thornber 	struct queue dirty;
82766a63635SJoe Thornber 
82866a63635SJoe Thornber 	struct stats hotspot_stats;
82966a63635SJoe Thornber 	struct stats cache_stats;
83066a63635SJoe Thornber 
83166a63635SJoe Thornber 	/*
83266a63635SJoe Thornber 	 * Keeps track of time, incremented by the core.  We use this to
83366a63635SJoe Thornber 	 * avoid attributing multiple hits within the same tick.
83466a63635SJoe Thornber 	 */
83566a63635SJoe Thornber 	unsigned tick;
83666a63635SJoe Thornber 
83766a63635SJoe Thornber 	/*
83866a63635SJoe Thornber 	 * The hash tables allows us to quickly find an entry by origin
83966a63635SJoe Thornber 	 * block.
84066a63635SJoe Thornber 	 */
841b29d4986SJoe Thornber 	struct smq_hash_table table;
842b29d4986SJoe Thornber 	struct smq_hash_table hotspot_table;
84366a63635SJoe Thornber 
84466a63635SJoe Thornber 	bool current_writeback_sentinels;
84566a63635SJoe Thornber 	unsigned long next_writeback_period;
84666a63635SJoe Thornber 
84766a63635SJoe Thornber 	bool current_demote_sentinels;
84866a63635SJoe Thornber 	unsigned long next_demote_period;
84966a63635SJoe Thornber 
85066a63635SJoe Thornber 	unsigned write_promote_level;
85166a63635SJoe Thornber 	unsigned read_promote_level;
85266a63635SJoe Thornber 
85366a63635SJoe Thornber 	unsigned long next_hotspot_period;
85466a63635SJoe Thornber 	unsigned long next_cache_period;
855b29d4986SJoe Thornber 
856b29d4986SJoe Thornber 	struct background_tracker *bg_work;
857b29d4986SJoe Thornber 
858b29d4986SJoe Thornber 	bool migrations_allowed;
85966a63635SJoe Thornber };
86066a63635SJoe Thornber 
86166a63635SJoe Thornber /*----------------------------------------------------------------*/
86266a63635SJoe Thornber 
86366a63635SJoe Thornber static struct entry *get_sentinel(struct entry_alloc *ea, unsigned level, bool which)
86466a63635SJoe Thornber {
86566a63635SJoe Thornber 	return get_entry(ea, which ? level : NR_CACHE_LEVELS + level);
86666a63635SJoe Thornber }
86766a63635SJoe Thornber 
86866a63635SJoe Thornber static struct entry *writeback_sentinel(struct smq_policy *mq, unsigned level)
86966a63635SJoe Thornber {
87066a63635SJoe Thornber 	return get_sentinel(&mq->writeback_sentinel_alloc, level, mq->current_writeback_sentinels);
87166a63635SJoe Thornber }
87266a63635SJoe Thornber 
87366a63635SJoe Thornber static struct entry *demote_sentinel(struct smq_policy *mq, unsigned level)
87466a63635SJoe Thornber {
87566a63635SJoe Thornber 	return get_sentinel(&mq->demote_sentinel_alloc, level, mq->current_demote_sentinels);
87666a63635SJoe Thornber }
87766a63635SJoe Thornber 
87866a63635SJoe Thornber static void __update_writeback_sentinels(struct smq_policy *mq)
87966a63635SJoe Thornber {
88066a63635SJoe Thornber 	unsigned level;
88166a63635SJoe Thornber 	struct queue *q = &mq->dirty;
88266a63635SJoe Thornber 	struct entry *sentinel;
88366a63635SJoe Thornber 
88466a63635SJoe Thornber 	for (level = 0; level < q->nr_levels; level++) {
88566a63635SJoe Thornber 		sentinel = writeback_sentinel(mq, level);
88666a63635SJoe Thornber 		q_del(q, sentinel);
88766a63635SJoe Thornber 		q_push(q, sentinel);
88866a63635SJoe Thornber 	}
88966a63635SJoe Thornber }
89066a63635SJoe Thornber 
89166a63635SJoe Thornber static void __update_demote_sentinels(struct smq_policy *mq)
89266a63635SJoe Thornber {
89366a63635SJoe Thornber 	unsigned level;
89466a63635SJoe Thornber 	struct queue *q = &mq->clean;
89566a63635SJoe Thornber 	struct entry *sentinel;
89666a63635SJoe Thornber 
89766a63635SJoe Thornber 	for (level = 0; level < q->nr_levels; level++) {
89866a63635SJoe Thornber 		sentinel = demote_sentinel(mq, level);
89966a63635SJoe Thornber 		q_del(q, sentinel);
90066a63635SJoe Thornber 		q_push(q, sentinel);
90166a63635SJoe Thornber 	}
90266a63635SJoe Thornber }
90366a63635SJoe Thornber 
90466a63635SJoe Thornber static void update_sentinels(struct smq_policy *mq)
90566a63635SJoe Thornber {
90666a63635SJoe Thornber 	if (time_after(jiffies, mq->next_writeback_period)) {
90766a63635SJoe Thornber 		mq->next_writeback_period = jiffies + WRITEBACK_PERIOD;
90866a63635SJoe Thornber 		mq->current_writeback_sentinels = !mq->current_writeback_sentinels;
909b29d4986SJoe Thornber 		__update_writeback_sentinels(mq);
91066a63635SJoe Thornber 	}
91166a63635SJoe Thornber 
91266a63635SJoe Thornber 	if (time_after(jiffies, mq->next_demote_period)) {
91366a63635SJoe Thornber 		mq->next_demote_period = jiffies + DEMOTE_PERIOD;
91466a63635SJoe Thornber 		mq->current_demote_sentinels = !mq->current_demote_sentinels;
915b29d4986SJoe Thornber 		__update_demote_sentinels(mq);
91666a63635SJoe Thornber 	}
91766a63635SJoe Thornber }
91866a63635SJoe Thornber 
91966a63635SJoe Thornber static void __sentinels_init(struct smq_policy *mq)
92066a63635SJoe Thornber {
92166a63635SJoe Thornber 	unsigned level;
92266a63635SJoe Thornber 	struct entry *sentinel;
92366a63635SJoe Thornber 
92466a63635SJoe Thornber 	for (level = 0; level < NR_CACHE_LEVELS; level++) {
92566a63635SJoe Thornber 		sentinel = writeback_sentinel(mq, level);
92666a63635SJoe Thornber 		sentinel->level = level;
92766a63635SJoe Thornber 		q_push(&mq->dirty, sentinel);
92866a63635SJoe Thornber 
92966a63635SJoe Thornber 		sentinel = demote_sentinel(mq, level);
93066a63635SJoe Thornber 		sentinel->level = level;
93166a63635SJoe Thornber 		q_push(&mq->clean, sentinel);
93266a63635SJoe Thornber 	}
93366a63635SJoe Thornber }
93466a63635SJoe Thornber 
93566a63635SJoe Thornber static void sentinels_init(struct smq_policy *mq)
93666a63635SJoe Thornber {
93766a63635SJoe Thornber 	mq->next_writeback_period = jiffies + WRITEBACK_PERIOD;
93866a63635SJoe Thornber 	mq->next_demote_period = jiffies + DEMOTE_PERIOD;
93966a63635SJoe Thornber 
94066a63635SJoe Thornber 	mq->current_writeback_sentinels = false;
94166a63635SJoe Thornber 	mq->current_demote_sentinels = false;
94266a63635SJoe Thornber 	__sentinels_init(mq);
94366a63635SJoe Thornber 
94466a63635SJoe Thornber 	mq->current_writeback_sentinels = !mq->current_writeback_sentinels;
94566a63635SJoe Thornber 	mq->current_demote_sentinels = !mq->current_demote_sentinels;
94666a63635SJoe Thornber 	__sentinels_init(mq);
94766a63635SJoe Thornber }
94866a63635SJoe Thornber 
94966a63635SJoe Thornber /*----------------------------------------------------------------*/
95066a63635SJoe Thornber 
951b29d4986SJoe Thornber static void del_queue(struct smq_policy *mq, struct entry *e)
95266a63635SJoe Thornber {
953b29d4986SJoe Thornber 	q_del(e->dirty ? &mq->dirty : &mq->clean, e);
95466a63635SJoe Thornber }
95566a63635SJoe Thornber 
956b29d4986SJoe Thornber static void push_queue(struct smq_policy *mq, struct entry *e)
957b29d4986SJoe Thornber {
958b29d4986SJoe Thornber 	if (e->dirty)
959b29d4986SJoe Thornber 		q_push(&mq->dirty, e);
960b29d4986SJoe Thornber 	else
961b29d4986SJoe Thornber 		q_push(&mq->clean, e);
962b29d4986SJoe Thornber }
963b29d4986SJoe Thornber 
964b29d4986SJoe Thornber // !h, !q, a -> h, q, a
96566a63635SJoe Thornber static void push(struct smq_policy *mq, struct entry *e)
96666a63635SJoe Thornber {
96766a63635SJoe Thornber 	h_insert(&mq->table, e);
968b29d4986SJoe Thornber 	if (!e->pending_work)
969b29d4986SJoe Thornber 		push_queue(mq, e);
97066a63635SJoe Thornber }
97166a63635SJoe Thornber 
972b29d4986SJoe Thornber static void push_queue_front(struct smq_policy *mq, struct entry *e)
97366a63635SJoe Thornber {
974b29d4986SJoe Thornber 	if (e->dirty)
975b29d4986SJoe Thornber 		q_push_front(&mq->dirty, e);
976b29d4986SJoe Thornber 	else
977b29d4986SJoe Thornber 		q_push_front(&mq->clean, e);
97866a63635SJoe Thornber }
97966a63635SJoe Thornber 
980b29d4986SJoe Thornber static void push_front(struct smq_policy *mq, struct entry *e)
98166a63635SJoe Thornber {
982b29d4986SJoe Thornber 	h_insert(&mq->table, e);
983b29d4986SJoe Thornber 	if (!e->pending_work)
984b29d4986SJoe Thornber 		push_queue_front(mq, e);
98566a63635SJoe Thornber }
98666a63635SJoe Thornber 
98766a63635SJoe Thornber static dm_cblock_t infer_cblock(struct smq_policy *mq, struct entry *e)
98866a63635SJoe Thornber {
98966a63635SJoe Thornber 	return to_cblock(get_index(&mq->cache_alloc, e));
99066a63635SJoe Thornber }
99166a63635SJoe Thornber 
99266a63635SJoe Thornber static void requeue(struct smq_policy *mq, struct entry *e)
99366a63635SJoe Thornber {
994b29d4986SJoe Thornber 	/*
995b29d4986SJoe Thornber 	 * Pending work has temporarily been taken out of the queues.
996b29d4986SJoe Thornber 	 */
997b29d4986SJoe Thornber 	if (e->pending_work)
998b29d4986SJoe Thornber 		return;
99966a63635SJoe Thornber 
100066a63635SJoe Thornber 	if (!test_and_set_bit(from_cblock(infer_cblock(mq, e)), mq->cache_hit_bits)) {
1001b29d4986SJoe Thornber 		if (!e->dirty) {
1002b29d4986SJoe Thornber 			q_requeue(&mq->clean, e, 1u, NULL, NULL);
1003b29d4986SJoe Thornber 			return;
100466a63635SJoe Thornber 		}
1005b29d4986SJoe Thornber 
1006b29d4986SJoe Thornber 		q_requeue(&mq->dirty, e, 1u,
1007b29d4986SJoe Thornber 			  get_sentinel(&mq->writeback_sentinel_alloc, e->level, !mq->current_writeback_sentinels),
1008b29d4986SJoe Thornber 			  get_sentinel(&mq->writeback_sentinel_alloc, e->level, mq->current_writeback_sentinels));
100966a63635SJoe Thornber 	}
101066a63635SJoe Thornber }
101166a63635SJoe Thornber 
101266a63635SJoe Thornber static unsigned default_promote_level(struct smq_policy *mq)
101366a63635SJoe Thornber {
101466a63635SJoe Thornber 	/*
101566a63635SJoe Thornber 	 * The promote level depends on the current performance of the
101666a63635SJoe Thornber 	 * cache.
101766a63635SJoe Thornber 	 *
101866a63635SJoe Thornber 	 * If the cache is performing badly, then we can't afford
101966a63635SJoe Thornber 	 * to promote much without causing performance to drop below that
102066a63635SJoe Thornber 	 * of the origin device.
102166a63635SJoe Thornber 	 *
102266a63635SJoe Thornber 	 * If the cache is performing well, then we don't need to promote
102366a63635SJoe Thornber 	 * much.  If it isn't broken, don't fix it.
102466a63635SJoe Thornber 	 *
102566a63635SJoe Thornber 	 * If the cache is middling then we promote more.
102666a63635SJoe Thornber 	 *
102766a63635SJoe Thornber 	 * This scheme reminds me of a graph of entropy vs probability of a
102866a63635SJoe Thornber 	 * binary variable.
102966a63635SJoe Thornber 	 */
1030302f0351SColin Ian King 	static const unsigned int table[] = {
1031302f0351SColin Ian King 		1, 1, 1, 2, 4, 6, 7, 8, 7, 6, 4, 4, 3, 3, 2, 2, 1
1032302f0351SColin Ian King 	};
103366a63635SJoe Thornber 
103466a63635SJoe Thornber 	unsigned hits = mq->cache_stats.hits;
103566a63635SJoe Thornber 	unsigned misses = mq->cache_stats.misses;
103666a63635SJoe Thornber 	unsigned index = safe_div(hits << 4u, hits + misses);
103766a63635SJoe Thornber 	return table[index];
103866a63635SJoe Thornber }
103966a63635SJoe Thornber 
104066a63635SJoe Thornber static void update_promote_levels(struct smq_policy *mq)
104166a63635SJoe Thornber {
104266a63635SJoe Thornber 	/*
104366a63635SJoe Thornber 	 * If there are unused cache entries then we want to be really
104466a63635SJoe Thornber 	 * eager to promote.
104566a63635SJoe Thornber 	 */
104666a63635SJoe Thornber 	unsigned threshold_level = allocator_empty(&mq->cache_alloc) ?
104766a63635SJoe Thornber 		default_promote_level(mq) : (NR_HOTSPOT_LEVELS / 2u);
104866a63635SJoe Thornber 
1049b29d4986SJoe Thornber 	threshold_level = max(threshold_level, NR_HOTSPOT_LEVELS);
1050b29d4986SJoe Thornber 
105166a63635SJoe Thornber 	/*
105266a63635SJoe Thornber 	 * If the hotspot queue is performing badly then we have little
105366a63635SJoe Thornber 	 * confidence that we know which blocks to promote.  So we cut down
105466a63635SJoe Thornber 	 * the amount of promotions.
105566a63635SJoe Thornber 	 */
105666a63635SJoe Thornber 	switch (stats_assess(&mq->hotspot_stats)) {
105766a63635SJoe Thornber 	case Q_POOR:
105866a63635SJoe Thornber 		threshold_level /= 4u;
105966a63635SJoe Thornber 		break;
106066a63635SJoe Thornber 
106166a63635SJoe Thornber 	case Q_FAIR:
106266a63635SJoe Thornber 		threshold_level /= 2u;
106366a63635SJoe Thornber 		break;
106466a63635SJoe Thornber 
106566a63635SJoe Thornber 	case Q_WELL:
106666a63635SJoe Thornber 		break;
106766a63635SJoe Thornber 	}
106866a63635SJoe Thornber 
106966a63635SJoe Thornber 	mq->read_promote_level = NR_HOTSPOT_LEVELS - threshold_level;
1070b29d4986SJoe Thornber 	mq->write_promote_level = (NR_HOTSPOT_LEVELS - threshold_level);
107166a63635SJoe Thornber }
107266a63635SJoe Thornber 
107366a63635SJoe Thornber /*
107466a63635SJoe Thornber  * If the hotspot queue is performing badly, then we try and move entries
107566a63635SJoe Thornber  * around more quickly.
107666a63635SJoe Thornber  */
107766a63635SJoe Thornber static void update_level_jump(struct smq_policy *mq)
107866a63635SJoe Thornber {
107966a63635SJoe Thornber 	switch (stats_assess(&mq->hotspot_stats)) {
108066a63635SJoe Thornber 	case Q_POOR:
108166a63635SJoe Thornber 		mq->hotspot_level_jump = 4u;
108266a63635SJoe Thornber 		break;
108366a63635SJoe Thornber 
108466a63635SJoe Thornber 	case Q_FAIR:
108566a63635SJoe Thornber 		mq->hotspot_level_jump = 2u;
108666a63635SJoe Thornber 		break;
108766a63635SJoe Thornber 
108866a63635SJoe Thornber 	case Q_WELL:
108966a63635SJoe Thornber 		mq->hotspot_level_jump = 1u;
109066a63635SJoe Thornber 		break;
109166a63635SJoe Thornber 	}
109266a63635SJoe Thornber }
109366a63635SJoe Thornber 
109466a63635SJoe Thornber static void end_hotspot_period(struct smq_policy *mq)
109566a63635SJoe Thornber {
109666a63635SJoe Thornber 	clear_bitset(mq->hotspot_hit_bits, mq->nr_hotspot_blocks);
109766a63635SJoe Thornber 	update_promote_levels(mq);
109866a63635SJoe Thornber 
109966a63635SJoe Thornber 	if (time_after(jiffies, mq->next_hotspot_period)) {
110066a63635SJoe Thornber 		update_level_jump(mq);
110166a63635SJoe Thornber 		q_redistribute(&mq->hotspot);
110266a63635SJoe Thornber 		stats_reset(&mq->hotspot_stats);
110366a63635SJoe Thornber 		mq->next_hotspot_period = jiffies + HOTSPOT_UPDATE_PERIOD;
110466a63635SJoe Thornber 	}
110566a63635SJoe Thornber }
110666a63635SJoe Thornber 
110766a63635SJoe Thornber static void end_cache_period(struct smq_policy *mq)
110866a63635SJoe Thornber {
110966a63635SJoe Thornber 	if (time_after(jiffies, mq->next_cache_period)) {
111066a63635SJoe Thornber 		clear_bitset(mq->cache_hit_bits, from_cblock(mq->cache_size));
111166a63635SJoe Thornber 
111266a63635SJoe Thornber 		q_redistribute(&mq->dirty);
111366a63635SJoe Thornber 		q_redistribute(&mq->clean);
111466a63635SJoe Thornber 		stats_reset(&mq->cache_stats);
111566a63635SJoe Thornber 
111666a63635SJoe Thornber 		mq->next_cache_period = jiffies + CACHE_UPDATE_PERIOD;
111766a63635SJoe Thornber 	}
111866a63635SJoe Thornber }
111966a63635SJoe Thornber 
1120b29d4986SJoe Thornber /*----------------------------------------------------------------*/
1121b29d4986SJoe Thornber 
1122b29d4986SJoe Thornber /*
1123b29d4986SJoe Thornber  * Targets are given as a percentage.
1124b29d4986SJoe Thornber  */
1125b29d4986SJoe Thornber #define CLEAN_TARGET 25u
1126b29d4986SJoe Thornber #define FREE_TARGET 25u
1127b29d4986SJoe Thornber 
1128b29d4986SJoe Thornber static unsigned percent_to_target(struct smq_policy *mq, unsigned p)
112966a63635SJoe Thornber {
1130b29d4986SJoe Thornber 	return from_cblock(mq->cache_size) * p / 100u;
113166a63635SJoe Thornber }
113266a63635SJoe Thornber 
1133b29d4986SJoe Thornber static bool clean_target_met(struct smq_policy *mq, bool idle)
1134b29d4986SJoe Thornber {
1135b29d4986SJoe Thornber 	/*
1136b29d4986SJoe Thornber 	 * Cache entries may not be populated.  So we cannot rely on the
1137b29d4986SJoe Thornber 	 * size of the clean queue.
1138b29d4986SJoe Thornber 	 */
113997dfb203SMike Snitzer 	if (idle) {
1140b29d4986SJoe Thornber 		/*
1141b29d4986SJoe Thornber 		 * We'd like to clean everything.
1142b29d4986SJoe Thornber 		 */
1143b29d4986SJoe Thornber 		return q_size(&mq->dirty) == 0u;
114497dfb203SMike Snitzer 	}
114597dfb203SMike Snitzer 
11462e633095SJoe Thornber 	/*
11472e633095SJoe Thornber 	 * If we're busy we don't worry about cleaning at all.
11482e633095SJoe Thornber 	 */
11492e633095SJoe Thornber 	return true;
1150b29d4986SJoe Thornber }
1151b29d4986SJoe Thornber 
11526cf4cc8fSJoe Thornber static bool free_target_met(struct smq_policy *mq)
1153b29d4986SJoe Thornber {
115497dfb203SMike Snitzer 	unsigned nr_free;
1155b29d4986SJoe Thornber 
115697dfb203SMike Snitzer 	nr_free = from_cblock(mq->cache_size) - mq->cache_alloc.nr_allocated;
1157b29d4986SJoe Thornber 	return (nr_free + btracker_nr_demotions_queued(mq->bg_work)) >=
1158b29d4986SJoe Thornber 		percent_to_target(mq, FREE_TARGET);
1159b29d4986SJoe Thornber }
1160b29d4986SJoe Thornber 
1161b29d4986SJoe Thornber /*----------------------------------------------------------------*/
1162b29d4986SJoe Thornber 
1163b29d4986SJoe Thornber static void mark_pending(struct smq_policy *mq, struct entry *e)
1164b29d4986SJoe Thornber {
1165b29d4986SJoe Thornber 	BUG_ON(e->sentinel);
1166b29d4986SJoe Thornber 	BUG_ON(!e->allocated);
1167b29d4986SJoe Thornber 	BUG_ON(e->pending_work);
1168b29d4986SJoe Thornber 	e->pending_work = true;
1169b29d4986SJoe Thornber }
1170b29d4986SJoe Thornber 
1171b29d4986SJoe Thornber static void clear_pending(struct smq_policy *mq, struct entry *e)
1172b29d4986SJoe Thornber {
1173b29d4986SJoe Thornber 	BUG_ON(!e->pending_work);
1174b29d4986SJoe Thornber 	e->pending_work = false;
1175b29d4986SJoe Thornber }
1176b29d4986SJoe Thornber 
1177deb71918SJoe Thornber static void queue_writeback(struct smq_policy *mq, bool idle)
1178b29d4986SJoe Thornber {
1179b29d4986SJoe Thornber 	int r;
1180b29d4986SJoe Thornber 	struct policy_work work;
1181b29d4986SJoe Thornber 	struct entry *e;
1182b29d4986SJoe Thornber 
1183deb71918SJoe Thornber 	e = q_peek(&mq->dirty, mq->dirty.nr_levels, idle);
1184b29d4986SJoe Thornber 	if (e) {
1185b29d4986SJoe Thornber 		mark_pending(mq, e);
1186b29d4986SJoe Thornber 		q_del(&mq->dirty, e);
1187b29d4986SJoe Thornber 
1188b29d4986SJoe Thornber 		work.op = POLICY_WRITEBACK;
1189b29d4986SJoe Thornber 		work.oblock = e->oblock;
1190b29d4986SJoe Thornber 		work.cblock = infer_cblock(mq, e);
1191b29d4986SJoe Thornber 
1192b29d4986SJoe Thornber 		r = btracker_queue(mq->bg_work, &work, NULL);
11931e72a8e8SJoe Thornber 		if (r) {
11941e72a8e8SJoe Thornber 			clear_pending(mq, e);
11951e72a8e8SJoe Thornber 			q_push_front(&mq->dirty, e);
11961e72a8e8SJoe Thornber 		}
1197b29d4986SJoe Thornber 	}
1198b29d4986SJoe Thornber }
1199b29d4986SJoe Thornber 
1200b29d4986SJoe Thornber static void queue_demotion(struct smq_policy *mq)
1201b29d4986SJoe Thornber {
12021e72a8e8SJoe Thornber 	int r;
1203b29d4986SJoe Thornber 	struct policy_work work;
1204b29d4986SJoe Thornber 	struct entry *e;
1205b29d4986SJoe Thornber 
1206bab5d988SIgor Stoppa 	if (WARN_ON_ONCE(!mq->migrations_allowed))
1207b29d4986SJoe Thornber 		return;
1208b29d4986SJoe Thornber 
1209a8cd1ebaSJoe Thornber 	e = q_peek(&mq->clean, mq->clean.nr_levels / 2, true);
1210b29d4986SJoe Thornber 	if (!e) {
121178c45607SJoe Thornber 		if (!clean_target_met(mq, true))
1212deb71918SJoe Thornber 			queue_writeback(mq, false);
1213b29d4986SJoe Thornber 		return;
1214b29d4986SJoe Thornber 	}
1215b29d4986SJoe Thornber 
1216b29d4986SJoe Thornber 	mark_pending(mq, e);
1217b29d4986SJoe Thornber 	q_del(&mq->clean, e);
1218b29d4986SJoe Thornber 
1219b29d4986SJoe Thornber 	work.op = POLICY_DEMOTE;
1220b29d4986SJoe Thornber 	work.oblock = e->oblock;
1221b29d4986SJoe Thornber 	work.cblock = infer_cblock(mq, e);
12221e72a8e8SJoe Thornber 	r = btracker_queue(mq->bg_work, &work, NULL);
12231e72a8e8SJoe Thornber 	if (r) {
12241e72a8e8SJoe Thornber 		clear_pending(mq, e);
12251e72a8e8SJoe Thornber 		q_push_front(&mq->clean, e);
12261e72a8e8SJoe Thornber 	}
1227b29d4986SJoe Thornber }
1228b29d4986SJoe Thornber 
1229b29d4986SJoe Thornber static void queue_promotion(struct smq_policy *mq, dm_oblock_t oblock,
1230b29d4986SJoe Thornber 			    struct policy_work **workp)
1231b29d4986SJoe Thornber {
12321e72a8e8SJoe Thornber 	int r;
1233b29d4986SJoe Thornber 	struct entry *e;
1234b29d4986SJoe Thornber 	struct policy_work work;
1235b29d4986SJoe Thornber 
1236b29d4986SJoe Thornber 	if (!mq->migrations_allowed)
1237b29d4986SJoe Thornber 		return;
1238b29d4986SJoe Thornber 
1239b29d4986SJoe Thornber 	if (allocator_empty(&mq->cache_alloc)) {
1240ce1d64e8SJoe Thornber 		/*
1241ce1d64e8SJoe Thornber 		 * We always claim to be 'idle' to ensure some demotions happen
1242ce1d64e8SJoe Thornber 		 * with continuous loads.
1243ce1d64e8SJoe Thornber 		 */
12446cf4cc8fSJoe Thornber 		if (!free_target_met(mq))
1245b29d4986SJoe Thornber 			queue_demotion(mq);
1246b29d4986SJoe Thornber 		return;
1247b29d4986SJoe Thornber 	}
1248b29d4986SJoe Thornber 
1249b29d4986SJoe Thornber 	if (btracker_promotion_already_present(mq->bg_work, oblock))
1250b29d4986SJoe Thornber 		return;
1251b29d4986SJoe Thornber 
1252b29d4986SJoe Thornber 	/*
1253b29d4986SJoe Thornber 	 * We allocate the entry now to reserve the cblock.  If the
1254b29d4986SJoe Thornber 	 * background work is aborted we must remember to free it.
1255b29d4986SJoe Thornber 	 */
1256b29d4986SJoe Thornber 	e = alloc_entry(&mq->cache_alloc);
1257b29d4986SJoe Thornber 	BUG_ON(!e);
1258b29d4986SJoe Thornber 	e->pending_work = true;
1259b29d4986SJoe Thornber 	work.op = POLICY_PROMOTE;
1260b29d4986SJoe Thornber 	work.oblock = oblock;
1261b29d4986SJoe Thornber 	work.cblock = infer_cblock(mq, e);
12621e72a8e8SJoe Thornber 	r = btracker_queue(mq->bg_work, &work, workp);
12631e72a8e8SJoe Thornber 	if (r)
12641e72a8e8SJoe Thornber 		free_entry(&mq->cache_alloc, e);
1265b29d4986SJoe Thornber }
1266b29d4986SJoe Thornber 
1267b29d4986SJoe Thornber /*----------------------------------------------------------------*/
1268b29d4986SJoe Thornber 
126966a63635SJoe Thornber enum promote_result {
127066a63635SJoe Thornber 	PROMOTE_NOT,
127166a63635SJoe Thornber 	PROMOTE_TEMPORARY,
127266a63635SJoe Thornber 	PROMOTE_PERMANENT
127366a63635SJoe Thornber };
127466a63635SJoe Thornber 
127566a63635SJoe Thornber /*
127666a63635SJoe Thornber  * Converts a boolean into a promote result.
127766a63635SJoe Thornber  */
127866a63635SJoe Thornber static enum promote_result maybe_promote(bool promote)
127966a63635SJoe Thornber {
128066a63635SJoe Thornber 	return promote ? PROMOTE_PERMANENT : PROMOTE_NOT;
128166a63635SJoe Thornber }
128266a63635SJoe Thornber 
1283b29d4986SJoe Thornber static enum promote_result should_promote(struct smq_policy *mq, struct entry *hs_e,
1284b29d4986SJoe Thornber 					  int data_dir, bool fast_promote)
128566a63635SJoe Thornber {
1286b29d4986SJoe Thornber 	if (data_dir == WRITE) {
128766a63635SJoe Thornber 		if (!allocator_empty(&mq->cache_alloc) && fast_promote)
128866a63635SJoe Thornber 			return PROMOTE_TEMPORARY;
128966a63635SJoe Thornber 
129066a63635SJoe Thornber 		return maybe_promote(hs_e->level >= mq->write_promote_level);
129166a63635SJoe Thornber 	} else
129266a63635SJoe Thornber 		return maybe_promote(hs_e->level >= mq->read_promote_level);
129366a63635SJoe Thornber }
129466a63635SJoe Thornber 
129566a63635SJoe Thornber static dm_oblock_t to_hblock(struct smq_policy *mq, dm_oblock_t b)
129666a63635SJoe Thornber {
129766a63635SJoe Thornber 	sector_t r = from_oblock(b);
129866a63635SJoe Thornber 	(void) sector_div(r, mq->cache_blocks_per_hotspot_block);
129966a63635SJoe Thornber 	return to_oblock(r);
130066a63635SJoe Thornber }
130166a63635SJoe Thornber 
1302b29d4986SJoe Thornber static struct entry *update_hotspot_queue(struct smq_policy *mq, dm_oblock_t b)
130366a63635SJoe Thornber {
130466a63635SJoe Thornber 	unsigned hi;
130566a63635SJoe Thornber 	dm_oblock_t hb = to_hblock(mq, b);
130666a63635SJoe Thornber 	struct entry *e = h_lookup(&mq->hotspot_table, hb);
130766a63635SJoe Thornber 
130866a63635SJoe Thornber 	if (e) {
130966a63635SJoe Thornber 		stats_level_accessed(&mq->hotspot_stats, e->level);
131066a63635SJoe Thornber 
131166a63635SJoe Thornber 		hi = get_index(&mq->hotspot_alloc, e);
131266a63635SJoe Thornber 		q_requeue(&mq->hotspot, e,
131366a63635SJoe Thornber 			  test_and_set_bit(hi, mq->hotspot_hit_bits) ?
1314b29d4986SJoe Thornber 			  0u : mq->hotspot_level_jump,
1315b29d4986SJoe Thornber 			  NULL, NULL);
131666a63635SJoe Thornber 
131766a63635SJoe Thornber 	} else {
131866a63635SJoe Thornber 		stats_miss(&mq->hotspot_stats);
131966a63635SJoe Thornber 
132066a63635SJoe Thornber 		e = alloc_entry(&mq->hotspot_alloc);
132166a63635SJoe Thornber 		if (!e) {
132266a63635SJoe Thornber 			e = q_pop(&mq->hotspot);
132366a63635SJoe Thornber 			if (e) {
132466a63635SJoe Thornber 				h_remove(&mq->hotspot_table, e);
132566a63635SJoe Thornber 				hi = get_index(&mq->hotspot_alloc, e);
132666a63635SJoe Thornber 				clear_bit(hi, mq->hotspot_hit_bits);
132766a63635SJoe Thornber 			}
132866a63635SJoe Thornber 
132966a63635SJoe Thornber 		}
133066a63635SJoe Thornber 
133166a63635SJoe Thornber 		if (e) {
133266a63635SJoe Thornber 			e->oblock = hb;
133366a63635SJoe Thornber 			q_push(&mq->hotspot, e);
133466a63635SJoe Thornber 			h_insert(&mq->hotspot_table, e);
133566a63635SJoe Thornber 		}
133666a63635SJoe Thornber 	}
133766a63635SJoe Thornber 
133866a63635SJoe Thornber 	return e;
133966a63635SJoe Thornber }
134066a63635SJoe Thornber 
134166a63635SJoe Thornber /*----------------------------------------------------------------*/
134266a63635SJoe Thornber 
134366a63635SJoe Thornber /*
134466a63635SJoe Thornber  * Public interface, via the policy struct.  See dm-cache-policy.h for a
134566a63635SJoe Thornber  * description of these.
134666a63635SJoe Thornber  */
134766a63635SJoe Thornber 
134866a63635SJoe Thornber static struct smq_policy *to_smq_policy(struct dm_cache_policy *p)
134966a63635SJoe Thornber {
135066a63635SJoe Thornber 	return container_of(p, struct smq_policy, policy);
135166a63635SJoe Thornber }
135266a63635SJoe Thornber 
135366a63635SJoe Thornber static void smq_destroy(struct dm_cache_policy *p)
135466a63635SJoe Thornber {
135566a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
135666a63635SJoe Thornber 
1357b29d4986SJoe Thornber 	btracker_destroy(mq->bg_work);
135866a63635SJoe Thornber 	h_exit(&mq->hotspot_table);
135966a63635SJoe Thornber 	h_exit(&mq->table);
136066a63635SJoe Thornber 	free_bitset(mq->hotspot_hit_bits);
136166a63635SJoe Thornber 	free_bitset(mq->cache_hit_bits);
136266a63635SJoe Thornber 	space_exit(&mq->es);
136366a63635SJoe Thornber 	kfree(mq);
136466a63635SJoe Thornber }
136566a63635SJoe Thornber 
1366b29d4986SJoe Thornber /*----------------------------------------------------------------*/
1367b29d4986SJoe Thornber 
1368b29d4986SJoe Thornber static int __lookup(struct smq_policy *mq, dm_oblock_t oblock, dm_cblock_t *cblock,
1369b29d4986SJoe Thornber 		    int data_dir, bool fast_copy,
1370b29d4986SJoe Thornber 		    struct policy_work **work, bool *background_work)
137166a63635SJoe Thornber {
1372b29d4986SJoe Thornber 	struct entry *e, *hs_e;
1373b29d4986SJoe Thornber 	enum promote_result pr;
137466a63635SJoe Thornber 
1375b29d4986SJoe Thornber 	*background_work = false;
137666a63635SJoe Thornber 
137766a63635SJoe Thornber 	e = h_lookup(&mq->table, oblock);
137866a63635SJoe Thornber 	if (e) {
1379b29d4986SJoe Thornber 		stats_level_accessed(&mq->cache_stats, e->level);
1380b29d4986SJoe Thornber 
1381b29d4986SJoe Thornber 		requeue(mq, e);
138266a63635SJoe Thornber 		*cblock = infer_cblock(mq, e);
1383b29d4986SJoe Thornber 		return 0;
1384b29d4986SJoe Thornber 
1385b29d4986SJoe Thornber 	} else {
1386b29d4986SJoe Thornber 		stats_miss(&mq->cache_stats);
1387b29d4986SJoe Thornber 
1388b29d4986SJoe Thornber 		/*
1389b29d4986SJoe Thornber 		 * The hotspot queue only gets updated with misses.
1390b29d4986SJoe Thornber 		 */
1391b29d4986SJoe Thornber 		hs_e = update_hotspot_queue(mq, oblock);
1392b29d4986SJoe Thornber 
1393b29d4986SJoe Thornber 		pr = should_promote(mq, hs_e, data_dir, fast_copy);
1394b29d4986SJoe Thornber 		if (pr != PROMOTE_NOT) {
1395b29d4986SJoe Thornber 			queue_promotion(mq, oblock, work);
1396b29d4986SJoe Thornber 			*background_work = true;
1397b29d4986SJoe Thornber 		}
1398b29d4986SJoe Thornber 
1399b29d4986SJoe Thornber 		return -ENOENT;
1400b29d4986SJoe Thornber 	}
1401b29d4986SJoe Thornber }
1402b29d4986SJoe Thornber 
1403b29d4986SJoe Thornber static int smq_lookup(struct dm_cache_policy *p, dm_oblock_t oblock, dm_cblock_t *cblock,
1404b29d4986SJoe Thornber 		      int data_dir, bool fast_copy,
1405b29d4986SJoe Thornber 		      bool *background_work)
1406b29d4986SJoe Thornber {
1407b29d4986SJoe Thornber 	int r;
1408b29d4986SJoe Thornber 	unsigned long flags;
1409b29d4986SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
1410b29d4986SJoe Thornber 
1411b29d4986SJoe Thornber 	spin_lock_irqsave(&mq->lock, flags);
1412b29d4986SJoe Thornber 	r = __lookup(mq, oblock, cblock,
1413b29d4986SJoe Thornber 		     data_dir, fast_copy,
1414b29d4986SJoe Thornber 		     NULL, background_work);
14154051aab7SJoe Thornber 	spin_unlock_irqrestore(&mq->lock, flags);
141666a63635SJoe Thornber 
141766a63635SJoe Thornber 	return r;
141866a63635SJoe Thornber }
141966a63635SJoe Thornber 
1420b29d4986SJoe Thornber static int smq_lookup_with_work(struct dm_cache_policy *p,
1421b29d4986SJoe Thornber 				dm_oblock_t oblock, dm_cblock_t *cblock,
1422b29d4986SJoe Thornber 				int data_dir, bool fast_copy,
1423b29d4986SJoe Thornber 				struct policy_work **work)
142466a63635SJoe Thornber {
1425b29d4986SJoe Thornber 	int r;
1426b29d4986SJoe Thornber 	bool background_queued;
1427b29d4986SJoe Thornber 	unsigned long flags;
1428b29d4986SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
142966a63635SJoe Thornber 
1430b29d4986SJoe Thornber 	spin_lock_irqsave(&mq->lock, flags);
1431b29d4986SJoe Thornber 	r = __lookup(mq, oblock, cblock, data_dir, fast_copy, work, &background_queued);
1432b29d4986SJoe Thornber 	spin_unlock_irqrestore(&mq->lock, flags);
143366a63635SJoe Thornber 
1434b29d4986SJoe Thornber 	return r;
143566a63635SJoe Thornber }
143666a63635SJoe Thornber 
1437b29d4986SJoe Thornber static int smq_get_background_work(struct dm_cache_policy *p, bool idle,
1438b29d4986SJoe Thornber 				   struct policy_work **result)
1439b29d4986SJoe Thornber {
1440b29d4986SJoe Thornber 	int r;
1441b29d4986SJoe Thornber 	unsigned long flags;
1442b29d4986SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
1443b29d4986SJoe Thornber 
1444b29d4986SJoe Thornber 	spin_lock_irqsave(&mq->lock, flags);
1445b29d4986SJoe Thornber 	r = btracker_issue(mq->bg_work, result);
1446b29d4986SJoe Thornber 	if (r == -ENODATA) {
14476cf4cc8fSJoe Thornber 		if (!clean_target_met(mq, idle)) {
1448deb71918SJoe Thornber 			queue_writeback(mq, idle);
1449b29d4986SJoe Thornber 			r = btracker_issue(mq->bg_work, result);
1450b29d4986SJoe Thornber 		}
14516cf4cc8fSJoe Thornber 	}
1452b29d4986SJoe Thornber 	spin_unlock_irqrestore(&mq->lock, flags);
1453b29d4986SJoe Thornber 
1454b29d4986SJoe Thornber 	return r;
1455b29d4986SJoe Thornber }
1456b29d4986SJoe Thornber 
1457b29d4986SJoe Thornber /*
1458b29d4986SJoe Thornber  * We need to clear any pending work flags that have been set, and in the
1459b29d4986SJoe Thornber  * case of promotion free the entry for the destination cblock.
1460b29d4986SJoe Thornber  */
1461b29d4986SJoe Thornber static void __complete_background_work(struct smq_policy *mq,
1462b29d4986SJoe Thornber 				       struct policy_work *work,
1463b29d4986SJoe Thornber 				       bool success)
1464b29d4986SJoe Thornber {
1465b29d4986SJoe Thornber 	struct entry *e = get_entry(&mq->cache_alloc,
1466b29d4986SJoe Thornber 				    from_cblock(work->cblock));
1467b29d4986SJoe Thornber 
1468b29d4986SJoe Thornber 	switch (work->op) {
1469b29d4986SJoe Thornber 	case POLICY_PROMOTE:
1470b29d4986SJoe Thornber 		// !h, !q, a
1471b29d4986SJoe Thornber 		clear_pending(mq, e);
1472b29d4986SJoe Thornber 		if (success) {
1473b29d4986SJoe Thornber 			e->oblock = work->oblock;
14744d44ec5aSJoe Thornber 			e->level = NR_CACHE_LEVELS - 1;
1475b29d4986SJoe Thornber 			push(mq, e);
1476b29d4986SJoe Thornber 			// h, q, a
1477b29d4986SJoe Thornber 		} else {
1478b29d4986SJoe Thornber 			free_entry(&mq->cache_alloc, e);
1479b29d4986SJoe Thornber 			// !h, !q, !a
1480b29d4986SJoe Thornber 		}
1481b29d4986SJoe Thornber 		break;
1482b29d4986SJoe Thornber 
1483b29d4986SJoe Thornber 	case POLICY_DEMOTE:
1484b29d4986SJoe Thornber 		// h, !q, a
1485b29d4986SJoe Thornber 		if (success) {
1486b29d4986SJoe Thornber 			h_remove(&mq->table, e);
1487b29d4986SJoe Thornber 			free_entry(&mq->cache_alloc, e);
1488b29d4986SJoe Thornber 			// !h, !q, !a
1489b29d4986SJoe Thornber 		} else {
1490b29d4986SJoe Thornber 			clear_pending(mq, e);
1491b29d4986SJoe Thornber 			push_queue(mq, e);
1492b29d4986SJoe Thornber 			// h, q, a
1493b29d4986SJoe Thornber 		}
1494b29d4986SJoe Thornber 		break;
1495b29d4986SJoe Thornber 
1496b29d4986SJoe Thornber 	case POLICY_WRITEBACK:
1497b29d4986SJoe Thornber 		// h, !q, a
1498b29d4986SJoe Thornber 		clear_pending(mq, e);
1499b29d4986SJoe Thornber 		push_queue(mq, e);
1500b29d4986SJoe Thornber 		// h, q, a
1501b29d4986SJoe Thornber 		break;
1502b29d4986SJoe Thornber 	}
1503b29d4986SJoe Thornber 
1504b29d4986SJoe Thornber 	btracker_complete(mq->bg_work, work);
1505b29d4986SJoe Thornber }
1506b29d4986SJoe Thornber 
1507b29d4986SJoe Thornber static void smq_complete_background_work(struct dm_cache_policy *p,
1508b29d4986SJoe Thornber 					 struct policy_work *work,
1509b29d4986SJoe Thornber 					 bool success)
151066a63635SJoe Thornber {
15114051aab7SJoe Thornber 	unsigned long flags;
151266a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
151366a63635SJoe Thornber 
15144051aab7SJoe Thornber 	spin_lock_irqsave(&mq->lock, flags);
1515b29d4986SJoe Thornber 	__complete_background_work(mq, work, success);
15164051aab7SJoe Thornber 	spin_unlock_irqrestore(&mq->lock, flags);
151766a63635SJoe Thornber }
151866a63635SJoe Thornber 
1519b29d4986SJoe Thornber // in_hash(oblock) -> in_hash(oblock)
1520b29d4986SJoe Thornber static void __smq_set_clear_dirty(struct smq_policy *mq, dm_cblock_t cblock, bool set)
1521b29d4986SJoe Thornber {
1522b29d4986SJoe Thornber 	struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock));
1523b29d4986SJoe Thornber 
1524b29d4986SJoe Thornber 	if (e->pending_work)
1525b29d4986SJoe Thornber 		e->dirty = set;
1526b29d4986SJoe Thornber 	else {
1527b29d4986SJoe Thornber 		del_queue(mq, e);
1528b29d4986SJoe Thornber 		e->dirty = set;
1529b29d4986SJoe Thornber 		push_queue(mq, e);
1530b29d4986SJoe Thornber 	}
1531b29d4986SJoe Thornber }
1532b29d4986SJoe Thornber 
1533b29d4986SJoe Thornber static void smq_set_dirty(struct dm_cache_policy *p, dm_cblock_t cblock)
1534b29d4986SJoe Thornber {
1535b29d4986SJoe Thornber 	unsigned long flags;
1536b29d4986SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
1537b29d4986SJoe Thornber 
1538b29d4986SJoe Thornber 	spin_lock_irqsave(&mq->lock, flags);
1539b29d4986SJoe Thornber 	__smq_set_clear_dirty(mq, cblock, true);
1540b29d4986SJoe Thornber 	spin_unlock_irqrestore(&mq->lock, flags);
1541b29d4986SJoe Thornber }
1542b29d4986SJoe Thornber 
1543b29d4986SJoe Thornber static void smq_clear_dirty(struct dm_cache_policy *p, dm_cblock_t cblock)
154466a63635SJoe Thornber {
154566a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
15464051aab7SJoe Thornber 	unsigned long flags;
154766a63635SJoe Thornber 
15484051aab7SJoe Thornber 	spin_lock_irqsave(&mq->lock, flags);
1549b29d4986SJoe Thornber 	__smq_set_clear_dirty(mq, cblock, false);
15504051aab7SJoe Thornber 	spin_unlock_irqrestore(&mq->lock, flags);
155166a63635SJoe Thornber }
155266a63635SJoe Thornber 
15539d1b404cSJoe Thornber static unsigned random_level(dm_cblock_t cblock)
15549d1b404cSJoe Thornber {
1555e99dda8fSMike Snitzer 	return hash_32(from_cblock(cblock), 9) & (NR_CACHE_LEVELS - 1);
15569d1b404cSJoe Thornber }
15579d1b404cSJoe Thornber 
155866a63635SJoe Thornber static int smq_load_mapping(struct dm_cache_policy *p,
155966a63635SJoe Thornber 			    dm_oblock_t oblock, dm_cblock_t cblock,
1560b29d4986SJoe Thornber 			    bool dirty, uint32_t hint, bool hint_valid)
156166a63635SJoe Thornber {
156266a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
156366a63635SJoe Thornber 	struct entry *e;
156466a63635SJoe Thornber 
156566a63635SJoe Thornber 	e = alloc_particular_entry(&mq->cache_alloc, from_cblock(cblock));
156666a63635SJoe Thornber 	e->oblock = oblock;
1567b29d4986SJoe Thornber 	e->dirty = dirty;
15689d1b404cSJoe Thornber 	e->level = hint_valid ? min(hint, NR_CACHE_LEVELS - 1) : random_level(cblock);
1569b29d4986SJoe Thornber 	e->pending_work = false;
157066a63635SJoe Thornber 
1571b29d4986SJoe Thornber 	/*
1572b29d4986SJoe Thornber 	 * When we load mappings we push ahead of both sentinels in order to
1573b29d4986SJoe Thornber 	 * allow demotions and cleaning to occur immediately.
1574b29d4986SJoe Thornber 	 */
1575b29d4986SJoe Thornber 	push_front(mq, e);
1576b29d4986SJoe Thornber 
1577b29d4986SJoe Thornber 	return 0;
1578b29d4986SJoe Thornber }
1579b29d4986SJoe Thornber 
1580b29d4986SJoe Thornber static int smq_invalidate_mapping(struct dm_cache_policy *p, dm_cblock_t cblock)
1581b29d4986SJoe Thornber {
1582b29d4986SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
1583b29d4986SJoe Thornber 	struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock));
1584b29d4986SJoe Thornber 
1585b29d4986SJoe Thornber 	if (!e->allocated)
1586b29d4986SJoe Thornber 		return -ENODATA;
1587b29d4986SJoe Thornber 
1588b29d4986SJoe Thornber 	// FIXME: what if this block has pending background work?
1589b29d4986SJoe Thornber 	del_queue(mq, e);
1590b29d4986SJoe Thornber 	h_remove(&mq->table, e);
1591b29d4986SJoe Thornber 	free_entry(&mq->cache_alloc, e);
159266a63635SJoe Thornber 	return 0;
159366a63635SJoe Thornber }
159466a63635SJoe Thornber 
15954e781b49SJoe Thornber static uint32_t smq_get_hint(struct dm_cache_policy *p, dm_cblock_t cblock)
159666a63635SJoe Thornber {
159766a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
15984e781b49SJoe Thornber 	struct entry *e = get_entry(&mq->cache_alloc, from_cblock(cblock));
159966a63635SJoe Thornber 
16004e781b49SJoe Thornber 	if (!e->allocated)
16014e781b49SJoe Thornber 		return 0;
160266a63635SJoe Thornber 
16034e781b49SJoe Thornber 	return e->level;
160466a63635SJoe Thornber }
160566a63635SJoe Thornber 
160666a63635SJoe Thornber static dm_cblock_t smq_residency(struct dm_cache_policy *p)
160766a63635SJoe Thornber {
160866a63635SJoe Thornber 	dm_cblock_t r;
16094051aab7SJoe Thornber 	unsigned long flags;
161066a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
161166a63635SJoe Thornber 
16124051aab7SJoe Thornber 	spin_lock_irqsave(&mq->lock, flags);
161366a63635SJoe Thornber 	r = to_cblock(mq->cache_alloc.nr_allocated);
16144051aab7SJoe Thornber 	spin_unlock_irqrestore(&mq->lock, flags);
161566a63635SJoe Thornber 
161666a63635SJoe Thornber 	return r;
161766a63635SJoe Thornber }
161866a63635SJoe Thornber 
1619fba10109SJoe Thornber static void smq_tick(struct dm_cache_policy *p, bool can_block)
162066a63635SJoe Thornber {
162166a63635SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
162266a63635SJoe Thornber 	unsigned long flags;
162366a63635SJoe Thornber 
16244051aab7SJoe Thornber 	spin_lock_irqsave(&mq->lock, flags);
16254051aab7SJoe Thornber 	mq->tick++;
16264051aab7SJoe Thornber 	update_sentinels(mq);
16274051aab7SJoe Thornber 	end_hotspot_period(mq);
16284051aab7SJoe Thornber 	end_cache_period(mq);
16294051aab7SJoe Thornber 	spin_unlock_irqrestore(&mq->lock, flags);
163066a63635SJoe Thornber }
163166a63635SJoe Thornber 
1632b29d4986SJoe Thornber static void smq_allow_migrations(struct dm_cache_policy *p, bool allow)
1633b29d4986SJoe Thornber {
1634b29d4986SJoe Thornber 	struct smq_policy *mq = to_smq_policy(p);
1635b29d4986SJoe Thornber 	mq->migrations_allowed = allow;
1636b29d4986SJoe Thornber }
1637b29d4986SJoe Thornber 
16389ed84698SJoe Thornber /*
16399ed84698SJoe Thornber  * smq has no config values, but the old mq policy did.  To avoid breaking
16409ed84698SJoe Thornber  * software we continue to accept these configurables for the mq policy,
16419ed84698SJoe Thornber  * but they have no effect.
16429ed84698SJoe Thornber  */
16439ed84698SJoe Thornber static int mq_set_config_value(struct dm_cache_policy *p,
16449ed84698SJoe Thornber 			       const char *key, const char *value)
16459ed84698SJoe Thornber {
16469ed84698SJoe Thornber 	unsigned long tmp;
16479ed84698SJoe Thornber 
16489ed84698SJoe Thornber 	if (kstrtoul(value, 10, &tmp))
16499ed84698SJoe Thornber 		return -EINVAL;
16509ed84698SJoe Thornber 
16519ed84698SJoe Thornber 	if (!strcasecmp(key, "random_threshold") ||
16529ed84698SJoe Thornber 	    !strcasecmp(key, "sequential_threshold") ||
16539ed84698SJoe Thornber 	    !strcasecmp(key, "discard_promote_adjustment") ||
16549ed84698SJoe Thornber 	    !strcasecmp(key, "read_promote_adjustment") ||
16559ed84698SJoe Thornber 	    !strcasecmp(key, "write_promote_adjustment")) {
16569ed84698SJoe Thornber 		DMWARN("tunable '%s' no longer has any effect, mq policy is now an alias for smq", key);
16579ed84698SJoe Thornber 		return 0;
16589ed84698SJoe Thornber 	}
16599ed84698SJoe Thornber 
16609ed84698SJoe Thornber 	return -EINVAL;
16619ed84698SJoe Thornber }
16629ed84698SJoe Thornber 
16639ed84698SJoe Thornber static int mq_emit_config_values(struct dm_cache_policy *p, char *result,
16649ed84698SJoe Thornber 				 unsigned maxlen, ssize_t *sz_ptr)
16659ed84698SJoe Thornber {
16669ed84698SJoe Thornber 	ssize_t sz = *sz_ptr;
16679ed84698SJoe Thornber 
16689ed84698SJoe Thornber 	DMEMIT("10 random_threshold 0 "
16699ed84698SJoe Thornber 	       "sequential_threshold 0 "
16709ed84698SJoe Thornber 	       "discard_promote_adjustment 0 "
16719ed84698SJoe Thornber 	       "read_promote_adjustment 0 "
16729ed84698SJoe Thornber 	       "write_promote_adjustment 0 ");
16739ed84698SJoe Thornber 
16749ed84698SJoe Thornber 	*sz_ptr = sz;
16759ed84698SJoe Thornber 	return 0;
16769ed84698SJoe Thornber }
16779ed84698SJoe Thornber 
167866a63635SJoe Thornber /* Init the policy plugin interface function pointers. */
16799ed84698SJoe Thornber static void init_policy_functions(struct smq_policy *mq, bool mimic_mq)
168066a63635SJoe Thornber {
168166a63635SJoe Thornber 	mq->policy.destroy = smq_destroy;
168266a63635SJoe Thornber 	mq->policy.lookup = smq_lookup;
1683b29d4986SJoe Thornber 	mq->policy.lookup_with_work = smq_lookup_with_work;
1684b29d4986SJoe Thornber 	mq->policy.get_background_work = smq_get_background_work;
1685b29d4986SJoe Thornber 	mq->policy.complete_background_work = smq_complete_background_work;
168666a63635SJoe Thornber 	mq->policy.set_dirty = smq_set_dirty;
168766a63635SJoe Thornber 	mq->policy.clear_dirty = smq_clear_dirty;
168866a63635SJoe Thornber 	mq->policy.load_mapping = smq_load_mapping;
1689b29d4986SJoe Thornber 	mq->policy.invalidate_mapping = smq_invalidate_mapping;
16904e781b49SJoe Thornber 	mq->policy.get_hint = smq_get_hint;
169166a63635SJoe Thornber 	mq->policy.residency = smq_residency;
169266a63635SJoe Thornber 	mq->policy.tick = smq_tick;
1693b29d4986SJoe Thornber 	mq->policy.allow_migrations = smq_allow_migrations;
16949ed84698SJoe Thornber 
16959ed84698SJoe Thornber 	if (mimic_mq) {
16969ed84698SJoe Thornber 		mq->policy.set_config_value = mq_set_config_value;
16979ed84698SJoe Thornber 		mq->policy.emit_config_values = mq_emit_config_values;
16989ed84698SJoe Thornber 	}
169966a63635SJoe Thornber }
170066a63635SJoe Thornber 
170166a63635SJoe Thornber static bool too_many_hotspot_blocks(sector_t origin_size,
170266a63635SJoe Thornber 				    sector_t hotspot_block_size,
170366a63635SJoe Thornber 				    unsigned nr_hotspot_blocks)
170466a63635SJoe Thornber {
170566a63635SJoe Thornber 	return (hotspot_block_size * nr_hotspot_blocks) > origin_size;
170666a63635SJoe Thornber }
170766a63635SJoe Thornber 
170866a63635SJoe Thornber static void calc_hotspot_params(sector_t origin_size,
170966a63635SJoe Thornber 				sector_t cache_block_size,
171066a63635SJoe Thornber 				unsigned nr_cache_blocks,
171166a63635SJoe Thornber 				sector_t *hotspot_block_size,
171266a63635SJoe Thornber 				unsigned *nr_hotspot_blocks)
171366a63635SJoe Thornber {
171466a63635SJoe Thornber 	*hotspot_block_size = cache_block_size * 16u;
171566a63635SJoe Thornber 	*nr_hotspot_blocks = max(nr_cache_blocks / 4u, 1024u);
171666a63635SJoe Thornber 
171766a63635SJoe Thornber 	while ((*hotspot_block_size > cache_block_size) &&
171866a63635SJoe Thornber 	       too_many_hotspot_blocks(origin_size, *hotspot_block_size, *nr_hotspot_blocks))
171966a63635SJoe Thornber 		*hotspot_block_size /= 2u;
172066a63635SJoe Thornber }
172166a63635SJoe Thornber 
17229ed84698SJoe Thornber static struct dm_cache_policy *__smq_create(dm_cblock_t cache_size,
172366a63635SJoe Thornber 					    sector_t origin_size,
17249ed84698SJoe Thornber 					    sector_t cache_block_size,
1725b29d4986SJoe Thornber 					    bool mimic_mq,
1726b29d4986SJoe Thornber 					    bool migrations_allowed)
172766a63635SJoe Thornber {
172866a63635SJoe Thornber 	unsigned i;
172966a63635SJoe Thornber 	unsigned nr_sentinels_per_queue = 2u * NR_CACHE_LEVELS;
173066a63635SJoe Thornber 	unsigned total_sentinels = 2u * nr_sentinels_per_queue;
173166a63635SJoe Thornber 	struct smq_policy *mq = kzalloc(sizeof(*mq), GFP_KERNEL);
173266a63635SJoe Thornber 
173366a63635SJoe Thornber 	if (!mq)
173466a63635SJoe Thornber 		return NULL;
173566a63635SJoe Thornber 
17369ed84698SJoe Thornber 	init_policy_functions(mq, mimic_mq);
173766a63635SJoe Thornber 	mq->cache_size = cache_size;
173866a63635SJoe Thornber 	mq->cache_block_size = cache_block_size;
173966a63635SJoe Thornber 
174066a63635SJoe Thornber 	calc_hotspot_params(origin_size, cache_block_size, from_cblock(cache_size),
174166a63635SJoe Thornber 			    &mq->hotspot_block_size, &mq->nr_hotspot_blocks);
174266a63635SJoe Thornber 
174366a63635SJoe Thornber 	mq->cache_blocks_per_hotspot_block = div64_u64(mq->hotspot_block_size, mq->cache_block_size);
174466a63635SJoe Thornber 	mq->hotspot_level_jump = 1u;
174566a63635SJoe Thornber 	if (space_init(&mq->es, total_sentinels + mq->nr_hotspot_blocks + from_cblock(cache_size))) {
174666a63635SJoe Thornber 		DMERR("couldn't initialize entry space");
174766a63635SJoe Thornber 		goto bad_pool_init;
174866a63635SJoe Thornber 	}
174966a63635SJoe Thornber 
175066a63635SJoe Thornber 	init_allocator(&mq->writeback_sentinel_alloc, &mq->es, 0, nr_sentinels_per_queue);
175166a63635SJoe Thornber 	for (i = 0; i < nr_sentinels_per_queue; i++)
175266a63635SJoe Thornber 		get_entry(&mq->writeback_sentinel_alloc, i)->sentinel = true;
175366a63635SJoe Thornber 
175466a63635SJoe Thornber 	init_allocator(&mq->demote_sentinel_alloc, &mq->es, nr_sentinels_per_queue, total_sentinels);
175566a63635SJoe Thornber 	for (i = 0; i < nr_sentinels_per_queue; i++)
175666a63635SJoe Thornber 		get_entry(&mq->demote_sentinel_alloc, i)->sentinel = true;
175766a63635SJoe Thornber 
175866a63635SJoe Thornber 	init_allocator(&mq->hotspot_alloc, &mq->es, total_sentinels,
175966a63635SJoe Thornber 		       total_sentinels + mq->nr_hotspot_blocks);
176066a63635SJoe Thornber 
176166a63635SJoe Thornber 	init_allocator(&mq->cache_alloc, &mq->es,
176266a63635SJoe Thornber 		       total_sentinels + mq->nr_hotspot_blocks,
176366a63635SJoe Thornber 		       total_sentinels + mq->nr_hotspot_blocks + from_cblock(cache_size));
176466a63635SJoe Thornber 
176566a63635SJoe Thornber 	mq->hotspot_hit_bits = alloc_bitset(mq->nr_hotspot_blocks);
176666a63635SJoe Thornber 	if (!mq->hotspot_hit_bits) {
176766a63635SJoe Thornber 		DMERR("couldn't allocate hotspot hit bitset");
176866a63635SJoe Thornber 		goto bad_hotspot_hit_bits;
176966a63635SJoe Thornber 	}
177066a63635SJoe Thornber 	clear_bitset(mq->hotspot_hit_bits, mq->nr_hotspot_blocks);
177166a63635SJoe Thornber 
177266a63635SJoe Thornber 	if (from_cblock(cache_size)) {
177366a63635SJoe Thornber 		mq->cache_hit_bits = alloc_bitset(from_cblock(cache_size));
1774134bf30cSColin Ian King 		if (!mq->cache_hit_bits) {
177566a63635SJoe Thornber 			DMERR("couldn't allocate cache hit bitset");
177666a63635SJoe Thornber 			goto bad_cache_hit_bits;
177766a63635SJoe Thornber 		}
177866a63635SJoe Thornber 		clear_bitset(mq->cache_hit_bits, from_cblock(mq->cache_size));
177966a63635SJoe Thornber 	} else
178066a63635SJoe Thornber 		mq->cache_hit_bits = NULL;
178166a63635SJoe Thornber 
178266a63635SJoe Thornber 	mq->tick = 0;
17834051aab7SJoe Thornber 	spin_lock_init(&mq->lock);
178466a63635SJoe Thornber 
178566a63635SJoe Thornber 	q_init(&mq->hotspot, &mq->es, NR_HOTSPOT_LEVELS);
178666a63635SJoe Thornber 	mq->hotspot.nr_top_levels = 8;
178766a63635SJoe Thornber 	mq->hotspot.nr_in_top_levels = min(mq->nr_hotspot_blocks / NR_HOTSPOT_LEVELS,
178866a63635SJoe Thornber 					   from_cblock(mq->cache_size) / mq->cache_blocks_per_hotspot_block);
178966a63635SJoe Thornber 
179066a63635SJoe Thornber 	q_init(&mq->clean, &mq->es, NR_CACHE_LEVELS);
179166a63635SJoe Thornber 	q_init(&mq->dirty, &mq->es, NR_CACHE_LEVELS);
179266a63635SJoe Thornber 
179366a63635SJoe Thornber 	stats_init(&mq->hotspot_stats, NR_HOTSPOT_LEVELS);
179466a63635SJoe Thornber 	stats_init(&mq->cache_stats, NR_CACHE_LEVELS);
179566a63635SJoe Thornber 
179666a63635SJoe Thornber 	if (h_init(&mq->table, &mq->es, from_cblock(cache_size)))
179766a63635SJoe Thornber 		goto bad_alloc_table;
179866a63635SJoe Thornber 
179966a63635SJoe Thornber 	if (h_init(&mq->hotspot_table, &mq->es, mq->nr_hotspot_blocks))
180066a63635SJoe Thornber 		goto bad_alloc_hotspot_table;
180166a63635SJoe Thornber 
180266a63635SJoe Thornber 	sentinels_init(mq);
180366a63635SJoe Thornber 	mq->write_promote_level = mq->read_promote_level = NR_HOTSPOT_LEVELS;
180466a63635SJoe Thornber 
180566a63635SJoe Thornber 	mq->next_hotspot_period = jiffies;
180666a63635SJoe Thornber 	mq->next_cache_period = jiffies;
180766a63635SJoe Thornber 
18088ee18edeSJoe Thornber 	mq->bg_work = btracker_create(4096); /* FIXME: hard coded value */
1809b29d4986SJoe Thornber 	if (!mq->bg_work)
1810b29d4986SJoe Thornber 		goto bad_btracker;
1811b29d4986SJoe Thornber 
1812b29d4986SJoe Thornber 	mq->migrations_allowed = migrations_allowed;
1813b29d4986SJoe Thornber 
181466a63635SJoe Thornber 	return &mq->policy;
181566a63635SJoe Thornber 
1816b29d4986SJoe Thornber bad_btracker:
1817b29d4986SJoe Thornber 	h_exit(&mq->hotspot_table);
181866a63635SJoe Thornber bad_alloc_hotspot_table:
181966a63635SJoe Thornber 	h_exit(&mq->table);
182066a63635SJoe Thornber bad_alloc_table:
182166a63635SJoe Thornber 	free_bitset(mq->cache_hit_bits);
182266a63635SJoe Thornber bad_cache_hit_bits:
182366a63635SJoe Thornber 	free_bitset(mq->hotspot_hit_bits);
182466a63635SJoe Thornber bad_hotspot_hit_bits:
182566a63635SJoe Thornber 	space_exit(&mq->es);
182666a63635SJoe Thornber bad_pool_init:
182766a63635SJoe Thornber 	kfree(mq);
182866a63635SJoe Thornber 
182966a63635SJoe Thornber 	return NULL;
183066a63635SJoe Thornber }
183166a63635SJoe Thornber 
18329ed84698SJoe Thornber static struct dm_cache_policy *smq_create(dm_cblock_t cache_size,
18339ed84698SJoe Thornber 					  sector_t origin_size,
18349ed84698SJoe Thornber 					  sector_t cache_block_size)
18359ed84698SJoe Thornber {
1836b29d4986SJoe Thornber 	return __smq_create(cache_size, origin_size, cache_block_size, false, true);
18379ed84698SJoe Thornber }
18389ed84698SJoe Thornber 
18399ed84698SJoe Thornber static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
18409ed84698SJoe Thornber 					 sector_t origin_size,
18419ed84698SJoe Thornber 					 sector_t cache_block_size)
18429ed84698SJoe Thornber {
1843b29d4986SJoe Thornber 	return __smq_create(cache_size, origin_size, cache_block_size, true, true);
1844b29d4986SJoe Thornber }
1845b29d4986SJoe Thornber 
1846b29d4986SJoe Thornber static struct dm_cache_policy *cleaner_create(dm_cblock_t cache_size,
1847b29d4986SJoe Thornber 					      sector_t origin_size,
1848b29d4986SJoe Thornber 					      sector_t cache_block_size)
1849b29d4986SJoe Thornber {
1850b29d4986SJoe Thornber 	return __smq_create(cache_size, origin_size, cache_block_size, false, false);
18519ed84698SJoe Thornber }
18529ed84698SJoe Thornber 
185366a63635SJoe Thornber /*----------------------------------------------------------------*/
185466a63635SJoe Thornber 
185566a63635SJoe Thornber static struct dm_cache_policy_type smq_policy_type = {
185666a63635SJoe Thornber 	.name = "smq",
1857b29d4986SJoe Thornber 	.version = {2, 0, 0},
185866a63635SJoe Thornber 	.hint_size = 4,
185966a63635SJoe Thornber 	.owner = THIS_MODULE,
186066a63635SJoe Thornber 	.create = smq_create
186166a63635SJoe Thornber };
186266a63635SJoe Thornber 
18639ed84698SJoe Thornber static struct dm_cache_policy_type mq_policy_type = {
18649ed84698SJoe Thornber 	.name = "mq",
1865b29d4986SJoe Thornber 	.version = {2, 0, 0},
18669ed84698SJoe Thornber 	.hint_size = 4,
18679ed84698SJoe Thornber 	.owner = THIS_MODULE,
18689ed84698SJoe Thornber 	.create = mq_create,
18699ed84698SJoe Thornber };
18709ed84698SJoe Thornber 
1871b29d4986SJoe Thornber static struct dm_cache_policy_type cleaner_policy_type = {
1872b29d4986SJoe Thornber 	.name = "cleaner",
1873b29d4986SJoe Thornber 	.version = {2, 0, 0},
1874b29d4986SJoe Thornber 	.hint_size = 4,
1875b29d4986SJoe Thornber 	.owner = THIS_MODULE,
1876b29d4986SJoe Thornber 	.create = cleaner_create,
1877b29d4986SJoe Thornber };
1878b29d4986SJoe Thornber 
1879bccab6a0SMike Snitzer static struct dm_cache_policy_type default_policy_type = {
1880bccab6a0SMike Snitzer 	.name = "default",
1881b29d4986SJoe Thornber 	.version = {2, 0, 0},
1882bccab6a0SMike Snitzer 	.hint_size = 4,
1883bccab6a0SMike Snitzer 	.owner = THIS_MODULE,
1884bccab6a0SMike Snitzer 	.create = smq_create,
1885bccab6a0SMike Snitzer 	.real = &smq_policy_type
1886bccab6a0SMike Snitzer };
1887bccab6a0SMike Snitzer 
188866a63635SJoe Thornber static int __init smq_init(void)
188966a63635SJoe Thornber {
189066a63635SJoe Thornber 	int r;
189166a63635SJoe Thornber 
189266a63635SJoe Thornber 	r = dm_cache_policy_register(&smq_policy_type);
189366a63635SJoe Thornber 	if (r) {
189466a63635SJoe Thornber 		DMERR("register failed %d", r);
189566a63635SJoe Thornber 		return -ENOMEM;
189666a63635SJoe Thornber 	}
189766a63635SJoe Thornber 
18989ed84698SJoe Thornber 	r = dm_cache_policy_register(&mq_policy_type);
18999ed84698SJoe Thornber 	if (r) {
19007dd85bb0SMike Snitzer 		DMERR("register failed (as mq) %d", r);
1901b29d4986SJoe Thornber 		goto out_mq;
1902b29d4986SJoe Thornber 	}
1903b29d4986SJoe Thornber 
1904b29d4986SJoe Thornber 	r = dm_cache_policy_register(&cleaner_policy_type);
1905b29d4986SJoe Thornber 	if (r) {
1906b29d4986SJoe Thornber 		DMERR("register failed (as cleaner) %d", r);
1907b29d4986SJoe Thornber 		goto out_cleaner;
19089ed84698SJoe Thornber 	}
19099ed84698SJoe Thornber 
1910bccab6a0SMike Snitzer 	r = dm_cache_policy_register(&default_policy_type);
1911bccab6a0SMike Snitzer 	if (r) {
1912bccab6a0SMike Snitzer 		DMERR("register failed (as default) %d", r);
1913b29d4986SJoe Thornber 		goto out_default;
1914bccab6a0SMike Snitzer 	}
1915bccab6a0SMike Snitzer 
191666a63635SJoe Thornber 	return 0;
1917b29d4986SJoe Thornber 
1918b29d4986SJoe Thornber out_default:
1919b29d4986SJoe Thornber 	dm_cache_policy_unregister(&cleaner_policy_type);
1920b29d4986SJoe Thornber out_cleaner:
1921b29d4986SJoe Thornber 	dm_cache_policy_unregister(&mq_policy_type);
1922b29d4986SJoe Thornber out_mq:
1923b29d4986SJoe Thornber 	dm_cache_policy_unregister(&smq_policy_type);
1924b29d4986SJoe Thornber 
1925b29d4986SJoe Thornber 	return -ENOMEM;
192666a63635SJoe Thornber }
192766a63635SJoe Thornber 
192866a63635SJoe Thornber static void __exit smq_exit(void)
192966a63635SJoe Thornber {
1930b29d4986SJoe Thornber 	dm_cache_policy_unregister(&cleaner_policy_type);
193166a63635SJoe Thornber 	dm_cache_policy_unregister(&smq_policy_type);
19329ed84698SJoe Thornber 	dm_cache_policy_unregister(&mq_policy_type);
1933bccab6a0SMike Snitzer 	dm_cache_policy_unregister(&default_policy_type);
193466a63635SJoe Thornber }
193566a63635SJoe Thornber 
193666a63635SJoe Thornber module_init(smq_init);
193766a63635SJoe Thornber module_exit(smq_exit);
193866a63635SJoe Thornber 
193966a63635SJoe Thornber MODULE_AUTHOR("Joe Thornber <dm-devel@redhat.com>");
194066a63635SJoe Thornber MODULE_LICENSE("GPL");
194166a63635SJoe Thornber MODULE_DESCRIPTION("smq cache policy");
194234dd0517SYi Zhang 
194334dd0517SYi Zhang MODULE_ALIAS("dm-cache-default");
19449ed84698SJoe Thornber MODULE_ALIAS("dm-cache-mq");
1945b29d4986SJoe Thornber MODULE_ALIAS("dm-cache-cleaner");
1946