Commit 5e96581a authored by Joel Becker's avatar Joel Becker Committed by Mark Fasheh

ocfs2: Wrap extent block reads in a dedicated function.

We weren't consistently checking extent blocks after we read them.
Most places checked the signature, but none checked h_blkno or
h_fs_signature.  Create a toplevel ocfs2_read_extent_block() that does
the read and the validation.
Signed-off-by: default avatarJoel Becker <joel.becker@oracle.com>
Signed-off-by: default avatarMark Fasheh <mfasheh@suse.com>
parent 42035306
...@@ -678,6 +678,66 @@ struct ocfs2_merge_ctxt { ...@@ -678,6 +678,66 @@ struct ocfs2_merge_ctxt {
int c_split_covers_rec; int c_split_covers_rec;
}; };
static int ocfs2_validate_extent_block(struct super_block *sb,
struct buffer_head *bh)
{
struct ocfs2_extent_block *eb =
(struct ocfs2_extent_block *)bh->b_data;
if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
ocfs2_error(sb,
"Extent block #%llu has bad signature %.*s",
(unsigned long long)bh->b_blocknr, 7,
eb->h_signature);
return -EINVAL;
}
if (le64_to_cpu(eb->h_blkno) != bh->b_blocknr) {
ocfs2_error(sb,
"Extent block #%llu has an invalid h_blkno "
"of %llu",
(unsigned long long)bh->b_blocknr,
(unsigned long long)le64_to_cpu(eb->h_blkno));
return -EINVAL;
}
if (le32_to_cpu(eb->h_fs_generation) != OCFS2_SB(sb)->fs_generation) {
ocfs2_error(sb,
"Extent block #%llu has an invalid "
"h_fs_generation of #%u",
(unsigned long long)bh->b_blocknr,
le32_to_cpu(eb->h_fs_generation));
return -EINVAL;
}
return 0;
}
int ocfs2_read_extent_block(struct inode *inode, u64 eb_blkno,
struct buffer_head **bh)
{
int rc;
struct buffer_head *tmp = *bh;
rc = ocfs2_read_block(inode, eb_blkno, &tmp);
if (rc)
goto out;
rc = ocfs2_validate_extent_block(inode->i_sb, tmp);
if (rc) {
brelse(tmp);
goto out;
}
/* If ocfs2_read_block() got us a new bh, pass it up. */
if (!*bh)
*bh = tmp;
out:
return rc;
}
/* /*
* How many free extents have we got before we need more meta data? * How many free extents have we got before we need more meta data?
*/ */
...@@ -697,8 +757,7 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb, ...@@ -697,8 +757,7 @@ int ocfs2_num_free_extents(struct ocfs2_super *osb,
last_eb_blk = ocfs2_et_get_last_eb_blk(et); last_eb_blk = ocfs2_et_get_last_eb_blk(et);
if (last_eb_blk) { if (last_eb_blk) {
retval = ocfs2_read_block(inode, last_eb_blk, retval = ocfs2_read_extent_block(inode, last_eb_blk, &eb_bh);
&eb_bh);
if (retval < 0) { if (retval < 0) {
mlog_errno(retval); mlog_errno(retval);
goto bail; goto bail;
...@@ -900,11 +959,8 @@ static int ocfs2_add_branch(struct ocfs2_super *osb, ...@@ -900,11 +959,8 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
for(i = 0; i < new_blocks; i++) { for(i = 0; i < new_blocks; i++) {
bh = new_eb_bhs[i]; bh = new_eb_bhs[i];
eb = (struct ocfs2_extent_block *) bh->b_data; eb = (struct ocfs2_extent_block *) bh->b_data;
if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { /* ocfs2_create_new_meta_bhs() should create it right! */
OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); BUG_ON(!OCFS2_IS_VALID_EXTENT_BLOCK(eb));
status = -EIO;
goto bail;
}
eb_el = &eb->h_list; eb_el = &eb->h_list;
status = ocfs2_journal_access(handle, inode, bh, status = ocfs2_journal_access(handle, inode, bh,
...@@ -1044,11 +1100,8 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, ...@@ -1044,11 +1100,8 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
} }
eb = (struct ocfs2_extent_block *) new_eb_bh->b_data; eb = (struct ocfs2_extent_block *) new_eb_bh->b_data;
if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { /* ocfs2_create_new_meta_bhs() should create it right! */
OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); BUG_ON(!OCFS2_IS_VALID_EXTENT_BLOCK(eb));
status = -EIO;
goto bail;
}
eb_el = &eb->h_list; eb_el = &eb->h_list;
root_el = et->et_root_el; root_el = et->et_root_el;
...@@ -1168,18 +1221,13 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb, ...@@ -1168,18 +1221,13 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb,
brelse(bh); brelse(bh);
bh = NULL; bh = NULL;
status = ocfs2_read_block(inode, blkno, &bh); status = ocfs2_read_extent_block(inode, blkno, &bh);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto bail; goto bail;
} }
eb = (struct ocfs2_extent_block *) bh->b_data; eb = (struct ocfs2_extent_block *) bh->b_data;
if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
status = -EIO;
goto bail;
}
el = &eb->h_list; el = &eb->h_list;
if (le16_to_cpu(el->l_next_free_rec) < if (le16_to_cpu(el->l_next_free_rec) <
...@@ -1532,7 +1580,7 @@ static int __ocfs2_find_path(struct inode *inode, ...@@ -1532,7 +1580,7 @@ static int __ocfs2_find_path(struct inode *inode,
brelse(bh); brelse(bh);
bh = NULL; bh = NULL;
ret = ocfs2_read_block(inode, blkno, &bh); ret = ocfs2_read_extent_block(inode, blkno, &bh);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
...@@ -1540,11 +1588,6 @@ static int __ocfs2_find_path(struct inode *inode, ...@@ -1540,11 +1588,6 @@ static int __ocfs2_find_path(struct inode *inode,
eb = (struct ocfs2_extent_block *) bh->b_data; eb = (struct ocfs2_extent_block *) bh->b_data;
el = &eb->h_list; el = &eb->h_list;
if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
ret = -EIO;
goto out;
}
if (le16_to_cpu(el->l_next_free_rec) > if (le16_to_cpu(el->l_next_free_rec) >
le16_to_cpu(el->l_count)) { le16_to_cpu(el->l_count)) {
...@@ -4089,8 +4132,15 @@ ocfs2_figure_merge_contig_type(struct inode *inode, struct ocfs2_path *path, ...@@ -4089,8 +4132,15 @@ ocfs2_figure_merge_contig_type(struct inode *inode, struct ocfs2_path *path,
le16_to_cpu(new_el->l_count)) { le16_to_cpu(new_el->l_count)) {
bh = path_leaf_bh(left_path); bh = path_leaf_bh(left_path);
eb = (struct ocfs2_extent_block *)bh->b_data; eb = (struct ocfs2_extent_block *)bh->b_data;
OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, ocfs2_error(inode->i_sb,
eb); "Extent block #%llu has an "
"invalid l_next_free_rec of "
"%d. It should have "
"matched the l_count of %d",
(unsigned long long)le64_to_cpu(eb->h_blkno),
le16_to_cpu(new_el->l_next_free_rec),
le16_to_cpu(new_el->l_count));
status = -EINVAL;
goto out; goto out;
} }
rec = &new_el->l_recs[ rec = &new_el->l_recs[
...@@ -4139,8 +4189,12 @@ ocfs2_figure_merge_contig_type(struct inode *inode, struct ocfs2_path *path, ...@@ -4139,8 +4189,12 @@ ocfs2_figure_merge_contig_type(struct inode *inode, struct ocfs2_path *path,
if (le16_to_cpu(new_el->l_next_free_rec) <= 1) { if (le16_to_cpu(new_el->l_next_free_rec) <= 1) {
bh = path_leaf_bh(right_path); bh = path_leaf_bh(right_path);
eb = (struct ocfs2_extent_block *)bh->b_data; eb = (struct ocfs2_extent_block *)bh->b_data;
OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, ocfs2_error(inode->i_sb,
eb); "Extent block #%llu has an "
"invalid l_next_free_rec of %d",
(unsigned long long)le64_to_cpu(eb->h_blkno),
le16_to_cpu(new_el->l_next_free_rec));
status = -EINVAL;
goto out; goto out;
} }
rec = &new_el->l_recs[1]; rec = &new_el->l_recs[1];
...@@ -4286,7 +4340,9 @@ static int ocfs2_figure_insert_type(struct inode *inode, ...@@ -4286,7 +4340,9 @@ static int ocfs2_figure_insert_type(struct inode *inode,
* ocfs2_figure_insert_type() and ocfs2_add_branch() * ocfs2_figure_insert_type() and ocfs2_add_branch()
* may want it later. * may want it later.
*/ */
ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et), &bh); ret = ocfs2_read_extent_block(inode,
ocfs2_et_get_last_eb_blk(et),
&bh);
if (ret) { if (ret) {
mlog_exit(ret); mlog_exit(ret);
goto out; goto out;
...@@ -4752,20 +4808,15 @@ static int __ocfs2_mark_extent_written(struct inode *inode, ...@@ -4752,20 +4808,15 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
if (path->p_tree_depth) { if (path->p_tree_depth) {
struct ocfs2_extent_block *eb; struct ocfs2_extent_block *eb;
ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et), ret = ocfs2_read_extent_block(inode,
&last_eb_bh); ocfs2_et_get_last_eb_blk(et),
&last_eb_bh);
if (ret) { if (ret) {
mlog_exit(ret); mlog_exit(ret);
goto out; goto out;
} }
eb = (struct ocfs2_extent_block *) last_eb_bh->b_data; eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
ret = -EROFS;
goto out;
}
rightmost_el = &eb->h_list; rightmost_el = &eb->h_list;
} else } else
rightmost_el = path_root_el(path); rightmost_el = path_root_el(path);
...@@ -4910,8 +4961,9 @@ static int ocfs2_split_tree(struct inode *inode, struct ocfs2_extent_tree *et, ...@@ -4910,8 +4961,9 @@ static int ocfs2_split_tree(struct inode *inode, struct ocfs2_extent_tree *et,
depth = path->p_tree_depth; depth = path->p_tree_depth;
if (depth > 0) { if (depth > 0) {
ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et), ret = ocfs2_read_extent_block(inode,
&last_eb_bh); ocfs2_et_get_last_eb_blk(et),
&last_eb_bh);
if (ret < 0) { if (ret < 0) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
...@@ -6231,11 +6283,10 @@ static int ocfs2_find_new_last_ext_blk(struct inode *inode, ...@@ -6231,11 +6283,10 @@ static int ocfs2_find_new_last_ext_blk(struct inode *inode,
eb = (struct ocfs2_extent_block *) bh->b_data; eb = (struct ocfs2_extent_block *) bh->b_data;
el = &eb->h_list; el = &eb->h_list;
if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb); /* ocfs2_find_leaf() gets the eb from ocfs2_read_extent_block().
ret = -EROFS; * Any corruption is a code bug. */
goto out; BUG_ON(!OCFS2_IS_VALID_EXTENT_BLOCK(eb));
}
*new_last_eb = bh; *new_last_eb = bh;
get_bh(*new_last_eb); get_bh(*new_last_eb);
...@@ -7140,20 +7191,14 @@ int ocfs2_prepare_truncate(struct ocfs2_super *osb, ...@@ -7140,20 +7191,14 @@ int ocfs2_prepare_truncate(struct ocfs2_super *osb,
ocfs2_init_dealloc_ctxt(&(*tc)->tc_dealloc); ocfs2_init_dealloc_ctxt(&(*tc)->tc_dealloc);
if (fe->id2.i_list.l_tree_depth) { if (fe->id2.i_list.l_tree_depth) {
status = ocfs2_read_block(inode, le64_to_cpu(fe->i_last_eb_blk), status = ocfs2_read_extent_block(inode,
&last_eb_bh); le64_to_cpu(fe->i_last_eb_blk),
&last_eb_bh);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto bail; goto bail;
} }
eb = (struct ocfs2_extent_block *) last_eb_bh->b_data; eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
brelse(last_eb_bh);
status = -EIO;
goto bail;
}
} }
(*tc)->tc_last_eb_bh = last_eb_bh; (*tc)->tc_last_eb_bh = last_eb_bh;
......
...@@ -73,6 +73,14 @@ void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et, ...@@ -73,6 +73,14 @@ void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
struct buffer_head *bh, struct buffer_head *bh,
struct ocfs2_xattr_value_root *xv); struct ocfs2_xattr_value_root *xv);
/*
* Read an extent block into *bh. If *bh is NULL, a bh will be
* allocated. This is a cached read. The extent block will be validated
* with ocfs2_validate_extent_block().
*/
int ocfs2_read_extent_block(struct inode *inode, u64 eb_blkno,
struct buffer_head **bh);
struct ocfs2_alloc_context; struct ocfs2_alloc_context;
int ocfs2_insert_extent(struct ocfs2_super *osb, int ocfs2_insert_extent(struct ocfs2_super *osb,
handle_t *handle, handle_t *handle,
......
...@@ -293,7 +293,7 @@ static int ocfs2_last_eb_is_empty(struct inode *inode, ...@@ -293,7 +293,7 @@ static int ocfs2_last_eb_is_empty(struct inode *inode,
struct ocfs2_extent_block *eb; struct ocfs2_extent_block *eb;
struct ocfs2_extent_list *el; struct ocfs2_extent_list *el;
ret = ocfs2_read_block(inode, last_eb_blk, &eb_bh); ret = ocfs2_read_extent_block(inode, last_eb_blk, &eb_bh);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
...@@ -302,12 +302,6 @@ static int ocfs2_last_eb_is_empty(struct inode *inode, ...@@ -302,12 +302,6 @@ static int ocfs2_last_eb_is_empty(struct inode *inode,
eb = (struct ocfs2_extent_block *) eb_bh->b_data; eb = (struct ocfs2_extent_block *) eb_bh->b_data;
el = &eb->h_list; el = &eb->h_list;
if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) {
ret = -EROFS;
OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, eb);
goto out;
}
if (el->l_tree_depth) { if (el->l_tree_depth) {
ocfs2_error(inode->i_sb, ocfs2_error(inode->i_sb,
"Inode %lu has non zero tree depth in " "Inode %lu has non zero tree depth in "
...@@ -381,23 +375,16 @@ static int ocfs2_figure_hole_clusters(struct inode *inode, ...@@ -381,23 +375,16 @@ static int ocfs2_figure_hole_clusters(struct inode *inode,
if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL) if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL)
goto no_more_extents; goto no_more_extents;
ret = ocfs2_read_block(inode, ret = ocfs2_read_extent_block(inode,
le64_to_cpu(eb->h_next_leaf_blk), le64_to_cpu(eb->h_next_leaf_blk),
&next_eb_bh); &next_eb_bh);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
} }
next_eb = (struct ocfs2_extent_block *)next_eb_bh->b_data;
if (!OCFS2_IS_VALID_EXTENT_BLOCK(next_eb)) {
ret = -EROFS;
OCFS2_RO_ON_INVALID_EXTENT_BLOCK(inode->i_sb, next_eb);
goto out;
}
next_eb = (struct ocfs2_extent_block *)next_eb_bh->b_data;
el = &next_eb->h_list; el = &next_eb->h_list;
i = ocfs2_search_for_hole_index(el, v_cluster); i = ocfs2_search_for_hole_index(el, v_cluster);
} }
......
...@@ -447,14 +447,6 @@ static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb) ...@@ -447,14 +447,6 @@ static inline int ocfs2_uses_extended_slot_map(struct ocfs2_super *osb)
#define OCFS2_IS_VALID_EXTENT_BLOCK(ptr) \ #define OCFS2_IS_VALID_EXTENT_BLOCK(ptr) \
(!strcmp((ptr)->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE)) (!strcmp((ptr)->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE))
#define OCFS2_RO_ON_INVALID_EXTENT_BLOCK(__sb, __eb) do { \
typeof(__eb) ____eb = (__eb); \
ocfs2_error((__sb), \
"Extent Block # %llu has bad signature %.*s", \
(unsigned long long)le64_to_cpu((____eb)->h_blkno), 7, \
(____eb)->h_signature); \
} while (0)
#define OCFS2_IS_VALID_GROUP_DESC(ptr) \ #define OCFS2_IS_VALID_GROUP_DESC(ptr) \
(!strcmp((ptr)->bg_signature, OCFS2_GROUP_DESC_SIGNATURE)) (!strcmp((ptr)->bg_signature, OCFS2_GROUP_DESC_SIGNATURE))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment