|
@@ -52,6 +52,46 @@
|
|
|
#define EXT4_EXT_MARK_UNINIT1 0x2 /* mark first 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,
|
|
|
struct inode *inode,
|
|
|
struct ext4_ext_path *path,
|
|
@@ -117,6 +157,7 @@ static int __ext4_ext_dirty(const char *where, unsigned int line,
|
|
|
{
|
|
|
int err;
|
|
|
if (path->p_bh) {
|
|
|
+ ext4_extent_block_csum_set(inode, ext_block_hdr(path->p_bh));
|
|
|
/* path points to block */
|
|
|
err = __ext4_handle_dirty_metadata(where, line, handle,
|
|
|
inode, path->p_bh);
|
|
@@ -391,6 +432,12 @@ static int __ext4_ext_check(const char *function, unsigned int line,
|
|
|
error_msg = "invalid extent entries";
|
|
|
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;
|
|
|
|
|
|
corrupted:
|
|
@@ -930,6 +977,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
|
|
le16_add_cpu(&neh->eh_entries, m);
|
|
|
}
|
|
|
|
|
|
+ ext4_extent_block_csum_set(inode, neh);
|
|
|
set_buffer_uptodate(bh);
|
|
|
unlock_buffer(bh);
|
|
|
|
|
@@ -1008,6 +1056,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
|
|
|
sizeof(struct ext4_extent_idx) * m);
|
|
|
le16_add_cpu(&neh->eh_entries, m);
|
|
|
}
|
|
|
+ ext4_extent_block_csum_set(inode, neh);
|
|
|
set_buffer_uptodate(bh);
|
|
|
unlock_buffer(bh);
|
|
|
|
|
@@ -1105,6 +1154,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
|
|
|
else
|
|
|
neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
|
|
|
neh->eh_magic = EXT4_EXT_MAGIC;
|
|
|
+ ext4_extent_block_csum_set(inode, neh);
|
|
|
set_buffer_uptodate(bh);
|
|
|
unlock_buffer(bh);
|
|
|
|