aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2012-04-29 18:31:10 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-04-29 18:31:10 -0400
commit814525f4df50a196464ce2c7abe91f693203060f (patch)
tree221de5b0331240ff6bc99a2dd7c48460e1305075 /fs/ext4
parenta9c4731780544d52b243bf46e4dd635c67fa9f84 (diff)
ext4: calculate and verify inode checksums
This patch introduces to ext4 the ability to calculate and verify inode checksums. This requires the use of a new ro compatibility flag and some accompanying e2fsprogs patches to provide the relevant features in tune2fs and e2fsck. The inode generation changes have been integrated into this patch. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/ext4.h3
-rw-r--r--fs/ext4/ialloc.c13
-rw-r--r--fs/ext4/inode.c111
-rw-r--r--fs/ext4/ioctl.c7
4 files changed, 126 insertions, 8 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 5adbce519b66..ca96401b4b81 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -915,6 +915,9 @@ struct ext4_inode_info {
915 */ 915 */
916 tid_t i_sync_tid; 916 tid_t i_sync_tid;
917 tid_t i_datasync_tid; 917 tid_t i_datasync_tid;
918
919 /* Precomputed uuid+inum+igen checksum for seeding inode checksums */
920 __u32 i_csum_seed;
918}; 921};
919 922
920/* 923/*
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 409c2ee7750a..8207dfab2682 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -850,6 +850,19 @@ got:
850 inode->i_generation = sbi->s_next_generation++; 850 inode->i_generation = sbi->s_next_generation++;
851 spin_unlock(&sbi->s_next_gen_lock); 851 spin_unlock(&sbi->s_next_gen_lock);
852 852
853 /* Precompute checksum seed for inode metadata */
854 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
855 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
856 __u32 csum;
857 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
858 __le32 inum = cpu_to_le32(inode->i_ino);
859 __le32 gen = cpu_to_le32(inode->i_generation);
860 csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum,
861 sizeof(inum));
862 ei->i_csum_seed = ext4_chksum(sbi, csum, (__u8 *)&gen,
863 sizeof(gen));
864 }
865
853 ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */ 866 ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */
854 ext4_set_inode_state(inode, EXT4_STATE_NEW); 867 ext4_set_inode_state(inode, EXT4_STATE_NEW);
855 868
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 8bc21ecc1df5..16a67359b4c7 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{
@@ -3644,6 +3711,39 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
3644 if (ret < 0) 3711 if (ret < 0)
3645 goto bad_inode; 3712 goto bad_inode;
3646 raw_inode = ext4_raw_inode(&iloc); 3713 raw_inode = ext4_raw_inode(&iloc);
3714
3715 if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
3716 ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
3717 if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
3718 EXT4_INODE_SIZE(inode->i_sb)) {
3719 EXT4_ERROR_INODE(inode, "bad extra_isize (%u != %u)",
3720 EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize,
3721 EXT4_INODE_SIZE(inode->i_sb));
3722 ret = -EIO;
3723 goto bad_inode;
3724 }
3725 } else
3726 ei->i_extra_isize = 0;
3727
3728 /* Precompute checksum seed for inode metadata */
3729 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
3730 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
3731 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
3732 __u32 csum;
3733 __le32 inum = cpu_to_le32(inode->i_ino);
3734 __le32 gen = raw_inode->i_generation;
3735 csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum,
3736 sizeof(inum));
3737 ei->i_csum_seed = ext4_chksum(sbi, csum, (__u8 *)&gen,
3738 sizeof(gen));
3739 }
3740
3741 if (!ext4_inode_csum_verify(inode, raw_inode, ei)) {
3742 EXT4_ERROR_INODE(inode, "checksum invalid");
3743 ret = -EIO;
3744 goto bad_inode;
3745 }
3746
3647 inode->i_mode = le16_to_cpu(raw_inode->i_mode); 3747 inode->i_mode = le16_to_cpu(raw_inode->i_mode);
3648 inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); 3748 inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
3649 inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); 3749 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)
3721 } 3821 }
3722 3822
3723 if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { 3823 if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
3724 ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
3725 if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
3726 EXT4_INODE_SIZE(inode->i_sb)) {
3727 ret = -EIO;
3728 goto bad_inode;
3729 }
3730 if (ei->i_extra_isize == 0) { 3824 if (ei->i_extra_isize == 0) {
3731 /* The extra space is currently unused. Use it. */ 3825 /* The extra space is currently unused. Use it. */
3732 ei->i_extra_isize = sizeof(struct ext4_inode) - 3826 ei->i_extra_isize = sizeof(struct ext4_inode) -
@@ -3738,8 +3832,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
3738 if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) 3832 if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC))
3739 ext4_set_inode_state(inode, EXT4_STATE_XATTR); 3833 ext4_set_inode_state(inode, EXT4_STATE_XATTR);
3740 } 3834 }
3741 } else 3835 }
3742 ei->i_extra_isize = 0;
3743 3836
3744 EXT4_INODE_GET_XTIME(i_ctime, inode, raw_inode); 3837 EXT4_INODE_GET_XTIME(i_ctime, inode, raw_inode);
3745 EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode); 3838 EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode);
@@ -3963,6 +4056,8 @@ static int ext4_do_update_inode(handle_t *handle,
3963 raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); 4056 raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
3964 } 4057 }
3965 4058
4059 ext4_inode_csum_set(inode, raw_inode, ei);
4060
3966 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); 4061 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
3967 rc = ext4_handle_dirty_metadata(handle, NULL, bh); 4062 rc = ext4_handle_dirty_metadata(handle, NULL, bh);
3968 if (!err) 4063 if (!err)
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 6eee25591b81..feba55a225a6 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -152,6 +152,13 @@ flags_out:
152 if (!inode_owner_or_capable(inode)) 152 if (!inode_owner_or_capable(inode))
153 return -EPERM; 153 return -EPERM;
154 154
155 if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
156 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
157 ext4_warning(sb, "Setting inode version is not "
158 "supported with metadata_csum enabled.");
159 return -ENOTTY;
160 }
161
155 err = mnt_want_write_file(filp); 162 err = mnt_want_write_file(filp);
156 if (err) 163 if (err)
157 return err; 164 return err;