提交 7e0926fe 编写于 作者: A Alexander Block 提交者: Chris Mason

Btrfs: fix use of radix_tree for name_cache in send/receive

We can't easily use the index of the radix tree for inums as the
radix tree uses 32bit indexes on 32bit kernels. For 32bit kernels,
we now use the lower 32bit of the inum as index and an additional
list to store multiple entries per radix tree entry.
Reported-by: NArne Jansen <sensille@gmx.net>
Signed-off-by: NAlexander Block <ablock84@googlemail.com>
上级 17589bd9
...@@ -125,6 +125,15 @@ struct send_ctx { ...@@ -125,6 +125,15 @@ struct send_ctx {
struct name_cache_entry { struct name_cache_entry {
struct list_head list; struct list_head list;
/*
* radix_tree has only 32bit entries but we need to handle 64bit inums.
* We use the lower 32bit of the 64bit inum to store it in the tree. If
* more then one inum would fall into the same entry, we use radix_list
* to store the additional entries. radix_list is also used to store
* entries where two entries have the same inum but different
* generations.
*/
struct list_head radix_list;
u64 ino; u64 ino;
u64 gen; u64 gen;
u64 parent_ino; u64 parent_ino;
...@@ -1726,27 +1735,21 @@ static int name_cache_insert(struct send_ctx *sctx, ...@@ -1726,27 +1735,21 @@ static int name_cache_insert(struct send_ctx *sctx,
struct name_cache_entry *nce) struct name_cache_entry *nce)
{ {
int ret = 0; int ret = 0;
struct name_cache_entry **ncea; struct list_head *nce_head;
ncea = radix_tree_lookup(&sctx->name_cache, nce->ino); nce_head = radix_tree_lookup(&sctx->name_cache,
if (ncea) { (unsigned long)nce->ino);
if (!ncea[0]) if (!nce_head) {
ncea[0] = nce; nce_head = kmalloc(sizeof(*nce_head), GFP_NOFS);
else if (!ncea[1]) if (!nce_head)
ncea[1] = nce;
else
BUG();
} else {
ncea = kmalloc(sizeof(void *) * 2, GFP_NOFS);
if (!ncea)
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(nce_head);
ncea[0] = nce; ret = radix_tree_insert(&sctx->name_cache, nce->ino, nce_head);
ncea[1] = NULL;
ret = radix_tree_insert(&sctx->name_cache, nce->ino, ncea);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
list_add_tail(&nce->radix_list, nce_head);
list_add_tail(&nce->list, &sctx->name_cache_list); list_add_tail(&nce->list, &sctx->name_cache_list);
sctx->name_cache_size++; sctx->name_cache_size++;
...@@ -1756,41 +1759,36 @@ static int name_cache_insert(struct send_ctx *sctx, ...@@ -1756,41 +1759,36 @@ static int name_cache_insert(struct send_ctx *sctx,
static void name_cache_delete(struct send_ctx *sctx, static void name_cache_delete(struct send_ctx *sctx,
struct name_cache_entry *nce) struct name_cache_entry *nce)
{ {
struct name_cache_entry **ncea; struct list_head *nce_head;
ncea = radix_tree_lookup(&sctx->name_cache, nce->ino);
BUG_ON(!ncea);
if (ncea[0] == nce)
ncea[0] = NULL;
else if (ncea[1] == nce)
ncea[1] = NULL;
else
BUG();
if (!ncea[0] && !ncea[1]) { nce_head = radix_tree_lookup(&sctx->name_cache,
radix_tree_delete(&sctx->name_cache, nce->ino); (unsigned long)nce->ino);
kfree(ncea); BUG_ON(!nce_head);
}
list_del(&nce->radix_list);
list_del(&nce->list); list_del(&nce->list);
sctx->name_cache_size--; sctx->name_cache_size--;
if (list_empty(nce_head)) {
radix_tree_delete(&sctx->name_cache, (unsigned long)nce->ino);
kfree(nce_head);
}
} }
static struct name_cache_entry *name_cache_search(struct send_ctx *sctx, static struct name_cache_entry *name_cache_search(struct send_ctx *sctx,
u64 ino, u64 gen) u64 ino, u64 gen)
{ {
struct name_cache_entry **ncea; struct list_head *nce_head;
struct name_cache_entry *cur;
ncea = radix_tree_lookup(&sctx->name_cache, ino); nce_head = radix_tree_lookup(&sctx->name_cache, (unsigned long)ino);
if (!ncea) if (!nce_head)
return NULL; return NULL;
if (ncea[0] && ncea[0]->gen == gen) list_for_each_entry(cur, nce_head, radix_list) {
return ncea[0]; if (cur->ino == ino && cur->gen == gen)
else if (ncea[1] && ncea[1]->gen == gen) return cur;
return ncea[1]; }
return NULL; return NULL;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册