xref: /openbmc/linux/fs/btrfs/lru_cache.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
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