aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/super.c
diff options
context:
space:
mode:
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 e2bdf93693a6..dd4ff9c87358 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -37,12 +37,14 @@
37#include <linux/quotaops.h> 37#include <linux/quotaops.h>
38#include <linux/seq_file.h> 38#include <linux/seq_file.h>
39#include <linux/log2.h> 39#include <linux/log2.h>
40#include <linux/crc16.h>
40 41
41#include <asm/uaccess.h> 42#include <asm/uaccess.h>
42 43
43#include "xattr.h" 44#include "xattr.h"
44#include "acl.h" 45#include "acl.h"
45#include "namei.h" 46#include "namei.h"
47#include "group.h"
46 48
47static int ext4_load_journal(struct super_block *, struct ext4_super_block *, 49static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
48 unsigned long journal_devnum); 50 unsigned long journal_devnum);
@@ -1308,6 +1310,43 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
1308 return res; 1310 return res;
1309} 1311}
1310 1312
1313__le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
1314 struct ext4_group_desc *gdp)
1315{
1316 __u16 crc = 0;
1317
1318 if (sbi->s_es->s_feature_ro_compat &
1319 cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
1320 int offset = offsetof(struct ext4_group_desc, bg_checksum);
1321 __le32 le_group = cpu_to_le32(block_group);
1322
1323 crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
1324 crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
1325 crc = crc16(crc, (__u8 *)gdp, offset);
1326 offset += sizeof(gdp->bg_checksum); /* skip checksum */
1327 /* for checksum of struct ext4_group_desc do the rest...*/
1328 if ((sbi->s_es->s_feature_incompat &
1329 cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
1330 offset < le16_to_cpu(sbi->s_es->s_desc_size))
1331 crc = crc16(crc, (__u8 *)gdp + offset,
1332 le16_to_cpu(sbi->s_es->s_desc_size) -
1333 offset);
1334 }
1335
1336 return cpu_to_le16(crc);
1337}
1338
1339int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group,
1340 struct ext4_group_desc *gdp)
1341{
1342 if ((sbi->s_es->s_feature_ro_compat &
1343 cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) &&
1344 (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp)))
1345 return 0;
1346
1347 return 1;
1348}
1349
1311/* Called at mount-time, super-block is locked */ 1350/* Called at mount-time, super-block is locked */
1312static int ext4_check_descriptors (struct super_block * sb) 1351static int ext4_check_descriptors (struct super_block * sb)
1313{ 1352{
@@ -1362,6 +1401,14 @@ static int ext4_check_descriptors (struct super_block * sb)
1362 i, inode_table); 1401 i, inode_table);
1363 return 0; 1402 return 0;
1364 } 1403 }
1404 if (!ext4_group_desc_csum_verify(sbi, i, gdp)) {
1405 ext4_error(sb, __FUNCTION__,
1406 "Checksum for group %d failed (%u!=%u)\n", i,
1407 le16_to_cpu(ext4_group_desc_csum(sbi, i,
1408 gdp)),
1409 le16_to_cpu(gdp->bg_checksum));
1410 return 0;
1411 }
1365 first_block += EXT4_BLOCKS_PER_GROUP(sb); 1412 first_block += EXT4_BLOCKS_PER_GROUP(sb);
1366 gdp = (struct ext4_group_desc *) 1413 gdp = (struct ext4_group_desc *)
1367 ((__u8 *)gdp + EXT4_DESC_SIZE(sb)); 1414 ((__u8 *)gdp + EXT4_DESC_SIZE(sb));