aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/lru_cache.c12
-rw-r--r--fs/btrfs/lru_cache.h9
-rw-r--r--fs/btrfs/send.c8
3 files changed, 20 insertions, 9 deletions
diff --git a/fs/btrfs/lru_cache.c b/fs/btrfs/lru_cache.c
index 6012bceedffc..01821d66a8a2 100644
--- a/fs/btrfs/lru_cache.c
+++ b/fs/btrfs/lru_cache.c
@@ -18,12 +18,13 @@ void btrfs_lru_cache_init(struct btrfs_lru_cache *cache, unsigned int max_size)
cache->max_size = max_size;
}
-static struct btrfs_lru_cache_entry *match_entry(struct list_head *head, u64 key)
+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)
+ if (entry->key == key && entry->gen == gen)
return entry;
}
@@ -35,11 +36,12 @@ static struct btrfs_lru_cache_entry *match_entry(struct list_head *head, u64 key
*
* @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 key, u64 gen)
{
struct list_head *head;
struct btrfs_lru_cache_entry *entry;
@@ -48,7 +50,7 @@ struct btrfs_lru_cache_entry *btrfs_lru_cache_lookup(struct btrfs_lru_cache *cac
if (!head)
return NULL;
- entry = match_entry(head, key);
+ entry = match_entry(head, key, gen);
if (entry)
list_move_tail(&entry->lru_list, &cache->lru_list);
@@ -111,7 +113,7 @@ int btrfs_lru_cache_store(struct btrfs_lru_cache *cache,
kfree(head);
head = mtree_load(&cache->entries, key);
ASSERT(head != NULL);
- if (match_entry(head, key) != NULL)
+ if (match_entry(head, key, new_entry->gen) != NULL)
return -EEXIST;
list_add_tail(&new_entry->list, head);
} else if (ret < 0) {
diff --git a/fs/btrfs/lru_cache.h b/fs/btrfs/lru_cache.h
index 7a255cd2958e..c1f20f4b7038 100644
--- a/fs/btrfs/lru_cache.h
+++ b/fs/btrfs/lru_cache.h
@@ -18,6 +18,13 @@ struct btrfs_lru_cache_entry {
struct list_head lru_list;
u64 key;
/*
+ * Optional generation associated to a key. Use 0 if not needed/used.
+ * Entries with the same key and different generations are stored in a
+ * linked list, so use this only for cases where there's a small number
+ * of different generations.
+ */
+ u64 gen;
+ /*
* The maple tree uses unsigned long type for the keys, which is 32 bits
* on 32 bits systems, and 64 bits on 64 bits systems. So if we want to
* use something like inode numbers as keys, which are always a u64, we
@@ -47,7 +54,7 @@ static inline unsigned int btrfs_lru_cache_size(const struct btrfs_lru_cache *ca
void btrfs_lru_cache_init(struct btrfs_lru_cache *cache, unsigned int max_size);
struct btrfs_lru_cache_entry *btrfs_lru_cache_lookup(struct btrfs_lru_cache *cache,
- u64 key);
+ u64 key, u64 gen);
int btrfs_lru_cache_store(struct btrfs_lru_cache *cache,
struct btrfs_lru_cache_entry *new_entry,
gfp_t gfp);
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 1cde74638939..8a7d8979bf57 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -120,7 +120,7 @@ static_assert(offsetof(struct backref_cache_entry, entry) == 0);
/*
* Max number of entries in the cache that stores directories that were already
* created. The cache uses raw struct btrfs_lru_cache_entry entries, so it uses
- * at most 4096 bytes - sizeof(struct btrfs_lru_cache_entry) is 40 bytes, but
+ * at most 4096 bytes - sizeof(struct btrfs_lru_cache_entry) is 48 bytes, but
* the kmalloc-64 slab is used, so we get 4096 bytes (64 bytes * 64).
*/
#define SEND_MAX_DIR_CREATED_CACHE_SIZE 64
@@ -1422,7 +1422,7 @@ static bool lookup_backref_cache(u64 leaf_bytenr, void *ctx,
return false;
}
- raw_entry = btrfs_lru_cache_lookup(&sctx->backref_cache, key);
+ raw_entry = btrfs_lru_cache_lookup(&sctx->backref_cache, key, 0);
if (!raw_entry)
return false;
@@ -1455,6 +1455,7 @@ static void store_backref_cache(u64 leaf_bytenr, const struct ulist *root_ids,
return;
new_entry->entry.key = leaf_bytenr >> fs_info->sectorsize_bits;
+ new_entry->entry.gen = 0;
new_entry->num_roots = 0;
ULIST_ITER_INIT(&uiter);
while ((node = ulist_next(root_ids, &uiter)) != NULL) {
@@ -2957,6 +2958,7 @@ static void cache_dir_created(struct send_ctx *sctx, u64 dir)
return;
entry->key = dir;
+ entry->gen = 0;
ret = btrfs_lru_cache_store(&sctx->dir_created_cache, entry, GFP_KERNEL);
if (ret < 0)
kfree(entry);
@@ -2977,7 +2979,7 @@ static int did_create_dir(struct send_ctx *sctx, u64 dir)
struct btrfs_key di_key;
struct btrfs_dir_item *di;
- if (btrfs_lru_cache_lookup(&sctx->dir_created_cache, dir))
+ if (btrfs_lru_cache_lookup(&sctx->dir_created_cache, dir, 0))
return 1;
path = alloc_path_for_send();