166 lines · 3.8 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0 #include <linux/mm.h>#include "lru_cache.h"#include "messages.h" /* * Initialize a cache object. * * @cache:      The cache. * @max_size:   Maximum size (number of entries) for the cache. *              Use 0 for unlimited size, it's the user's responsibility to *              trim the cache in that case. */void btrfs_lru_cache_init(struct btrfs_lru_cache *cache, unsigned int max_size){	INIT_LIST_HEAD(&cache->lru_list);	mt_init(&cache->entries);	cache->size = 0;	cache->max_size = max_size;} static struct btrfs_lru_cache_entry *match_entry(struct list_head *head, u64 key,						 u64 gen){	struct btrfs_lru_cache_entry *entry; 	list_for_each_entry(entry, head, list) {		if (entry->key == key && entry->gen == gen)			return entry;	} 	return NULL;} /* * Lookup for an entry in the cache. * * @cache:      The cache. * @key:        The key of the entry we are looking for. * @gen:        Generation associated to the key. * * Returns the entry associated with the key or NULL if none found. */struct btrfs_lru_cache_entry *btrfs_lru_cache_lookup(struct btrfs_lru_cache *cache,						     u64 key, u64 gen){	struct list_head *head;	struct btrfs_lru_cache_entry *entry; 	head = mtree_load(&cache->entries, key);	if (!head)		return NULL; 	entry = match_entry(head, key, gen);	if (entry)		list_move_tail(&entry->lru_list, &cache->lru_list); 	return entry;} /* * Remove an entry from the cache. * * @cache:     The cache to remove from. * @entry:     The entry to remove from the cache. * * Note: this also frees the memory used by the entry. */void btrfs_lru_cache_remove(struct btrfs_lru_cache *cache,			    struct btrfs_lru_cache_entry *entry){	struct list_head *prev = entry->list.prev; 	ASSERT(cache->size > 0);	ASSERT(!mtree_empty(&cache->entries)); 	list_del(&entry->list);	list_del(&entry->lru_list); 	if (list_empty(prev)) {		struct list_head *head; 		/*		 * If previous element in the list entry->list is now empty, it		 * means it's a head entry not pointing to any cached entries,		 * so remove it from the maple tree and free it.		 */		head = mtree_erase(&cache->entries, entry->key);		ASSERT(head == prev);		kfree(head);	} 	kfree(entry);	cache->size--;} /* * Store an entry in the cache. * * @cache:      The cache. * @entry:      The entry to store. * * Returns 0 on success and < 0 on error. */int btrfs_lru_cache_store(struct btrfs_lru_cache *cache,			  struct btrfs_lru_cache_entry *new_entry,			  gfp_t gfp){	const u64 key = new_entry->key;	struct list_head *head;	int ret; 	head = kmalloc_obj(*head, gfp);	if (!head)		return -ENOMEM; 	ret = mtree_insert(&cache->entries, key, head, gfp);	if (ret == 0) {		INIT_LIST_HEAD(head);		list_add_tail(&new_entry->list, head);	} else if (ret == -EEXIST) {		kfree(head);		head = mtree_load(&cache->entries, key);		ASSERT(head != NULL);		if (match_entry(head, key, new_entry->gen) != NULL)			return -EEXIST;		list_add_tail(&new_entry->list, head);	} else if (ret < 0) {		kfree(head);		return ret;	} 	if (cache->max_size > 0 && cache->size == cache->max_size) {		struct btrfs_lru_cache_entry *lru_entry; 		lru_entry = list_first_entry(&cache->lru_list,					     struct btrfs_lru_cache_entry,					     lru_list);		btrfs_lru_cache_remove(cache, lru_entry);	} 	list_add_tail(&new_entry->lru_list, &cache->lru_list);	cache->size++; 	return 0;} /* * Empty a cache. * * @cache:     The cache to empty. * * Removes all entries from the cache. */void btrfs_lru_cache_clear(struct btrfs_lru_cache *cache){	struct btrfs_lru_cache_entry *entry;	struct btrfs_lru_cache_entry *tmp; 	list_for_each_entry_safe(entry, tmp, &cache->lru_list, lru_list)		btrfs_lru_cache_remove(cache, entry); 	ASSERT(cache->size == 0);	ASSERT(mtree_empty(&cache->entries));}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t