diff options
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 119 |
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 | ||
50 | static __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 | |||
77 | static 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 | |||
99 | static 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 | |||
50 | static inline int ext4_begin_ordered_truncate(struct inode *inode, | 117 | static 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; |