aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2012-04-29 18:37:10 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-04-29 18:37:10 -0400
commit7ac5990d5a3e2e465162880819cc46c6427d3b6f (patch)
tree7ff0eafbf69010425c69bca61bddbc1c58adc89b
parentfa77dcfafeaa6bc73293c646bfc3d5192dcf0be2 (diff)
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: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r--fs/ext4/ext4_extents.h11
-rw-r--r--fs/ext4/extents.c50
2 files changed, 61 insertions, 0 deletions
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h
index 94822e74ef73..cb1b2c919963 100644
--- a/fs/ext4/ext4_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -114,6 +114,17 @@ struct ext4_extent_header {
114 114
115#define EXT4_EXT_MAGIC cpu_to_le16(0xf30a) 115#define EXT4_EXT_MAGIC cpu_to_le16(0xf30a)
116 116
117#define EXT4_EXTENT_TAIL_OFFSET(hdr) \
118 (sizeof(struct ext4_extent_header) + \
119 (sizeof(struct ext4_extent) * le16_to_cpu((hdr)->eh_max)))
120
121static inline struct ext4_extent_tail *
122find_ext4_extent_tail(struct ext4_extent_header *eh)
123{
124 return (struct ext4_extent_tail *)(((void *)eh) +
125 EXT4_EXTENT_TAIL_OFFSET(eh));
126}
127
117/* 128/*
118 * Array of ext4_ext_path contains path to some extent. 129 * Array of ext4_ext_path contains path to some extent.
119 * Creation/lookup routines use it for traversal/splitting/etc. 130 * Creation/lookup routines use it for traversal/splitting/etc.
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 8c1334ee8c7f..6f3b49bd34c7 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -52,6 +52,46 @@
52#define EXT4_EXT_MARK_UNINIT1 0x2 /* mark first half uninitialized */ 52#define EXT4_EXT_MARK_UNINIT1 0x2 /* mark first half uninitialized */
53#define EXT4_EXT_MARK_UNINIT2 0x4 /* mark second half uninitialized */ 53#define EXT4_EXT_MARK_UNINIT2 0x4 /* mark second half uninitialized */
54 54
55static __le32 ext4_extent_block_csum(struct inode *inode,
56 struct ext4_extent_header *eh)
57{
58 struct ext4_inode_info *ei = EXT4_I(inode);
59 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
60 __u32 csum;
61
62 csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)eh,
63 EXT4_EXTENT_TAIL_OFFSET(eh));
64 return cpu_to_le32(csum);
65}
66
67static int ext4_extent_block_csum_verify(struct inode *inode,
68 struct ext4_extent_header *eh)
69{
70 struct ext4_extent_tail *et;
71
72 if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
73 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
74 return 1;
75
76 et = find_ext4_extent_tail(eh);
77 if (et->et_checksum != ext4_extent_block_csum(inode, eh))
78 return 0;
79 return 1;
80}
81
82static void ext4_extent_block_csum_set(struct inode *inode,
83 struct ext4_extent_header *eh)
84{
85 struct ext4_extent_tail *et;
86
87 if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
88 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
89 return;
90
91 et = find_ext4_extent_tail(eh);
92 et->et_checksum = ext4_extent_block_csum(inode, eh);
93}
94
55static int ext4_split_extent(handle_t *handle, 95static int ext4_split_extent(handle_t *handle,
56 struct inode *inode, 96 struct inode *inode,
57 struct ext4_ext_path *path, 97 struct ext4_ext_path *path,
@@ -117,6 +157,7 @@ static int __ext4_ext_dirty(const char *where, unsigned int line,
117{ 157{
118 int err; 158 int err;
119 if (path->p_bh) { 159 if (path->p_bh) {
160 ext4_extent_block_csum_set(inode, ext_block_hdr(path->p_bh));
120 /* path points to block */ 161 /* path points to block */
121 err = __ext4_handle_dirty_metadata(where, line, handle, 162 err = __ext4_handle_dirty_metadata(where, line, handle,
122 inode, path->p_bh); 163 inode, path->p_bh);
@@ -391,6 +432,12 @@ static int __ext4_ext_check(const char *function, unsigned int line,
391 error_msg = "invalid extent entries"; 432 error_msg = "invalid extent entries";
392 goto corrupted; 433 goto corrupted;
393 } 434 }
435 /* Verify checksum on non-root extent tree nodes */
436 if (ext_depth(inode) != depth &&
437 !ext4_extent_block_csum_verify(inode, eh)) {
438 error_msg = "extent tree corrupted";
439 goto corrupted;
440 }
394 return 0; 441 return 0;
395 442
396corrupted: 443corrupted:
@@ -930,6 +977,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
930 le16_add_cpu(&neh->eh_entries, m); 977 le16_add_cpu(&neh->eh_entries, m);
931 } 978 }
932 979
980 ext4_extent_block_csum_set(inode, neh);
933 set_buffer_uptodate(bh); 981 set_buffer_uptodate(bh);
934 unlock_buffer(bh); 982 unlock_buffer(bh);
935 983
@@ -1008,6 +1056,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
1008 sizeof(struct ext4_extent_idx) * m); 1056 sizeof(struct ext4_extent_idx) * m);
1009 le16_add_cpu(&neh->eh_entries, m); 1057 le16_add_cpu(&neh->eh_entries, m);
1010 } 1058 }
1059 ext4_extent_block_csum_set(inode, neh);
1011 set_buffer_uptodate(bh); 1060 set_buffer_uptodate(bh);
1012 unlock_buffer(bh); 1061 unlock_buffer(bh);
1013 1062
@@ -1105,6 +1154,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
1105 else 1154 else
1106 neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0)); 1155 neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
1107 neh->eh_magic = EXT4_EXT_MAGIC; 1156 neh->eh_magic = EXT4_EXT_MAGIC;
1157 ext4_extent_block_csum_set(inode, neh);
1108 set_buffer_uptodate(bh); 1158 set_buffer_uptodate(bh);
1109 unlock_buffer(bh); 1159 unlock_buffer(bh);
1110 1160