aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorAlexander Block <ablock84@googlemail.com>2012-07-28 08:20:58 -0400
committerChris Mason <chris.mason@fusionio.com>2012-10-01 15:18:52 -0400
commit7e0926fe5f20b5c88e51cba68512302b10f73d2a (patch)
tree0b434c576f76da0902eefbe7bec8e526f8803a8d /fs/btrfs
parent17589bd96eeb7c2ef2d3baeb05005a24932cd1e9 (diff)
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: Arne Jansen <sensille@gmx.net> Signed-off-by: Alexander Block <ablock84@googlemail.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/send.c76
1 files changed, 37 insertions, 39 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 9cee678c0fb6..02e901adc3e8 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -125,6 +125,15 @@ struct send_ctx {
125 125
126struct name_cache_entry { 126struct name_cache_entry {
127 struct list_head list; 127 struct list_head list;
128 /*
129 * radix_tree has only 32bit entries but we need to handle 64bit inums.
130 * We use the lower 32bit of the 64bit inum to store it in the tree. If
131 * more then one inum would fall into the same entry, we use radix_list
132 * to store the additional entries. radix_list is also used to store
133 * entries where two entries have the same inum but different
134 * generations.
135 */
136 struct list_head radix_list;
128 u64 ino; 137 u64 ino;
129 u64 gen; 138 u64 gen;
130 u64 parent_ino; 139 u64 parent_ino;
@@ -1726,27 +1735,21 @@ static int name_cache_insert(struct send_ctx *sctx,
1726 struct name_cache_entry *nce) 1735 struct name_cache_entry *nce)
1727{ 1736{
1728 int ret = 0; 1737 int ret = 0;
1729 struct name_cache_entry **ncea; 1738 struct list_head *nce_head;
1730 1739
1731 ncea = radix_tree_lookup(&sctx->name_cache, nce->ino); 1740 nce_head = radix_tree_lookup(&sctx->name_cache,
1732 if (ncea) { 1741 (unsigned long)nce->ino);
1733 if (!ncea[0]) 1742 if (!nce_head) {
1734 ncea[0] = nce; 1743 nce_head = kmalloc(sizeof(*nce_head), GFP_NOFS);
1735 else if (!ncea[1]) 1744 if (!nce_head)
1736 ncea[1] = nce;
1737 else
1738 BUG();
1739 } else {
1740 ncea = kmalloc(sizeof(void *) * 2, GFP_NOFS);
1741 if (!ncea)
1742 return -ENOMEM; 1745 return -ENOMEM;
1746 INIT_LIST_HEAD(nce_head);
1743 1747
1744 ncea[0] = nce; 1748 ret = radix_tree_insert(&sctx->name_cache, nce->ino, nce_head);
1745 ncea[1] = NULL;
1746 ret = radix_tree_insert(&sctx->name_cache, nce->ino, ncea);
1747 if (ret < 0) 1749 if (ret < 0)
1748 return ret; 1750 return ret;
1749 } 1751 }
1752 list_add_tail(&nce->radix_list, nce_head);
1750 list_add_tail(&nce->list, &sctx->name_cache_list); 1753 list_add_tail(&nce->list, &sctx->name_cache_list);
1751 sctx->name_cache_size++; 1754 sctx->name_cache_size++;
1752 1755
@@ -1756,41 +1759,36 @@ static int name_cache_insert(struct send_ctx *sctx,
1756static void name_cache_delete(struct send_ctx *sctx, 1759static void name_cache_delete(struct send_ctx *sctx,
1757 struct name_cache_entry *nce) 1760 struct name_cache_entry *nce)
1758{ 1761{
1759 struct name_cache_entry **ncea; 1762 struct list_head *nce_head;
1760
1761 ncea = radix_tree_lookup(&sctx->name_cache, nce->ino);
1762 BUG_ON(!ncea);
1763
1764 if (ncea[0] == nce)
1765 ncea[0] = NULL;
1766 else if (ncea[1] == nce)
1767 ncea[1] = NULL;
1768 else
1769 BUG();
1770 1763
1771 if (!ncea[0] && !ncea[1]) { 1764 nce_head = radix_tree_lookup(&sctx->name_cache,
1772 radix_tree_delete(&sctx->name_cache, nce->ino); 1765 (unsigned long)nce->ino);
1773 kfree(ncea); 1766 BUG_ON(!nce_head);
1774 }
1775 1767
1768 list_del(&nce->radix_list);
1776 list_del(&nce->list); 1769 list_del(&nce->list);
1777
1778 sctx->name_cache_size--; 1770 sctx->name_cache_size--;
1771
1772 if (list_empty(nce_head)) {
1773 radix_tree_delete(&sctx->name_cache, (unsigned long)nce->ino);
1774 kfree(nce_head);
1775 }
1779} 1776}
1780 1777
1781static struct name_cache_entry *name_cache_search(struct send_ctx *sctx, 1778static struct name_cache_entry *name_cache_search(struct send_ctx *sctx,
1782 u64 ino, u64 gen) 1779 u64 ino, u64 gen)
1783{ 1780{
1784 struct name_cache_entry **ncea; 1781 struct list_head *nce_head;
1782 struct name_cache_entry *cur;
1785 1783
1786 ncea = radix_tree_lookup(&sctx->name_cache, ino); 1784 nce_head = radix_tree_lookup(&sctx->name_cache, (unsigned long)ino);
1787 if (!ncea) 1785 if (!nce_head)
1788 return NULL; 1786 return NULL;
1789 1787
1790 if (ncea[0] && ncea[0]->gen == gen) 1788 list_for_each_entry(cur, nce_head, radix_list) {
1791 return ncea[0]; 1789 if (cur->ino == ino && cur->gen == gen)
1792 else if (ncea[1] && ncea[1]->gen == gen) 1790 return cur;
1793 return ncea[1]; 1791 }
1794 return NULL; 1792 return NULL;
1795} 1793}
1796 1794