diff options
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r-- | fs/ext4/super.c | 47 |
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 | ||
125 | static __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 | |||
137 | int 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 | |||
147 | void 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 | |||
125 | void *ext4_kvmalloc(size_t size, gfp_t flags) | 157 | void *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); |