aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/disk-io.c103
-rw-r--r--fs/btrfs/disk-io.h10
-rw-r--r--fs/btrfs/extent-tree.c2
-rw-r--r--fs/btrfs/volumes.c2
4 files changed, 79 insertions, 38 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 97f22ff8326f..94ecac33cf2d 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -100,38 +100,83 @@ struct async_submit_bio {
100 struct btrfs_work work; 100 struct btrfs_work work;
101}; 101};
102 102
103/* These are used to set the lockdep class on the extent buffer locks. 103/*
104 * The class is set by the readpage_end_io_hook after the buffer has 104 * Lockdep class keys for extent_buffer->lock's in this root. For a given
105 * passed csum validation but before the pages are unlocked. 105 * eb, the lockdep key is determined by the btrfs_root it belongs to and
106 * the level the eb occupies in the tree.
107 *
108 * Different roots are used for different purposes and may nest inside each
109 * other and they require separate keysets. As lockdep keys should be
110 * static, assign keysets according to the purpose of the root as indicated
111 * by btrfs_root->objectid. This ensures that all special purpose roots
112 * have separate keysets.
106 * 113 *
107 * The lockdep class is also set by btrfs_init_new_buffer on freshly 114 * Lock-nesting across peer nodes is always done with the immediate parent
108 * allocated blocks. 115 * node locked thus preventing deadlock. As lockdep doesn't know this, use
116 * subclass to avoid triggering lockdep warning in such cases.
109 * 117 *
110 * The class is based on the level in the tree block, which allows lockdep 118 * The key is set by the readpage_end_io_hook after the buffer has passed
111 * to know that lower nodes nest inside the locks of higher nodes. 119 * csum validation but before the pages are unlocked. It is also set by
120 * btrfs_init_new_buffer on freshly allocated blocks.
112 * 121 *
113 * We also add a check to make sure the highest level of the tree is 122 * We also add a check to make sure the highest level of the tree is the
114 * the same as our lockdep setup here. If BTRFS_MAX_LEVEL changes, this 123 * same as our lockdep setup here. If BTRFS_MAX_LEVEL changes, this code
115 * code needs update as well. 124 * needs update as well.
116 */ 125 */
117#ifdef CONFIG_DEBUG_LOCK_ALLOC 126#ifdef CONFIG_DEBUG_LOCK_ALLOC
118# if BTRFS_MAX_LEVEL != 8 127# if BTRFS_MAX_LEVEL != 8
119# error 128# error
120# endif 129# endif
121static struct lock_class_key btrfs_eb_class[BTRFS_MAX_LEVEL + 1]; 130
122static const char *btrfs_eb_name[BTRFS_MAX_LEVEL + 1] = { 131static struct btrfs_lockdep_keyset {
123 /* leaf */ 132 u64 id; /* root objectid */
124 "btrfs-extent-00", 133 const char *name_stem; /* lock name stem */
125 "btrfs-extent-01", 134 char names[BTRFS_MAX_LEVEL + 1][20];
126 "btrfs-extent-02", 135 struct lock_class_key keys[BTRFS_MAX_LEVEL + 1];
127 "btrfs-extent-03", 136} btrfs_lockdep_keysets[] = {
128 "btrfs-extent-04", 137 { .id = BTRFS_ROOT_TREE_OBJECTID, .name_stem = "root" },
129 "btrfs-extent-05", 138 { .id = BTRFS_EXTENT_TREE_OBJECTID, .name_stem = "extent" },
130 "btrfs-extent-06", 139 { .id = BTRFS_CHUNK_TREE_OBJECTID, .name_stem = "chunk" },
131 "btrfs-extent-07", 140 { .id = BTRFS_DEV_TREE_OBJECTID, .name_stem = "dev" },
132 /* highest possible level */ 141 { .id = BTRFS_FS_TREE_OBJECTID, .name_stem = "fs" },
133 "btrfs-extent-08", 142 { .id = BTRFS_CSUM_TREE_OBJECTID, .name_stem = "csum" },
143 { .id = BTRFS_ORPHAN_OBJECTID, .name_stem = "orphan" },
144 { .id = BTRFS_TREE_LOG_OBJECTID, .name_stem = "log" },
145 { .id = BTRFS_TREE_RELOC_OBJECTID, .name_stem = "treloc" },
146 { .id = BTRFS_DATA_RELOC_TREE_OBJECTID, .name_stem = "dreloc" },
147 { .id = 0, .name_stem = "tree" },
134}; 148};
149
150void __init btrfs_init_lockdep(void)
151{
152 int i, j;
153
154 /* initialize lockdep class names */
155 for (i = 0; i < ARRAY_SIZE(btrfs_lockdep_keysets); i++) {
156 struct btrfs_lockdep_keyset *ks = &btrfs_lockdep_keysets[i];
157
158 for (j = 0; j < ARRAY_SIZE(ks->names); j++)
159 snprintf(ks->names[j], sizeof(ks->names[j]),
160 "btrfs-%s-%02d", ks->name_stem, j);
161 }
162}
163
164void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb,
165 int level)
166{
167 struct btrfs_lockdep_keyset *ks;
168
169 BUG_ON(level >= ARRAY_SIZE(ks->keys));
170
171 /* find the matching keyset, id 0 is the default entry */
172 for (ks = btrfs_lockdep_keysets; ks->id; ks++)
173 if (ks->id == objectid)
174 break;
175
176 lockdep_set_class_and_name(&eb->lock,
177 &ks->keys[level], ks->names[level]);
178}
179
135#endif 180#endif
136 181
137/* 182/*
@@ -491,15 +536,6 @@ static noinline int check_leaf(struct btrfs_root *root,
491 return 0; 536 return 0;
492} 537}
493 538
494#ifdef CONFIG_DEBUG_LOCK_ALLOC
495void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, int level)
496{
497 lockdep_set_class_and_name(&eb->lock,
498 &btrfs_eb_class[level],
499 btrfs_eb_name[level]);
500}
501#endif
502
503static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end, 539static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
504 struct extent_state *state) 540 struct extent_state *state)
505{ 541{
@@ -550,7 +586,8 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
550 } 586 }
551 found_level = btrfs_header_level(eb); 587 found_level = btrfs_header_level(eb);
552 588
553 btrfs_set_buffer_lockdep_class(eb, found_level); 589 btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb),
590 eb, found_level);
554 591
555 ret = csum_tree_block(root, eb, 1); 592 ret = csum_tree_block(root, eb, 1);
556 if (ret) { 593 if (ret) {
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index a0b610a67aae..bec3ea4bd67f 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -87,10 +87,14 @@ int btree_lock_page_hook(struct page *page);
87 87
88 88
89#ifdef CONFIG_DEBUG_LOCK_ALLOC 89#ifdef CONFIG_DEBUG_LOCK_ALLOC
90void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, int level); 90void btrfs_init_lockdep(void);
91void btrfs_set_buffer_lockdep_class(u64 objectid,
92 struct extent_buffer *eb, int level);
91#else 93#else
92static inline void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, 94static inline void btrfs_init_lockdep(void)
93 int level) 95{ }
96static inline void btrfs_set_buffer_lockdep_class(u64 objectid,
97 struct extent_buffer *eb, int level)
94{ 98{
95} 99}
96#endif 100#endif
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 2a782c2fcb62..06a5ee29b446 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -5625,7 +5625,7 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
5625 if (!buf) 5625 if (!buf)
5626 return ERR_PTR(-ENOMEM); 5626 return ERR_PTR(-ENOMEM);
5627 btrfs_set_header_generation(buf, trans->transid); 5627 btrfs_set_header_generation(buf, trans->transid);
5628 btrfs_set_buffer_lockdep_class(buf, level); 5628 btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level);
5629 btrfs_tree_lock(buf); 5629 btrfs_tree_lock(buf);
5630 clean_tree_block(trans, root, buf); 5630 clean_tree_block(trans, root, buf);
5631 5631
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 19450bc53632..b89e372c7544 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -3595,7 +3595,7 @@ int btrfs_read_sys_array(struct btrfs_root *root)
3595 if (!sb) 3595 if (!sb)
3596 return -ENOMEM; 3596 return -ENOMEM;
3597 btrfs_set_buffer_uptodate(sb); 3597 btrfs_set_buffer_uptodate(sb);
3598 btrfs_set_buffer_lockdep_class(sb, 0); 3598 btrfs_set_buffer_lockdep_class(root->root_key.objectid, sb, 0);
3599 3599
3600 write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE); 3600 write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE);
3601 array_size = btrfs_super_sys_array_size(super_copy); 3601 array_size = btrfs_super_sys_array_size(super_copy);