162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci   lru_cache.c
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci   This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci   Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
862306a36Sopenharmony_ci   Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
962306a36Sopenharmony_ci   Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/bitops.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/string.h> /* for memset */
1862306a36Sopenharmony_ci#include <linux/seq_file.h> /* for seq_printf */
1962306a36Sopenharmony_ci#include <linux/lru_cache.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciMODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, "
2262306a36Sopenharmony_ci	      "Lars Ellenberg <lars@linbit.com>");
2362306a36Sopenharmony_ciMODULE_DESCRIPTION("lru_cache - Track sets of hot objects");
2462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* this is developers aid only.
2762306a36Sopenharmony_ci * it catches concurrent access (lack of locking on the users part) */
2862306a36Sopenharmony_ci#define PARANOIA_ENTRY() do {		\
2962306a36Sopenharmony_ci	BUG_ON(!lc);			\
3062306a36Sopenharmony_ci	BUG_ON(!lc->nr_elements);	\
3162306a36Sopenharmony_ci	BUG_ON(test_and_set_bit(__LC_PARANOIA, &lc->flags)); \
3262306a36Sopenharmony_ci} while (0)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define RETURN(x...)     do { \
3562306a36Sopenharmony_ci	clear_bit_unlock(__LC_PARANOIA, &lc->flags); \
3662306a36Sopenharmony_ci	return x ; } while (0)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* BUG() if e is not one of the elements tracked by lc */
3962306a36Sopenharmony_ci#define PARANOIA_LC_ELEMENT(lc, e) do {	\
4062306a36Sopenharmony_ci	struct lru_cache *lc_ = (lc);	\
4162306a36Sopenharmony_ci	struct lc_element *e_ = (e);	\
4262306a36Sopenharmony_ci	unsigned i = e_->lc_index;	\
4362306a36Sopenharmony_ci	BUG_ON(i >= lc_->nr_elements);	\
4462306a36Sopenharmony_ci	BUG_ON(lc_->lc_element[i] != e_); } while (0)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/* We need to atomically
4862306a36Sopenharmony_ci *  - try to grab the lock (set LC_LOCKED)
4962306a36Sopenharmony_ci *  - only if there is no pending transaction
5062306a36Sopenharmony_ci *    (neither LC_DIRTY nor LC_STARVING is set)
5162306a36Sopenharmony_ci * Because of PARANOIA_ENTRY() above abusing lc->flags as well,
5262306a36Sopenharmony_ci * it is not sufficient to just say
5362306a36Sopenharmony_ci *	return 0 == cmpxchg(&lc->flags, 0, LC_LOCKED);
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_ciint lc_try_lock(struct lru_cache *lc)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	unsigned long val;
5862306a36Sopenharmony_ci	do {
5962306a36Sopenharmony_ci		val = cmpxchg(&lc->flags, 0, LC_LOCKED);
6062306a36Sopenharmony_ci	} while (unlikely (val == LC_PARANOIA));
6162306a36Sopenharmony_ci	/* Spin until no-one is inside a PARANOIA_ENTRY()/RETURN() section. */
6262306a36Sopenharmony_ci	return 0 == val;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/**
6662306a36Sopenharmony_ci * lc_create - prepares to track objects in an active set
6762306a36Sopenharmony_ci * @name: descriptive name only used in lc_seq_printf_stats and lc_seq_dump_details
6862306a36Sopenharmony_ci * @cache: cache root pointer
6962306a36Sopenharmony_ci * @max_pending_changes: maximum changes to accumulate until a transaction is required
7062306a36Sopenharmony_ci * @e_count: number of elements allowed to be active simultaneously
7162306a36Sopenharmony_ci * @e_size: size of the tracked objects
7262306a36Sopenharmony_ci * @e_off: offset to the &struct lc_element member in a tracked object
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * Returns a pointer to a newly initialized struct lru_cache on success,
7562306a36Sopenharmony_ci * or NULL on (allocation) failure.
7662306a36Sopenharmony_ci */
7762306a36Sopenharmony_cistruct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
7862306a36Sopenharmony_ci		unsigned max_pending_changes,
7962306a36Sopenharmony_ci		unsigned e_count, size_t e_size, size_t e_off)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	struct hlist_head *slot = NULL;
8262306a36Sopenharmony_ci	struct lc_element **element = NULL;
8362306a36Sopenharmony_ci	struct lru_cache *lc;
8462306a36Sopenharmony_ci	struct lc_element *e;
8562306a36Sopenharmony_ci	unsigned cache_obj_size = kmem_cache_size(cache);
8662306a36Sopenharmony_ci	unsigned i;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	WARN_ON(cache_obj_size < e_size);
8962306a36Sopenharmony_ci	if (cache_obj_size < e_size)
9062306a36Sopenharmony_ci		return NULL;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/* e_count too big; would probably fail the allocation below anyways.
9362306a36Sopenharmony_ci	 * for typical use cases, e_count should be few thousand at most. */
9462306a36Sopenharmony_ci	if (e_count > LC_MAX_ACTIVE)
9562306a36Sopenharmony_ci		return NULL;
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	slot = kcalloc(e_count, sizeof(struct hlist_head), GFP_KERNEL);
9862306a36Sopenharmony_ci	if (!slot)
9962306a36Sopenharmony_ci		goto out_fail;
10062306a36Sopenharmony_ci	element = kcalloc(e_count, sizeof(struct lc_element *), GFP_KERNEL);
10162306a36Sopenharmony_ci	if (!element)
10262306a36Sopenharmony_ci		goto out_fail;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	lc = kzalloc(sizeof(*lc), GFP_KERNEL);
10562306a36Sopenharmony_ci	if (!lc)
10662306a36Sopenharmony_ci		goto out_fail;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	INIT_LIST_HEAD(&lc->in_use);
10962306a36Sopenharmony_ci	INIT_LIST_HEAD(&lc->lru);
11062306a36Sopenharmony_ci	INIT_LIST_HEAD(&lc->free);
11162306a36Sopenharmony_ci	INIT_LIST_HEAD(&lc->to_be_changed);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	lc->name = name;
11462306a36Sopenharmony_ci	lc->element_size = e_size;
11562306a36Sopenharmony_ci	lc->element_off = e_off;
11662306a36Sopenharmony_ci	lc->nr_elements = e_count;
11762306a36Sopenharmony_ci	lc->max_pending_changes = max_pending_changes;
11862306a36Sopenharmony_ci	lc->lc_cache = cache;
11962306a36Sopenharmony_ci	lc->lc_element = element;
12062306a36Sopenharmony_ci	lc->lc_slot = slot;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	/* preallocate all objects */
12362306a36Sopenharmony_ci	for (i = 0; i < e_count; i++) {
12462306a36Sopenharmony_ci		void *p = kmem_cache_alloc(cache, GFP_KERNEL);
12562306a36Sopenharmony_ci		if (!p)
12662306a36Sopenharmony_ci			break;
12762306a36Sopenharmony_ci		memset(p, 0, lc->element_size);
12862306a36Sopenharmony_ci		e = p + e_off;
12962306a36Sopenharmony_ci		e->lc_index = i;
13062306a36Sopenharmony_ci		e->lc_number = LC_FREE;
13162306a36Sopenharmony_ci		e->lc_new_number = LC_FREE;
13262306a36Sopenharmony_ci		list_add(&e->list, &lc->free);
13362306a36Sopenharmony_ci		element[i] = e;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci	if (i == e_count)
13662306a36Sopenharmony_ci		return lc;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/* else: could not allocate all elements, give up */
13962306a36Sopenharmony_ci	while (i) {
14062306a36Sopenharmony_ci		void *p = element[--i];
14162306a36Sopenharmony_ci		kmem_cache_free(cache, p - e_off);
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci	kfree(lc);
14462306a36Sopenharmony_ciout_fail:
14562306a36Sopenharmony_ci	kfree(element);
14662306a36Sopenharmony_ci	kfree(slot);
14762306a36Sopenharmony_ci	return NULL;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void lc_free_by_index(struct lru_cache *lc, unsigned i)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	void *p = lc->lc_element[i];
15362306a36Sopenharmony_ci	WARN_ON(!p);
15462306a36Sopenharmony_ci	if (p) {
15562306a36Sopenharmony_ci		p -= lc->element_off;
15662306a36Sopenharmony_ci		kmem_cache_free(lc->lc_cache, p);
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci/**
16162306a36Sopenharmony_ci * lc_destroy - frees memory allocated by lc_create()
16262306a36Sopenharmony_ci * @lc: the lru cache to destroy
16362306a36Sopenharmony_ci */
16462306a36Sopenharmony_civoid lc_destroy(struct lru_cache *lc)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	unsigned i;
16762306a36Sopenharmony_ci	if (!lc)
16862306a36Sopenharmony_ci		return;
16962306a36Sopenharmony_ci	for (i = 0; i < lc->nr_elements; i++)
17062306a36Sopenharmony_ci		lc_free_by_index(lc, i);
17162306a36Sopenharmony_ci	kfree(lc->lc_element);
17262306a36Sopenharmony_ci	kfree(lc->lc_slot);
17362306a36Sopenharmony_ci	kfree(lc);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci/**
17762306a36Sopenharmony_ci * lc_reset - does a full reset for @lc and the hash table slots.
17862306a36Sopenharmony_ci * @lc: the lru cache to operate on
17962306a36Sopenharmony_ci *
18062306a36Sopenharmony_ci * It is roughly the equivalent of re-allocating a fresh lru_cache object,
18162306a36Sopenharmony_ci * basically a short cut to lc_destroy(lc); lc = lc_create(...);
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_civoid lc_reset(struct lru_cache *lc)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	unsigned i;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	INIT_LIST_HEAD(&lc->in_use);
18862306a36Sopenharmony_ci	INIT_LIST_HEAD(&lc->lru);
18962306a36Sopenharmony_ci	INIT_LIST_HEAD(&lc->free);
19062306a36Sopenharmony_ci	INIT_LIST_HEAD(&lc->to_be_changed);
19162306a36Sopenharmony_ci	lc->used = 0;
19262306a36Sopenharmony_ci	lc->hits = 0;
19362306a36Sopenharmony_ci	lc->misses = 0;
19462306a36Sopenharmony_ci	lc->starving = 0;
19562306a36Sopenharmony_ci	lc->locked = 0;
19662306a36Sopenharmony_ci	lc->changed = 0;
19762306a36Sopenharmony_ci	lc->pending_changes = 0;
19862306a36Sopenharmony_ci	lc->flags = 0;
19962306a36Sopenharmony_ci	memset(lc->lc_slot, 0, sizeof(struct hlist_head) * lc->nr_elements);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	for (i = 0; i < lc->nr_elements; i++) {
20262306a36Sopenharmony_ci		struct lc_element *e = lc->lc_element[i];
20362306a36Sopenharmony_ci		void *p = e;
20462306a36Sopenharmony_ci		p -= lc->element_off;
20562306a36Sopenharmony_ci		memset(p, 0, lc->element_size);
20662306a36Sopenharmony_ci		/* re-init it */
20762306a36Sopenharmony_ci		e->lc_index = i;
20862306a36Sopenharmony_ci		e->lc_number = LC_FREE;
20962306a36Sopenharmony_ci		e->lc_new_number = LC_FREE;
21062306a36Sopenharmony_ci		list_add(&e->list, &lc->free);
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/**
21562306a36Sopenharmony_ci * lc_seq_printf_stats - print stats about @lc into @seq
21662306a36Sopenharmony_ci * @seq: the seq_file to print into
21762306a36Sopenharmony_ci * @lc: the lru cache to print statistics of
21862306a36Sopenharmony_ci */
21962306a36Sopenharmony_civoid lc_seq_printf_stats(struct seq_file *seq, struct lru_cache *lc)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	/* NOTE:
22262306a36Sopenharmony_ci	 * total calls to lc_get are
22362306a36Sopenharmony_ci	 * (starving + hits + misses)
22462306a36Sopenharmony_ci	 * misses include "locked" count (update from an other thread in
22562306a36Sopenharmony_ci	 * progress) and "changed", when this in fact lead to an successful
22662306a36Sopenharmony_ci	 * update of the cache.
22762306a36Sopenharmony_ci	 */
22862306a36Sopenharmony_ci	seq_printf(seq, "\t%s: used:%u/%u hits:%lu misses:%lu starving:%lu locked:%lu changed:%lu\n",
22962306a36Sopenharmony_ci		   lc->name, lc->used, lc->nr_elements,
23062306a36Sopenharmony_ci		   lc->hits, lc->misses, lc->starving, lc->locked, lc->changed);
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic struct hlist_head *lc_hash_slot(struct lru_cache *lc, unsigned int enr)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	return  lc->lc_slot + (enr % lc->nr_elements);
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic struct lc_element *__lc_find(struct lru_cache *lc, unsigned int enr,
24062306a36Sopenharmony_ci		bool include_changing)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct lc_element *e;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	BUG_ON(!lc);
24562306a36Sopenharmony_ci	BUG_ON(!lc->nr_elements);
24662306a36Sopenharmony_ci	hlist_for_each_entry(e, lc_hash_slot(lc, enr), colision) {
24762306a36Sopenharmony_ci		/* "about to be changed" elements, pending transaction commit,
24862306a36Sopenharmony_ci		 * are hashed by their "new number". "Normal" elements have
24962306a36Sopenharmony_ci		 * lc_number == lc_new_number. */
25062306a36Sopenharmony_ci		if (e->lc_new_number != enr)
25162306a36Sopenharmony_ci			continue;
25262306a36Sopenharmony_ci		if (e->lc_new_number == e->lc_number || include_changing)
25362306a36Sopenharmony_ci			return e;
25462306a36Sopenharmony_ci		break;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci	return NULL;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci/**
26062306a36Sopenharmony_ci * lc_find - find element by label, if present in the hash table
26162306a36Sopenharmony_ci * @lc: The lru_cache object
26262306a36Sopenharmony_ci * @enr: element number
26362306a36Sopenharmony_ci *
26462306a36Sopenharmony_ci * Returns the pointer to an element, if the element with the requested
26562306a36Sopenharmony_ci * "label" or element number is present in the hash table,
26662306a36Sopenharmony_ci * or NULL if not found. Does not change the refcnt.
26762306a36Sopenharmony_ci * Ignores elements that are "about to be used", i.e. not yet in the active
26862306a36Sopenharmony_ci * set, but still pending transaction commit.
26962306a36Sopenharmony_ci */
27062306a36Sopenharmony_cistruct lc_element *lc_find(struct lru_cache *lc, unsigned int enr)
27162306a36Sopenharmony_ci{
27262306a36Sopenharmony_ci	return __lc_find(lc, enr, 0);
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci/**
27662306a36Sopenharmony_ci * lc_is_used - find element by label
27762306a36Sopenharmony_ci * @lc: The lru_cache object
27862306a36Sopenharmony_ci * @enr: element number
27962306a36Sopenharmony_ci *
28062306a36Sopenharmony_ci * Returns true, if the element with the requested "label" or element number is
28162306a36Sopenharmony_ci * present in the hash table, and is used (refcnt > 0).
28262306a36Sopenharmony_ci * Also finds elements that are not _currently_ used but only "about to be
28362306a36Sopenharmony_ci * used", i.e. on the "to_be_changed" list, pending transaction commit.
28462306a36Sopenharmony_ci */
28562306a36Sopenharmony_cibool lc_is_used(struct lru_cache *lc, unsigned int enr)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	struct lc_element *e = __lc_find(lc, enr, 1);
28862306a36Sopenharmony_ci	return e && e->refcnt;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/**
29262306a36Sopenharmony_ci * lc_del - removes an element from the cache
29362306a36Sopenharmony_ci * @lc: The lru_cache object
29462306a36Sopenharmony_ci * @e: The element to remove
29562306a36Sopenharmony_ci *
29662306a36Sopenharmony_ci * @e must be unused (refcnt == 0). Moves @e from "lru" to "free" list,
29762306a36Sopenharmony_ci * sets @e->enr to %LC_FREE.
29862306a36Sopenharmony_ci */
29962306a36Sopenharmony_civoid lc_del(struct lru_cache *lc, struct lc_element *e)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	PARANOIA_ENTRY();
30262306a36Sopenharmony_ci	PARANOIA_LC_ELEMENT(lc, e);
30362306a36Sopenharmony_ci	BUG_ON(e->refcnt);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	e->lc_number = e->lc_new_number = LC_FREE;
30662306a36Sopenharmony_ci	hlist_del_init(&e->colision);
30762306a36Sopenharmony_ci	list_move(&e->list, &lc->free);
30862306a36Sopenharmony_ci	RETURN();
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic struct lc_element *lc_prepare_for_change(struct lru_cache *lc, unsigned new_number)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct list_head *n;
31462306a36Sopenharmony_ci	struct lc_element *e;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (!list_empty(&lc->free))
31762306a36Sopenharmony_ci		n = lc->free.next;
31862306a36Sopenharmony_ci	else if (!list_empty(&lc->lru))
31962306a36Sopenharmony_ci		n = lc->lru.prev;
32062306a36Sopenharmony_ci	else
32162306a36Sopenharmony_ci		return NULL;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	e = list_entry(n, struct lc_element, list);
32462306a36Sopenharmony_ci	PARANOIA_LC_ELEMENT(lc, e);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	e->lc_new_number = new_number;
32762306a36Sopenharmony_ci	if (!hlist_unhashed(&e->colision))
32862306a36Sopenharmony_ci		__hlist_del(&e->colision);
32962306a36Sopenharmony_ci	hlist_add_head(&e->colision, lc_hash_slot(lc, new_number));
33062306a36Sopenharmony_ci	list_move(&e->list, &lc->to_be_changed);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return e;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic int lc_unused_element_available(struct lru_cache *lc)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	if (!list_empty(&lc->free))
33862306a36Sopenharmony_ci		return 1; /* something on the free list */
33962306a36Sopenharmony_ci	if (!list_empty(&lc->lru))
34062306a36Sopenharmony_ci		return 1;  /* something to evict */
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	return 0;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci/* used as internal flags to __lc_get */
34662306a36Sopenharmony_cienum {
34762306a36Sopenharmony_ci	LC_GET_MAY_CHANGE = 1,
34862306a36Sopenharmony_ci	LC_GET_MAY_USE_UNCOMMITTED = 2,
34962306a36Sopenharmony_ci};
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic struct lc_element *__lc_get(struct lru_cache *lc, unsigned int enr, unsigned int flags)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct lc_element *e;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	PARANOIA_ENTRY();
35662306a36Sopenharmony_ci	if (test_bit(__LC_STARVING, &lc->flags)) {
35762306a36Sopenharmony_ci		++lc->starving;
35862306a36Sopenharmony_ci		RETURN(NULL);
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	e = __lc_find(lc, enr, 1);
36262306a36Sopenharmony_ci	/* if lc_new_number != lc_number,
36362306a36Sopenharmony_ci	 * this enr is currently being pulled in already,
36462306a36Sopenharmony_ci	 * and will be available once the pending transaction
36562306a36Sopenharmony_ci	 * has been committed. */
36662306a36Sopenharmony_ci	if (e) {
36762306a36Sopenharmony_ci		if (e->lc_new_number != e->lc_number) {
36862306a36Sopenharmony_ci			/* It has been found above, but on the "to_be_changed"
36962306a36Sopenharmony_ci			 * list, not yet committed.  Don't pull it in twice,
37062306a36Sopenharmony_ci			 * wait for the transaction, then try again...
37162306a36Sopenharmony_ci			 */
37262306a36Sopenharmony_ci			if (!(flags & LC_GET_MAY_USE_UNCOMMITTED))
37362306a36Sopenharmony_ci				RETURN(NULL);
37462306a36Sopenharmony_ci			/* ... unless the caller is aware of the implications,
37562306a36Sopenharmony_ci			 * probably preparing a cumulative transaction. */
37662306a36Sopenharmony_ci			++e->refcnt;
37762306a36Sopenharmony_ci			++lc->hits;
37862306a36Sopenharmony_ci			RETURN(e);
37962306a36Sopenharmony_ci		}
38062306a36Sopenharmony_ci		/* else: lc_new_number == lc_number; a real hit. */
38162306a36Sopenharmony_ci		++lc->hits;
38262306a36Sopenharmony_ci		if (e->refcnt++ == 0)
38362306a36Sopenharmony_ci			lc->used++;
38462306a36Sopenharmony_ci		list_move(&e->list, &lc->in_use); /* Not evictable... */
38562306a36Sopenharmony_ci		RETURN(e);
38662306a36Sopenharmony_ci	}
38762306a36Sopenharmony_ci	/* e == NULL */
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	++lc->misses;
39062306a36Sopenharmony_ci	if (!(flags & LC_GET_MAY_CHANGE))
39162306a36Sopenharmony_ci		RETURN(NULL);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* To avoid races with lc_try_lock(), first, mark us dirty
39462306a36Sopenharmony_ci	 * (using test_and_set_bit, as it implies memory barriers), ... */
39562306a36Sopenharmony_ci	test_and_set_bit(__LC_DIRTY, &lc->flags);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/* ... only then check if it is locked anyways. If lc_unlock clears
39862306a36Sopenharmony_ci	 * the dirty bit again, that's not a problem, we will come here again.
39962306a36Sopenharmony_ci	 */
40062306a36Sopenharmony_ci	if (test_bit(__LC_LOCKED, &lc->flags)) {
40162306a36Sopenharmony_ci		++lc->locked;
40262306a36Sopenharmony_ci		RETURN(NULL);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* In case there is nothing available and we can not kick out
40662306a36Sopenharmony_ci	 * the LRU element, we have to wait ...
40762306a36Sopenharmony_ci	 */
40862306a36Sopenharmony_ci	if (!lc_unused_element_available(lc)) {
40962306a36Sopenharmony_ci		set_bit(__LC_STARVING, &lc->flags);
41062306a36Sopenharmony_ci		RETURN(NULL);
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	/* It was not present in the active set.  We are going to recycle an
41462306a36Sopenharmony_ci	 * unused (or even "free") element, but we won't accumulate more than
41562306a36Sopenharmony_ci	 * max_pending_changes changes.  */
41662306a36Sopenharmony_ci	if (lc->pending_changes >= lc->max_pending_changes)
41762306a36Sopenharmony_ci		RETURN(NULL);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	e = lc_prepare_for_change(lc, enr);
42062306a36Sopenharmony_ci	BUG_ON(!e);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	clear_bit(__LC_STARVING, &lc->flags);
42362306a36Sopenharmony_ci	BUG_ON(++e->refcnt != 1);
42462306a36Sopenharmony_ci	lc->used++;
42562306a36Sopenharmony_ci	lc->pending_changes++;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	RETURN(e);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci/**
43162306a36Sopenharmony_ci * lc_get - get element by label, maybe change the active set
43262306a36Sopenharmony_ci * @lc: the lru cache to operate on
43362306a36Sopenharmony_ci * @enr: the label to look up
43462306a36Sopenharmony_ci *
43562306a36Sopenharmony_ci * Finds an element in the cache, increases its usage count,
43662306a36Sopenharmony_ci * "touches" and returns it.
43762306a36Sopenharmony_ci *
43862306a36Sopenharmony_ci * In case the requested number is not present, it needs to be added to the
43962306a36Sopenharmony_ci * cache. Therefore it is possible that an other element becomes evicted from
44062306a36Sopenharmony_ci * the cache. In either case, the user is notified so he is able to e.g. keep
44162306a36Sopenharmony_ci * a persistent log of the cache changes, and therefore the objects in use.
44262306a36Sopenharmony_ci *
44362306a36Sopenharmony_ci * Return values:
44462306a36Sopenharmony_ci *  NULL
44562306a36Sopenharmony_ci *     The cache was marked %LC_STARVING,
44662306a36Sopenharmony_ci *     or the requested label was not in the active set
44762306a36Sopenharmony_ci *     and a changing transaction is still pending (@lc was marked %LC_DIRTY).
44862306a36Sopenharmony_ci *     Or no unused or free element could be recycled (@lc will be marked as
44962306a36Sopenharmony_ci *     %LC_STARVING, blocking further lc_get() operations).
45062306a36Sopenharmony_ci *
45162306a36Sopenharmony_ci *  pointer to the element with the REQUESTED element number.
45262306a36Sopenharmony_ci *     In this case, it can be used right away
45362306a36Sopenharmony_ci *
45462306a36Sopenharmony_ci *  pointer to an UNUSED element with some different element number,
45562306a36Sopenharmony_ci *          where that different number may also be %LC_FREE.
45662306a36Sopenharmony_ci *
45762306a36Sopenharmony_ci *          In this case, the cache is marked %LC_DIRTY,
45862306a36Sopenharmony_ci *          so lc_try_lock() will no longer succeed.
45962306a36Sopenharmony_ci *          The returned element pointer is moved to the "to_be_changed" list,
46062306a36Sopenharmony_ci *          and registered with the new element number on the hash collision chains,
46162306a36Sopenharmony_ci *          so it is possible to pick it up from lc_is_used().
46262306a36Sopenharmony_ci *          Up to "max_pending_changes" (see lc_create()) can be accumulated.
46362306a36Sopenharmony_ci *          The user now should do whatever housekeeping is necessary,
46462306a36Sopenharmony_ci *          typically serialize on lc_try_lock_for_transaction(), then call
46562306a36Sopenharmony_ci *          lc_committed(lc) and lc_unlock(), to finish the change.
46662306a36Sopenharmony_ci *
46762306a36Sopenharmony_ci * NOTE: The user needs to check the lc_number on EACH use, so he recognizes
46862306a36Sopenharmony_ci *       any cache set change.
46962306a36Sopenharmony_ci */
47062306a36Sopenharmony_cistruct lc_element *lc_get(struct lru_cache *lc, unsigned int enr)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	return __lc_get(lc, enr, LC_GET_MAY_CHANGE);
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci/**
47662306a36Sopenharmony_ci * lc_get_cumulative - like lc_get; also finds to-be-changed elements
47762306a36Sopenharmony_ci * @lc: the lru cache to operate on
47862306a36Sopenharmony_ci * @enr: the label to look up
47962306a36Sopenharmony_ci *
48062306a36Sopenharmony_ci * Unlike lc_get this also returns the element for @enr, if it is belonging to
48162306a36Sopenharmony_ci * a pending transaction, so the return values are like for lc_get(),
48262306a36Sopenharmony_ci * plus:
48362306a36Sopenharmony_ci *
48462306a36Sopenharmony_ci * pointer to an element already on the "to_be_changed" list.
48562306a36Sopenharmony_ci * 	In this case, the cache was already marked %LC_DIRTY.
48662306a36Sopenharmony_ci *
48762306a36Sopenharmony_ci * Caller needs to make sure that the pending transaction is completed,
48862306a36Sopenharmony_ci * before proceeding to actually use this element.
48962306a36Sopenharmony_ci */
49062306a36Sopenharmony_cistruct lc_element *lc_get_cumulative(struct lru_cache *lc, unsigned int enr)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	return __lc_get(lc, enr, LC_GET_MAY_CHANGE|LC_GET_MAY_USE_UNCOMMITTED);
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci/**
49662306a36Sopenharmony_ci * lc_try_get - get element by label, if present; do not change the active set
49762306a36Sopenharmony_ci * @lc: the lru cache to operate on
49862306a36Sopenharmony_ci * @enr: the label to look up
49962306a36Sopenharmony_ci *
50062306a36Sopenharmony_ci * Finds an element in the cache, increases its usage count,
50162306a36Sopenharmony_ci * "touches" and returns it.
50262306a36Sopenharmony_ci *
50362306a36Sopenharmony_ci * Return values:
50462306a36Sopenharmony_ci *  NULL
50562306a36Sopenharmony_ci *     The cache was marked %LC_STARVING,
50662306a36Sopenharmony_ci *     or the requested label was not in the active set
50762306a36Sopenharmony_ci *
50862306a36Sopenharmony_ci *  pointer to the element with the REQUESTED element number.
50962306a36Sopenharmony_ci *     In this case, it can be used right away
51062306a36Sopenharmony_ci */
51162306a36Sopenharmony_cistruct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	return __lc_get(lc, enr, 0);
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci/**
51762306a36Sopenharmony_ci * lc_committed - tell @lc that pending changes have been recorded
51862306a36Sopenharmony_ci * @lc: the lru cache to operate on
51962306a36Sopenharmony_ci *
52062306a36Sopenharmony_ci * User is expected to serialize on explicit lc_try_lock_for_transaction()
52162306a36Sopenharmony_ci * before the transaction is started, and later needs to lc_unlock() explicitly
52262306a36Sopenharmony_ci * as well.
52362306a36Sopenharmony_ci */
52462306a36Sopenharmony_civoid lc_committed(struct lru_cache *lc)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	struct lc_element *e, *tmp;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	PARANOIA_ENTRY();
52962306a36Sopenharmony_ci	list_for_each_entry_safe(e, tmp, &lc->to_be_changed, list) {
53062306a36Sopenharmony_ci		/* count number of changes, not number of transactions */
53162306a36Sopenharmony_ci		++lc->changed;
53262306a36Sopenharmony_ci		e->lc_number = e->lc_new_number;
53362306a36Sopenharmony_ci		list_move(&e->list, &lc->in_use);
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci	lc->pending_changes = 0;
53662306a36Sopenharmony_ci	RETURN();
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci/**
54162306a36Sopenharmony_ci * lc_put - give up refcnt of @e
54262306a36Sopenharmony_ci * @lc: the lru cache to operate on
54362306a36Sopenharmony_ci * @e: the element to put
54462306a36Sopenharmony_ci *
54562306a36Sopenharmony_ci * If refcnt reaches zero, the element is moved to the lru list,
54662306a36Sopenharmony_ci * and a %LC_STARVING (if set) is cleared.
54762306a36Sopenharmony_ci * Returns the new (post-decrement) refcnt.
54862306a36Sopenharmony_ci */
54962306a36Sopenharmony_ciunsigned int lc_put(struct lru_cache *lc, struct lc_element *e)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	PARANOIA_ENTRY();
55262306a36Sopenharmony_ci	PARANOIA_LC_ELEMENT(lc, e);
55362306a36Sopenharmony_ci	BUG_ON(e->refcnt == 0);
55462306a36Sopenharmony_ci	BUG_ON(e->lc_number != e->lc_new_number);
55562306a36Sopenharmony_ci	if (--e->refcnt == 0) {
55662306a36Sopenharmony_ci		/* move it to the front of LRU. */
55762306a36Sopenharmony_ci		list_move(&e->list, &lc->lru);
55862306a36Sopenharmony_ci		lc->used--;
55962306a36Sopenharmony_ci		clear_bit_unlock(__LC_STARVING, &lc->flags);
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci	RETURN(e->refcnt);
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci/**
56562306a36Sopenharmony_ci * lc_element_by_index
56662306a36Sopenharmony_ci * @lc: the lru cache to operate on
56762306a36Sopenharmony_ci * @i: the index of the element to return
56862306a36Sopenharmony_ci */
56962306a36Sopenharmony_cistruct lc_element *lc_element_by_index(struct lru_cache *lc, unsigned i)
57062306a36Sopenharmony_ci{
57162306a36Sopenharmony_ci	BUG_ON(i >= lc->nr_elements);
57262306a36Sopenharmony_ci	BUG_ON(lc->lc_element[i] == NULL);
57362306a36Sopenharmony_ci	BUG_ON(lc->lc_element[i]->lc_index != i);
57462306a36Sopenharmony_ci	return lc->lc_element[i];
57562306a36Sopenharmony_ci}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci/**
57862306a36Sopenharmony_ci * lc_seq_dump_details - Dump a complete LRU cache to seq in textual form.
57962306a36Sopenharmony_ci * @lc: the lru cache to operate on
58062306a36Sopenharmony_ci * @seq: the &struct seq_file pointer to seq_printf into
58162306a36Sopenharmony_ci * @utext: user supplied additional "heading" or other info
58262306a36Sopenharmony_ci * @detail: function pointer the user may provide to dump further details
58362306a36Sopenharmony_ci * of the object the lc_element is embedded in. May be NULL.
58462306a36Sopenharmony_ci * Note: a leading space ' ' and trailing newline '\n' is implied.
58562306a36Sopenharmony_ci */
58662306a36Sopenharmony_civoid lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext,
58762306a36Sopenharmony_ci	     void (*detail) (struct seq_file *, struct lc_element *))
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	unsigned int nr_elements = lc->nr_elements;
59062306a36Sopenharmony_ci	struct lc_element *e;
59162306a36Sopenharmony_ci	int i;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	seq_printf(seq, "\tnn: lc_number (new nr) refcnt %s\n ", utext);
59462306a36Sopenharmony_ci	for (i = 0; i < nr_elements; i++) {
59562306a36Sopenharmony_ci		e = lc_element_by_index(lc, i);
59662306a36Sopenharmony_ci		if (e->lc_number != e->lc_new_number)
59762306a36Sopenharmony_ci			seq_printf(seq, "\t%5d: %6d %8d %6d ",
59862306a36Sopenharmony_ci				i, e->lc_number, e->lc_new_number, e->refcnt);
59962306a36Sopenharmony_ci		else
60062306a36Sopenharmony_ci			seq_printf(seq, "\t%5d: %6d %-8s %6d ",
60162306a36Sopenharmony_ci				i, e->lc_number, "-\"-", e->refcnt);
60262306a36Sopenharmony_ci		if (detail)
60362306a36Sopenharmony_ci			detail(seq, e);
60462306a36Sopenharmony_ci		seq_putc(seq, '\n');
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ciEXPORT_SYMBOL(lc_create);
60962306a36Sopenharmony_ciEXPORT_SYMBOL(lc_reset);
61062306a36Sopenharmony_ciEXPORT_SYMBOL(lc_destroy);
61162306a36Sopenharmony_ciEXPORT_SYMBOL(lc_del);
61262306a36Sopenharmony_ciEXPORT_SYMBOL(lc_try_get);
61362306a36Sopenharmony_ciEXPORT_SYMBOL(lc_find);
61462306a36Sopenharmony_ciEXPORT_SYMBOL(lc_get);
61562306a36Sopenharmony_ciEXPORT_SYMBOL(lc_put);
61662306a36Sopenharmony_ciEXPORT_SYMBOL(lc_committed);
61762306a36Sopenharmony_ciEXPORT_SYMBOL(lc_element_by_index);
61862306a36Sopenharmony_ciEXPORT_SYMBOL(lc_seq_printf_stats);
61962306a36Sopenharmony_ciEXPORT_SYMBOL(lc_seq_dump_details);
62062306a36Sopenharmony_ciEXPORT_SYMBOL(lc_try_lock);
62162306a36Sopenharmony_ciEXPORT_SYMBOL(lc_is_used);
62262306a36Sopenharmony_ciEXPORT_SYMBOL(lc_get_cumulative);
623