aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/ext4.h10
-rw-r--r--fs/ext4/ext4_jbd2.c9
-rw-r--r--fs/ext4/ext4_jbd2.h7
-rw-r--r--fs/ext4/inode.c2
-rw-r--r--fs/ext4/namei.c4
-rw-r--r--fs/ext4/resize.c4
-rw-r--r--fs/ext4/super.c47
7 files changed, 76 insertions, 7 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index f19192bde094..5adbce519b66 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1280,6 +1280,9 @@ struct ext4_sb_info {
1280 1280
1281 /* Reference to checksum algorithm driver via cryptoapi */ 1281 /* Reference to checksum algorithm driver via cryptoapi */
1282 struct crypto_shash *s_chksum_driver; 1282 struct crypto_shash *s_chksum_driver;
1283
1284 /* Precomputed FS UUID checksum for seeding other checksums */
1285 __u32 s_csum_seed;
1283}; 1286};
1284 1287
1285static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) 1288static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
@@ -2004,6 +2007,10 @@ extern int ext4_group_extend(struct super_block *sb,
2004extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count); 2007extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count);
2005 2008
2006/* super.c */ 2009/* super.c */
2010extern int ext4_superblock_csum_verify(struct super_block *sb,
2011 struct ext4_super_block *es);
2012extern void ext4_superblock_csum_set(struct super_block *sb,
2013 struct ext4_super_block *es);
2007extern void *ext4_kvmalloc(size_t size, gfp_t flags); 2014extern void *ext4_kvmalloc(size_t size, gfp_t flags);
2008extern void *ext4_kvzalloc(size_t size, gfp_t flags); 2015extern void *ext4_kvzalloc(size_t size, gfp_t flags);
2009extern void ext4_kvfree(void *ptr); 2016extern void ext4_kvfree(void *ptr);
@@ -2279,6 +2286,9 @@ static inline void ext4_unlock_group(struct super_block *sb,
2279 2286
2280static inline void ext4_mark_super_dirty(struct super_block *sb) 2287static inline void ext4_mark_super_dirty(struct super_block *sb)
2281{ 2288{
2289 struct ext4_super_block *es = EXT4_SB(sb)->s_es;
2290
2291 ext4_superblock_csum_set(sb, es);
2282 if (EXT4_SB(sb)->s_journal == NULL) 2292 if (EXT4_SB(sb)->s_journal == NULL)
2283 sb->s_dirt =1; 2293 sb->s_dirt =1;
2284} 2294}
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index aca179017582..90f7c2e84db1 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -138,16 +138,23 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
138} 138}
139 139
140int __ext4_handle_dirty_super(const char *where, unsigned int line, 140int __ext4_handle_dirty_super(const char *where, unsigned int line,
141 handle_t *handle, struct super_block *sb) 141 handle_t *handle, struct super_block *sb,
142 int now)
142{ 143{
143 struct buffer_head *bh = EXT4_SB(sb)->s_sbh; 144 struct buffer_head *bh = EXT4_SB(sb)->s_sbh;
144 int err = 0; 145 int err = 0;
145 146
146 if (ext4_handle_valid(handle)) { 147 if (ext4_handle_valid(handle)) {
148 ext4_superblock_csum_set(sb,
149 (struct ext4_super_block *)bh->b_data);
147 err = jbd2_journal_dirty_metadata(handle, bh); 150 err = jbd2_journal_dirty_metadata(handle, bh);
148 if (err) 151 if (err)
149 ext4_journal_abort_handle(where, line, __func__, 152 ext4_journal_abort_handle(where, line, __func__,
150 bh, handle, err); 153 bh, handle, err);
154 } else if (now) {
155 ext4_superblock_csum_set(sb,
156 (struct ext4_super_block *)bh->b_data);
157 mark_buffer_dirty(bh);
151 } else 158 } else
152 sb->s_dirt = 1; 159 sb->s_dirt = 1;
153 return err; 160 return err;
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
index 83b20fcf9400..f440e8f1841f 100644
--- a/fs/ext4/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -213,7 +213,8 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
213 struct buffer_head *bh); 213 struct buffer_head *bh);
214 214
215int __ext4_handle_dirty_super(const char *where, unsigned int line, 215int __ext4_handle_dirty_super(const char *where, unsigned int line,
216 handle_t *handle, struct super_block *sb); 216 handle_t *handle, struct super_block *sb,
217 int now);
217 218
218#define ext4_journal_get_write_access(handle, bh) \ 219#define ext4_journal_get_write_access(handle, bh) \
219 __ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh)) 220 __ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh))
@@ -225,8 +226,10 @@ int __ext4_handle_dirty_super(const char *where, unsigned int line,
225#define ext4_handle_dirty_metadata(handle, inode, bh) \ 226#define ext4_handle_dirty_metadata(handle, inode, bh) \
226 __ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \ 227 __ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \
227 (bh)) 228 (bh))
229#define ext4_handle_dirty_super_now(handle, sb) \
230 __ext4_handle_dirty_super(__func__, __LINE__, (handle), (sb), 1)
228#define ext4_handle_dirty_super(handle, sb) \ 231#define ext4_handle_dirty_super(handle, sb) \
229 __ext4_handle_dirty_super(__func__, __LINE__, (handle), (sb)) 232 __ext4_handle_dirty_super(__func__, __LINE__, (handle), (sb), 0)
230 233
231handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks); 234handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks);
232int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle); 235int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c77b0bd2c711..8bc21ecc1df5 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3936,7 +3936,7 @@ static int ext4_do_update_inode(handle_t *handle,
3936 EXT4_SET_RO_COMPAT_FEATURE(sb, 3936 EXT4_SET_RO_COMPAT_FEATURE(sb,
3937 EXT4_FEATURE_RO_COMPAT_LARGE_FILE); 3937 EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
3938 ext4_handle_sync(handle); 3938 ext4_handle_sync(handle);
3939 err = ext4_handle_dirty_super(handle, sb); 3939 err = ext4_handle_dirty_super_now(handle, sb);
3940 } 3940 }
3941 } 3941 }
3942 raw_inode->i_generation = cpu_to_le32(inode->i_generation); 3942 raw_inode->i_generation = cpu_to_le32(inode->i_generation);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index b58bd5c8ffe7..625125172d05 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2021,7 +2021,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
2021 /* Insert this inode at the head of the on-disk orphan list... */ 2021 /* Insert this inode at the head of the on-disk orphan list... */
2022 NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan); 2022 NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan);
2023 EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); 2023 EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);
2024 err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); 2024 err = ext4_handle_dirty_super_now(handle, sb);
2025 rc = ext4_mark_iloc_dirty(handle, inode, &iloc); 2025 rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
2026 if (!err) 2026 if (!err)
2027 err = rc; 2027 err = rc;
@@ -2094,7 +2094,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
2094 if (err) 2094 if (err)
2095 goto out_brelse; 2095 goto out_brelse;
2096 sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); 2096 sbi->s_es->s_last_orphan = cpu_to_le32(ino_next);
2097 err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh); 2097 err = ext4_handle_dirty_super_now(handle, inode->i_sb);
2098 } else { 2098 } else {
2099 struct ext4_iloc iloc2; 2099 struct ext4_iloc iloc2;
2100 struct inode *i_prev = 2100 struct inode *i_prev =
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index 59fa0be27251..e0374757a94b 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -796,7 +796,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
796 ext4_kvfree(o_group_desc); 796 ext4_kvfree(o_group_desc);
797 797
798 le16_add_cpu(&es->s_reserved_gdt_blocks, -1); 798 le16_add_cpu(&es->s_reserved_gdt_blocks, -1);
799 err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); 799 err = ext4_handle_dirty_super_now(handle, sb);
800 if (err) 800 if (err)
801 ext4_std_error(sb, err); 801 ext4_std_error(sb, err);
802 802
@@ -968,6 +968,8 @@ static void update_backups(struct super_block *sb,
968 goto exit_err; 968 goto exit_err;
969 } 969 }
970 970
971 ext4_superblock_csum_set(sb, (struct ext4_super_block *)data);
972
971 while ((group = ext4_list_backups(sb, &three, &five, &seven)) < last) { 973 while ((group = ext4_list_backups(sb, &three, &five, &seven)) < last) {
972 struct buffer_head *bh; 974 struct buffer_head *bh;
973 975
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 11a0a7078da7..f80c7e612829 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -122,6 +122,38 @@ static int ext4_verify_csum_type(struct super_block *sb,
122 return es->s_checksum_type == EXT4_CRC32C_CHKSUM; 122 return es->s_checksum_type == EXT4_CRC32C_CHKSUM;
123} 123}
124 124
125static __le32 ext4_superblock_csum(struct super_block *sb,
126 struct ext4_super_block *es)
127{
128 struct ext4_sb_info *sbi = EXT4_SB(sb);
129 int offset = offsetof(struct ext4_super_block, s_checksum);
130 __u32 csum;
131
132 csum = ext4_chksum(sbi, ~0, (char *)es, offset);
133
134 return cpu_to_le32(csum);
135}
136
137int ext4_superblock_csum_verify(struct super_block *sb,
138 struct ext4_super_block *es)
139{
140 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
141 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
142 return 1;
143
144 return es->s_checksum == ext4_superblock_csum(sb, es);
145}
146
147void ext4_superblock_csum_set(struct super_block *sb,
148 struct ext4_super_block *es)
149{
150 if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
151 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
152 return;
153
154 es->s_checksum = ext4_superblock_csum(sb, es);
155}
156
125void *ext4_kvmalloc(size_t size, gfp_t flags) 157void *ext4_kvmalloc(size_t size, gfp_t flags)
126{ 158{
127 void *ret; 159 void *ret;
@@ -3057,6 +3089,20 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
3057 } 3089 }
3058 } 3090 }
3059 3091
3092 /* Check superblock checksum */
3093 if (!ext4_superblock_csum_verify(sb, es)) {
3094 ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with "
3095 "invalid superblock checksum. Run e2fsck?");
3096 silent = 1;
3097 goto cantfind_ext4;
3098 }
3099
3100 /* Precompute checksum seed for all metadata */
3101 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
3102 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
3103 sbi->s_csum_seed = ext4_chksum(sbi, ~0, es->s_uuid,
3104 sizeof(es->s_uuid));
3105
3060 /* Set defaults before we parse the mount options */ 3106 /* Set defaults before we parse the mount options */
3061 def_mount_opts = le32_to_cpu(es->s_default_mount_opts); 3107 def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
3062 set_opt(sb, INIT_INODE_TABLE); 3108 set_opt(sb, INIT_INODE_TABLE);
@@ -4059,6 +4105,7 @@ static int ext4_commit_super(struct super_block *sb, int sync)
4059 &EXT4_SB(sb)->s_freeinodes_counter)); 4105 &EXT4_SB(sb)->s_freeinodes_counter));
4060 sb->s_dirt = 0; 4106 sb->s_dirt = 0;
4061 BUFFER_TRACE(sbh, "marking dirty"); 4107 BUFFER_TRACE(sbh, "marking dirty");
4108 ext4_superblock_csum_set(sb, es);
4062 mark_buffer_dirty(sbh); 4109 mark_buffer_dirty(sbh);
4063 if (sync) { 4110 if (sync) {
4064 error = sync_dirty_buffer(sbh); 4111 error = sync_dirty_buffer(sbh);