diff options
Diffstat (limited to 'fs/btrfs/ctree.c')
| -rw-r--r-- | fs/btrfs/ctree.c | 58 |
1 files changed, 37 insertions, 21 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 35443cc4b9a9..42491d728e99 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
| @@ -38,19 +38,12 @@ static int balance_node_right(struct btrfs_trans_handle *trans, | |||
| 38 | static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, | 38 | static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root, |
| 39 | struct btrfs_path *path, int level, int slot); | 39 | struct btrfs_path *path, int level, int slot); |
| 40 | 40 | ||
| 41 | inline void btrfs_init_path(struct btrfs_path *p) | ||
| 42 | { | ||
| 43 | memset(p, 0, sizeof(*p)); | ||
| 44 | } | ||
| 45 | |||
| 46 | struct btrfs_path *btrfs_alloc_path(void) | 41 | struct btrfs_path *btrfs_alloc_path(void) |
| 47 | { | 42 | { |
| 48 | struct btrfs_path *path; | 43 | struct btrfs_path *path; |
| 49 | path = kmem_cache_alloc(btrfs_path_cachep, GFP_NOFS); | 44 | path = kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS); |
| 50 | if (path) { | 45 | if (path) |
| 51 | btrfs_init_path(path); | ||
| 52 | path->reada = 1; | 46 | path->reada = 1; |
| 53 | } | ||
| 54 | return path; | 47 | return path; |
| 55 | } | 48 | } |
| 56 | 49 | ||
| @@ -69,14 +62,38 @@ noinline void btrfs_set_path_blocking(struct btrfs_path *p) | |||
| 69 | 62 | ||
| 70 | /* | 63 | /* |
| 71 | * 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 | ||
| 72 | */ | 70 | */ |
| 73 | noinline void btrfs_clear_path_blocking(struct btrfs_path *p) | 71 | noinline void btrfs_clear_path_blocking(struct btrfs_path *p, |
| 72 | struct extent_buffer *held) | ||
| 74 | { | 73 | { |
| 75 | int i; | 74 | int i; |
| 76 | 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--) { | ||
| 77 | if (p->nodes[i] && p->locks[i]) | 89 | if (p->nodes[i] && p->locks[i]) |
| 78 | btrfs_clear_lock_blocking(p->nodes[i]); | 90 | btrfs_clear_lock_blocking(p->nodes[i]); |
| 79 | } | 91 | } |
| 92 | |||
| 93 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
| 94 | if (held) | ||
| 95 | btrfs_clear_lock_blocking(held); | ||
| 96 | #endif | ||
| 80 | } | 97 | } |
| 81 | 98 | ||
| 82 | /* this also releases the path */ | 99 | /* this also releases the path */ |
| @@ -286,7 +303,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
| 286 | trans->transid, level, &ins); | 303 | trans->transid, level, &ins); |
| 287 | BUG_ON(ret); | 304 | BUG_ON(ret); |
| 288 | cow = btrfs_init_new_buffer(trans, root, prealloc_dest, | 305 | cow = btrfs_init_new_buffer(trans, root, prealloc_dest, |
| 289 | buf->len); | 306 | buf->len, level); |
| 290 | } else { | 307 | } else { |
| 291 | cow = btrfs_alloc_free_block(trans, root, buf->len, | 308 | cow = btrfs_alloc_free_block(trans, root, buf->len, |
| 292 | parent_start, | 309 | parent_start, |
| @@ -917,9 +934,9 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, | |||
| 917 | 934 | ||
| 918 | /* promote the child to a root */ | 935 | /* promote the child to a root */ |
| 919 | child = read_node_slot(root, mid, 0); | 936 | child = read_node_slot(root, mid, 0); |
| 937 | BUG_ON(!child); | ||
| 920 | btrfs_tree_lock(child); | 938 | btrfs_tree_lock(child); |
| 921 | btrfs_set_lock_blocking(child); | 939 | btrfs_set_lock_blocking(child); |
| 922 | BUG_ON(!child); | ||
| 923 | ret = btrfs_cow_block(trans, root, child, mid, 0, &child, 0); | 940 | ret = btrfs_cow_block(trans, root, child, mid, 0, &child, 0); |
| 924 | BUG_ON(ret); | 941 | BUG_ON(ret); |
| 925 | 942 | ||
| @@ -1566,7 +1583,7 @@ cow_done: | |||
| 1566 | if (!p->skip_locking) | 1583 | if (!p->skip_locking) |
| 1567 | p->locks[level] = 1; | 1584 | p->locks[level] = 1; |
| 1568 | 1585 | ||
| 1569 | btrfs_clear_path_blocking(p); | 1586 | btrfs_clear_path_blocking(p, NULL); |
| 1570 | 1587 | ||
| 1571 | /* | 1588 | /* |
| 1572 | * 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 |
| @@ -1605,7 +1622,7 @@ cow_done: | |||
| 1605 | 1622 | ||
| 1606 | btrfs_set_path_blocking(p); | 1623 | btrfs_set_path_blocking(p); |
| 1607 | sret = split_node(trans, root, p, level); | 1624 | sret = split_node(trans, root, p, level); |
| 1608 | btrfs_clear_path_blocking(p); | 1625 | btrfs_clear_path_blocking(p, NULL); |
| 1609 | 1626 | ||
| 1610 | BUG_ON(sret > 0); | 1627 | BUG_ON(sret > 0); |
| 1611 | if (sret) { | 1628 | if (sret) { |
| @@ -1625,7 +1642,7 @@ cow_done: | |||
| 1625 | 1642 | ||
| 1626 | btrfs_set_path_blocking(p); | 1643 | btrfs_set_path_blocking(p); |
| 1627 | sret = balance_level(trans, root, p, level); | 1644 | sret = balance_level(trans, root, p, level); |
| 1628 | btrfs_clear_path_blocking(p); | 1645 | btrfs_clear_path_blocking(p, NULL); |
| 1629 | 1646 | ||
| 1630 | if (sret) { | 1647 | if (sret) { |
| 1631 | ret = sret; | 1648 | ret = sret; |
| @@ -1688,13 +1705,13 @@ cow_done: | |||
| 1688 | if (!p->skip_locking) { | 1705 | if (!p->skip_locking) { |
| 1689 | int lret; | 1706 | int lret; |
| 1690 | 1707 | ||
| 1691 | btrfs_clear_path_blocking(p); | 1708 | btrfs_clear_path_blocking(p, NULL); |
| 1692 | lret = btrfs_try_spin_lock(b); | 1709 | lret = btrfs_try_spin_lock(b); |
| 1693 | 1710 | ||
| 1694 | if (!lret) { | 1711 | if (!lret) { |
| 1695 | btrfs_set_path_blocking(p); | 1712 | btrfs_set_path_blocking(p); |
| 1696 | btrfs_tree_lock(b); | 1713 | btrfs_tree_lock(b); |
| 1697 | btrfs_clear_path_blocking(p); | 1714 | btrfs_clear_path_blocking(p, b); |
| 1698 | } | 1715 | } |
| 1699 | } | 1716 | } |
| 1700 | } else { | 1717 | } else { |
| @@ -1706,7 +1723,7 @@ cow_done: | |||
| 1706 | btrfs_set_path_blocking(p); | 1723 | btrfs_set_path_blocking(p); |
| 1707 | sret = split_leaf(trans, root, key, | 1724 | sret = split_leaf(trans, root, key, |
| 1708 | p, ins_len, ret == 0); | 1725 | p, ins_len, ret == 0); |
| 1709 | btrfs_clear_path_blocking(p); | 1726 | btrfs_clear_path_blocking(p, NULL); |
| 1710 | 1727 | ||
| 1711 | BUG_ON(sret > 0); | 1728 | BUG_ON(sret > 0); |
| 1712 | if (sret) { | 1729 | if (sret) { |
| @@ -3926,7 +3943,6 @@ find_next_key: | |||
| 3926 | btrfs_release_path(root, path); | 3943 | btrfs_release_path(root, path); |
| 3927 | goto again; | 3944 | goto again; |
| 3928 | } else { | 3945 | } else { |
| 3929 | btrfs_clear_path_blocking(path); | ||
| 3930 | goto out; | 3946 | goto out; |
| 3931 | } | 3947 | } |
| 3932 | } | 3948 | } |
| @@ -3946,7 +3962,7 @@ find_next_key: | |||
| 3946 | path->locks[level - 1] = 1; | 3962 | path->locks[level - 1] = 1; |
| 3947 | path->nodes[level - 1] = cur; | 3963 | path->nodes[level - 1] = cur; |
| 3948 | unlock_up(path, level, 1); | 3964 | unlock_up(path, level, 1); |
| 3949 | btrfs_clear_path_blocking(path); | 3965 | btrfs_clear_path_blocking(path, NULL); |
| 3950 | } | 3966 | } |
| 3951 | out: | 3967 | out: |
| 3952 | if (ret == 0) | 3968 | if (ret == 0) |
