aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiu Bo <bo.li.liu@oracle.com>2017-08-18 17:15:24 -0400
committerDavid Sterba <dsterba@suse.com>2017-08-21 11:47:43 -0400
commit64ecdb647ddb83dcff9c8e2a5c40119f171ea004 (patch)
treedba62d928939249fdb9ba235899bf0d6fa35e078
parentcdccee993f2f3466f69a358daec19de744a02f92 (diff)
Btrfs: add one more sanity check for shared ref type
Every shared ref has a parent tree block, which can be get from btrfs_extent_inline_ref_offset(). And the tree block must be aligned to the nodesize, so we'd know this inline ref is not valid if this block's bytenr is not aligned to the nodesize, in which case, most likely the ref type has been misused. This adds the above mentioned check and also updates print_extent_item() called by btrfs_print_leaf() to point out the invalid ref while printing the tree structure. Signed-off-by: Liu Bo <bo.li.liu@oracle.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/extent-tree.c29
-rw-r--r--fs/btrfs/print-tree.c27
2 files changed, 46 insertions, 10 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 51a691532fd8..96e49fd5b888 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1158,19 +1158,40 @@ int btrfs_get_extent_inline_ref_type(const struct extent_buffer *eb,
1158 enum btrfs_inline_ref_type is_data) 1158 enum btrfs_inline_ref_type is_data)
1159{ 1159{
1160 int type = btrfs_extent_inline_ref_type(eb, iref); 1160 int type = btrfs_extent_inline_ref_type(eb, iref);
1161 u64 offset = btrfs_extent_inline_ref_offset(eb, iref);
1161 1162
1162 if (type == BTRFS_TREE_BLOCK_REF_KEY || 1163 if (type == BTRFS_TREE_BLOCK_REF_KEY ||
1163 type == BTRFS_SHARED_BLOCK_REF_KEY || 1164 type == BTRFS_SHARED_BLOCK_REF_KEY ||
1164 type == BTRFS_SHARED_DATA_REF_KEY || 1165 type == BTRFS_SHARED_DATA_REF_KEY ||
1165 type == BTRFS_EXTENT_DATA_REF_KEY) { 1166 type == BTRFS_EXTENT_DATA_REF_KEY) {
1166 if (is_data == BTRFS_REF_TYPE_BLOCK) { 1167 if (is_data == BTRFS_REF_TYPE_BLOCK) {
1167 if (type == BTRFS_TREE_BLOCK_REF_KEY || 1168 if (type == BTRFS_TREE_BLOCK_REF_KEY)
1168 type == BTRFS_SHARED_BLOCK_REF_KEY)
1169 return type; 1169 return type;
1170 if (type == BTRFS_SHARED_BLOCK_REF_KEY) {
1171 ASSERT(eb->fs_info);
1172 /*
1173 * Every shared one has parent tree
1174 * block, which must be aligned to
1175 * nodesize.
1176 */
1177 if (offset &&
1178 IS_ALIGNED(offset, eb->fs_info->nodesize))
1179 return type;
1180 }
1170 } else if (is_data == BTRFS_REF_TYPE_DATA) { 1181 } else if (is_data == BTRFS_REF_TYPE_DATA) {
1171 if (type == BTRFS_EXTENT_DATA_REF_KEY || 1182 if (type == BTRFS_EXTENT_DATA_REF_KEY)
1172 type == BTRFS_SHARED_DATA_REF_KEY)
1173 return type; 1183 return type;
1184 if (type == BTRFS_SHARED_DATA_REF_KEY) {
1185 ASSERT(eb->fs_info);
1186 /*
1187 * Every shared one has parent tree
1188 * block, which must be aligned to
1189 * nodesize.
1190 */
1191 if (offset &&
1192 IS_ALIGNED(offset, eb->fs_info->nodesize))
1193 return type;
1194 }
1174 } else { 1195 } else {
1175 ASSERT(is_data == BTRFS_REF_TYPE_ANY); 1196 ASSERT(is_data == BTRFS_REF_TYPE_ANY);
1176 return type; 1197 return type;
diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c
index c1acbdcb476c..569205e651c7 100644
--- a/fs/btrfs/print-tree.c
+++ b/fs/btrfs/print-tree.c
@@ -44,7 +44,7 @@ static void print_dev_item(struct extent_buffer *eb,
44static void print_extent_data_ref(struct extent_buffer *eb, 44static void print_extent_data_ref(struct extent_buffer *eb,
45 struct btrfs_extent_data_ref *ref) 45 struct btrfs_extent_data_ref *ref)
46{ 46{
47 pr_info("\t\textent data backref root %llu objectid %llu offset %llu count %u\n", 47 pr_cont("extent data backref root %llu objectid %llu offset %llu count %u\n",
48 btrfs_extent_data_ref_root(eb, ref), 48 btrfs_extent_data_ref_root(eb, ref),
49 btrfs_extent_data_ref_objectid(eb, ref), 49 btrfs_extent_data_ref_objectid(eb, ref),
50 btrfs_extent_data_ref_offset(eb, ref), 50 btrfs_extent_data_ref_offset(eb, ref),
@@ -63,6 +63,7 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
63 u32 item_size = btrfs_item_size_nr(eb, slot); 63 u32 item_size = btrfs_item_size_nr(eb, slot);
64 u64 flags; 64 u64 flags;
65 u64 offset; 65 u64 offset;
66 int ref_index = 0;
66 67
67 if (item_size < sizeof(*ei)) { 68 if (item_size < sizeof(*ei)) {
68#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 69#ifdef BTRFS_COMPAT_EXTENT_TREE_V0
@@ -104,12 +105,20 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
104 iref = (struct btrfs_extent_inline_ref *)ptr; 105 iref = (struct btrfs_extent_inline_ref *)ptr;
105 type = btrfs_extent_inline_ref_type(eb, iref); 106 type = btrfs_extent_inline_ref_type(eb, iref);
106 offset = btrfs_extent_inline_ref_offset(eb, iref); 107 offset = btrfs_extent_inline_ref_offset(eb, iref);
108 pr_info("\t\tref#%d: ", ref_index++);
107 switch (type) { 109 switch (type) {
108 case BTRFS_TREE_BLOCK_REF_KEY: 110 case BTRFS_TREE_BLOCK_REF_KEY:
109 pr_info("\t\ttree block backref root %llu\n", offset); 111 pr_cont("tree block backref root %llu\n", offset);
110 break; 112 break;
111 case BTRFS_SHARED_BLOCK_REF_KEY: 113 case BTRFS_SHARED_BLOCK_REF_KEY:
112 pr_info("\t\tshared block backref parent %llu\n", offset); 114 pr_cont("shared block backref parent %llu\n", offset);
115 /*
116 * offset is supposed to be a tree block which
117 * must be aligned to nodesize.
118 */
119 if (!IS_ALIGNED(offset, eb->fs_info->nodesize))
120 pr_info("\t\t\t(parent %llu is NOT ALIGNED to nodesize %llu)\n",
121 offset, (unsigned long long)eb->fs_info->nodesize);
113 break; 122 break;
114 case BTRFS_EXTENT_DATA_REF_KEY: 123 case BTRFS_EXTENT_DATA_REF_KEY:
115 dref = (struct btrfs_extent_data_ref *)(&iref->offset); 124 dref = (struct btrfs_extent_data_ref *)(&iref->offset);
@@ -117,12 +126,18 @@ static void print_extent_item(struct extent_buffer *eb, int slot, int type)
117 break; 126 break;
118 case BTRFS_SHARED_DATA_REF_KEY: 127 case BTRFS_SHARED_DATA_REF_KEY:
119 sref = (struct btrfs_shared_data_ref *)(iref + 1); 128 sref = (struct btrfs_shared_data_ref *)(iref + 1);
120 pr_info("\t\tshared data backref parent %llu count %u\n", 129 pr_cont("shared data backref parent %llu count %u\n",
121 offset, btrfs_shared_data_ref_count(eb, sref)); 130 offset, btrfs_shared_data_ref_count(eb, sref));
131 /*
132 * offset is supposed to be a tree block which
133 * must be aligned to nodesize.
134 */
135 if (!IS_ALIGNED(offset, eb->fs_info->nodesize))
136 pr_info("\t\t\t(parent %llu is NOT ALIGNED to nodesize %llu)\n",
137 offset, (unsigned long long)eb->fs_info->nodesize);
122 break; 138 break;
123 default: 139 default:
124 btrfs_err(eb->fs_info, 140 pr_cont("(extent %llu has INVALID ref type %d)\n",
125 "extent %llu has invalid ref type %d",
126 eb->start, type); 141 eb->start, type);
127 return; 142 return;
128 } 143 }