|
@@ -47,6 +47,73 @@
|
|
|
|
|
|
#define MPAGE_DA_EXTENT_TAIL 0x01
|
|
|
|
|
|
+static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw,
|
|
|
+ struct ext4_inode_info *ei)
|
|
|
+{
|
|
|
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
|
|
+ __u16 csum_lo;
|
|
|
+ __u16 csum_hi = 0;
|
|
|
+ __u32 csum;
|
|
|
+
|
|
|
+ csum_lo = raw->i_checksum_lo;
|
|
|
+ raw->i_checksum_lo = 0;
|
|
|
+ if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
|
|
|
+ EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) {
|
|
|
+ csum_hi = raw->i_checksum_hi;
|
|
|
+ raw->i_checksum_hi = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)raw,
|
|
|
+ EXT4_INODE_SIZE(inode->i_sb));
|
|
|
+
|
|
|
+ raw->i_checksum_lo = csum_lo;
|
|
|
+ if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
|
|
|
+ EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
|
|
|
+ raw->i_checksum_hi = csum_hi;
|
|
|
+
|
|
|
+ return csum;
|
|
|
+}
|
|
|
+
|
|
|
+static int ext4_inode_csum_verify(struct inode *inode, struct ext4_inode *raw,
|
|
|
+ struct ext4_inode_info *ei)
|
|
|
+{
|
|
|
+ __u32 provided, calculated;
|
|
|
+
|
|
|
+ if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
|
|
|
+ cpu_to_le32(EXT4_OS_LINUX) ||
|
|
|
+ !EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
|
|
|
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ provided = le16_to_cpu(raw->i_checksum_lo);
|
|
|
+ calculated = ext4_inode_csum(inode, raw, ei);
|
|
|
+ if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
|
|
|
+ EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
|
|
|
+ provided |= ((__u32)le16_to_cpu(raw->i_checksum_hi)) << 16;
|
|
|
+ else
|
|
|
+ calculated &= 0xFFFF;
|
|
|
+
|
|
|
+ return provided == calculated;
|
|
|
+}
|
|
|
+
|
|
|
+static void ext4_inode_csum_set(struct inode *inode, struct ext4_inode *raw,
|
|
|
+ struct ext4_inode_info *ei)
|
|
|
+{
|
|
|
+ __u32 csum;
|
|
|
+
|
|
|
+ if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
|
|
|
+ cpu_to_le32(EXT4_OS_LINUX) ||
|
|
|
+ !EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
|
|
|
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
|
|
|
+ return;
|
|
|
+
|
|
|
+ csum = ext4_inode_csum(inode, raw, ei);
|
|
|
+ raw->i_checksum_lo = cpu_to_le16(csum & 0xFFFF);
|
|
|
+ if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
|
|
|
+ EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
|
|
|
+ raw->i_checksum_hi = cpu_to_le16(csum >> 16);
|
|
|
+}
|
|
|
+
|
|
|
static inline int ext4_begin_ordered_truncate(struct inode *inode,
|
|
|
loff_t new_size)
|
|
|
{
|
|
@@ -3644,6 +3711,39 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
|
|
if (ret < 0)
|
|
|
goto bad_inode;
|
|
|
raw_inode = ext4_raw_inode(&iloc);
|
|
|
+
|
|
|
+ if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
|
|
|
+ ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
|
|
|
+ if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
|
|
|
+ EXT4_INODE_SIZE(inode->i_sb)) {
|
|
|
+ EXT4_ERROR_INODE(inode, "bad extra_isize (%u != %u)",
|
|
|
+ EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize,
|
|
|
+ EXT4_INODE_SIZE(inode->i_sb));
|
|
|
+ ret = -EIO;
|
|
|
+ goto bad_inode;
|
|
|
+ }
|
|
|
+ } else
|
|
|
+ ei->i_extra_isize = 0;
|
|
|
+
|
|
|
+ /* Precompute checksum seed for inode metadata */
|
|
|
+ if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
|
|
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
|
|
|
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
|
|
|
+ __u32 csum;
|
|
|
+ __le32 inum = cpu_to_le32(inode->i_ino);
|
|
|
+ __le32 gen = raw_inode->i_generation;
|
|
|
+ csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum,
|
|
|
+ sizeof(inum));
|
|
|
+ ei->i_csum_seed = ext4_chksum(sbi, csum, (__u8 *)&gen,
|
|
|
+ sizeof(gen));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ext4_inode_csum_verify(inode, raw_inode, ei)) {
|
|
|
+ EXT4_ERROR_INODE(inode, "checksum invalid");
|
|
|
+ ret = -EIO;
|
|
|
+ goto bad_inode;
|
|
|
+ }
|
|
|
+
|
|
|
inode->i_mode = le16_to_cpu(raw_inode->i_mode);
|
|
|
inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
|
|
|
inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
|
|
@@ -3721,12 +3821,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
|
|
}
|
|
|
|
|
|
if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
|
|
|
- ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
|
|
|
- if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
|
|
|
- EXT4_INODE_SIZE(inode->i_sb)) {
|
|
|
- ret = -EIO;
|
|
|
- goto bad_inode;
|
|
|
- }
|
|
|
if (ei->i_extra_isize == 0) {
|
|
|
/* The extra space is currently unused. Use it. */
|
|
|
ei->i_extra_isize = sizeof(struct ext4_inode) -
|
|
@@ -3738,8 +3832,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
|
|
if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC))
|
|
|
ext4_set_inode_state(inode, EXT4_STATE_XATTR);
|
|
|
}
|
|
|
- } else
|
|
|
- ei->i_extra_isize = 0;
|
|
|
+ }
|
|
|
|
|
|
EXT4_INODE_GET_XTIME(i_ctime, inode, raw_inode);
|
|
|
EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode);
|
|
@@ -3963,6 +4056,8 @@ static int ext4_do_update_inode(handle_t *handle,
|
|
|
raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
|
|
|
}
|
|
|
|
|
|
+ ext4_inode_csum_set(inode, raw_inode, ei);
|
|
|
+
|
|
|
BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
|
|
|
rc = ext4_handle_dirty_metadata(handle, NULL, bh);
|
|
|
if (!err)
|