c6ae4c04a861d (Thomas Gleixner 2019-05-22 09:51:37 +0200 1) // SPDX-License-Identifier: GPL-2.0-or-later
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 2) /*
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 3) lru_cache.c
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 4)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 5) This file is part of DRBD by Philipp Reisner and Lars Ellenberg.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 6)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 7) Copyright (C) 2003-2008, LINBIT Information Technologies GmbH.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 8) Copyright (C) 2003-2008, Philipp Reisner <philipp.reisner@linbit.com>.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 9) Copyright (C) 2003-2008, Lars Ellenberg <lars.ellenberg@linbit.com>.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 10)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 11)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 12) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 13)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 14) #include <linux/module.h>
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 15) #include <linux/bitops.h>
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 16) #include <linux/slab.h>
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 17) #include <linux/string.h> /* for memset */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 18) #include <linux/seq_file.h> /* for seq_printf */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 19) #include <linux/lru_cache.h>
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 20)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 21) MODULE_AUTHOR("Philipp Reisner <phil@linbit.com>, "
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 22) "Lars Ellenberg <lars@linbit.com>");
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 23) MODULE_DESCRIPTION("lru_cache - Track sets of hot objects");
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 24) MODULE_LICENSE("GPL");
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 25)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 26) /* this is developers aid only.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 27) * it catches concurrent access (lack of locking on the users part) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 28) #define PARANOIA_ENTRY() do { \
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 29) BUG_ON(!lc); \
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 30) BUG_ON(!lc->nr_elements); \
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 31) BUG_ON(test_and_set_bit(__LC_PARANOIA, &lc->flags)); \
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 32) } while (0)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 33)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 34) #define RETURN(x...) do { \
4738fa16907a9 (Lars Ellenberg 2011-02-21 13:20:55 +0100 35) clear_bit_unlock(__LC_PARANOIA, &lc->flags); \
4738fa16907a9 (Lars Ellenberg 2011-02-21 13:20:55 +0100 36) return x ; } while (0)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 37)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 38) /* BUG() if e is not one of the elements tracked by lc */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 39) #define PARANOIA_LC_ELEMENT(lc, e) do { \
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 40) struct lru_cache *lc_ = (lc); \
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 41) struct lc_element *e_ = (e); \
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 42) unsigned i = e_->lc_index; \
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 43) BUG_ON(i >= lc_->nr_elements); \
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 44) BUG_ON(lc_->lc_element[i] != e_); } while (0)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 45)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 46)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 47) /* We need to atomically
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 48) * - try to grab the lock (set LC_LOCKED)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 49) * - only if there is no pending transaction
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 50) * (neither LC_DIRTY nor LC_STARVING is set)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 51) * Because of PARANOIA_ENTRY() above abusing lc->flags as well,
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 52) * it is not sufficient to just say
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 53) * return 0 == cmpxchg(&lc->flags, 0, LC_LOCKED);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 54) */
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 55) int lc_try_lock(struct lru_cache *lc)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 56) {
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 57) unsigned long val;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 58) do {
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 59) val = cmpxchg(&lc->flags, 0, LC_LOCKED);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 60) } while (unlikely (val == LC_PARANOIA));
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 61) /* Spin until no-one is inside a PARANOIA_ENTRY()/RETURN() section. */
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 62) return 0 == val;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 63) #if 0
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 64) /* Alternative approach, spin in case someone enters or leaves a
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 65) * PARANOIA_ENTRY()/RETURN() section. */
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 66) unsigned long old, new, val;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 67) do {
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 68) old = lc->flags & LC_PARANOIA;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 69) new = old | LC_LOCKED;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 70) val = cmpxchg(&lc->flags, old, new);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 71) } while (unlikely (val == (old ^ LC_PARANOIA)));
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 72) return old == val;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 73) #endif
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 74) }
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 75)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 76) /**
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 77) * lc_create - prepares to track objects in an active set
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 78) * @name: descriptive name only used in lc_seq_printf_stats and lc_seq_dump_details
c95c2d328cd05 (Randy Dunlap 2021-04-16 15:46:26 -0700 79) * @cache: cache root pointer
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 80) * @max_pending_changes: maximum changes to accumulate until a transaction is required
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 81) * @e_count: number of elements allowed to be active simultaneously
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 82) * @e_size: size of the tracked objects
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 83) * @e_off: offset to the &struct lc_element member in a tracked object
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 84) *
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 85) * Returns a pointer to a newly initialized struct lru_cache on success,
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 86) * or NULL on (allocation) failure.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 87) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 88) struct lru_cache *lc_create(const char *name, struct kmem_cache *cache,
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 89) unsigned max_pending_changes,
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 90) unsigned e_count, size_t e_size, size_t e_off)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 91) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 92) struct hlist_head *slot = NULL;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 93) struct lc_element **element = NULL;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 94) struct lru_cache *lc;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 95) struct lc_element *e;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 96) unsigned cache_obj_size = kmem_cache_size(cache);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 97) unsigned i;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 98)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 99) WARN_ON(cache_obj_size < e_size);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 100) if (cache_obj_size < e_size)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 101) return NULL;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 102)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 103) /* e_count too big; would probably fail the allocation below anyways.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 104) * for typical use cases, e_count should be few thousand at most. */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 105) if (e_count > LC_MAX_ACTIVE)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 106) return NULL;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 107)
a08aa355af18c (Ilia Mirkin 2011-05-24 17:13:30 -0700 108) slot = kcalloc(e_count, sizeof(struct hlist_head), GFP_KERNEL);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 109) if (!slot)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 110) goto out_fail;
6396bb221514d (Kees Cook 2018-06-12 14:03:40 -0700 111) element = kcalloc(e_count, sizeof(struct lc_element *), GFP_KERNEL);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 112) if (!element)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 113) goto out_fail;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 114)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 115) lc = kzalloc(sizeof(*lc), GFP_KERNEL);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 116) if (!lc)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 117) goto out_fail;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 118)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 119) INIT_LIST_HEAD(&lc->in_use);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 120) INIT_LIST_HEAD(&lc->lru);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 121) INIT_LIST_HEAD(&lc->free);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 122) INIT_LIST_HEAD(&lc->to_be_changed);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 123)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 124) lc->name = name;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 125) lc->element_size = e_size;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 126) lc->element_off = e_off;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 127) lc->nr_elements = e_count;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 128) lc->max_pending_changes = max_pending_changes;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 129) lc->lc_cache = cache;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 130) lc->lc_element = element;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 131) lc->lc_slot = slot;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 132)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 133) /* preallocate all objects */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 134) for (i = 0; i < e_count; i++) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 135) void *p = kmem_cache_alloc(cache, GFP_KERNEL);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 136) if (!p)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 137) break;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 138) memset(p, 0, lc->element_size);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 139) e = p + e_off;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 140) e->lc_index = i;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 141) e->lc_number = LC_FREE;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 142) e->lc_new_number = LC_FREE;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 143) list_add(&e->list, &lc->free);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 144) element[i] = e;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 145) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 146) if (i == e_count)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 147) return lc;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 148)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 149) /* else: could not allocate all elements, give up */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 150) for (i--; i; i--) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 151) void *p = element[i];
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 152) kmem_cache_free(cache, p - e_off);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 153) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 154) kfree(lc);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 155) out_fail:
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 156) kfree(element);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 157) kfree(slot);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 158) return NULL;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 159) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 160)
8ce953aa39e2b (Lars Ellenberg 2014-02-27 09:46:18 +0100 161) static void lc_free_by_index(struct lru_cache *lc, unsigned i)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 162) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 163) void *p = lc->lc_element[i];
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 164) WARN_ON(!p);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 165) if (p) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 166) p -= lc->element_off;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 167) kmem_cache_free(lc->lc_cache, p);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 168) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 169) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 170)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 171) /**
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 172) * lc_destroy - frees memory allocated by lc_create()
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 173) * @lc: the lru cache to destroy
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 174) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 175) void lc_destroy(struct lru_cache *lc)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 176) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 177) unsigned i;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 178) if (!lc)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 179) return;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 180) for (i = 0; i < lc->nr_elements; i++)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 181) lc_free_by_index(lc, i);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 182) kfree(lc->lc_element);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 183) kfree(lc->lc_slot);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 184) kfree(lc);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 185) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 186)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 187) /**
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 188) * lc_reset - does a full reset for @lc and the hash table slots.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 189) * @lc: the lru cache to operate on
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 190) *
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 191) * It is roughly the equivalent of re-allocating a fresh lru_cache object,
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 192) * basically a short cut to lc_destroy(lc); lc = lc_create(...);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 193) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 194) void lc_reset(struct lru_cache *lc)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 195) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 196) unsigned i;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 197)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 198) INIT_LIST_HEAD(&lc->in_use);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 199) INIT_LIST_HEAD(&lc->lru);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 200) INIT_LIST_HEAD(&lc->free);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 201) INIT_LIST_HEAD(&lc->to_be_changed);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 202) lc->used = 0;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 203) lc->hits = 0;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 204) lc->misses = 0;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 205) lc->starving = 0;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 206) lc->locked = 0;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 207) lc->changed = 0;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 208) lc->pending_changes = 0;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 209) lc->flags = 0;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 210) memset(lc->lc_slot, 0, sizeof(struct hlist_head) * lc->nr_elements);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 211)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 212) for (i = 0; i < lc->nr_elements; i++) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 213) struct lc_element *e = lc->lc_element[i];
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 214) void *p = e;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 215) p -= lc->element_off;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 216) memset(p, 0, lc->element_size);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 217) /* re-init it */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 218) e->lc_index = i;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 219) e->lc_number = LC_FREE;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 220) e->lc_new_number = LC_FREE;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 221) list_add(&e->list, &lc->free);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 222) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 223) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 224)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 225) /**
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 226) * lc_seq_printf_stats - print stats about @lc into @seq
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 227) * @seq: the seq_file to print into
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 228) * @lc: the lru cache to print statistics of
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 229) */
bb649b34dd3d8 (Roland Kammerer 2015-04-16 10:17:51 +0200 230) void lc_seq_printf_stats(struct seq_file *seq, struct lru_cache *lc)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 231) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 232) /* NOTE:
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 233) * total calls to lc_get are
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 234) * (starving + hits + misses)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 235) * misses include "locked" count (update from an other thread in
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 236) * progress) and "changed", when this in fact lead to an successful
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 237) * update of the cache.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 238) */
d50f8f8d91a7d (Joe Perches 2015-04-15 16:18:25 -0700 239) seq_printf(seq, "\t%s: used:%u/%u hits:%lu misses:%lu starving:%lu locked:%lu changed:%lu\n",
d50f8f8d91a7d (Joe Perches 2015-04-15 16:18:25 -0700 240) lc->name, lc->used, lc->nr_elements,
d50f8f8d91a7d (Joe Perches 2015-04-15 16:18:25 -0700 241) lc->hits, lc->misses, lc->starving, lc->locked, lc->changed);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 242) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 243)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 244) static struct hlist_head *lc_hash_slot(struct lru_cache *lc, unsigned int enr)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 245) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 246) return lc->lc_slot + (enr % lc->nr_elements);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 247) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 248)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 249)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 250) static struct lc_element *__lc_find(struct lru_cache *lc, unsigned int enr,
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 251) bool include_changing)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 252) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 253) struct lc_element *e;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 254)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 255) BUG_ON(!lc);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 256) BUG_ON(!lc->nr_elements);
b67bfe0d42cac (Sasha Levin 2013-02-27 17:06:00 -0800 257) hlist_for_each_entry(e, lc_hash_slot(lc, enr), colision) {
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 258) /* "about to be changed" elements, pending transaction commit,
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 259) * are hashed by their "new number". "Normal" elements have
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 260) * lc_number == lc_new_number. */
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 261) if (e->lc_new_number != enr)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 262) continue;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 263) if (e->lc_new_number == e->lc_number || include_changing)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 264) return e;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 265) break;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 266) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 267) return NULL;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 268) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 269)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 270) /**
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 271) * lc_find - find element by label, if present in the hash table
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 272) * @lc: The lru_cache object
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 273) * @enr: element number
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 274) *
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 275) * Returns the pointer to an element, if the element with the requested
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 276) * "label" or element number is present in the hash table,
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 277) * or NULL if not found. Does not change the refcnt.
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 278) * Ignores elements that are "about to be used", i.e. not yet in the active
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 279) * set, but still pending transaction commit.
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 280) */
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 281) struct lc_element *lc_find(struct lru_cache *lc, unsigned int enr)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 282) {
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 283) return __lc_find(lc, enr, 0);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 284) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 285)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 286) /**
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 287) * lc_is_used - find element by label
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 288) * @lc: The lru_cache object
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 289) * @enr: element number
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 290) *
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 291) * Returns true, if the element with the requested "label" or element number is
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 292) * present in the hash table, and is used (refcnt > 0).
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 293) * Also finds elements that are not _currently_ used but only "about to be
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 294) * used", i.e. on the "to_be_changed" list, pending transaction commit.
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 295) */
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 296) bool lc_is_used(struct lru_cache *lc, unsigned int enr)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 297) {
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 298) struct lc_element *e = __lc_find(lc, enr, 1);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 299) return e && e->refcnt;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 300) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 301)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 302) /**
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 303) * lc_del - removes an element from the cache
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 304) * @lc: The lru_cache object
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 305) * @e: The element to remove
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 306) *
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 307) * @e must be unused (refcnt == 0). Moves @e from "lru" to "free" list,
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 308) * sets @e->enr to %LC_FREE.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 309) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 310) void lc_del(struct lru_cache *lc, struct lc_element *e)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 311) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 312) PARANOIA_ENTRY();
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 313) PARANOIA_LC_ELEMENT(lc, e);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 314) BUG_ON(e->refcnt);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 315)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 316) e->lc_number = e->lc_new_number = LC_FREE;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 317) hlist_del_init(&e->colision);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 318) list_move(&e->list, &lc->free);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 319) RETURN();
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 320) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 321)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 322) static struct lc_element *lc_prepare_for_change(struct lru_cache *lc, unsigned new_number)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 323) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 324) struct list_head *n;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 325) struct lc_element *e;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 326)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 327) if (!list_empty(&lc->free))
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 328) n = lc->free.next;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 329) else if (!list_empty(&lc->lru))
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 330) n = lc->lru.prev;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 331) else
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 332) return NULL;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 333)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 334) e = list_entry(n, struct lc_element, list);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 335) PARANOIA_LC_ELEMENT(lc, e);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 336)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 337) e->lc_new_number = new_number;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 338) if (!hlist_unhashed(&e->colision))
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 339) __hlist_del(&e->colision);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 340) hlist_add_head(&e->colision, lc_hash_slot(lc, new_number));
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 341) list_move(&e->list, &lc->to_be_changed);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 342)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 343) return e;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 344) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 345)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 346) static int lc_unused_element_available(struct lru_cache *lc)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 347) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 348) if (!list_empty(&lc->free))
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 349) return 1; /* something on the free list */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 350) if (!list_empty(&lc->lru))
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 351) return 1; /* something to evict */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 352)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 353) return 0;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 354) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 355)
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 356) /* used as internal flags to __lc_get */
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 357) enum {
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 358) LC_GET_MAY_CHANGE = 1,
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 359) LC_GET_MAY_USE_UNCOMMITTED = 2,
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 360) };
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 361)
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 362) static struct lc_element *__lc_get(struct lru_cache *lc, unsigned int enr, unsigned int flags)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 363) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 364) struct lc_element *e;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 365)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 366) PARANOIA_ENTRY();
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 367) if (lc->flags & LC_STARVING) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 368) ++lc->starving;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 369) RETURN(NULL);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 370) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 371)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 372) e = __lc_find(lc, enr, 1);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 373) /* if lc_new_number != lc_number,
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 374) * this enr is currently being pulled in already,
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 375) * and will be available once the pending transaction
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 376) * has been committed. */
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 377) if (e) {
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 378) if (e->lc_new_number != e->lc_number) {
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 379) /* It has been found above, but on the "to_be_changed"
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 380) * list, not yet committed. Don't pull it in twice,
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 381) * wait for the transaction, then try again...
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 382) */
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 383) if (!(flags & LC_GET_MAY_USE_UNCOMMITTED))
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 384) RETURN(NULL);
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 385) /* ... unless the caller is aware of the implications,
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 386) * probably preparing a cumulative transaction. */
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 387) ++e->refcnt;
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 388) ++lc->hits;
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 389) RETURN(e);
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 390) }
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 391) /* else: lc_new_number == lc_number; a real hit. */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 392) ++lc->hits;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 393) if (e->refcnt++ == 0)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 394) lc->used++;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 395) list_move(&e->list, &lc->in_use); /* Not evictable... */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 396) RETURN(e);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 397) }
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 398) /* e == NULL */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 399)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 400) ++lc->misses;
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 401) if (!(flags & LC_GET_MAY_CHANGE))
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 402) RETURN(NULL);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 403)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 404) /* To avoid races with lc_try_lock(), first, mark us dirty
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 405) * (using test_and_set_bit, as it implies memory barriers), ... */
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 406) test_and_set_bit(__LC_DIRTY, &lc->flags);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 407)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 408) /* ... only then check if it is locked anyways. If lc_unlock clears
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 409) * the dirty bit again, that's not a problem, we will come here again.
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 410) */
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 411) if (test_bit(__LC_LOCKED, &lc->flags)) {
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 412) ++lc->locked;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 413) RETURN(NULL);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 414) }
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 415)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 416) /* In case there is nothing available and we can not kick out
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 417) * the LRU element, we have to wait ...
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 418) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 419) if (!lc_unused_element_available(lc)) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 420) __set_bit(__LC_STARVING, &lc->flags);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 421) RETURN(NULL);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 422) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 423)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 424) /* It was not present in the active set. We are going to recycle an
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 425) * unused (or even "free") element, but we won't accumulate more than
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 426) * max_pending_changes changes. */
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 427) if (lc->pending_changes >= lc->max_pending_changes)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 428) RETURN(NULL);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 429)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 430) e = lc_prepare_for_change(lc, enr);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 431) BUG_ON(!e);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 432)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 433) clear_bit(__LC_STARVING, &lc->flags);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 434) BUG_ON(++e->refcnt != 1);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 435) lc->used++;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 436) lc->pending_changes++;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 437)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 438) RETURN(e);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 439) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 440)
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 441) /**
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 442) * lc_get - get element by label, maybe change the active set
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 443) * @lc: the lru cache to operate on
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 444) * @enr: the label to look up
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 445) *
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 446) * Finds an element in the cache, increases its usage count,
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 447) * "touches" and returns it.
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 448) *
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 449) * In case the requested number is not present, it needs to be added to the
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 450) * cache. Therefore it is possible that an other element becomes evicted from
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 451) * the cache. In either case, the user is notified so he is able to e.g. keep
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 452) * a persistent log of the cache changes, and therefore the objects in use.
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 453) *
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 454) * Return values:
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 455) * NULL
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 456) * The cache was marked %LC_STARVING,
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 457) * or the requested label was not in the active set
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 458) * and a changing transaction is still pending (@lc was marked %LC_DIRTY).
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 459) * Or no unused or free element could be recycled (@lc will be marked as
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 460) * %LC_STARVING, blocking further lc_get() operations).
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 461) *
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 462) * pointer to the element with the REQUESTED element number.
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 463) * In this case, it can be used right away
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 464) *
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 465) * pointer to an UNUSED element with some different element number,
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 466) * where that different number may also be %LC_FREE.
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 467) *
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 468) * In this case, the cache is marked %LC_DIRTY,
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 469) * so lc_try_lock() will no longer succeed.
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 470) * The returned element pointer is moved to the "to_be_changed" list,
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 471) * and registered with the new element number on the hash collision chains,
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 472) * so it is possible to pick it up from lc_is_used().
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 473) * Up to "max_pending_changes" (see lc_create()) can be accumulated.
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 474) * The user now should do whatever housekeeping is necessary,
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 475) * typically serialize on lc_try_lock_for_transaction(), then call
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 476) * lc_committed(lc) and lc_unlock(), to finish the change.
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 477) *
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 478) * NOTE: The user needs to check the lc_number on EACH use, so he recognizes
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 479) * any cache set change.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 480) */
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 481) struct lc_element *lc_get(struct lru_cache *lc, unsigned int enr)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 482) {
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 483) return __lc_get(lc, enr, LC_GET_MAY_CHANGE);
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 484) }
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 485)
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 486) /**
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 487) * lc_get_cumulative - like lc_get; also finds to-be-changed elements
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 488) * @lc: the lru cache to operate on
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 489) * @enr: the label to look up
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 490) *
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 491) * Unlike lc_get this also returns the element for @enr, if it is belonging to
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 492) * a pending transaction, so the return values are like for lc_get(),
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 493) * plus:
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 494) *
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 495) * pointer to an element already on the "to_be_changed" list.
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 496) * In this case, the cache was already marked %LC_DIRTY.
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 497) *
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 498) * Caller needs to make sure that the pending transaction is completed,
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 499) * before proceeding to actually use this element.
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 500) */
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 501) struct lc_element *lc_get_cumulative(struct lru_cache *lc, unsigned int enr)
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 502) {
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 503) return __lc_get(lc, enr, LC_GET_MAY_CHANGE|LC_GET_MAY_USE_UNCOMMITTED);
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 504) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 505)
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 506) /**
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 507) * lc_try_get - get element by label, if present; do not change the active set
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 508) * @lc: the lru cache to operate on
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 509) * @enr: the label to look up
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 510) *
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 511) * Finds an element in the cache, increases its usage count,
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 512) * "touches" and returns it.
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 513) *
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 514) * Return values:
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 515) * NULL
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 516) * The cache was marked %LC_STARVING,
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 517) * or the requested label was not in the active set
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 518) *
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 519) * pointer to the element with the REQUESTED element number.
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 520) * In this case, it can be used right away
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 521) */
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 522) struct lc_element *lc_try_get(struct lru_cache *lc, unsigned int enr)
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 523) {
a9efc748d679e (Lars Ellenberg 2011-02-21 13:20:58 +0100 524) return __lc_get(lc, enr, 0);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 525) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 526)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 527) /**
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 528) * lc_committed - tell @lc that pending changes have been recorded
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 529) * @lc: the lru cache to operate on
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 530) *
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 531) * User is expected to serialize on explicit lc_try_lock_for_transaction()
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 532) * before the transaction is started, and later needs to lc_unlock() explicitly
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 533) * as well.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 534) */
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 535) void lc_committed(struct lru_cache *lc)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 536) {
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 537) struct lc_element *e, *tmp;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 538)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 539) PARANOIA_ENTRY();
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 540) list_for_each_entry_safe(e, tmp, &lc->to_be_changed, list) {
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 541) /* count number of changes, not number of transactions */
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 542) ++lc->changed;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 543) e->lc_number = e->lc_new_number;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 544) list_move(&e->list, &lc->in_use);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 545) }
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 546) lc->pending_changes = 0;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 547) RETURN();
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 548) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 549)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 550)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 551) /**
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 552) * lc_put - give up refcnt of @e
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 553) * @lc: the lru cache to operate on
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 554) * @e: the element to put
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 555) *
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 556) * If refcnt reaches zero, the element is moved to the lru list,
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 557) * and a %LC_STARVING (if set) is cleared.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 558) * Returns the new (post-decrement) refcnt.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 559) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 560) unsigned int lc_put(struct lru_cache *lc, struct lc_element *e)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 561) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 562) PARANOIA_ENTRY();
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 563) PARANOIA_LC_ELEMENT(lc, e);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 564) BUG_ON(e->refcnt == 0);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 565) BUG_ON(e->lc_number != e->lc_new_number);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 566) if (--e->refcnt == 0) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 567) /* move it to the front of LRU. */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 568) list_move(&e->list, &lc->lru);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 569) lc->used--;
4738fa16907a9 (Lars Ellenberg 2011-02-21 13:20:55 +0100 570) clear_bit_unlock(__LC_STARVING, &lc->flags);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 571) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 572) RETURN(e->refcnt);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 573) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 574)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 575) /**
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 576) * lc_element_by_index
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 577) * @lc: the lru cache to operate on
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 578) * @i: the index of the element to return
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 579) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 580) struct lc_element *lc_element_by_index(struct lru_cache *lc, unsigned i)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 581) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 582) BUG_ON(i >= lc->nr_elements);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 583) BUG_ON(lc->lc_element[i] == NULL);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 584) BUG_ON(lc->lc_element[i]->lc_index != i);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 585) return lc->lc_element[i];
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 586) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 587)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 588) /**
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 589) * lc_index_of
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 590) * @lc: the lru cache to operate on
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 591) * @e: the element to query for its index position in lc->element
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 592) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 593) unsigned int lc_index_of(struct lru_cache *lc, struct lc_element *e)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 594) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 595) PARANOIA_LC_ELEMENT(lc, e);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 596) return e->lc_index;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 597) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 598)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 599) /**
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 600) * lc_set - associate index with label
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 601) * @lc: the lru cache to operate on
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 602) * @enr: the label to set
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 603) * @index: the element index to associate label with.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 604) *
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 605) * Used to initialize the active set to some previously recorded state.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 606) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 607) void lc_set(struct lru_cache *lc, unsigned int enr, int index)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 608) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 609) struct lc_element *e;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 610) struct list_head *lh;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 611)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 612) if (index < 0 || index >= lc->nr_elements)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 613) return;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 614)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 615) e = lc_element_by_index(lc, index);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 616) BUG_ON(e->lc_number != e->lc_new_number);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 617) BUG_ON(e->refcnt != 0);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 618)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 619) e->lc_number = e->lc_new_number = enr;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 620) hlist_del_init(&e->colision);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 621) if (enr == LC_FREE)
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 622) lh = &lc->free;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 623) else {
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 624) hlist_add_head(&e->colision, lc_hash_slot(lc, enr));
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 625) lh = &lc->lru;
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 626) }
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 627) list_move(&e->list, lh);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 628) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 629)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 630) /**
c95c2d328cd05 (Randy Dunlap 2021-04-16 15:46:26 -0700 631) * lc_seq_dump_details - Dump a complete LRU cache to seq in textual form.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 632) * @lc: the lru cache to operate on
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 633) * @seq: the &struct seq_file pointer to seq_printf into
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 634) * @utext: user supplied additional "heading" or other info
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 635) * @detail: function pointer the user may provide to dump further details
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 636) * of the object the lc_element is embedded in. May be NULL.
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 637) * Note: a leading space ' ' and trailing newline '\n' is implied.
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 638) */
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 639) void lc_seq_dump_details(struct seq_file *seq, struct lru_cache *lc, char *utext,
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 640) void (*detail) (struct seq_file *, struct lc_element *))
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 641) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 642) unsigned int nr_elements = lc->nr_elements;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 643) struct lc_element *e;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 644) int i;
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 645)
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 646) seq_printf(seq, "\tnn: lc_number (new nr) refcnt %s\n ", utext);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 647) for (i = 0; i < nr_elements; i++) {
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 648) e = lc_element_by_index(lc, i);
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 649) if (e->lc_number != e->lc_new_number)
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 650) seq_printf(seq, "\t%5d: %6d %8d %6d ",
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 651) i, e->lc_number, e->lc_new_number, e->refcnt);
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 652) else
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 653) seq_printf(seq, "\t%5d: %6d %-8s %6d ",
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 654) i, e->lc_number, "-\"-", e->refcnt);
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 655) if (detail)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 656) detail(seq, e);
54e6fc38e888a (Lars Ellenberg 2014-05-08 13:39:35 +0200 657) seq_putc(seq, '\n');
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 658) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 659) }
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 660)
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 661) EXPORT_SYMBOL(lc_create);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 662) EXPORT_SYMBOL(lc_reset);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 663) EXPORT_SYMBOL(lc_destroy);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 664) EXPORT_SYMBOL(lc_set);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 665) EXPORT_SYMBOL(lc_del);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 666) EXPORT_SYMBOL(lc_try_get);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 667) EXPORT_SYMBOL(lc_find);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 668) EXPORT_SYMBOL(lc_get);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 669) EXPORT_SYMBOL(lc_put);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 670) EXPORT_SYMBOL(lc_committed);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 671) EXPORT_SYMBOL(lc_element_by_index);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 672) EXPORT_SYMBOL(lc_index_of);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 673) EXPORT_SYMBOL(lc_seq_printf_stats);
b411b3637fa71 (Philipp Reisner 2009-09-25 16:07:19 -0700 674) EXPORT_SYMBOL(lc_seq_dump_details);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 675) EXPORT_SYMBOL(lc_try_lock);
46a15bc3ec425 (Lars Ellenberg 2011-02-21 13:21:01 +0100 676) EXPORT_SYMBOL(lc_is_used);
cbe5e6109538d (Lars Ellenberg 2013-03-22 22:17:36 -0600 677) EXPORT_SYMBOL(lc_get_cumulative);