aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/super.c
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2012-04-29 18:29:10 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-04-29 18:29:10 -0400
commita9c4731780544d52b243bf46e4dd635c67fa9f84 (patch)
treedc735f2f59fa2107e8fed8e3d26f259557e34008 /fs/ext4/super.c
parent0441984a3398970ab4820410b9cf4ff85bf3a6b0 (diff)
ext4: calculate and verify superblock checksum
Calculate and verify the superblock checksum. Since the UUID and block group number are embedded in each copy of the superblock, we need only checksum the entire block. Refactor some of the code to eliminate open-coding of the checksum update call. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r--fs/ext4/super.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 11a0a7078da7..f80c7e612829 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -122,6 +122,38 @@ static int ext4_verify_csum_type(struct super_block *sb,
122 return es->s_checksum_type == EXT4_CRC32C_CHKSUM; 122 return es->s_checksum_type == EXT4_CRC32C_CHKSUM;
123} 123}
124 124
125static __le32 ext4_superblock_csum(struct super_block *sb,
126 struct ext4_super_block *es)
127{
128 struct ext4_sb_info *sbi = EXT4_SB(sb);
129 int offset = offsetof(struct ext4_super_block, s_checksum);
130 __u32 csum;
131
132 csum = ext4_chksum(sbi, ~0, (char *)es, offset);
133
134 return cpu_to_le32(csum);
135}
136
137int ext4_superblock_csum_verify(struct super_block *sb,
138 struct ext4_super_block *es)
139{
140 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
141 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
142 return 1;
143
144 return es->s_checksum == ext4_superblock_csum(sb, es);
145}
146
147void ext4_superblock_csum_set(struct super_block *sb,
148 struct ext4_super_block *es)
149{
150 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
151 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
152 return;
153
154 es->s_checksum = ext4_superblock_csum(sb, es);
155}
156
125void *ext4_kvmalloc(size_t size, gfp_t flags) 157void *ext4_kvmalloc(size_t size, gfp_t flags)
126{ 158{
127 void *ret; 159 void *ret;
@@ -3057,6 +3089,20 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
3057 } 3089 }
3058 } 3090 }
3059 3091
3092 /* Check superblock checksum */
3093 if (!ext4_superblock_csum_verify(sb, es)) {
3094 ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with "
3095 "invalid superblock checksum. Run e2fsck?");
3096 silent = 1;
3097 goto cantfind_ext4;
3098 }
3099
3100 /* Precompute checksum seed for all metadata */
3101 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
3102 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
3103 sbi->s_csum_seed = ext4_chksum(sbi, ~0, es->s_uuid,
3104 sizeof(es->s_uuid));
3105
3060 /* Set defaults before we parse the mount options */ 3106 /* Set defaults before we parse the mount options */
3061 def_mount_opts = le32_to_cpu(es->s_default_mount_opts); 3107 def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
3062 set_opt(sb, INIT_INODE_TABLE); 3108 set_opt(sb, INIT_INODE_TABLE);
@@ -4059,6 +4105,7 @@ static int ext4_commit_super(struct super_block *sb, int sync)
4059 &EXT4_SB(sb)->s_freeinodes_counter)); 4105 &EXT4_SB(sb)->s_freeinodes_counter));
4060 sb->s_dirt = 0; 4106 sb->s_dirt = 0;
4061 BUFFER_TRACE(sbh, "marking dirty"); 4107 BUFFER_TRACE(sbh, "marking dirty");
4108 ext4_superblock_csum_set(sb, es);
4062 mark_buffer_dirty(sbh); 4109 mark_buffer_dirty(sbh);
4063 if (sync) { 4110 if (sync) {
4064 error = sync_dirty_buffer(sbh); 4111 error = sync_dirty_buffer(sbh);