aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c119
1 files changed, 107 insertions, 12 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 07eaf565fdcb..02bc8cbe7281 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -47,6 +47,73 @@
47 47
48#define MPAGE_DA_EXTENT_TAIL 0x01 48#define MPAGE_DA_EXTENT_TAIL 0x01
49 49
50static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw,
51 struct ext4_inode_info *ei)
52{
53 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
54 __u16 csum_lo;
55 __u16 csum_hi = 0;
56 __u32 csum;
57
58 csum_lo = raw->i_checksum_lo;
59 raw->i_checksum_lo = 0;
60 if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
61 EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) {
62 csum_hi = raw->i_checksum_hi;
63 raw->i_checksum_hi = 0;
64 }
65
66 csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)raw,
67 EXT4_INODE_SIZE(inode->i_sb));
68
69 raw->i_checksum_lo = csum_lo;
70 if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
71 EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
72 raw->i_checksum_hi = csum_hi;
73
74 return csum;
75}
76
77static int ext4_inode_csum_verify(struct inode *inode, struct ext4_inode *raw,
78 struct ext4_inode_info *ei)
79{
80 __u32 provided, calculated;
81
82 if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
83 cpu_to_le32(EXT4_OS_LINUX) ||
84 !EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
85 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
86 return 1;
87
88 provided = le16_to_cpu(raw->i_checksum_lo);
89 calculated = ext4_inode_csum(inode, raw, ei);
90 if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
91 EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
92 provided |= ((__u32)le16_to_cpu(raw->i_checksum_hi)) << 16;
93 else
94 calculated &= 0xFFFF;
95
96 return provided == calculated;
97}
98
99static void ext4_inode_csum_set(struct inode *inode, struct ext4_inode *raw,
100 struct ext4_inode_info *ei)
101{
102 __u32 csum;
103
104 if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
105 cpu_to_le32(EXT4_OS_LINUX) ||
106 !EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
107 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
108 return;
109
110 csum = ext4_inode_csum(inode, raw, ei);
111 raw->i_checksum_lo = cpu_to_le16(csum & 0xFFFF);
112 if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
113 EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
114 raw->i_checksum_hi = cpu_to_le16(csum >> 16);
115}
116
50static inline int ext4_begin_ordered_truncate(struct inode *inode, 117static inline int ext4_begin_ordered_truncate(struct inode *inode,
51 loff_t new_size) 118 loff_t new_size)
52{ 119{
@@ -3517,8 +3584,7 @@ make_io:
3517 b = table; 3584 b = table;
3518 end = b + EXT4_SB(sb)->s_inode_readahead_blks; 3585 end = b + EXT4_SB(sb)->s_inode_readahead_blks;
3519 num = EXT4_INODES_PER_GROUP(sb); 3586 num = EXT4_INODES_PER_GROUP(sb);
3520 if (EXT4_HAS_RO_COMPAT_FEATURE(sb, 3587 if (ext4_has_group_desc_csum(sb))
3521 EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
3522 num -= ext4_itable_unused_count(sb, gdp); 3588 num -= ext4_itable_unused_count(sb, gdp);
3523 table += num / inodes_per_block; 3589 table += num / inodes_per_block;
3524 if (end > table) 3590 if (end > table)
@@ -3646,6 +3712,39 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
3646 if (ret < 0) 3712 if (ret < 0)
3647 goto bad_inode; 3713 goto bad_inode;
3648 raw_inode = ext4_raw_inode(&iloc); 3714 raw_inode = ext4_raw_inode(&iloc);
3715
3716 if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
3717 ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
3718 if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
3719 EXT4_INODE_SIZE(inode->i_sb)) {
3720 EXT4_ERROR_INODE(inode, "bad extra_isize (%u != %u)",
3721 EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize,
3722 EXT4_INODE_SIZE(inode->i_sb));
3723 ret = -EIO;
3724 goto bad_inode;
3725 }
3726 } else
3727 ei->i_extra_isize = 0;
3728
3729 /* Precompute checksum seed for inode metadata */
3730 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
3731 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
3732 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
3733 __u32 csum;
3734 __le32 inum = cpu_to_le32(inode->i_ino);
3735 __le32 gen = raw_inode->i_generation;
3736 csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum,
3737 sizeof(inum));
3738 ei->i_csum_seed = ext4_chksum(sbi, csum, (__u8 *)&gen,
3739 sizeof(gen));
3740 }
3741
3742 if (!ext4_inode_csum_verify(inode, raw_inode, ei)) {
3743 EXT4_ERROR_INODE(inode, "checksum invalid");
3744 ret = -EIO;
3745 goto bad_inode;
3746 }
3747
3649 inode->i_mode = le16_to_cpu(raw_inode->i_mode); 3748 inode->i_mode = le16_to_cpu(raw_inode->i_mode);
3650 i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); 3749 i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
3651 i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); 3750 i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
@@ -3725,12 +3824,6 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
3725 } 3824 }
3726 3825
3727 if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { 3826 if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
3728 ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
3729 if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
3730 EXT4_INODE_SIZE(inode->i_sb)) {
3731 ret = -EIO;
3732 goto bad_inode;
3733 }
3734 if (ei->i_extra_isize == 0) { 3827 if (ei->i_extra_isize == 0) {
3735 /* The extra space is currently unused. Use it. */ 3828 /* The extra space is currently unused. Use it. */
3736 ei->i_extra_isize = sizeof(struct ext4_inode) - 3829 ei->i_extra_isize = sizeof(struct ext4_inode) -
@@ -3742,8 +3835,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
3742 if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) 3835 if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC))
3743 ext4_set_inode_state(inode, EXT4_STATE_XATTR); 3836 ext4_set_inode_state(inode, EXT4_STATE_XATTR);
3744 } 3837 }
3745 } else 3838 }
3746 ei->i_extra_isize = 0;
3747 3839
3748 EXT4_INODE_GET_XTIME(i_ctime, inode, raw_inode); 3840 EXT4_INODE_GET_XTIME(i_ctime, inode, raw_inode);
3749 EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode); 3841 EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode);
@@ -3942,7 +4034,7 @@ static int ext4_do_update_inode(handle_t *handle,
3942 EXT4_SET_RO_COMPAT_FEATURE(sb, 4034 EXT4_SET_RO_COMPAT_FEATURE(sb,
3943 EXT4_FEATURE_RO_COMPAT_LARGE_FILE); 4035 EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
3944 ext4_handle_sync(handle); 4036 ext4_handle_sync(handle);
3945 err = ext4_handle_dirty_super(handle, sb); 4037 err = ext4_handle_dirty_super_now(handle, sb);
3946 } 4038 }
3947 } 4039 }
3948 raw_inode->i_generation = cpu_to_le32(inode->i_generation); 4040 raw_inode->i_generation = cpu_to_le32(inode->i_generation);
@@ -3969,6 +4061,8 @@ static int ext4_do_update_inode(handle_t *handle,
3969 raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); 4061 raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
3970 } 4062 }
3971 4063
4064 ext4_inode_csum_set(inode, raw_inode, ei);
4065
3972 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); 4066 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
3973 rc = ext4_handle_dirty_metadata(handle, NULL, bh); 4067 rc = ext4_handle_dirty_metadata(handle, NULL, bh);
3974 if (!err) 4068 if (!err)
@@ -4213,7 +4307,8 @@ int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry,
4213 * will return the blocks that include the delayed allocation 4307 * will return the blocks that include the delayed allocation
4214 * blocks for this file. 4308 * blocks for this file.
4215 */ 4309 */
4216 delalloc_blocks = EXT4_I(inode)->i_reserved_data_blocks; 4310 delalloc_blocks = EXT4_C2B(EXT4_SB(inode->i_sb),
4311 EXT4_I(inode)->i_reserved_data_blocks);
4217 4312
4218 stat->blocks += (delalloc_blocks << inode->i_sb->s_blocksize_bits)>>9; 4313 stat->blocks += (delalloc_blocks << inode->i_sb->s_blocksize_bits)>>9;
4219 return 0; 4314 return 0;