190b90d4aSFilipe Manana // SPDX-License-Identifier: GPL-2.0
290b90d4aSFilipe Manana
390b90d4aSFilipe Manana #include <linux/mm.h>
490b90d4aSFilipe Manana #include "lru_cache.h"
590b90d4aSFilipe Manana #include "messages.h"
690b90d4aSFilipe Manana
790b90d4aSFilipe Manana /*
890b90d4aSFilipe Manana * Initialize a cache object.
990b90d4aSFilipe Manana *
1090b90d4aSFilipe Manana * @cache: The cache.
1190b90d4aSFilipe Manana * @max_size: Maximum size (number of entries) for the cache.
12*3e49363bSFilipe Manana * Use 0 for unlimited size, it's the user's responsability to
13*3e49363bSFilipe Manana * trim the cache in that case.
1490b90d4aSFilipe Manana */
btrfs_lru_cache_init(struct btrfs_lru_cache * cache,unsigned int max_size)1590b90d4aSFilipe Manana void btrfs_lru_cache_init(struct btrfs_lru_cache *cache, unsigned int max_size)
1690b90d4aSFilipe Manana {
1790b90d4aSFilipe Manana INIT_LIST_HEAD(&cache->lru_list);
1890b90d4aSFilipe Manana mt_init(&cache->entries);
1990b90d4aSFilipe Manana cache->size = 0;
2090b90d4aSFilipe Manana cache->max_size = max_size;
2190b90d4aSFilipe Manana }
2290b90d4aSFilipe Manana
match_entry(struct list_head * head,u64 key,u64 gen)230da0c560SFilipe Manana static struct btrfs_lru_cache_entry *match_entry(struct list_head *head, u64 key,
240da0c560SFilipe Manana u64 gen)
256273ee62SFilipe Manana {
266273ee62SFilipe Manana struct btrfs_lru_cache_entry *entry;
276273ee62SFilipe Manana
286273ee62SFilipe Manana list_for_each_entry(entry, head, list) {
290da0c560SFilipe Manana if (entry->key == key && entry->gen == gen)
306273ee62SFilipe Manana return entry;
316273ee62SFilipe Manana }
326273ee62SFilipe Manana
336273ee62SFilipe Manana return NULL;
346273ee62SFilipe Manana }
356273ee62SFilipe Manana
3690b90d4aSFilipe Manana /*
3790b90d4aSFilipe Manana * Lookup for an entry in the cache.
3890b90d4aSFilipe Manana *
3990b90d4aSFilipe Manana * @cache: The cache.
4090b90d4aSFilipe Manana * @key: The key of the entry we are looking for.
410da0c560SFilipe Manana * @gen: Generation associated to the key.
4290b90d4aSFilipe Manana *
4390b90d4aSFilipe Manana * Returns the entry associated with the key or NULL if none found.
4490b90d4aSFilipe Manana */
btrfs_lru_cache_lookup(struct btrfs_lru_cache * cache,u64 key,u64 gen)4590b90d4aSFilipe Manana struct btrfs_lru_cache_entry *btrfs_lru_cache_lookup(struct btrfs_lru_cache *cache,
460da0c560SFilipe Manana u64 key, u64 gen)
4790b90d4aSFilipe Manana {
486273ee62SFilipe Manana struct list_head *head;
4990b90d4aSFilipe Manana struct btrfs_lru_cache_entry *entry;
5090b90d4aSFilipe Manana
516273ee62SFilipe Manana head = mtree_load(&cache->entries, key);
526273ee62SFilipe Manana if (!head)
536273ee62SFilipe Manana return NULL;
546273ee62SFilipe Manana
550da0c560SFilipe Manana entry = match_entry(head, key, gen);
5690b90d4aSFilipe Manana if (entry)
5790b90d4aSFilipe Manana list_move_tail(&entry->lru_list, &cache->lru_list);
5890b90d4aSFilipe Manana
5990b90d4aSFilipe Manana return entry;
6090b90d4aSFilipe Manana }
6190b90d4aSFilipe Manana
62d588adaeSFilipe Manana /*
63d588adaeSFilipe Manana * Remove an entry from the cache.
64d588adaeSFilipe Manana *
65d588adaeSFilipe Manana * @cache: The cache to remove from.
66d588adaeSFilipe Manana * @entry: The entry to remove from the cache.
67d588adaeSFilipe Manana *
68d588adaeSFilipe Manana * Note: this also frees the memory used by the entry.
69d588adaeSFilipe Manana */
btrfs_lru_cache_remove(struct btrfs_lru_cache * cache,struct btrfs_lru_cache_entry * entry)70d588adaeSFilipe Manana void btrfs_lru_cache_remove(struct btrfs_lru_cache *cache,
716273ee62SFilipe Manana struct btrfs_lru_cache_entry *entry)
726273ee62SFilipe Manana {
736273ee62SFilipe Manana struct list_head *prev = entry->list.prev;
746273ee62SFilipe Manana
756273ee62SFilipe Manana ASSERT(cache->size > 0);
766273ee62SFilipe Manana ASSERT(!mtree_empty(&cache->entries));
776273ee62SFilipe Manana
786273ee62SFilipe Manana list_del(&entry->list);
796273ee62SFilipe Manana list_del(&entry->lru_list);
806273ee62SFilipe Manana
816273ee62SFilipe Manana if (list_empty(prev)) {
826273ee62SFilipe Manana struct list_head *head;
836273ee62SFilipe Manana
846273ee62SFilipe Manana /*
856273ee62SFilipe Manana * If previous element in the list entry->list is now empty, it
866273ee62SFilipe Manana * means it's a head entry not pointing to any cached entries,
876273ee62SFilipe Manana * so remove it from the maple tree and free it.
886273ee62SFilipe Manana */
896273ee62SFilipe Manana head = mtree_erase(&cache->entries, entry->key);
906273ee62SFilipe Manana ASSERT(head == prev);
916273ee62SFilipe Manana kfree(head);
926273ee62SFilipe Manana }
936273ee62SFilipe Manana
946273ee62SFilipe Manana kfree(entry);
956273ee62SFilipe Manana cache->size--;
966273ee62SFilipe Manana }
976273ee62SFilipe Manana
9890b90d4aSFilipe Manana /*
9990b90d4aSFilipe Manana * Store an entry in the cache.
10090b90d4aSFilipe Manana *
10190b90d4aSFilipe Manana * @cache: The cache.
10290b90d4aSFilipe Manana * @entry: The entry to store.
10390b90d4aSFilipe Manana *
10490b90d4aSFilipe Manana * Returns 0 on success and < 0 on error.
10590b90d4aSFilipe Manana */
btrfs_lru_cache_store(struct btrfs_lru_cache * cache,struct btrfs_lru_cache_entry * new_entry,gfp_t gfp)10690b90d4aSFilipe Manana int btrfs_lru_cache_store(struct btrfs_lru_cache *cache,
10790b90d4aSFilipe Manana struct btrfs_lru_cache_entry *new_entry,
10890b90d4aSFilipe Manana gfp_t gfp)
10990b90d4aSFilipe Manana {
1106273ee62SFilipe Manana const u64 key = new_entry->key;
1116273ee62SFilipe Manana struct list_head *head;
11290b90d4aSFilipe Manana int ret;
11390b90d4aSFilipe Manana
1146273ee62SFilipe Manana head = kmalloc(sizeof(*head), gfp);
1156273ee62SFilipe Manana if (!head)
1166273ee62SFilipe Manana return -ENOMEM;
1176273ee62SFilipe Manana
1186273ee62SFilipe Manana ret = mtree_insert(&cache->entries, key, head, gfp);
1196273ee62SFilipe Manana if (ret == 0) {
1206273ee62SFilipe Manana INIT_LIST_HEAD(head);
1216273ee62SFilipe Manana list_add_tail(&new_entry->list, head);
1226273ee62SFilipe Manana } else if (ret == -EEXIST) {
1236273ee62SFilipe Manana kfree(head);
1246273ee62SFilipe Manana head = mtree_load(&cache->entries, key);
1256273ee62SFilipe Manana ASSERT(head != NULL);
1260da0c560SFilipe Manana if (match_entry(head, key, new_entry->gen) != NULL)
1276273ee62SFilipe Manana return -EEXIST;
1286273ee62SFilipe Manana list_add_tail(&new_entry->list, head);
1296273ee62SFilipe Manana } else if (ret < 0) {
1306273ee62SFilipe Manana kfree(head);
1316273ee62SFilipe Manana return ret;
1326273ee62SFilipe Manana }
1336273ee62SFilipe Manana
134*3e49363bSFilipe Manana if (cache->max_size > 0 && cache->size == cache->max_size) {
13590b90d4aSFilipe Manana struct btrfs_lru_cache_entry *lru_entry;
13690b90d4aSFilipe Manana
13790b90d4aSFilipe Manana lru_entry = list_first_entry(&cache->lru_list,
13890b90d4aSFilipe Manana struct btrfs_lru_cache_entry,
13990b90d4aSFilipe Manana lru_list);
140d588adaeSFilipe Manana btrfs_lru_cache_remove(cache, lru_entry);
14190b90d4aSFilipe Manana }
14290b90d4aSFilipe Manana
14390b90d4aSFilipe Manana list_add_tail(&new_entry->lru_list, &cache->lru_list);
14490b90d4aSFilipe Manana cache->size++;
14590b90d4aSFilipe Manana
14690b90d4aSFilipe Manana return 0;
14790b90d4aSFilipe Manana }
14890b90d4aSFilipe Manana
14990b90d4aSFilipe Manana /*
15090b90d4aSFilipe Manana * Empty a cache.
15190b90d4aSFilipe Manana *
15290b90d4aSFilipe Manana * @cache: The cache to empty.
15390b90d4aSFilipe Manana *
15490b90d4aSFilipe Manana * Removes all entries from the cache.
15590b90d4aSFilipe Manana */
btrfs_lru_cache_clear(struct btrfs_lru_cache * cache)15690b90d4aSFilipe Manana void btrfs_lru_cache_clear(struct btrfs_lru_cache *cache)
15790b90d4aSFilipe Manana {
15890b90d4aSFilipe Manana struct btrfs_lru_cache_entry *entry;
15990b90d4aSFilipe Manana struct btrfs_lru_cache_entry *tmp;
16090b90d4aSFilipe Manana
16190b90d4aSFilipe Manana list_for_each_entry_safe(entry, tmp, &cache->lru_list, lru_list)
162d588adaeSFilipe Manana btrfs_lru_cache_remove(cache, entry);
16390b90d4aSFilipe Manana
1646273ee62SFilipe Manana ASSERT(cache->size == 0);
1656273ee62SFilipe Manana ASSERT(mtree_empty(&cache->entries));
16690b90d4aSFilipe Manana }
167