diff options
Diffstat (limited to 'fs/btrfs/disk-io.c')
| -rw-r--r-- | fs/btrfs/disk-io.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 5aebddd71193..adda739a0215 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -75,6 +75,40 @@ struct async_submit_bio { | |||
| 75 | struct btrfs_work work; | 75 | struct btrfs_work work; |
| 76 | }; | 76 | }; |
| 77 | 77 | ||
| 78 | /* These are used to set the lockdep class on the extent buffer locks. | ||
| 79 | * The class is set by the readpage_end_io_hook after the buffer has | ||
| 80 | * passed csum validation but before the pages are unlocked. | ||
| 81 | * | ||
| 82 | * The lockdep class is also set by btrfs_init_new_buffer on freshly | ||
| 83 | * allocated blocks. | ||
| 84 | * | ||
| 85 | * The class is based on the level in the tree block, which allows lockdep | ||
| 86 | * to know that lower nodes nest inside the locks of higher nodes. | ||
| 87 | * | ||
| 88 | * We also add a check to make sure the highest level of the tree is | ||
| 89 | * the same as our lockdep setup here. If BTRFS_MAX_LEVEL changes, this | ||
| 90 | * code needs update as well. | ||
| 91 | */ | ||
| 92 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
| 93 | # if BTRFS_MAX_LEVEL != 8 | ||
| 94 | # error | ||
| 95 | # endif | ||
| 96 | static struct lock_class_key btrfs_eb_class[BTRFS_MAX_LEVEL + 1]; | ||
| 97 | static const char *btrfs_eb_name[BTRFS_MAX_LEVEL + 1] = { | ||
| 98 | /* leaf */ | ||
| 99 | "btrfs-extent-00", | ||
| 100 | "btrfs-extent-01", | ||
| 101 | "btrfs-extent-02", | ||
| 102 | "btrfs-extent-03", | ||
| 103 | "btrfs-extent-04", | ||
| 104 | "btrfs-extent-05", | ||
| 105 | "btrfs-extent-06", | ||
| 106 | "btrfs-extent-07", | ||
| 107 | /* highest possible level */ | ||
| 108 | "btrfs-extent-08", | ||
| 109 | }; | ||
| 110 | #endif | ||
| 111 | |||
| 78 | /* | 112 | /* |
| 79 | * extents on the btree inode are pretty simple, there's one extent | 113 | * extents on the btree inode are pretty simple, there's one extent |
| 80 | * that covers the entire device | 114 | * that covers the entire device |
| @@ -347,6 +381,15 @@ static int check_tree_block_fsid(struct btrfs_root *root, | |||
| 347 | return ret; | 381 | return ret; |
| 348 | } | 382 | } |
| 349 | 383 | ||
| 384 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
| 385 | void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, int level) | ||
| 386 | { | ||
| 387 | lockdep_set_class_and_name(&eb->lock, | ||
| 388 | &btrfs_eb_class[level], | ||
| 389 | btrfs_eb_name[level]); | ||
| 390 | } | ||
| 391 | #endif | ||
| 392 | |||
| 350 | static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | 393 | static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, |
| 351 | struct extent_state *state) | 394 | struct extent_state *state) |
| 352 | { | 395 | { |
| @@ -392,6 +435,8 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, | |||
| 392 | } | 435 | } |
| 393 | found_level = btrfs_header_level(eb); | 436 | found_level = btrfs_header_level(eb); |
| 394 | 437 | ||
| 438 | btrfs_set_buffer_lockdep_class(eb, found_level); | ||
| 439 | |||
| 395 | ret = csum_tree_block(root, eb, 1); | 440 | ret = csum_tree_block(root, eb, 1); |
| 396 | if (ret) | 441 | if (ret) |
| 397 | ret = -EIO; | 442 | ret = -EIO; |
| @@ -1777,7 +1822,6 @@ struct btrfs_root *open_ctree(struct super_block *sb, | |||
| 1777 | ret = find_and_setup_root(tree_root, fs_info, | 1822 | ret = find_and_setup_root(tree_root, fs_info, |
| 1778 | BTRFS_DEV_TREE_OBJECTID, dev_root); | 1823 | BTRFS_DEV_TREE_OBJECTID, dev_root); |
| 1779 | dev_root->track_dirty = 1; | 1824 | dev_root->track_dirty = 1; |
| 1780 | |||
| 1781 | if (ret) | 1825 | if (ret) |
| 1782 | goto fail_extent_root; | 1826 | goto fail_extent_root; |
| 1783 | 1827 | ||
