aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/ctree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2009-02-12 14:09:45 -0500
committerChris Mason <chris.mason@oracle.com>2009-02-12 14:09:45 -0500
commit4008c04a07c73ec3cb1be4c1391d2159a8f75d6d (patch)
treec0b10a7287ac810bfc406541e32b850ad4580248 /fs/btrfs/ctree.c
parent3f3420df505e47751ef76a652b5cb660e5360d6f (diff)
Btrfs: make a lockdep class for the extent buffer locks
Btrfs is currently using spin_lock_nested with a nested value based on the tree depth of the block. But, this doesn't quite work because the max tree depth is bigger than what spin_lock_nested can deal with, and because locks are sometimes taken before the level field is filled in. The solution here is to use lockdep_set_class_and_name instead, and to set the class before unlocking the pages when the block is read from the disk and just after init of a freshly allocated tree block. btrfs_clear_path_blocking is also changed to take the locks in the proper order, and it also makes sure all the locks currently held are properly set to blocking before it tries to retake the spinlocks. Otherwise, lockdep gets upset about bad lock orderin. The lockdep magic cam from Peter Zijlstra <peterz@infradead.org> Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ctree.c')
-rw-r--r--fs/btrfs/ctree.c45
1 files changed, 34 insertions, 11 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index c8f4c540cc2c..42491d728e99 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -62,14 +62,38 @@ noinline void btrfs_set_path_blocking(struct btrfs_path *p)
62 62
63/* 63/*
64 * reset all the locked nodes in the patch to spinning locks. 64 * reset all the locked nodes in the patch to spinning locks.
65 *
66 * held is used to keep lockdep happy, when lockdep is enabled
67 * we set held to a blocking lock before we go around and
68 * retake all the spinlocks in the path. You can safely use NULL
69 * for held
65 */ 70 */
66noinline void btrfs_clear_path_blocking(struct btrfs_path *p) 71noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
72 struct extent_buffer *held)
67{ 73{
68 int i; 74 int i;
69 for (i = 0; i < BTRFS_MAX_LEVEL; i++) { 75
76#ifdef CONFIG_DEBUG_LOCK_ALLOC
77 /* lockdep really cares that we take all of these spinlocks
78 * in the right order. If any of the locks in the path are not
79 * currently blocking, it is going to complain. So, make really
80 * really sure by forcing the path to blocking before we clear
81 * the path blocking.
82 */
83 if (held)
84 btrfs_set_lock_blocking(held);
85 btrfs_set_path_blocking(p);
86#endif
87
88 for (i = BTRFS_MAX_LEVEL - 1; i >= 0; i--) {
70 if (p->nodes[i] && p->locks[i]) 89 if (p->nodes[i] && p->locks[i])
71 btrfs_clear_lock_blocking(p->nodes[i]); 90 btrfs_clear_lock_blocking(p->nodes[i]);
72 } 91 }
92
93#ifdef CONFIG_DEBUG_LOCK_ALLOC
94 if (held)
95 btrfs_clear_lock_blocking(held);
96#endif
73} 97}
74 98
75/* this also releases the path */ 99/* this also releases the path */
@@ -279,7 +303,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
279 trans->transid, level, &ins); 303 trans->transid, level, &ins);
280 BUG_ON(ret); 304 BUG_ON(ret);
281 cow = btrfs_init_new_buffer(trans, root, prealloc_dest, 305 cow = btrfs_init_new_buffer(trans, root, prealloc_dest,
282 buf->len); 306 buf->len, level);
283 } else { 307 } else {
284 cow = btrfs_alloc_free_block(trans, root, buf->len, 308 cow = btrfs_alloc_free_block(trans, root, buf->len,
285 parent_start, 309 parent_start,
@@ -1559,7 +1583,7 @@ cow_done:
1559 if (!p->skip_locking) 1583 if (!p->skip_locking)
1560 p->locks[level] = 1; 1584 p->locks[level] = 1;
1561 1585
1562 btrfs_clear_path_blocking(p); 1586 btrfs_clear_path_blocking(p, NULL);
1563 1587
1564 /* 1588 /*
1565 * we have a lock on b and as long as we aren't changing 1589 * we have a lock on b and as long as we aren't changing
@@ -1598,7 +1622,7 @@ cow_done:
1598 1622
1599 btrfs_set_path_blocking(p); 1623 btrfs_set_path_blocking(p);
1600 sret = split_node(trans, root, p, level); 1624 sret = split_node(trans, root, p, level);
1601 btrfs_clear_path_blocking(p); 1625 btrfs_clear_path_blocking(p, NULL);
1602 1626
1603 BUG_ON(sret > 0); 1627 BUG_ON(sret > 0);
1604 if (sret) { 1628 if (sret) {
@@ -1618,7 +1642,7 @@ cow_done:
1618 1642
1619 btrfs_set_path_blocking(p); 1643 btrfs_set_path_blocking(p);
1620 sret = balance_level(trans, root, p, level); 1644 sret = balance_level(trans, root, p, level);
1621 btrfs_clear_path_blocking(p); 1645 btrfs_clear_path_blocking(p, NULL);
1622 1646
1623 if (sret) { 1647 if (sret) {
1624 ret = sret; 1648 ret = sret;
@@ -1681,13 +1705,13 @@ cow_done:
1681 if (!p->skip_locking) { 1705 if (!p->skip_locking) {
1682 int lret; 1706 int lret;
1683 1707
1684 btrfs_clear_path_blocking(p); 1708 btrfs_clear_path_blocking(p, NULL);
1685 lret = btrfs_try_spin_lock(b); 1709 lret = btrfs_try_spin_lock(b);
1686 1710
1687 if (!lret) { 1711 if (!lret) {
1688 btrfs_set_path_blocking(p); 1712 btrfs_set_path_blocking(p);
1689 btrfs_tree_lock(b); 1713 btrfs_tree_lock(b);
1690 btrfs_clear_path_blocking(p); 1714 btrfs_clear_path_blocking(p, b);
1691 } 1715 }
1692 } 1716 }
1693 } else { 1717 } else {
@@ -1699,7 +1723,7 @@ cow_done:
1699 btrfs_set_path_blocking(p); 1723 btrfs_set_path_blocking(p);
1700 sret = split_leaf(trans, root, key, 1724 sret = split_leaf(trans, root, key,
1701 p, ins_len, ret == 0); 1725 p, ins_len, ret == 0);
1702 btrfs_clear_path_blocking(p); 1726 btrfs_clear_path_blocking(p, NULL);
1703 1727
1704 BUG_ON(sret > 0); 1728 BUG_ON(sret > 0);
1705 if (sret) { 1729 if (sret) {
@@ -3919,7 +3943,6 @@ find_next_key:
3919 btrfs_release_path(root, path); 3943 btrfs_release_path(root, path);
3920 goto again; 3944 goto again;
3921 } else { 3945 } else {
3922 btrfs_clear_path_blocking(path);
3923 goto out; 3946 goto out;
3924 } 3947 }
3925 } 3948 }
@@ -3939,7 +3962,7 @@ find_next_key:
3939 path->locks[level - 1] = 1; 3962 path->locks[level - 1] = 1;
3940 path->nodes[level - 1] = cur; 3963 path->nodes[level - 1] = cur;
3941 unlock_up(path, level, 1); 3964 unlock_up(path, level, 1);
3942 btrfs_clear_path_blocking(path); 3965 btrfs_clear_path_blocking(path, NULL);
3943 } 3966 }
3944out: 3967out:
3945 if (ret == 0) 3968 if (ret == 0)