Commit 7ac5990d authored by Darrick J. Wong's avatar Darrick J. Wong Committed by Theodore Ts'o

ext4: verify and calculate checksums for extent tree blocks

Calculate and verify the checksum for each extent tree block.  The
checksum is located in the space immediately after the last possible
ext4_extent in the block.  The space is is typically the last 4-8
bytes in the block.
Signed-off-by: default avatarDarrick J. Wong <djwong@us.ibm.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent fa77dcfa
...@@ -114,6 +114,17 @@ struct ext4_extent_header { ...@@ -114,6 +114,17 @@ struct ext4_extent_header {
#define EXT4_EXT_MAGIC cpu_to_le16(0xf30a) #define EXT4_EXT_MAGIC cpu_to_le16(0xf30a)
#define EXT4_EXTENT_TAIL_OFFSET(hdr) \
(sizeof(struct ext4_extent_header) + \
(sizeof(struct ext4_extent) * le16_to_cpu((hdr)->eh_max)))
static inline struct ext4_extent_tail *
find_ext4_extent_tail(struct ext4_extent_header *eh)
{
return (struct ext4_extent_tail *)(((void *)eh) +
EXT4_EXTENT_TAIL_OFFSET(eh));
}
/* /*
* Array of ext4_ext_path contains path to some extent. * Array of ext4_ext_path contains path to some extent.
* Creation/lookup routines use it for traversal/splitting/etc. * Creation/lookup routines use it for traversal/splitting/etc.
......
...@@ -52,6 +52,46 @@ ...@@ -52,6 +52,46 @@
#define EXT4_EXT_MARK_UNINIT1 0x2 /* mark first half uninitialized */ #define EXT4_EXT_MARK_UNINIT1 0x2 /* mark first half uninitialized */
#define EXT4_EXT_MARK_UNINIT2 0x4 /* mark second half uninitialized */ #define EXT4_EXT_MARK_UNINIT2 0x4 /* mark second half uninitialized */
static __le32 ext4_extent_block_csum(struct inode *inode,
struct ext4_extent_header *eh)
{
struct ext4_inode_info *ei = EXT4_I(inode);
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
__u32 csum;
csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)eh,
EXT4_EXTENT_TAIL_OFFSET(eh));
return cpu_to_le32(csum);
}
static int ext4_extent_block_csum_verify(struct inode *inode,
struct ext4_extent_header *eh)
{
struct ext4_extent_tail *et;
if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return 1;
et = find_ext4_extent_tail(eh);
if (et->et_checksum != ext4_extent_block_csum(inode, eh))
return 0;
return 1;
}
static void ext4_extent_block_csum_set(struct inode *inode,
struct ext4_extent_header *eh)
{
struct ext4_extent_tail *et;
if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
return;
et = find_ext4_extent_tail(eh);
et->et_checksum = ext4_extent_block_csum(inode, eh);
}
static int ext4_split_extent(handle_t *handle, static int ext4_split_extent(handle_t *handle,
struct inode *inode, struct inode *inode,
struct ext4_ext_path *path, struct ext4_ext_path *path,
...@@ -117,6 +157,7 @@ static int __ext4_ext_dirty(const char *where, unsigned int line, ...@@ -117,6 +157,7 @@ static int __ext4_ext_dirty(const char *where, unsigned int line,
{ {
int err; int err;
if (path->p_bh) { if (path->p_bh) {
ext4_extent_block_csum_set(inode, ext_block_hdr(path->p_bh));
/* path points to block */ /* path points to block */
err = __ext4_handle_dirty_metadata(where, line, handle, err = __ext4_handle_dirty_metadata(where, line, handle,
inode, path->p_bh); inode, path->p_bh);
...@@ -391,6 +432,12 @@ static int __ext4_ext_check(const char *function, unsigned int line, ...@@ -391,6 +432,12 @@ static int __ext4_ext_check(const char *function, unsigned int line,
error_msg = "invalid extent entries"; error_msg = "invalid extent entries";
goto corrupted; goto corrupted;
} }
/* Verify checksum on non-root extent tree nodes */
if (ext_depth(inode) != depth &&
!ext4_extent_block_csum_verify(inode, eh)) {
error_msg = "extent tree corrupted";
goto corrupted;
}
return 0; return 0;
corrupted: corrupted:
...@@ -930,6 +977,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, ...@@ -930,6 +977,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
le16_add_cpu(&neh->eh_entries, m); le16_add_cpu(&neh->eh_entries, m);
} }
ext4_extent_block_csum_set(inode, neh);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
unlock_buffer(bh); unlock_buffer(bh);
...@@ -1008,6 +1056,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, ...@@ -1008,6 +1056,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
sizeof(struct ext4_extent_idx) * m); sizeof(struct ext4_extent_idx) * m);
le16_add_cpu(&neh->eh_entries, m); le16_add_cpu(&neh->eh_entries, m);
} }
ext4_extent_block_csum_set(inode, neh);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
unlock_buffer(bh); unlock_buffer(bh);
...@@ -1105,6 +1154,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, ...@@ -1105,6 +1154,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
else else
neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0)); neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
neh->eh_magic = EXT4_EXT_MAGIC; neh->eh_magic = EXT4_EXT_MAGIC;
ext4_extent_block_csum_set(inode, neh);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
unlock_buffer(bh); unlock_buffer(bh);
......
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