diff options
-rw-r--r-- | fs/ext4/Kconfig | 2 | ||||
-rw-r--r-- | fs/ext4/balloc.c | 41 | ||||
-rw-r--r-- | fs/ext4/bitmap.c | 83 | ||||
-rw-r--r-- | fs/ext4/dir.c | 12 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 130 | ||||
-rw-r--r-- | fs/ext4/ext4_extents.h | 24 | ||||
-rw-r--r-- | fs/ext4/ext4_jbd2.c | 9 | ||||
-rw-r--r-- | fs/ext4/ext4_jbd2.h | 7 | ||||
-rw-r--r-- | fs/ext4/extents.c | 91 | ||||
-rw-r--r-- | fs/ext4/file.c | 2 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 81 | ||||
-rw-r--r-- | fs/ext4/inode.c | 119 | ||||
-rw-r--r-- | fs/ext4/ioctl.c | 19 | ||||
-rw-r--r-- | fs/ext4/mballoc.c | 30 | ||||
-rw-r--r-- | fs/ext4/mmp.c | 44 | ||||
-rw-r--r-- | fs/ext4/namei.c | 445 | ||||
-rw-r--r-- | fs/ext4/resize.c | 71 | ||||
-rw-r--r-- | fs/ext4/super.c | 253 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 92 | ||||
-rw-r--r-- | fs/ext4/xattr.h | 4 | ||||
-rw-r--r-- | fs/jbd2/Kconfig | 2 | ||||
-rw-r--r-- | fs/jbd2/commit.c | 70 | ||||
-rw-r--r-- | fs/jbd2/journal.c | 132 | ||||
-rw-r--r-- | fs/jbd2/recovery.c | 126 | ||||
-rw-r--r-- | fs/jbd2/revoke.c | 27 | ||||
-rw-r--r-- | fs/jbd2/transaction.c | 4 | ||||
-rw-r--r-- | include/linux/jbd2.h | 59 | ||||
-rw-r--r-- | include/linux/jbd_common.h | 2 |
28 files changed, 1784 insertions, 197 deletions
diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index 9ed1bb1f319f..c22f17021b6e 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig | |||
@@ -2,6 +2,8 @@ config EXT4_FS | |||
2 | tristate "The Extended 4 (ext4) filesystem" | 2 | tristate "The Extended 4 (ext4) filesystem" |
3 | select JBD2 | 3 | select JBD2 |
4 | select CRC16 | 4 | select CRC16 |
5 | select CRYPTO | ||
6 | select CRYPTO_CRC32C | ||
5 | help | 7 | help |
6 | This is the next generation of the ext3 filesystem. | 8 | This is the next generation of the ext3 filesystem. |
7 | 9 | ||
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index c45c41129a35..99b6324290db 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -168,12 +168,14 @@ void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, | |||
168 | 168 | ||
169 | /* If checksum is bad mark all blocks used to prevent allocation | 169 | /* If checksum is bad mark all blocks used to prevent allocation |
170 | * essentially implementing a per-group read-only flag. */ | 170 | * essentially implementing a per-group read-only flag. */ |
171 | if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { | 171 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { |
172 | ext4_error(sb, "Checksum bad for group %u", block_group); | 172 | ext4_error(sb, "Checksum bad for group %u", block_group); |
173 | ext4_free_group_clusters_set(sb, gdp, 0); | 173 | ext4_free_group_clusters_set(sb, gdp, 0); |
174 | ext4_free_inodes_set(sb, gdp, 0); | 174 | ext4_free_inodes_set(sb, gdp, 0); |
175 | ext4_itable_unused_set(sb, gdp, 0); | 175 | ext4_itable_unused_set(sb, gdp, 0); |
176 | memset(bh->b_data, 0xff, sb->s_blocksize); | 176 | memset(bh->b_data, 0xff, sb->s_blocksize); |
177 | ext4_block_bitmap_csum_set(sb, block_group, gdp, bh, | ||
178 | EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||
177 | return; | 179 | return; |
178 | } | 180 | } |
179 | memset(bh->b_data, 0, sb->s_blocksize); | 181 | memset(bh->b_data, 0, sb->s_blocksize); |
@@ -210,6 +212,9 @@ void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, | |||
210 | */ | 212 | */ |
211 | ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group), | 213 | ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group), |
212 | sb->s_blocksize * 8, bh->b_data); | 214 | sb->s_blocksize * 8, bh->b_data); |
215 | ext4_block_bitmap_csum_set(sb, block_group, gdp, bh, | ||
216 | EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||
217 | ext4_group_desc_csum_set(sb, block_group, gdp); | ||
213 | } | 218 | } |
214 | 219 | ||
215 | /* Return the number of free blocks in a block group. It is used when | 220 | /* Return the number of free blocks in a block group. It is used when |
@@ -276,9 +281,9 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb, | |||
276 | } | 281 | } |
277 | 282 | ||
278 | static int ext4_valid_block_bitmap(struct super_block *sb, | 283 | static int ext4_valid_block_bitmap(struct super_block *sb, |
279 | struct ext4_group_desc *desc, | 284 | struct ext4_group_desc *desc, |
280 | unsigned int block_group, | 285 | unsigned int block_group, |
281 | struct buffer_head *bh) | 286 | struct buffer_head *bh) |
282 | { | 287 | { |
283 | ext4_grpblk_t offset; | 288 | ext4_grpblk_t offset; |
284 | ext4_grpblk_t next_zero_bit; | 289 | ext4_grpblk_t next_zero_bit; |
@@ -325,6 +330,23 @@ err_out: | |||
325 | block_group, bitmap_blk); | 330 | block_group, bitmap_blk); |
326 | return 0; | 331 | return 0; |
327 | } | 332 | } |
333 | |||
334 | void ext4_validate_block_bitmap(struct super_block *sb, | ||
335 | struct ext4_group_desc *desc, | ||
336 | unsigned int block_group, | ||
337 | struct buffer_head *bh) | ||
338 | { | ||
339 | if (buffer_verified(bh)) | ||
340 | return; | ||
341 | |||
342 | ext4_lock_group(sb, block_group); | ||
343 | if (ext4_valid_block_bitmap(sb, desc, block_group, bh) && | ||
344 | ext4_block_bitmap_csum_verify(sb, block_group, desc, bh, | ||
345 | EXT4_BLOCKS_PER_GROUP(sb) / 8)) | ||
346 | set_buffer_verified(bh); | ||
347 | ext4_unlock_group(sb, block_group); | ||
348 | } | ||
349 | |||
328 | /** | 350 | /** |
329 | * ext4_read_block_bitmap() | 351 | * ext4_read_block_bitmap() |
330 | * @sb: super block | 352 | * @sb: super block |
@@ -355,12 +377,12 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) | |||
355 | } | 377 | } |
356 | 378 | ||
357 | if (bitmap_uptodate(bh)) | 379 | if (bitmap_uptodate(bh)) |
358 | return bh; | 380 | goto verify; |
359 | 381 | ||
360 | lock_buffer(bh); | 382 | lock_buffer(bh); |
361 | if (bitmap_uptodate(bh)) { | 383 | if (bitmap_uptodate(bh)) { |
362 | unlock_buffer(bh); | 384 | unlock_buffer(bh); |
363 | return bh; | 385 | goto verify; |
364 | } | 386 | } |
365 | ext4_lock_group(sb, block_group); | 387 | ext4_lock_group(sb, block_group); |
366 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { | 388 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { |
@@ -379,7 +401,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) | |||
379 | */ | 401 | */ |
380 | set_bitmap_uptodate(bh); | 402 | set_bitmap_uptodate(bh); |
381 | unlock_buffer(bh); | 403 | unlock_buffer(bh); |
382 | return bh; | 404 | goto verify; |
383 | } | 405 | } |
384 | /* | 406 | /* |
385 | * submit the buffer_head for reading | 407 | * submit the buffer_head for reading |
@@ -390,6 +412,9 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) | |||
390 | get_bh(bh); | 412 | get_bh(bh); |
391 | submit_bh(READ, bh); | 413 | submit_bh(READ, bh); |
392 | return bh; | 414 | return bh; |
415 | verify: | ||
416 | ext4_validate_block_bitmap(sb, desc, block_group, bh); | ||
417 | return bh; | ||
393 | } | 418 | } |
394 | 419 | ||
395 | /* Returns 0 on success, 1 on error */ | 420 | /* Returns 0 on success, 1 on error */ |
@@ -412,7 +437,7 @@ int ext4_wait_block_bitmap(struct super_block *sb, ext4_group_t block_group, | |||
412 | } | 437 | } |
413 | clear_buffer_new(bh); | 438 | clear_buffer_new(bh); |
414 | /* Panic or remount fs read-only if block bitmap is invalid */ | 439 | /* Panic or remount fs read-only if block bitmap is invalid */ |
415 | ext4_valid_block_bitmap(sb, desc, block_group, bh); | 440 | ext4_validate_block_bitmap(sb, desc, block_group, bh); |
416 | return 0; | 441 | return 0; |
417 | } | 442 | } |
418 | 443 | ||
diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c index fa3af81ac565..b319721da26a 100644 --- a/fs/ext4/bitmap.c +++ b/fs/ext4/bitmap.c | |||
@@ -29,3 +29,86 @@ unsigned int ext4_count_free(struct buffer_head *map, unsigned int numchars) | |||
29 | 29 | ||
30 | #endif /* EXT4FS_DEBUG */ | 30 | #endif /* EXT4FS_DEBUG */ |
31 | 31 | ||
32 | int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | ||
33 | struct ext4_group_desc *gdp, | ||
34 | struct buffer_head *bh, int sz) | ||
35 | { | ||
36 | __u32 hi; | ||
37 | __u32 provided, calculated; | ||
38 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
39 | |||
40 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
41 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
42 | return 1; | ||
43 | |||
44 | provided = le16_to_cpu(gdp->bg_inode_bitmap_csum_lo); | ||
45 | calculated = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); | ||
46 | if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) { | ||
47 | hi = le16_to_cpu(gdp->bg_inode_bitmap_csum_hi); | ||
48 | provided |= (hi << 16); | ||
49 | } else | ||
50 | calculated &= 0xFFFF; | ||
51 | |||
52 | return provided == calculated; | ||
53 | } | ||
54 | |||
55 | void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | ||
56 | struct ext4_group_desc *gdp, | ||
57 | struct buffer_head *bh, int sz) | ||
58 | { | ||
59 | __u32 csum; | ||
60 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
61 | |||
62 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
63 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
64 | return; | ||
65 | |||
66 | csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); | ||
67 | gdp->bg_inode_bitmap_csum_lo = cpu_to_le16(csum & 0xFFFF); | ||
68 | if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) | ||
69 | gdp->bg_inode_bitmap_csum_hi = cpu_to_le16(csum >> 16); | ||
70 | } | ||
71 | |||
72 | int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | ||
73 | struct ext4_group_desc *gdp, | ||
74 | struct buffer_head *bh, int sz) | ||
75 | { | ||
76 | __u32 hi; | ||
77 | __u32 provided, calculated; | ||
78 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
79 | |||
80 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
81 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
82 | return 1; | ||
83 | |||
84 | provided = le16_to_cpu(gdp->bg_block_bitmap_csum_lo); | ||
85 | calculated = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); | ||
86 | if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END) { | ||
87 | hi = le16_to_cpu(gdp->bg_block_bitmap_csum_hi); | ||
88 | provided |= (hi << 16); | ||
89 | } else | ||
90 | calculated &= 0xFFFF; | ||
91 | |||
92 | if (provided == calculated) | ||
93 | return 1; | ||
94 | |||
95 | ext4_error(sb, "Bad block bitmap checksum: block_group = %u", group); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | ||
100 | struct ext4_group_desc *gdp, | ||
101 | struct buffer_head *bh, int sz) | ||
102 | { | ||
103 | __u32 csum; | ||
104 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
105 | |||
106 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
107 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
108 | return; | ||
109 | |||
110 | csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); | ||
111 | gdp->bg_block_bitmap_csum_lo = cpu_to_le16(csum & 0xFFFF); | ||
112 | if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END) | ||
113 | gdp->bg_block_bitmap_csum_hi = cpu_to_le16(csum >> 16); | ||
114 | } | ||
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index b86786202643..aa39e600d159 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c | |||
@@ -179,6 +179,18 @@ static int ext4_readdir(struct file *filp, | |||
179 | continue; | 179 | continue; |
180 | } | 180 | } |
181 | 181 | ||
182 | /* Check the checksum */ | ||
183 | if (!buffer_verified(bh) && | ||
184 | !ext4_dirent_csum_verify(inode, | ||
185 | (struct ext4_dir_entry *)bh->b_data)) { | ||
186 | EXT4_ERROR_FILE(filp, 0, "directory fails checksum " | ||
187 | "at offset %llu", | ||
188 | (unsigned long long)filp->f_pos); | ||
189 | filp->f_pos += sb->s_blocksize - offset; | ||
190 | continue; | ||
191 | } | ||
192 | set_buffer_verified(bh); | ||
193 | |||
182 | revalidate: | 194 | revalidate: |
183 | /* If the dir block has changed since the last call to | 195 | /* If the dir block has changed since the last call to |
184 | * readdir(2), then we might be pointing to an invalid | 196 | * readdir(2), then we might be pointing to an invalid |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index c21b1de51afb..cfc4e01b3c83 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/wait.h> | 29 | #include <linux/wait.h> |
30 | #include <linux/blockgroup_lock.h> | 30 | #include <linux/blockgroup_lock.h> |
31 | #include <linux/percpu_counter.h> | 31 | #include <linux/percpu_counter.h> |
32 | #include <crypto/hash.h> | ||
32 | #ifdef __KERNEL__ | 33 | #ifdef __KERNEL__ |
33 | #include <linux/compat.h> | 34 | #include <linux/compat.h> |
34 | #endif | 35 | #endif |
@@ -298,7 +299,9 @@ struct ext4_group_desc | |||
298 | __le16 bg_free_inodes_count_lo;/* Free inodes count */ | 299 | __le16 bg_free_inodes_count_lo;/* Free inodes count */ |
299 | __le16 bg_used_dirs_count_lo; /* Directories count */ | 300 | __le16 bg_used_dirs_count_lo; /* Directories count */ |
300 | __le16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ | 301 | __le16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ |
301 | __u32 bg_reserved[2]; /* Likely block/inode bitmap checksum */ | 302 | __le32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */ |
303 | __le16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bbitmap) LE */ | ||
304 | __le16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+ibitmap) LE */ | ||
302 | __le16 bg_itable_unused_lo; /* Unused inodes count */ | 305 | __le16 bg_itable_unused_lo; /* Unused inodes count */ |
303 | __le16 bg_checksum; /* crc16(sb_uuid+group+desc) */ | 306 | __le16 bg_checksum; /* crc16(sb_uuid+group+desc) */ |
304 | __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ | 307 | __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ |
@@ -308,9 +311,19 @@ struct ext4_group_desc | |||
308 | __le16 bg_free_inodes_count_hi;/* Free inodes count MSB */ | 311 | __le16 bg_free_inodes_count_hi;/* Free inodes count MSB */ |
309 | __le16 bg_used_dirs_count_hi; /* Directories count MSB */ | 312 | __le16 bg_used_dirs_count_hi; /* Directories count MSB */ |
310 | __le16 bg_itable_unused_hi; /* Unused inodes count MSB */ | 313 | __le16 bg_itable_unused_hi; /* Unused inodes count MSB */ |
311 | __u32 bg_reserved2[3]; | 314 | __le32 bg_exclude_bitmap_hi; /* Exclude bitmap block MSB */ |
315 | __le16 bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bbitmap) BE */ | ||
316 | __le16 bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+ibitmap) BE */ | ||
317 | __u32 bg_reserved; | ||
312 | }; | 318 | }; |
313 | 319 | ||
320 | #define EXT4_BG_INODE_BITMAP_CSUM_HI_END \ | ||
321 | (offsetof(struct ext4_group_desc, bg_inode_bitmap_csum_hi) + \ | ||
322 | sizeof(__le16)) | ||
323 | #define EXT4_BG_BLOCK_BITMAP_CSUM_HI_END \ | ||
324 | (offsetof(struct ext4_group_desc, bg_block_bitmap_csum_hi) + \ | ||
325 | sizeof(__le16)) | ||
326 | |||
314 | /* | 327 | /* |
315 | * Structure of a flex block group info | 328 | * Structure of a flex block group info |
316 | */ | 329 | */ |
@@ -650,7 +663,8 @@ struct ext4_inode { | |||
650 | __le16 l_i_file_acl_high; | 663 | __le16 l_i_file_acl_high; |
651 | __le16 l_i_uid_high; /* these 2 fields */ | 664 | __le16 l_i_uid_high; /* these 2 fields */ |
652 | __le16 l_i_gid_high; /* were reserved2[0] */ | 665 | __le16 l_i_gid_high; /* were reserved2[0] */ |
653 | __u32 l_i_reserved2; | 666 | __le16 l_i_checksum_lo;/* crc32c(uuid+inum+inode) LE */ |
667 | __le16 l_i_reserved; | ||
654 | } linux2; | 668 | } linux2; |
655 | struct { | 669 | struct { |
656 | __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ | 670 | __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ |
@@ -666,7 +680,7 @@ struct ext4_inode { | |||
666 | } masix2; | 680 | } masix2; |
667 | } osd2; /* OS dependent 2 */ | 681 | } osd2; /* OS dependent 2 */ |
668 | __le16 i_extra_isize; | 682 | __le16 i_extra_isize; |
669 | __le16 i_pad1; | 683 | __le16 i_checksum_hi; /* crc32c(uuid+inum+inode) BE */ |
670 | __le32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */ | 684 | __le32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */ |
671 | __le32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */ | 685 | __le32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */ |
672 | __le32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */ | 686 | __le32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */ |
@@ -768,7 +782,7 @@ do { \ | |||
768 | #define i_gid_low i_gid | 782 | #define i_gid_low i_gid |
769 | #define i_uid_high osd2.linux2.l_i_uid_high | 783 | #define i_uid_high osd2.linux2.l_i_uid_high |
770 | #define i_gid_high osd2.linux2.l_i_gid_high | 784 | #define i_gid_high osd2.linux2.l_i_gid_high |
771 | #define i_reserved2 osd2.linux2.l_i_reserved2 | 785 | #define i_checksum_lo osd2.linux2.l_i_checksum_lo |
772 | 786 | ||
773 | #elif defined(__GNU__) | 787 | #elif defined(__GNU__) |
774 | 788 | ||
@@ -908,6 +922,9 @@ struct ext4_inode_info { | |||
908 | */ | 922 | */ |
909 | tid_t i_sync_tid; | 923 | tid_t i_sync_tid; |
910 | tid_t i_datasync_tid; | 924 | tid_t i_datasync_tid; |
925 | |||
926 | /* Precomputed uuid+inum+igen checksum for seeding inode checksums */ | ||
927 | __u32 i_csum_seed; | ||
911 | }; | 928 | }; |
912 | 929 | ||
913 | /* | 930 | /* |
@@ -1001,6 +1018,9 @@ extern void ext4_set_bits(void *bm, int cur, int len); | |||
1001 | #define EXT4_ERRORS_PANIC 3 /* Panic */ | 1018 | #define EXT4_ERRORS_PANIC 3 /* Panic */ |
1002 | #define EXT4_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE | 1019 | #define EXT4_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE |
1003 | 1020 | ||
1021 | /* Metadata checksum algorithm codes */ | ||
1022 | #define EXT4_CRC32C_CHKSUM 1 | ||
1023 | |||
1004 | /* | 1024 | /* |
1005 | * Structure of the super block | 1025 | * Structure of the super block |
1006 | */ | 1026 | */ |
@@ -1087,7 +1107,7 @@ struct ext4_super_block { | |||
1087 | __le64 s_mmp_block; /* Block for multi-mount protection */ | 1107 | __le64 s_mmp_block; /* Block for multi-mount protection */ |
1088 | __le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ | 1108 | __le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ |
1089 | __u8 s_log_groups_per_flex; /* FLEX_BG group size */ | 1109 | __u8 s_log_groups_per_flex; /* FLEX_BG group size */ |
1090 | __u8 s_reserved_char_pad; | 1110 | __u8 s_checksum_type; /* metadata checksum algorithm used */ |
1091 | __le16 s_reserved_pad; | 1111 | __le16 s_reserved_pad; |
1092 | __le64 s_kbytes_written; /* nr of lifetime kilobytes written */ | 1112 | __le64 s_kbytes_written; /* nr of lifetime kilobytes written */ |
1093 | __le32 s_snapshot_inum; /* Inode number of active snapshot */ | 1113 | __le32 s_snapshot_inum; /* Inode number of active snapshot */ |
@@ -1113,7 +1133,8 @@ struct ext4_super_block { | |||
1113 | __le32 s_usr_quota_inum; /* inode for tracking user quota */ | 1133 | __le32 s_usr_quota_inum; /* inode for tracking user quota */ |
1114 | __le32 s_grp_quota_inum; /* inode for tracking group quota */ | 1134 | __le32 s_grp_quota_inum; /* inode for tracking group quota */ |
1115 | __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */ | 1135 | __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */ |
1116 | __le32 s_reserved[109]; /* Padding to the end of the block */ | 1136 | __le32 s_reserved[108]; /* Padding to the end of the block */ |
1137 | __le32 s_checksum; /* crc32c(superblock) */ | ||
1117 | }; | 1138 | }; |
1118 | 1139 | ||
1119 | #define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START) | 1140 | #define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START) |
@@ -1176,6 +1197,7 @@ struct ext4_sb_info { | |||
1176 | struct proc_dir_entry *s_proc; | 1197 | struct proc_dir_entry *s_proc; |
1177 | struct kobject s_kobj; | 1198 | struct kobject s_kobj; |
1178 | struct completion s_kobj_unregister; | 1199 | struct completion s_kobj_unregister; |
1200 | struct super_block *s_sb; | ||
1179 | 1201 | ||
1180 | /* Journaling */ | 1202 | /* Journaling */ |
1181 | struct journal_s *s_journal; | 1203 | struct journal_s *s_journal; |
@@ -1266,6 +1288,12 @@ struct ext4_sb_info { | |||
1266 | 1288 | ||
1267 | /* record the last minlen when FITRIM is called. */ | 1289 | /* record the last minlen when FITRIM is called. */ |
1268 | atomic_t s_last_trim_minblks; | 1290 | atomic_t s_last_trim_minblks; |
1291 | |||
1292 | /* Reference to checksum algorithm driver via cryptoapi */ | ||
1293 | struct crypto_shash *s_chksum_driver; | ||
1294 | |||
1295 | /* Precomputed FS UUID checksum for seeding other checksums */ | ||
1296 | __u32 s_csum_seed; | ||
1269 | }; | 1297 | }; |
1270 | 1298 | ||
1271 | static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) | 1299 | static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) |
@@ -1414,6 +1442,12 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei) | |||
1414 | #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 | 1442 | #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 |
1415 | #define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100 | 1443 | #define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100 |
1416 | #define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200 | 1444 | #define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200 |
1445 | /* | ||
1446 | * METADATA_CSUM also enables group descriptor checksums (GDT_CSUM). When | ||
1447 | * METADATA_CSUM is set, group descriptor checksums use the same algorithm as | ||
1448 | * all other data structures' checksums. However, the METADATA_CSUM and | ||
1449 | * GDT_CSUM bits are mutually exclusive. | ||
1450 | */ | ||
1417 | #define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400 | 1451 | #define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400 |
1418 | 1452 | ||
1419 | #define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001 | 1453 | #define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001 |
@@ -1461,7 +1495,8 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei) | |||
1461 | EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \ | 1495 | EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \ |
1462 | EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\ | 1496 | EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\ |
1463 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\ | 1497 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\ |
1464 | EXT4_FEATURE_RO_COMPAT_BIGALLOC) | 1498 | EXT4_FEATURE_RO_COMPAT_BIGALLOC |\ |
1499 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) | ||
1465 | 1500 | ||
1466 | /* | 1501 | /* |
1467 | * Default values for user and/or group using reserved blocks | 1502 | * Default values for user and/or group using reserved blocks |
@@ -1527,6 +1562,18 @@ struct ext4_dir_entry_2 { | |||
1527 | }; | 1562 | }; |
1528 | 1563 | ||
1529 | /* | 1564 | /* |
1565 | * This is a bogus directory entry at the end of each leaf block that | ||
1566 | * records checksums. | ||
1567 | */ | ||
1568 | struct ext4_dir_entry_tail { | ||
1569 | __le32 det_reserved_zero1; /* Pretend to be unused */ | ||
1570 | __le16 det_rec_len; /* 12 */ | ||
1571 | __u8 det_reserved_zero2; /* Zero name length */ | ||
1572 | __u8 det_reserved_ft; /* 0xDE, fake file type */ | ||
1573 | __le32 det_checksum; /* crc32c(uuid+inum+dirblock) */ | ||
1574 | }; | ||
1575 | |||
1576 | /* | ||
1530 | * Ext4 directory file types. Only the low 3 bits are used. The | 1577 | * Ext4 directory file types. Only the low 3 bits are used. The |
1531 | * other bits are reserved for now. | 1578 | * other bits are reserved for now. |
1532 | */ | 1579 | */ |
@@ -1541,6 +1588,8 @@ struct ext4_dir_entry_2 { | |||
1541 | 1588 | ||
1542 | #define EXT4_FT_MAX 8 | 1589 | #define EXT4_FT_MAX 8 |
1543 | 1590 | ||
1591 | #define EXT4_FT_DIR_CSUM 0xDE | ||
1592 | |||
1544 | /* | 1593 | /* |
1545 | * EXT4_DIR_PAD defines the directory entries boundaries | 1594 | * EXT4_DIR_PAD defines the directory entries boundaries |
1546 | * | 1595 | * |
@@ -1609,6 +1658,25 @@ static inline __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize) | |||
1609 | #define DX_HASH_HALF_MD4_UNSIGNED 4 | 1658 | #define DX_HASH_HALF_MD4_UNSIGNED 4 |
1610 | #define DX_HASH_TEA_UNSIGNED 5 | 1659 | #define DX_HASH_TEA_UNSIGNED 5 |
1611 | 1660 | ||
1661 | static inline u32 ext4_chksum(struct ext4_sb_info *sbi, u32 crc, | ||
1662 | const void *address, unsigned int length) | ||
1663 | { | ||
1664 | struct { | ||
1665 | struct shash_desc shash; | ||
1666 | char ctx[crypto_shash_descsize(sbi->s_chksum_driver)]; | ||
1667 | } desc; | ||
1668 | int err; | ||
1669 | |||
1670 | desc.shash.tfm = sbi->s_chksum_driver; | ||
1671 | desc.shash.flags = 0; | ||
1672 | *(u32 *)desc.ctx = crc; | ||
1673 | |||
1674 | err = crypto_shash_update(&desc.shash, address, length); | ||
1675 | BUG_ON(err); | ||
1676 | |||
1677 | return *(u32 *)desc.ctx; | ||
1678 | } | ||
1679 | |||
1612 | #ifdef __KERNEL__ | 1680 | #ifdef __KERNEL__ |
1613 | 1681 | ||
1614 | /* hash info structure used by the directory hash */ | 1682 | /* hash info structure used by the directory hash */ |
@@ -1741,7 +1809,8 @@ struct mmp_struct { | |||
1741 | __le16 mmp_check_interval; | 1809 | __le16 mmp_check_interval; |
1742 | 1810 | ||
1743 | __le16 mmp_pad1; | 1811 | __le16 mmp_pad1; |
1744 | __le32 mmp_pad2[227]; | 1812 | __le32 mmp_pad2[226]; |
1813 | __le32 mmp_checksum; /* crc32c(uuid+mmp_block) */ | ||
1745 | }; | 1814 | }; |
1746 | 1815 | ||
1747 | /* arguments passed to the mmp thread */ | 1816 | /* arguments passed to the mmp thread */ |
@@ -1784,8 +1853,24 @@ struct mmpd_data { | |||
1784 | 1853 | ||
1785 | /* bitmap.c */ | 1854 | /* bitmap.c */ |
1786 | extern unsigned int ext4_count_free(struct buffer_head *, unsigned); | 1855 | extern unsigned int ext4_count_free(struct buffer_head *, unsigned); |
1856 | void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | ||
1857 | struct ext4_group_desc *gdp, | ||
1858 | struct buffer_head *bh, int sz); | ||
1859 | int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | ||
1860 | struct ext4_group_desc *gdp, | ||
1861 | struct buffer_head *bh, int sz); | ||
1862 | void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | ||
1863 | struct ext4_group_desc *gdp, | ||
1864 | struct buffer_head *bh, int sz); | ||
1865 | int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, | ||
1866 | struct ext4_group_desc *gdp, | ||
1867 | struct buffer_head *bh, int sz); | ||
1787 | 1868 | ||
1788 | /* balloc.c */ | 1869 | /* balloc.c */ |
1870 | extern void ext4_validate_block_bitmap(struct super_block *sb, | ||
1871 | struct ext4_group_desc *desc, | ||
1872 | unsigned int block_group, | ||
1873 | struct buffer_head *bh); | ||
1789 | extern unsigned int ext4_block_group(struct super_block *sb, | 1874 | extern unsigned int ext4_block_group(struct super_block *sb, |
1790 | ext4_fsblk_t blocknr); | 1875 | ext4_fsblk_t blocknr); |
1791 | extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb, | 1876 | extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb, |
@@ -1864,7 +1949,7 @@ extern void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate); | |||
1864 | /* mballoc.c */ | 1949 | /* mballoc.c */ |
1865 | extern long ext4_mb_stats; | 1950 | extern long ext4_mb_stats; |
1866 | extern long ext4_mb_max_to_scan; | 1951 | extern long ext4_mb_max_to_scan; |
1867 | extern int ext4_mb_init(struct super_block *, int); | 1952 | extern int ext4_mb_init(struct super_block *); |
1868 | extern int ext4_mb_release(struct super_block *); | 1953 | extern int ext4_mb_release(struct super_block *); |
1869 | extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *, | 1954 | extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *, |
1870 | struct ext4_allocation_request *, int *); | 1955 | struct ext4_allocation_request *, int *); |
@@ -1936,6 +2021,8 @@ extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); | |||
1936 | extern int ext4_ext_migrate(struct inode *); | 2021 | extern int ext4_ext_migrate(struct inode *); |
1937 | 2022 | ||
1938 | /* namei.c */ | 2023 | /* namei.c */ |
2024 | extern int ext4_dirent_csum_verify(struct inode *inode, | ||
2025 | struct ext4_dir_entry *dirent); | ||
1939 | extern int ext4_orphan_add(handle_t *, struct inode *); | 2026 | extern int ext4_orphan_add(handle_t *, struct inode *); |
1940 | extern int ext4_orphan_del(handle_t *, struct inode *); | 2027 | extern int ext4_orphan_del(handle_t *, struct inode *); |
1941 | extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, | 2028 | extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, |
@@ -1950,6 +2037,10 @@ extern int ext4_group_extend(struct super_block *sb, | |||
1950 | extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count); | 2037 | extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count); |
1951 | 2038 | ||
1952 | /* super.c */ | 2039 | /* super.c */ |
2040 | extern int ext4_superblock_csum_verify(struct super_block *sb, | ||
2041 | struct ext4_super_block *es); | ||
2042 | extern void ext4_superblock_csum_set(struct super_block *sb, | ||
2043 | struct ext4_super_block *es); | ||
1953 | extern void *ext4_kvmalloc(size_t size, gfp_t flags); | 2044 | extern void *ext4_kvmalloc(size_t size, gfp_t flags); |
1954 | extern void *ext4_kvzalloc(size_t size, gfp_t flags); | 2045 | extern void *ext4_kvzalloc(size_t size, gfp_t flags); |
1955 | extern void ext4_kvfree(void *ptr); | 2046 | extern void ext4_kvfree(void *ptr); |
@@ -2025,10 +2116,17 @@ extern void ext4_used_dirs_set(struct super_block *sb, | |||
2025 | struct ext4_group_desc *bg, __u32 count); | 2116 | struct ext4_group_desc *bg, __u32 count); |
2026 | extern void ext4_itable_unused_set(struct super_block *sb, | 2117 | extern void ext4_itable_unused_set(struct super_block *sb, |
2027 | struct ext4_group_desc *bg, __u32 count); | 2118 | struct ext4_group_desc *bg, __u32 count); |
2028 | extern __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 group, | 2119 | extern int ext4_group_desc_csum_verify(struct super_block *sb, __u32 group, |
2029 | struct ext4_group_desc *gdp); | ||
2030 | extern int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 group, | ||
2031 | struct ext4_group_desc *gdp); | 2120 | struct ext4_group_desc *gdp); |
2121 | extern void ext4_group_desc_csum_set(struct super_block *sb, __u32 group, | ||
2122 | struct ext4_group_desc *gdp); | ||
2123 | |||
2124 | static inline int ext4_has_group_desc_csum(struct super_block *sb) | ||
2125 | { | ||
2126 | return EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
2127 | EXT4_FEATURE_RO_COMPAT_GDT_CSUM | | ||
2128 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); | ||
2129 | } | ||
2032 | 2130 | ||
2033 | static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es) | 2131 | static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es) |
2034 | { | 2132 | { |
@@ -2225,6 +2323,9 @@ static inline void ext4_unlock_group(struct super_block *sb, | |||
2225 | 2323 | ||
2226 | static inline void ext4_mark_super_dirty(struct super_block *sb) | 2324 | static inline void ext4_mark_super_dirty(struct super_block *sb) |
2227 | { | 2325 | { |
2326 | struct ext4_super_block *es = EXT4_SB(sb)->s_es; | ||
2327 | |||
2328 | ext4_superblock_csum_set(sb, es); | ||
2228 | if (EXT4_SB(sb)->s_journal == NULL) | 2329 | if (EXT4_SB(sb)->s_journal == NULL) |
2229 | sb->s_dirt =1; | 2330 | sb->s_dirt =1; |
2230 | } | 2331 | } |
@@ -2314,6 +2415,9 @@ extern int ext4_bio_write_page(struct ext4_io_submit *io, | |||
2314 | 2415 | ||
2315 | /* mmp.c */ | 2416 | /* mmp.c */ |
2316 | extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t); | 2417 | extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t); |
2418 | extern void ext4_mmp_csum_set(struct super_block *sb, struct mmp_struct *mmp); | ||
2419 | extern int ext4_mmp_csum_verify(struct super_block *sb, | ||
2420 | struct mmp_struct *mmp); | ||
2317 | 2421 | ||
2318 | /* BH_Uninit flag: blocks are allocated but uninitialized on disk */ | 2422 | /* BH_Uninit flag: blocks are allocated but uninitialized on disk */ |
2319 | enum ext4_state_bits { | 2423 | enum ext4_state_bits { |
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index 0f58b86e3a02..cb1b2c919963 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h | |||
@@ -63,9 +63,22 @@ | |||
63 | * ext4_inode has i_block array (60 bytes total). | 63 | * ext4_inode has i_block array (60 bytes total). |
64 | * The first 12 bytes store ext4_extent_header; | 64 | * The first 12 bytes store ext4_extent_header; |
65 | * the remainder stores an array of ext4_extent. | 65 | * the remainder stores an array of ext4_extent. |
66 | * For non-inode extent blocks, ext4_extent_tail | ||
67 | * follows the array. | ||
66 | */ | 68 | */ |
67 | 69 | ||
68 | /* | 70 | /* |
71 | * This is the extent tail on-disk structure. | ||
72 | * All other extent structures are 12 bytes long. It turns out that | ||
73 | * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which | ||
74 | * covers all valid ext4 block sizes. Therefore, this tail structure can be | ||
75 | * crammed into the end of the block without having to rebalance the tree. | ||
76 | */ | ||
77 | struct ext4_extent_tail { | ||
78 | __le32 et_checksum; /* crc32c(uuid+inum+extent_block) */ | ||
79 | }; | ||
80 | |||
81 | /* | ||
69 | * This is the extent on-disk structure. | 82 | * This is the extent on-disk structure. |
70 | * It's used at the bottom of the tree. | 83 | * It's used at the bottom of the tree. |
71 | */ | 84 | */ |
@@ -101,6 +114,17 @@ struct ext4_extent_header { | |||
101 | 114 | ||
102 | #define EXT4_EXT_MAGIC cpu_to_le16(0xf30a) | 115 | #define EXT4_EXT_MAGIC cpu_to_le16(0xf30a) |
103 | 116 | ||
117 | #define EXT4_EXTENT_TAIL_OFFSET(hdr) \ | ||
118 | (sizeof(struct ext4_extent_header) + \ | ||
119 | (sizeof(struct ext4_extent) * le16_to_cpu((hdr)->eh_max))) | ||
120 | |||
121 | static inline struct ext4_extent_tail * | ||
122 | find_ext4_extent_tail(struct ext4_extent_header *eh) | ||
123 | { | ||
124 | return (struct ext4_extent_tail *)(((void *)eh) + | ||
125 | EXT4_EXTENT_TAIL_OFFSET(eh)); | ||
126 | } | ||
127 | |||
104 | /* | 128 | /* |
105 | * Array of ext4_ext_path contains path to some extent. | 129 | * Array of ext4_ext_path contains path to some extent. |
106 | * Creation/lookup routines use it for traversal/splitting/etc. | 130 | * Creation/lookup routines use it for traversal/splitting/etc. |
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 | ||
140 | int __ext4_handle_dirty_super(const char *where, unsigned int line, | 140 | int __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 | ||
215 | int __ext4_handle_dirty_super(const char *where, unsigned int line, | 215 | int __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 | ||
231 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks); | 234 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks); |
232 | int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle); | 235 | int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle); |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index abcdeab67f52..91341ec6e06a 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -52,6 +52,46 @@ | |||
52 | #define EXT4_EXT_MARK_UNINIT1 0x2 /* mark first half uninitialized */ | 52 | #define EXT4_EXT_MARK_UNINIT1 0x2 /* mark first half uninitialized */ |
53 | #define EXT4_EXT_MARK_UNINIT2 0x4 /* mark second half uninitialized */ | 53 | #define EXT4_EXT_MARK_UNINIT2 0x4 /* mark second half uninitialized */ |
54 | 54 | ||
55 | static __le32 ext4_extent_block_csum(struct inode *inode, | ||
56 | struct ext4_extent_header *eh) | ||
57 | { | ||
58 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
59 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
60 | __u32 csum; | ||
61 | |||
62 | csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)eh, | ||
63 | EXT4_EXTENT_TAIL_OFFSET(eh)); | ||
64 | return cpu_to_le32(csum); | ||
65 | } | ||
66 | |||
67 | static int ext4_extent_block_csum_verify(struct inode *inode, | ||
68 | struct ext4_extent_header *eh) | ||
69 | { | ||
70 | struct ext4_extent_tail *et; | ||
71 | |||
72 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
73 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
74 | return 1; | ||
75 | |||
76 | et = find_ext4_extent_tail(eh); | ||
77 | if (et->et_checksum != ext4_extent_block_csum(inode, eh)) | ||
78 | return 0; | ||
79 | return 1; | ||
80 | } | ||
81 | |||
82 | static void ext4_extent_block_csum_set(struct inode *inode, | ||
83 | struct ext4_extent_header *eh) | ||
84 | { | ||
85 | struct ext4_extent_tail *et; | ||
86 | |||
87 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
88 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
89 | return; | ||
90 | |||
91 | et = find_ext4_extent_tail(eh); | ||
92 | et->et_checksum = ext4_extent_block_csum(inode, eh); | ||
93 | } | ||
94 | |||
55 | static int ext4_split_extent(handle_t *handle, | 95 | static int ext4_split_extent(handle_t *handle, |
56 | struct inode *inode, | 96 | struct inode *inode, |
57 | struct ext4_ext_path *path, | 97 | struct ext4_ext_path *path, |
@@ -117,6 +157,7 @@ static int __ext4_ext_dirty(const char *where, unsigned int line, | |||
117 | { | 157 | { |
118 | int err; | 158 | int err; |
119 | if (path->p_bh) { | 159 | if (path->p_bh) { |
160 | ext4_extent_block_csum_set(inode, ext_block_hdr(path->p_bh)); | ||
120 | /* path points to block */ | 161 | /* path points to block */ |
121 | err = __ext4_handle_dirty_metadata(where, line, handle, | 162 | err = __ext4_handle_dirty_metadata(where, line, handle, |
122 | inode, path->p_bh); | 163 | inode, path->p_bh); |
@@ -391,6 +432,12 @@ static int __ext4_ext_check(const char *function, unsigned int line, | |||
391 | error_msg = "invalid extent entries"; | 432 | error_msg = "invalid extent entries"; |
392 | goto corrupted; | 433 | goto corrupted; |
393 | } | 434 | } |
435 | /* Verify checksum on non-root extent tree nodes */ | ||
436 | if (ext_depth(inode) != depth && | ||
437 | !ext4_extent_block_csum_verify(inode, eh)) { | ||
438 | error_msg = "extent tree corrupted"; | ||
439 | goto corrupted; | ||
440 | } | ||
394 | return 0; | 441 | return 0; |
395 | 442 | ||
396 | corrupted: | 443 | corrupted: |
@@ -412,6 +459,26 @@ int ext4_ext_check_inode(struct inode *inode) | |||
412 | return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode)); | 459 | return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode)); |
413 | } | 460 | } |
414 | 461 | ||
462 | static int __ext4_ext_check_block(const char *function, unsigned int line, | ||
463 | struct inode *inode, | ||
464 | struct ext4_extent_header *eh, | ||
465 | int depth, | ||
466 | struct buffer_head *bh) | ||
467 | { | ||
468 | int ret; | ||
469 | |||
470 | if (buffer_verified(bh)) | ||
471 | return 0; | ||
472 | ret = ext4_ext_check(inode, eh, depth); | ||
473 | if (ret) | ||
474 | return ret; | ||
475 | set_buffer_verified(bh); | ||
476 | return ret; | ||
477 | } | ||
478 | |||
479 | #define ext4_ext_check_block(inode, eh, depth, bh) \ | ||
480 | __ext4_ext_check_block(__func__, __LINE__, inode, eh, depth, bh) | ||
481 | |||
415 | #ifdef EXT_DEBUG | 482 | #ifdef EXT_DEBUG |
416 | static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) | 483 | static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) |
417 | { | 484 | { |
@@ -536,7 +603,7 @@ ext4_ext_binsearch_idx(struct inode *inode, | |||
536 | } | 603 | } |
537 | 604 | ||
538 | path->p_idx = l - 1; | 605 | path->p_idx = l - 1; |
539 | ext_debug(" -> %d->%lld ", le32_to_cpu(path->p_idx->ei_block), | 606 | ext_debug(" -> %u->%lld ", le32_to_cpu(path->p_idx->ei_block), |
540 | ext4_idx_pblock(path->p_idx)); | 607 | ext4_idx_pblock(path->p_idx)); |
541 | 608 | ||
542 | #ifdef CHECK_BINSEARCH | 609 | #ifdef CHECK_BINSEARCH |
@@ -668,8 +735,6 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block, | |||
668 | i = depth; | 735 | i = depth; |
669 | /* walk through the tree */ | 736 | /* walk through the tree */ |
670 | while (i) { | 737 | while (i) { |
671 | int need_to_validate = 0; | ||
672 | |||
673 | ext_debug("depth %d: num %d, max %d\n", | 738 | ext_debug("depth %d: num %d, max %d\n", |
674 | ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); | 739 | ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); |
675 | 740 | ||
@@ -688,8 +753,6 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block, | |||
688 | put_bh(bh); | 753 | put_bh(bh); |
689 | goto err; | 754 | goto err; |
690 | } | 755 | } |
691 | /* validate the extent entries */ | ||
692 | need_to_validate = 1; | ||
693 | } | 756 | } |
694 | eh = ext_block_hdr(bh); | 757 | eh = ext_block_hdr(bh); |
695 | ppos++; | 758 | ppos++; |
@@ -703,7 +766,7 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block, | |||
703 | path[ppos].p_hdr = eh; | 766 | path[ppos].p_hdr = eh; |
704 | i--; | 767 | i--; |
705 | 768 | ||
706 | if (need_to_validate && ext4_ext_check(inode, eh, i)) | 769 | if (ext4_ext_check_block(inode, eh, i, bh)) |
707 | goto err; | 770 | goto err; |
708 | } | 771 | } |
709 | 772 | ||
@@ -914,6 +977,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, | |||
914 | le16_add_cpu(&neh->eh_entries, m); | 977 | le16_add_cpu(&neh->eh_entries, m); |
915 | } | 978 | } |
916 | 979 | ||
980 | ext4_extent_block_csum_set(inode, neh); | ||
917 | set_buffer_uptodate(bh); | 981 | set_buffer_uptodate(bh); |
918 | unlock_buffer(bh); | 982 | unlock_buffer(bh); |
919 | 983 | ||
@@ -992,6 +1056,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode, | |||
992 | sizeof(struct ext4_extent_idx) * m); | 1056 | sizeof(struct ext4_extent_idx) * m); |
993 | le16_add_cpu(&neh->eh_entries, m); | 1057 | le16_add_cpu(&neh->eh_entries, m); |
994 | } | 1058 | } |
1059 | ext4_extent_block_csum_set(inode, neh); | ||
995 | set_buffer_uptodate(bh); | 1060 | set_buffer_uptodate(bh); |
996 | unlock_buffer(bh); | 1061 | unlock_buffer(bh); |
997 | 1062 | ||
@@ -1089,6 +1154,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, | |||
1089 | else | 1154 | else |
1090 | neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0)); | 1155 | neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0)); |
1091 | neh->eh_magic = EXT4_EXT_MAGIC; | 1156 | neh->eh_magic = EXT4_EXT_MAGIC; |
1157 | ext4_extent_block_csum_set(inode, neh); | ||
1092 | set_buffer_uptodate(bh); | 1158 | set_buffer_uptodate(bh); |
1093 | unlock_buffer(bh); | 1159 | unlock_buffer(bh); |
1094 | 1160 | ||
@@ -1344,7 +1410,8 @@ got_index: | |||
1344 | return -EIO; | 1410 | return -EIO; |
1345 | eh = ext_block_hdr(bh); | 1411 | eh = ext_block_hdr(bh); |
1346 | /* subtract from p_depth to get proper eh_depth */ | 1412 | /* subtract from p_depth to get proper eh_depth */ |
1347 | if (ext4_ext_check(inode, eh, path->p_depth - depth)) { | 1413 | if (ext4_ext_check_block(inode, eh, |
1414 | path->p_depth - depth, bh)) { | ||
1348 | put_bh(bh); | 1415 | put_bh(bh); |
1349 | return -EIO; | 1416 | return -EIO; |
1350 | } | 1417 | } |
@@ -1357,7 +1424,7 @@ got_index: | |||
1357 | if (bh == NULL) | 1424 | if (bh == NULL) |
1358 | return -EIO; | 1425 | return -EIO; |
1359 | eh = ext_block_hdr(bh); | 1426 | eh = ext_block_hdr(bh); |
1360 | if (ext4_ext_check(inode, eh, path->p_depth - depth)) { | 1427 | if (ext4_ext_check_block(inode, eh, path->p_depth - depth, bh)) { |
1361 | put_bh(bh); | 1428 | put_bh(bh); |
1362 | return -EIO; | 1429 | return -EIO; |
1363 | } | 1430 | } |
@@ -2644,8 +2711,8 @@ cont: | |||
2644 | err = -EIO; | 2711 | err = -EIO; |
2645 | break; | 2712 | break; |
2646 | } | 2713 | } |
2647 | if (ext4_ext_check(inode, ext_block_hdr(bh), | 2714 | if (ext4_ext_check_block(inode, ext_block_hdr(bh), |
2648 | depth - i - 1)) { | 2715 | depth - i - 1, bh)) { |
2649 | err = -EIO; | 2716 | err = -EIO; |
2650 | break; | 2717 | break; |
2651 | } | 2718 | } |
@@ -4722,8 +4789,8 @@ int ext4_ext_punch_hole(struct file *file, loff_t offset, loff_t length) | |||
4722 | 4789 | ||
4723 | /* Now release the pages */ | 4790 | /* Now release the pages */ |
4724 | if (last_page_offset > first_page_offset) { | 4791 | if (last_page_offset > first_page_offset) { |
4725 | truncate_inode_pages_range(mapping, first_page_offset, | 4792 | truncate_pagecache_range(inode, first_page_offset, |
4726 | last_page_offset-1); | 4793 | last_page_offset - 1); |
4727 | } | 4794 | } |
4728 | 4795 | ||
4729 | /* finish any pending end_io work */ | 4796 | /* finish any pending end_io work */ |
diff --git a/fs/ext4/file.c b/fs/ext4/file.c index cb70f1812a70..8c7642a00054 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c | |||
@@ -95,7 +95,7 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
95 | { | 95 | { |
96 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; | 96 | struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; |
97 | int unaligned_aio = 0; | 97 | int unaligned_aio = 0; |
98 | int ret; | 98 | ssize_t ret; |
99 | 99 | ||
100 | /* | 100 | /* |
101 | * If we have encountered a bitmap-format file, the size limit | 101 | * If we have encountered a bitmap-format file, the size limit |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 9f9acac6c43f..d48e8b14928c 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -70,24 +70,27 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb, | |||
70 | ext4_group_t block_group, | 70 | ext4_group_t block_group, |
71 | struct ext4_group_desc *gdp) | 71 | struct ext4_group_desc *gdp) |
72 | { | 72 | { |
73 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
74 | |||
75 | J_ASSERT_BH(bh, buffer_locked(bh)); | 73 | J_ASSERT_BH(bh, buffer_locked(bh)); |
76 | 74 | ||
77 | /* If checksum is bad mark all blocks and inodes use to prevent | 75 | /* If checksum is bad mark all blocks and inodes use to prevent |
78 | * allocation, essentially implementing a per-group read-only flag. */ | 76 | * allocation, essentially implementing a per-group read-only flag. */ |
79 | if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { | 77 | if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { |
80 | ext4_error(sb, "Checksum bad for group %u", block_group); | 78 | ext4_error(sb, "Checksum bad for group %u", block_group); |
81 | ext4_free_group_clusters_set(sb, gdp, 0); | 79 | ext4_free_group_clusters_set(sb, gdp, 0); |
82 | ext4_free_inodes_set(sb, gdp, 0); | 80 | ext4_free_inodes_set(sb, gdp, 0); |
83 | ext4_itable_unused_set(sb, gdp, 0); | 81 | ext4_itable_unused_set(sb, gdp, 0); |
84 | memset(bh->b_data, 0xff, sb->s_blocksize); | 82 | memset(bh->b_data, 0xff, sb->s_blocksize); |
83 | ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh, | ||
84 | EXT4_INODES_PER_GROUP(sb) / 8); | ||
85 | return 0; | 85 | return 0; |
86 | } | 86 | } |
87 | 87 | ||
88 | memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); | 88 | memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); |
89 | ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, | 89 | ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, |
90 | bh->b_data); | 90 | bh->b_data); |
91 | ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh, | ||
92 | EXT4_INODES_PER_GROUP(sb) / 8); | ||
93 | ext4_group_desc_csum_set(sb, block_group, gdp); | ||
91 | 94 | ||
92 | return EXT4_INODES_PER_GROUP(sb); | 95 | return EXT4_INODES_PER_GROUP(sb); |
93 | } | 96 | } |
@@ -128,12 +131,12 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
128 | return NULL; | 131 | return NULL; |
129 | } | 132 | } |
130 | if (bitmap_uptodate(bh)) | 133 | if (bitmap_uptodate(bh)) |
131 | return bh; | 134 | goto verify; |
132 | 135 | ||
133 | lock_buffer(bh); | 136 | lock_buffer(bh); |
134 | if (bitmap_uptodate(bh)) { | 137 | if (bitmap_uptodate(bh)) { |
135 | unlock_buffer(bh); | 138 | unlock_buffer(bh); |
136 | return bh; | 139 | goto verify; |
137 | } | 140 | } |
138 | 141 | ||
139 | ext4_lock_group(sb, block_group); | 142 | ext4_lock_group(sb, block_group); |
@@ -141,6 +144,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
141 | ext4_init_inode_bitmap(sb, bh, block_group, desc); | 144 | ext4_init_inode_bitmap(sb, bh, block_group, desc); |
142 | set_bitmap_uptodate(bh); | 145 | set_bitmap_uptodate(bh); |
143 | set_buffer_uptodate(bh); | 146 | set_buffer_uptodate(bh); |
147 | set_buffer_verified(bh); | ||
144 | ext4_unlock_group(sb, block_group); | 148 | ext4_unlock_group(sb, block_group); |
145 | unlock_buffer(bh); | 149 | unlock_buffer(bh); |
146 | return bh; | 150 | return bh; |
@@ -154,7 +158,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
154 | */ | 158 | */ |
155 | set_bitmap_uptodate(bh); | 159 | set_bitmap_uptodate(bh); |
156 | unlock_buffer(bh); | 160 | unlock_buffer(bh); |
157 | return bh; | 161 | goto verify; |
158 | } | 162 | } |
159 | /* | 163 | /* |
160 | * submit the buffer_head for reading | 164 | * submit the buffer_head for reading |
@@ -171,6 +175,20 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) | |||
171 | block_group, bitmap_blk); | 175 | block_group, bitmap_blk); |
172 | return NULL; | 176 | return NULL; |
173 | } | 177 | } |
178 | |||
179 | verify: | ||
180 | ext4_lock_group(sb, block_group); | ||
181 | if (!buffer_verified(bh) && | ||
182 | !ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh, | ||
183 | EXT4_INODES_PER_GROUP(sb) / 8)) { | ||
184 | ext4_unlock_group(sb, block_group); | ||
185 | put_bh(bh); | ||
186 | ext4_error(sb, "Corrupt inode bitmap - block_group = %u, " | ||
187 | "inode_bitmap = %llu", block_group, bitmap_blk); | ||
188 | return NULL; | ||
189 | } | ||
190 | ext4_unlock_group(sb, block_group); | ||
191 | set_buffer_verified(bh); | ||
174 | return bh; | 192 | return bh; |
175 | } | 193 | } |
176 | 194 | ||
@@ -276,7 +294,9 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) | |||
276 | ext4_used_dirs_set(sb, gdp, count); | 294 | ext4_used_dirs_set(sb, gdp, count); |
277 | percpu_counter_dec(&sbi->s_dirs_counter); | 295 | percpu_counter_dec(&sbi->s_dirs_counter); |
278 | } | 296 | } |
279 | gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); | 297 | ext4_inode_bitmap_csum_set(sb, block_group, gdp, bitmap_bh, |
298 | EXT4_INODES_PER_GROUP(sb) / 8); | ||
299 | ext4_group_desc_csum_set(sb, block_group, gdp); | ||
280 | ext4_unlock_group(sb, block_group); | 300 | ext4_unlock_group(sb, block_group); |
281 | 301 | ||
282 | percpu_counter_inc(&sbi->s_freeinodes_counter); | 302 | percpu_counter_inc(&sbi->s_freeinodes_counter); |
@@ -488,10 +508,12 @@ fallback_retry: | |||
488 | for (i = 0; i < ngroups; i++) { | 508 | for (i = 0; i < ngroups; i++) { |
489 | grp = (parent_group + i) % ngroups; | 509 | grp = (parent_group + i) % ngroups; |
490 | desc = ext4_get_group_desc(sb, grp, NULL); | 510 | desc = ext4_get_group_desc(sb, grp, NULL); |
491 | grp_free = ext4_free_inodes_count(sb, desc); | 511 | if (desc) { |
492 | if (desc && grp_free && grp_free >= avefreei) { | 512 | grp_free = ext4_free_inodes_count(sb, desc); |
493 | *group = grp; | 513 | if (grp_free && grp_free >= avefreei) { |
494 | return 0; | 514 | *group = grp; |
515 | return 0; | ||
516 | } | ||
495 | } | 517 | } |
496 | } | 518 | } |
497 | 519 | ||
@@ -709,7 +731,7 @@ repeat_in_this_group: | |||
709 | 731 | ||
710 | got: | 732 | got: |
711 | /* We may have to initialize the block bitmap if it isn't already */ | 733 | /* We may have to initialize the block bitmap if it isn't already */ |
712 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && | 734 | if (ext4_has_group_desc_csum(sb) && |
713 | gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { | 735 | gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { |
714 | struct buffer_head *block_bitmap_bh; | 736 | struct buffer_head *block_bitmap_bh; |
715 | 737 | ||
@@ -731,8 +753,11 @@ got: | |||
731 | gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); | 753 | gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); |
732 | ext4_free_group_clusters_set(sb, gdp, | 754 | ext4_free_group_clusters_set(sb, gdp, |
733 | ext4_free_clusters_after_init(sb, group, gdp)); | 755 | ext4_free_clusters_after_init(sb, group, gdp)); |
734 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group, | 756 | ext4_block_bitmap_csum_set(sb, group, gdp, |
735 | gdp); | 757 | block_bitmap_bh, |
758 | EXT4_BLOCKS_PER_GROUP(sb) / | ||
759 | 8); | ||
760 | ext4_group_desc_csum_set(sb, group, gdp); | ||
736 | } | 761 | } |
737 | ext4_unlock_group(sb, group); | 762 | ext4_unlock_group(sb, group); |
738 | 763 | ||
@@ -751,7 +776,7 @@ got: | |||
751 | goto fail; | 776 | goto fail; |
752 | 777 | ||
753 | /* Update the relevant bg descriptor fields */ | 778 | /* Update the relevant bg descriptor fields */ |
754 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { | 779 | if (ext4_has_group_desc_csum(sb)) { |
755 | int free; | 780 | int free; |
756 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); | 781 | struct ext4_group_info *grp = ext4_get_group_info(sb, group); |
757 | 782 | ||
@@ -772,7 +797,10 @@ got: | |||
772 | ext4_itable_unused_set(sb, gdp, | 797 | ext4_itable_unused_set(sb, gdp, |
773 | (EXT4_INODES_PER_GROUP(sb) - ino)); | 798 | (EXT4_INODES_PER_GROUP(sb) - ino)); |
774 | up_read(&grp->alloc_sem); | 799 | up_read(&grp->alloc_sem); |
800 | } else { | ||
801 | ext4_lock_group(sb, group); | ||
775 | } | 802 | } |
803 | |||
776 | ext4_free_inodes_set(sb, gdp, ext4_free_inodes_count(sb, gdp) - 1); | 804 | ext4_free_inodes_set(sb, gdp, ext4_free_inodes_count(sb, gdp) - 1); |
777 | if (S_ISDIR(mode)) { | 805 | if (S_ISDIR(mode)) { |
778 | ext4_used_dirs_set(sb, gdp, ext4_used_dirs_count(sb, gdp) + 1); | 806 | ext4_used_dirs_set(sb, gdp, ext4_used_dirs_count(sb, gdp) + 1); |
@@ -782,10 +810,12 @@ got: | |||
782 | atomic_inc(&sbi->s_flex_groups[f].used_dirs); | 810 | atomic_inc(&sbi->s_flex_groups[f].used_dirs); |
783 | } | 811 | } |
784 | } | 812 | } |
785 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { | 813 | if (ext4_has_group_desc_csum(sb)) { |
786 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); | 814 | ext4_inode_bitmap_csum_set(sb, group, gdp, inode_bitmap_bh, |
787 | ext4_unlock_group(sb, group); | 815 | EXT4_INODES_PER_GROUP(sb) / 8); |
816 | ext4_group_desc_csum_set(sb, group, gdp); | ||
788 | } | 817 | } |
818 | ext4_unlock_group(sb, group); | ||
789 | 819 | ||
790 | BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata"); | 820 | BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata"); |
791 | err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh); | 821 | err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh); |
@@ -850,6 +880,19 @@ got: | |||
850 | inode->i_generation = sbi->s_next_generation++; | 880 | inode->i_generation = sbi->s_next_generation++; |
851 | spin_unlock(&sbi->s_next_gen_lock); | 881 | spin_unlock(&sbi->s_next_gen_lock); |
852 | 882 | ||
883 | /* Precompute checksum seed for inode metadata */ | ||
884 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
885 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { | ||
886 | __u32 csum; | ||
887 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
888 | __le32 inum = cpu_to_le32(inode->i_ino); | ||
889 | __le32 gen = cpu_to_le32(inode->i_generation); | ||
890 | csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum, | ||
891 | sizeof(inum)); | ||
892 | ei->i_csum_seed = ext4_chksum(sbi, csum, (__u8 *)&gen, | ||
893 | sizeof(gen)); | ||
894 | } | ||
895 | |||
853 | ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */ | 896 | ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */ |
854 | ext4_set_inode_state(inode, EXT4_STATE_NEW); | 897 | ext4_set_inode_state(inode, EXT4_STATE_NEW); |
855 | 898 | ||
@@ -1140,7 +1183,7 @@ int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, | |||
1140 | skip_zeroout: | 1183 | skip_zeroout: |
1141 | ext4_lock_group(sb, group); | 1184 | ext4_lock_group(sb, group); |
1142 | gdp->bg_flags |= cpu_to_le16(EXT4_BG_INODE_ZEROED); | 1185 | gdp->bg_flags |= cpu_to_le16(EXT4_BG_INODE_ZEROED); |
1143 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); | 1186 | ext4_group_desc_csum_set(sb, group, gdp); |
1144 | ext4_unlock_group(sb, group); | 1187 | ext4_unlock_group(sb, group); |
1145 | 1188 | ||
1146 | BUFFER_TRACE(group_desc_bh, | 1189 | BUFFER_TRACE(group_desc_bh, |
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; |
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 6eee25591b81..8ad112ae0ade 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -38,7 +38,7 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
38 | handle_t *handle = NULL; | 38 | handle_t *handle = NULL; |
39 | int err, migrate = 0; | 39 | int err, migrate = 0; |
40 | struct ext4_iloc iloc; | 40 | struct ext4_iloc iloc; |
41 | unsigned int oldflags; | 41 | unsigned int oldflags, mask, i; |
42 | unsigned int jflag; | 42 | unsigned int jflag; |
43 | 43 | ||
44 | if (!inode_owner_or_capable(inode)) | 44 | if (!inode_owner_or_capable(inode)) |
@@ -115,8 +115,14 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | |||
115 | if (err) | 115 | if (err) |
116 | goto flags_err; | 116 | goto flags_err; |
117 | 117 | ||
118 | flags = flags & EXT4_FL_USER_MODIFIABLE; | 118 | for (i = 0, mask = 1; i < 32; i++, mask <<= 1) { |
119 | flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE; | 119 | if (!(mask & EXT4_FL_USER_MODIFIABLE)) |
120 | continue; | ||
121 | if (mask & flags) | ||
122 | ext4_set_inode_flag(inode, i); | ||
123 | else | ||
124 | ext4_clear_inode_flag(inode, i); | ||
125 | } | ||
120 | ei->i_flags = flags; | 126 | ei->i_flags = flags; |
121 | 127 | ||
122 | ext4_set_inode_flags(inode); | 128 | ext4_set_inode_flags(inode); |
@@ -152,6 +158,13 @@ flags_out: | |||
152 | if (!inode_owner_or_capable(inode)) | 158 | if (!inode_owner_or_capable(inode)) |
153 | return -EPERM; | 159 | return -EPERM; |
154 | 160 | ||
161 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
162 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { | ||
163 | ext4_warning(sb, "Setting inode version is not " | ||
164 | "supported with metadata_csum enabled."); | ||
165 | return -ENOTTY; | ||
166 | } | ||
167 | |||
155 | err = mnt_want_write_file(filp); | 168 | err = mnt_want_write_file(filp); |
156 | if (err) | 169 | if (err) |
157 | return err; | 170 | return err; |
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 99ab428bcfa0..1cd6994fc446 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c | |||
@@ -788,7 +788,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore) | |||
788 | int first_block; | 788 | int first_block; |
789 | struct super_block *sb; | 789 | struct super_block *sb; |
790 | struct buffer_head *bhs; | 790 | struct buffer_head *bhs; |
791 | struct buffer_head **bh; | 791 | struct buffer_head **bh = NULL; |
792 | struct inode *inode; | 792 | struct inode *inode; |
793 | char *data; | 793 | char *data; |
794 | char *bitmap; | 794 | char *bitmap; |
@@ -2375,7 +2375,7 @@ static int ext4_groupinfo_create_slab(size_t size) | |||
2375 | return 0; | 2375 | return 0; |
2376 | } | 2376 | } |
2377 | 2377 | ||
2378 | int ext4_mb_init(struct super_block *sb, int needs_recovery) | 2378 | int ext4_mb_init(struct super_block *sb) |
2379 | { | 2379 | { |
2380 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 2380 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
2381 | unsigned i, j; | 2381 | unsigned i, j; |
@@ -2517,6 +2517,9 @@ int ext4_mb_release(struct super_block *sb) | |||
2517 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 2517 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
2518 | struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits); | 2518 | struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits); |
2519 | 2519 | ||
2520 | if (sbi->s_proc) | ||
2521 | remove_proc_entry("mb_groups", sbi->s_proc); | ||
2522 | |||
2520 | if (sbi->s_group_info) { | 2523 | if (sbi->s_group_info) { |
2521 | for (i = 0; i < ngroups; i++) { | 2524 | for (i = 0; i < ngroups; i++) { |
2522 | grinfo = ext4_get_group_info(sb, i); | 2525 | grinfo = ext4_get_group_info(sb, i); |
@@ -2564,8 +2567,6 @@ int ext4_mb_release(struct super_block *sb) | |||
2564 | } | 2567 | } |
2565 | 2568 | ||
2566 | free_percpu(sbi->s_locality_groups); | 2569 | free_percpu(sbi->s_locality_groups); |
2567 | if (sbi->s_proc) | ||
2568 | remove_proc_entry("mb_groups", sbi->s_proc); | ||
2569 | 2570 | ||
2570 | return 0; | 2571 | return 0; |
2571 | } | 2572 | } |
@@ -2797,7 +2798,9 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, | |||
2797 | } | 2798 | } |
2798 | len = ext4_free_group_clusters(sb, gdp) - ac->ac_b_ex.fe_len; | 2799 | len = ext4_free_group_clusters(sb, gdp) - ac->ac_b_ex.fe_len; |
2799 | ext4_free_group_clusters_set(sb, gdp, len); | 2800 | ext4_free_group_clusters_set(sb, gdp, len); |
2800 | gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp); | 2801 | ext4_block_bitmap_csum_set(sb, ac->ac_b_ex.fe_group, gdp, bitmap_bh, |
2802 | EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||
2803 | ext4_group_desc_csum_set(sb, ac->ac_b_ex.fe_group, gdp); | ||
2801 | 2804 | ||
2802 | ext4_unlock_group(sb, ac->ac_b_ex.fe_group); | 2805 | ext4_unlock_group(sb, ac->ac_b_ex.fe_group); |
2803 | percpu_counter_sub(&sbi->s_freeclusters_counter, ac->ac_b_ex.fe_len); | 2806 | percpu_counter_sub(&sbi->s_freeclusters_counter, ac->ac_b_ex.fe_len); |
@@ -3071,13 +3074,9 @@ static void ext4_mb_collect_stats(struct ext4_allocation_context *ac) | |||
3071 | static void ext4_discard_allocated_blocks(struct ext4_allocation_context *ac) | 3074 | static void ext4_discard_allocated_blocks(struct ext4_allocation_context *ac) |
3072 | { | 3075 | { |
3073 | struct ext4_prealloc_space *pa = ac->ac_pa; | 3076 | struct ext4_prealloc_space *pa = ac->ac_pa; |
3074 | int len; | ||
3075 | |||
3076 | if (pa && pa->pa_type == MB_INODE_PA) { | ||
3077 | len = ac->ac_b_ex.fe_len; | ||
3078 | pa->pa_free += len; | ||
3079 | } | ||
3080 | 3077 | ||
3078 | if (pa && pa->pa_type == MB_INODE_PA) | ||
3079 | pa->pa_free += ac->ac_b_ex.fe_len; | ||
3081 | } | 3080 | } |
3082 | 3081 | ||
3083 | /* | 3082 | /* |
@@ -4636,6 +4635,7 @@ do_more: | |||
4636 | */ | 4635 | */ |
4637 | new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS); | 4636 | new_entry = kmem_cache_alloc(ext4_free_data_cachep, GFP_NOFS); |
4638 | if (!new_entry) { | 4637 | if (!new_entry) { |
4638 | ext4_mb_unload_buddy(&e4b); | ||
4639 | err = -ENOMEM; | 4639 | err = -ENOMEM; |
4640 | goto error_return; | 4640 | goto error_return; |
4641 | } | 4641 | } |
@@ -4659,7 +4659,9 @@ do_more: | |||
4659 | 4659 | ||
4660 | ret = ext4_free_group_clusters(sb, gdp) + count_clusters; | 4660 | ret = ext4_free_group_clusters(sb, gdp) + count_clusters; |
4661 | ext4_free_group_clusters_set(sb, gdp, ret); | 4661 | ext4_free_group_clusters_set(sb, gdp, ret); |
4662 | gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp); | 4662 | ext4_block_bitmap_csum_set(sb, block_group, gdp, bitmap_bh, |
4663 | EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||
4664 | ext4_group_desc_csum_set(sb, block_group, gdp); | ||
4663 | ext4_unlock_group(sb, block_group); | 4665 | ext4_unlock_group(sb, block_group); |
4664 | percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters); | 4666 | percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters); |
4665 | 4667 | ||
@@ -4803,7 +4805,9 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, | |||
4803 | mb_free_blocks(NULL, &e4b, bit, count); | 4805 | mb_free_blocks(NULL, &e4b, bit, count); |
4804 | blk_free_count = blocks_freed + ext4_free_group_clusters(sb, desc); | 4806 | blk_free_count = blocks_freed + ext4_free_group_clusters(sb, desc); |
4805 | ext4_free_group_clusters_set(sb, desc, blk_free_count); | 4807 | ext4_free_group_clusters_set(sb, desc, blk_free_count); |
4806 | desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc); | 4808 | ext4_block_bitmap_csum_set(sb, block_group, desc, bitmap_bh, |
4809 | EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||
4810 | ext4_group_desc_csum_set(sb, block_group, desc); | ||
4807 | ext4_unlock_group(sb, block_group); | 4811 | ext4_unlock_group(sb, block_group); |
4808 | percpu_counter_add(&sbi->s_freeclusters_counter, | 4812 | percpu_counter_add(&sbi->s_freeclusters_counter, |
4809 | EXT4_B2C(sbi, blocks_freed)); | 4813 | EXT4_B2C(sbi, blocks_freed)); |
diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c index ed6548d89165..f99a1311e847 100644 --- a/fs/ext4/mmp.c +++ b/fs/ext4/mmp.c | |||
@@ -6,12 +6,45 @@ | |||
6 | 6 | ||
7 | #include "ext4.h" | 7 | #include "ext4.h" |
8 | 8 | ||
9 | /* Checksumming functions */ | ||
10 | static __u32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp) | ||
11 | { | ||
12 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
13 | int offset = offsetof(struct mmp_struct, mmp_checksum); | ||
14 | __u32 csum; | ||
15 | |||
16 | csum = ext4_chksum(sbi, sbi->s_csum_seed, (char *)mmp, offset); | ||
17 | |||
18 | return cpu_to_le32(csum); | ||
19 | } | ||
20 | |||
21 | int ext4_mmp_csum_verify(struct super_block *sb, struct mmp_struct *mmp) | ||
22 | { | ||
23 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
24 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
25 | return 1; | ||
26 | |||
27 | return mmp->mmp_checksum == ext4_mmp_csum(sb, mmp); | ||
28 | } | ||
29 | |||
30 | void ext4_mmp_csum_set(struct super_block *sb, struct mmp_struct *mmp) | ||
31 | { | ||
32 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
33 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
34 | return; | ||
35 | |||
36 | mmp->mmp_checksum = ext4_mmp_csum(sb, mmp); | ||
37 | } | ||
38 | |||
9 | /* | 39 | /* |
10 | * Write the MMP block using WRITE_SYNC to try to get the block on-disk | 40 | * Write the MMP block using WRITE_SYNC to try to get the block on-disk |
11 | * faster. | 41 | * faster. |
12 | */ | 42 | */ |
13 | static int write_mmp_block(struct buffer_head *bh) | 43 | static int write_mmp_block(struct super_block *sb, struct buffer_head *bh) |
14 | { | 44 | { |
45 | struct mmp_struct *mmp = (struct mmp_struct *)(bh->b_data); | ||
46 | |||
47 | ext4_mmp_csum_set(sb, mmp); | ||
15 | mark_buffer_dirty(bh); | 48 | mark_buffer_dirty(bh); |
16 | lock_buffer(bh); | 49 | lock_buffer(bh); |
17 | bh->b_end_io = end_buffer_write_sync; | 50 | bh->b_end_io = end_buffer_write_sync; |
@@ -59,7 +92,8 @@ static int read_mmp_block(struct super_block *sb, struct buffer_head **bh, | |||
59 | } | 92 | } |
60 | 93 | ||
61 | mmp = (struct mmp_struct *)((*bh)->b_data); | 94 | mmp = (struct mmp_struct *)((*bh)->b_data); |
62 | if (le32_to_cpu(mmp->mmp_magic) != EXT4_MMP_MAGIC) | 95 | if (le32_to_cpu(mmp->mmp_magic) != EXT4_MMP_MAGIC || |
96 | !ext4_mmp_csum_verify(sb, mmp)) | ||
63 | return -EINVAL; | 97 | return -EINVAL; |
64 | 98 | ||
65 | return 0; | 99 | return 0; |
@@ -120,7 +154,7 @@ static int kmmpd(void *data) | |||
120 | mmp->mmp_time = cpu_to_le64(get_seconds()); | 154 | mmp->mmp_time = cpu_to_le64(get_seconds()); |
121 | last_update_time = jiffies; | 155 | last_update_time = jiffies; |
122 | 156 | ||
123 | retval = write_mmp_block(bh); | 157 | retval = write_mmp_block(sb, bh); |
124 | /* | 158 | /* |
125 | * Don't spew too many error messages. Print one every | 159 | * Don't spew too many error messages. Print one every |
126 | * (s_mmp_update_interval * 60) seconds. | 160 | * (s_mmp_update_interval * 60) seconds. |
@@ -200,7 +234,7 @@ static int kmmpd(void *data) | |||
200 | mmp->mmp_seq = cpu_to_le32(EXT4_MMP_SEQ_CLEAN); | 234 | mmp->mmp_seq = cpu_to_le32(EXT4_MMP_SEQ_CLEAN); |
201 | mmp->mmp_time = cpu_to_le64(get_seconds()); | 235 | mmp->mmp_time = cpu_to_le64(get_seconds()); |
202 | 236 | ||
203 | retval = write_mmp_block(bh); | 237 | retval = write_mmp_block(sb, bh); |
204 | 238 | ||
205 | failed: | 239 | failed: |
206 | kfree(data); | 240 | kfree(data); |
@@ -299,7 +333,7 @@ skip: | |||
299 | seq = mmp_new_seq(); | 333 | seq = mmp_new_seq(); |
300 | mmp->mmp_seq = cpu_to_le32(seq); | 334 | mmp->mmp_seq = cpu_to_le32(seq); |
301 | 335 | ||
302 | retval = write_mmp_block(bh); | 336 | retval = write_mmp_block(sb, bh); |
303 | if (retval) | 337 | if (retval) |
304 | goto failed; | 338 | goto failed; |
305 | 339 | ||
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index e2a3f4b0ff78..5845cd97bf8b 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -145,6 +145,14 @@ struct dx_map_entry | |||
145 | u16 size; | 145 | u16 size; |
146 | }; | 146 | }; |
147 | 147 | ||
148 | /* | ||
149 | * This goes at the end of each htree block. | ||
150 | */ | ||
151 | struct dx_tail { | ||
152 | u32 dt_reserved; | ||
153 | __le32 dt_checksum; /* crc32c(uuid+inum+dirblock) */ | ||
154 | }; | ||
155 | |||
148 | static inline ext4_lblk_t dx_get_block(struct dx_entry *entry); | 156 | static inline ext4_lblk_t dx_get_block(struct dx_entry *entry); |
149 | static void dx_set_block(struct dx_entry *entry, ext4_lblk_t value); | 157 | static void dx_set_block(struct dx_entry *entry, ext4_lblk_t value); |
150 | static inline unsigned dx_get_hash(struct dx_entry *entry); | 158 | static inline unsigned dx_get_hash(struct dx_entry *entry); |
@@ -180,6 +188,230 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, | |||
180 | static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | 188 | static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, |
181 | struct inode *inode); | 189 | struct inode *inode); |
182 | 190 | ||
191 | /* checksumming functions */ | ||
192 | #define EXT4_DIRENT_TAIL(block, blocksize) \ | ||
193 | ((struct ext4_dir_entry_tail *)(((void *)(block)) + \ | ||
194 | ((blocksize) - \ | ||
195 | sizeof(struct ext4_dir_entry_tail)))) | ||
196 | |||
197 | static void initialize_dirent_tail(struct ext4_dir_entry_tail *t, | ||
198 | unsigned int blocksize) | ||
199 | { | ||
200 | memset(t, 0, sizeof(struct ext4_dir_entry_tail)); | ||
201 | t->det_rec_len = ext4_rec_len_to_disk( | ||
202 | sizeof(struct ext4_dir_entry_tail), blocksize); | ||
203 | t->det_reserved_ft = EXT4_FT_DIR_CSUM; | ||
204 | } | ||
205 | |||
206 | /* Walk through a dirent block to find a checksum "dirent" at the tail */ | ||
207 | static struct ext4_dir_entry_tail *get_dirent_tail(struct inode *inode, | ||
208 | struct ext4_dir_entry *de) | ||
209 | { | ||
210 | struct ext4_dir_entry_tail *t; | ||
211 | |||
212 | #ifdef PARANOID | ||
213 | struct ext4_dir_entry *d, *top; | ||
214 | |||
215 | d = de; | ||
216 | top = (struct ext4_dir_entry *)(((void *)de) + | ||
217 | (EXT4_BLOCK_SIZE(inode->i_sb) - | ||
218 | sizeof(struct ext4_dir_entry_tail))); | ||
219 | while (d < top && d->rec_len) | ||
220 | d = (struct ext4_dir_entry *)(((void *)d) + | ||
221 | le16_to_cpu(d->rec_len)); | ||
222 | |||
223 | if (d != top) | ||
224 | return NULL; | ||
225 | |||
226 | t = (struct ext4_dir_entry_tail *)d; | ||
227 | #else | ||
228 | t = EXT4_DIRENT_TAIL(de, EXT4_BLOCK_SIZE(inode->i_sb)); | ||
229 | #endif | ||
230 | |||
231 | if (t->det_reserved_zero1 || | ||
232 | le16_to_cpu(t->det_rec_len) != sizeof(struct ext4_dir_entry_tail) || | ||
233 | t->det_reserved_zero2 || | ||
234 | t->det_reserved_ft != EXT4_FT_DIR_CSUM) | ||
235 | return NULL; | ||
236 | |||
237 | return t; | ||
238 | } | ||
239 | |||
240 | static __le32 ext4_dirent_csum(struct inode *inode, | ||
241 | struct ext4_dir_entry *dirent, int size) | ||
242 | { | ||
243 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
244 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
245 | __u32 csum; | ||
246 | |||
247 | csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size); | ||
248 | return cpu_to_le32(csum); | ||
249 | } | ||
250 | |||
251 | int ext4_dirent_csum_verify(struct inode *inode, struct ext4_dir_entry *dirent) | ||
252 | { | ||
253 | struct ext4_dir_entry_tail *t; | ||
254 | |||
255 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
256 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
257 | return 1; | ||
258 | |||
259 | t = get_dirent_tail(inode, dirent); | ||
260 | if (!t) { | ||
261 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space in dir " | ||
262 | "leaf for checksum. Please run e2fsck -D."); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | if (t->det_checksum != ext4_dirent_csum(inode, dirent, | ||
267 | (void *)t - (void *)dirent)) | ||
268 | return 0; | ||
269 | |||
270 | return 1; | ||
271 | } | ||
272 | |||
273 | static void ext4_dirent_csum_set(struct inode *inode, | ||
274 | struct ext4_dir_entry *dirent) | ||
275 | { | ||
276 | struct ext4_dir_entry_tail *t; | ||
277 | |||
278 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
279 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
280 | return; | ||
281 | |||
282 | t = get_dirent_tail(inode, dirent); | ||
283 | if (!t) { | ||
284 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space in dir " | ||
285 | "leaf for checksum. Please run e2fsck -D."); | ||
286 | return; | ||
287 | } | ||
288 | |||
289 | t->det_checksum = ext4_dirent_csum(inode, dirent, | ||
290 | (void *)t - (void *)dirent); | ||
291 | } | ||
292 | |||
293 | static inline int ext4_handle_dirty_dirent_node(handle_t *handle, | ||
294 | struct inode *inode, | ||
295 | struct buffer_head *bh) | ||
296 | { | ||
297 | ext4_dirent_csum_set(inode, (struct ext4_dir_entry *)bh->b_data); | ||
298 | return ext4_handle_dirty_metadata(handle, inode, bh); | ||
299 | } | ||
300 | |||
301 | static struct dx_countlimit *get_dx_countlimit(struct inode *inode, | ||
302 | struct ext4_dir_entry *dirent, | ||
303 | int *offset) | ||
304 | { | ||
305 | struct ext4_dir_entry *dp; | ||
306 | struct dx_root_info *root; | ||
307 | int count_offset; | ||
308 | |||
309 | if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) | ||
310 | count_offset = 8; | ||
311 | else if (le16_to_cpu(dirent->rec_len) == 12) { | ||
312 | dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); | ||
313 | if (le16_to_cpu(dp->rec_len) != | ||
314 | EXT4_BLOCK_SIZE(inode->i_sb) - 12) | ||
315 | return NULL; | ||
316 | root = (struct dx_root_info *)(((void *)dp + 12)); | ||
317 | if (root->reserved_zero || | ||
318 | root->info_length != sizeof(struct dx_root_info)) | ||
319 | return NULL; | ||
320 | count_offset = 32; | ||
321 | } else | ||
322 | return NULL; | ||
323 | |||
324 | if (offset) | ||
325 | *offset = count_offset; | ||
326 | return (struct dx_countlimit *)(((void *)dirent) + count_offset); | ||
327 | } | ||
328 | |||
329 | static __le32 ext4_dx_csum(struct inode *inode, struct ext4_dir_entry *dirent, | ||
330 | int count_offset, int count, struct dx_tail *t) | ||
331 | { | ||
332 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
333 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
334 | __u32 csum, old_csum; | ||
335 | int size; | ||
336 | |||
337 | size = count_offset + (count * sizeof(struct dx_entry)); | ||
338 | old_csum = t->dt_checksum; | ||
339 | t->dt_checksum = 0; | ||
340 | csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size); | ||
341 | csum = ext4_chksum(sbi, csum, (__u8 *)t, sizeof(struct dx_tail)); | ||
342 | t->dt_checksum = old_csum; | ||
343 | |||
344 | return cpu_to_le32(csum); | ||
345 | } | ||
346 | |||
347 | static int ext4_dx_csum_verify(struct inode *inode, | ||
348 | struct ext4_dir_entry *dirent) | ||
349 | { | ||
350 | struct dx_countlimit *c; | ||
351 | struct dx_tail *t; | ||
352 | int count_offset, limit, count; | ||
353 | |||
354 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
355 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
356 | return 1; | ||
357 | |||
358 | c = get_dx_countlimit(inode, dirent, &count_offset); | ||
359 | if (!c) { | ||
360 | EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D."); | ||
361 | return 1; | ||
362 | } | ||
363 | limit = le16_to_cpu(c->limit); | ||
364 | count = le16_to_cpu(c->count); | ||
365 | if (count_offset + (limit * sizeof(struct dx_entry)) > | ||
366 | EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { | ||
367 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space for " | ||
368 | "tree checksum found. Run e2fsck -D."); | ||
369 | return 1; | ||
370 | } | ||
371 | t = (struct dx_tail *)(((struct dx_entry *)c) + limit); | ||
372 | |||
373 | if (t->dt_checksum != ext4_dx_csum(inode, dirent, count_offset, | ||
374 | count, t)) | ||
375 | return 0; | ||
376 | return 1; | ||
377 | } | ||
378 | |||
379 | static void ext4_dx_csum_set(struct inode *inode, struct ext4_dir_entry *dirent) | ||
380 | { | ||
381 | struct dx_countlimit *c; | ||
382 | struct dx_tail *t; | ||
383 | int count_offset, limit, count; | ||
384 | |||
385 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
386 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
387 | return; | ||
388 | |||
389 | c = get_dx_countlimit(inode, dirent, &count_offset); | ||
390 | if (!c) { | ||
391 | EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D."); | ||
392 | return; | ||
393 | } | ||
394 | limit = le16_to_cpu(c->limit); | ||
395 | count = le16_to_cpu(c->count); | ||
396 | if (count_offset + (limit * sizeof(struct dx_entry)) > | ||
397 | EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { | ||
398 | EXT4_ERROR_INODE(inode, "metadata_csum set but no space for " | ||
399 | "tree checksum. Run e2fsck -D."); | ||
400 | return; | ||
401 | } | ||
402 | t = (struct dx_tail *)(((struct dx_entry *)c) + limit); | ||
403 | |||
404 | t->dt_checksum = ext4_dx_csum(inode, dirent, count_offset, count, t); | ||
405 | } | ||
406 | |||
407 | static inline int ext4_handle_dirty_dx_node(handle_t *handle, | ||
408 | struct inode *inode, | ||
409 | struct buffer_head *bh) | ||
410 | { | ||
411 | ext4_dx_csum_set(inode, (struct ext4_dir_entry *)bh->b_data); | ||
412 | return ext4_handle_dirty_metadata(handle, inode, bh); | ||
413 | } | ||
414 | |||
183 | /* | 415 | /* |
184 | * p is at least 6 bytes before the end of page | 416 | * p is at least 6 bytes before the end of page |
185 | */ | 417 | */ |
@@ -239,12 +471,20 @@ static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize) | |||
239 | { | 471 | { |
240 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) - | 472 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) - |
241 | EXT4_DIR_REC_LEN(2) - infosize; | 473 | EXT4_DIR_REC_LEN(2) - infosize; |
474 | |||
475 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
476 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
477 | entry_space -= sizeof(struct dx_tail); | ||
242 | return entry_space / sizeof(struct dx_entry); | 478 | return entry_space / sizeof(struct dx_entry); |
243 | } | 479 | } |
244 | 480 | ||
245 | static inline unsigned dx_node_limit(struct inode *dir) | 481 | static inline unsigned dx_node_limit(struct inode *dir) |
246 | { | 482 | { |
247 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0); | 483 | unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0); |
484 | |||
485 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
486 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
487 | entry_space -= sizeof(struct dx_tail); | ||
248 | return entry_space / sizeof(struct dx_entry); | 488 | return entry_space / sizeof(struct dx_entry); |
249 | } | 489 | } |
250 | 490 | ||
@@ -390,6 +630,15 @@ dx_probe(const struct qstr *d_name, struct inode *dir, | |||
390 | goto fail; | 630 | goto fail; |
391 | } | 631 | } |
392 | 632 | ||
633 | if (!buffer_verified(bh) && | ||
634 | !ext4_dx_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data)) { | ||
635 | ext4_warning(dir->i_sb, "Root failed checksum"); | ||
636 | brelse(bh); | ||
637 | *err = ERR_BAD_DX_DIR; | ||
638 | goto fail; | ||
639 | } | ||
640 | set_buffer_verified(bh); | ||
641 | |||
393 | entries = (struct dx_entry *) (((char *)&root->info) + | 642 | entries = (struct dx_entry *) (((char *)&root->info) + |
394 | root->info.info_length); | 643 | root->info.info_length); |
395 | 644 | ||
@@ -450,6 +699,17 @@ dx_probe(const struct qstr *d_name, struct inode *dir, | |||
450 | if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err))) | 699 | if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err))) |
451 | goto fail2; | 700 | goto fail2; |
452 | at = entries = ((struct dx_node *) bh->b_data)->entries; | 701 | at = entries = ((struct dx_node *) bh->b_data)->entries; |
702 | |||
703 | if (!buffer_verified(bh) && | ||
704 | !ext4_dx_csum_verify(dir, | ||
705 | (struct ext4_dir_entry *)bh->b_data)) { | ||
706 | ext4_warning(dir->i_sb, "Node failed checksum"); | ||
707 | brelse(bh); | ||
708 | *err = ERR_BAD_DX_DIR; | ||
709 | goto fail; | ||
710 | } | ||
711 | set_buffer_verified(bh); | ||
712 | |||
453 | if (dx_get_limit(entries) != dx_node_limit (dir)) { | 713 | if (dx_get_limit(entries) != dx_node_limit (dir)) { |
454 | ext4_warning(dir->i_sb, | 714 | ext4_warning(dir->i_sb, |
455 | "dx entry: limit != node limit"); | 715 | "dx entry: limit != node limit"); |
@@ -549,6 +809,15 @@ static int ext4_htree_next_block(struct inode *dir, __u32 hash, | |||
549 | if (!(bh = ext4_bread(NULL, dir, dx_get_block(p->at), | 809 | if (!(bh = ext4_bread(NULL, dir, dx_get_block(p->at), |
550 | 0, &err))) | 810 | 0, &err))) |
551 | return err; /* Failure */ | 811 | return err; /* Failure */ |
812 | |||
813 | if (!buffer_verified(bh) && | ||
814 | !ext4_dx_csum_verify(dir, | ||
815 | (struct ext4_dir_entry *)bh->b_data)) { | ||
816 | ext4_warning(dir->i_sb, "Node failed checksum"); | ||
817 | return -EIO; | ||
818 | } | ||
819 | set_buffer_verified(bh); | ||
820 | |||
552 | p++; | 821 | p++; |
553 | brelse(p->bh); | 822 | brelse(p->bh); |
554 | p->bh = bh; | 823 | p->bh = bh; |
@@ -577,6 +846,11 @@ static int htree_dirblock_to_tree(struct file *dir_file, | |||
577 | if (!(bh = ext4_bread (NULL, dir, block, 0, &err))) | 846 | if (!(bh = ext4_bread (NULL, dir, block, 0, &err))) |
578 | return err; | 847 | return err; |
579 | 848 | ||
849 | if (!buffer_verified(bh) && | ||
850 | !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data)) | ||
851 | return -EIO; | ||
852 | set_buffer_verified(bh); | ||
853 | |||
580 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 854 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
581 | top = (struct ext4_dir_entry_2 *) ((char *) de + | 855 | top = (struct ext4_dir_entry_2 *) ((char *) de + |
582 | dir->i_sb->s_blocksize - | 856 | dir->i_sb->s_blocksize - |
@@ -936,6 +1210,15 @@ restart: | |||
936 | brelse(bh); | 1210 | brelse(bh); |
937 | goto next; | 1211 | goto next; |
938 | } | 1212 | } |
1213 | if (!buffer_verified(bh) && | ||
1214 | !ext4_dirent_csum_verify(dir, | ||
1215 | (struct ext4_dir_entry *)bh->b_data)) { | ||
1216 | EXT4_ERROR_INODE(dir, "checksumming directory " | ||
1217 | "block %lu", (unsigned long)block); | ||
1218 | brelse(bh); | ||
1219 | goto next; | ||
1220 | } | ||
1221 | set_buffer_verified(bh); | ||
939 | i = search_dirblock(bh, dir, d_name, | 1222 | i = search_dirblock(bh, dir, d_name, |
940 | block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); | 1223 | block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); |
941 | if (i == 1) { | 1224 | if (i == 1) { |
@@ -987,6 +1270,16 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct q | |||
987 | if (!(bh = ext4_bread(NULL, dir, block, 0, err))) | 1270 | if (!(bh = ext4_bread(NULL, dir, block, 0, err))) |
988 | goto errout; | 1271 | goto errout; |
989 | 1272 | ||
1273 | if (!buffer_verified(bh) && | ||
1274 | !ext4_dirent_csum_verify(dir, | ||
1275 | (struct ext4_dir_entry *)bh->b_data)) { | ||
1276 | EXT4_ERROR_INODE(dir, "checksumming directory " | ||
1277 | "block %lu", (unsigned long)block); | ||
1278 | brelse(bh); | ||
1279 | *err = -EIO; | ||
1280 | goto errout; | ||
1281 | } | ||
1282 | set_buffer_verified(bh); | ||
990 | retval = search_dirblock(bh, dir, d_name, | 1283 | retval = search_dirblock(bh, dir, d_name, |
991 | block << EXT4_BLOCK_SIZE_BITS(sb), | 1284 | block << EXT4_BLOCK_SIZE_BITS(sb), |
992 | res_dir); | 1285 | res_dir); |
@@ -1037,6 +1330,12 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru | |||
1037 | EXT4_ERROR_INODE(dir, "bad inode number: %u", ino); | 1330 | EXT4_ERROR_INODE(dir, "bad inode number: %u", ino); |
1038 | return ERR_PTR(-EIO); | 1331 | return ERR_PTR(-EIO); |
1039 | } | 1332 | } |
1333 | if (unlikely(ino == dir->i_ino)) { | ||
1334 | EXT4_ERROR_INODE(dir, "'%.*s' linked to parent dir", | ||
1335 | dentry->d_name.len, | ||
1336 | dentry->d_name.name); | ||
1337 | return ERR_PTR(-EIO); | ||
1338 | } | ||
1040 | inode = ext4_iget(dir->i_sb, ino); | 1339 | inode = ext4_iget(dir->i_sb, ino); |
1041 | if (inode == ERR_PTR(-ESTALE)) { | 1340 | if (inode == ERR_PTR(-ESTALE)) { |
1042 | EXT4_ERROR_INODE(dir, | 1341 | EXT4_ERROR_INODE(dir, |
@@ -1156,8 +1455,14 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1156 | char *data1 = (*bh)->b_data, *data2; | 1455 | char *data1 = (*bh)->b_data, *data2; |
1157 | unsigned split, move, size; | 1456 | unsigned split, move, size; |
1158 | struct ext4_dir_entry_2 *de = NULL, *de2; | 1457 | struct ext4_dir_entry_2 *de = NULL, *de2; |
1458 | struct ext4_dir_entry_tail *t; | ||
1459 | int csum_size = 0; | ||
1159 | int err = 0, i; | 1460 | int err = 0, i; |
1160 | 1461 | ||
1462 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
1463 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1464 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
1465 | |||
1161 | bh2 = ext4_append (handle, dir, &newblock, &err); | 1466 | bh2 = ext4_append (handle, dir, &newblock, &err); |
1162 | if (!(bh2)) { | 1467 | if (!(bh2)) { |
1163 | brelse(*bh); | 1468 | brelse(*bh); |
@@ -1204,10 +1509,20 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1204 | /* Fancy dance to stay within two buffers */ | 1509 | /* Fancy dance to stay within two buffers */ |
1205 | de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize); | 1510 | de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize); |
1206 | de = dx_pack_dirents(data1, blocksize); | 1511 | de = dx_pack_dirents(data1, blocksize); |
1207 | de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de, | 1512 | de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) - |
1513 | (char *) de, | ||
1208 | blocksize); | 1514 | blocksize); |
1209 | de2->rec_len = ext4_rec_len_to_disk(data2 + blocksize - (char *) de2, | 1515 | de2->rec_len = ext4_rec_len_to_disk(data2 + (blocksize - csum_size) - |
1516 | (char *) de2, | ||
1210 | blocksize); | 1517 | blocksize); |
1518 | if (csum_size) { | ||
1519 | t = EXT4_DIRENT_TAIL(data2, blocksize); | ||
1520 | initialize_dirent_tail(t, blocksize); | ||
1521 | |||
1522 | t = EXT4_DIRENT_TAIL(data1, blocksize); | ||
1523 | initialize_dirent_tail(t, blocksize); | ||
1524 | } | ||
1525 | |||
1211 | dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1)); | 1526 | dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1)); |
1212 | dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1)); | 1527 | dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1)); |
1213 | 1528 | ||
@@ -1218,10 +1533,10 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1218 | de = de2; | 1533 | de = de2; |
1219 | } | 1534 | } |
1220 | dx_insert_block(frame, hash2 + continued, newblock); | 1535 | dx_insert_block(frame, hash2 + continued, newblock); |
1221 | err = ext4_handle_dirty_metadata(handle, dir, bh2); | 1536 | err = ext4_handle_dirty_dirent_node(handle, dir, bh2); |
1222 | if (err) | 1537 | if (err) |
1223 | goto journal_error; | 1538 | goto journal_error; |
1224 | err = ext4_handle_dirty_metadata(handle, dir, frame->bh); | 1539 | err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); |
1225 | if (err) | 1540 | if (err) |
1226 | goto journal_error; | 1541 | goto journal_error; |
1227 | brelse(bh2); | 1542 | brelse(bh2); |
@@ -1258,11 +1573,16 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1258 | unsigned short reclen; | 1573 | unsigned short reclen; |
1259 | int nlen, rlen, err; | 1574 | int nlen, rlen, err; |
1260 | char *top; | 1575 | char *top; |
1576 | int csum_size = 0; | ||
1577 | |||
1578 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
1579 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1580 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
1261 | 1581 | ||
1262 | reclen = EXT4_DIR_REC_LEN(namelen); | 1582 | reclen = EXT4_DIR_REC_LEN(namelen); |
1263 | if (!de) { | 1583 | if (!de) { |
1264 | de = (struct ext4_dir_entry_2 *)bh->b_data; | 1584 | de = (struct ext4_dir_entry_2 *)bh->b_data; |
1265 | top = bh->b_data + blocksize - reclen; | 1585 | top = bh->b_data + (blocksize - csum_size) - reclen; |
1266 | while ((char *) de <= top) { | 1586 | while ((char *) de <= top) { |
1267 | if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) | 1587 | if (ext4_check_dir_entry(dir, NULL, de, bh, offset)) |
1268 | return -EIO; | 1588 | return -EIO; |
@@ -1295,11 +1615,8 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1295 | de = de1; | 1615 | de = de1; |
1296 | } | 1616 | } |
1297 | de->file_type = EXT4_FT_UNKNOWN; | 1617 | de->file_type = EXT4_FT_UNKNOWN; |
1298 | if (inode) { | 1618 | de->inode = cpu_to_le32(inode->i_ino); |
1299 | de->inode = cpu_to_le32(inode->i_ino); | 1619 | ext4_set_de_type(dir->i_sb, de, inode->i_mode); |
1300 | ext4_set_de_type(dir->i_sb, de, inode->i_mode); | ||
1301 | } else | ||
1302 | de->inode = 0; | ||
1303 | de->name_len = namelen; | 1620 | de->name_len = namelen; |
1304 | memcpy(de->name, name, namelen); | 1621 | memcpy(de->name, name, namelen); |
1305 | /* | 1622 | /* |
@@ -1318,7 +1635,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1318 | dir->i_version++; | 1635 | dir->i_version++; |
1319 | ext4_mark_inode_dirty(handle, dir); | 1636 | ext4_mark_inode_dirty(handle, dir); |
1320 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | 1637 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
1321 | err = ext4_handle_dirty_metadata(handle, dir, bh); | 1638 | err = ext4_handle_dirty_dirent_node(handle, dir, bh); |
1322 | if (err) | 1639 | if (err) |
1323 | ext4_std_error(dir->i_sb, err); | 1640 | ext4_std_error(dir->i_sb, err); |
1324 | return 0; | 1641 | return 0; |
@@ -1339,6 +1656,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1339 | struct dx_frame frames[2], *frame; | 1656 | struct dx_frame frames[2], *frame; |
1340 | struct dx_entry *entries; | 1657 | struct dx_entry *entries; |
1341 | struct ext4_dir_entry_2 *de, *de2; | 1658 | struct ext4_dir_entry_2 *de, *de2; |
1659 | struct ext4_dir_entry_tail *t; | ||
1342 | char *data1, *top; | 1660 | char *data1, *top; |
1343 | unsigned len; | 1661 | unsigned len; |
1344 | int retval; | 1662 | int retval; |
@@ -1346,6 +1664,11 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1346 | struct dx_hash_info hinfo; | 1664 | struct dx_hash_info hinfo; |
1347 | ext4_lblk_t block; | 1665 | ext4_lblk_t block; |
1348 | struct fake_dirent *fde; | 1666 | struct fake_dirent *fde; |
1667 | int csum_size = 0; | ||
1668 | |||
1669 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
1670 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1671 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
1349 | 1672 | ||
1350 | blocksize = dir->i_sb->s_blocksize; | 1673 | blocksize = dir->i_sb->s_blocksize; |
1351 | dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); | 1674 | dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); |
@@ -1366,7 +1689,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1366 | brelse(bh); | 1689 | brelse(bh); |
1367 | return -EIO; | 1690 | return -EIO; |
1368 | } | 1691 | } |
1369 | len = ((char *) root) + blocksize - (char *) de; | 1692 | len = ((char *) root) + (blocksize - csum_size) - (char *) de; |
1370 | 1693 | ||
1371 | /* Allocate new block for the 0th block's dirents */ | 1694 | /* Allocate new block for the 0th block's dirents */ |
1372 | bh2 = ext4_append(handle, dir, &block, &retval); | 1695 | bh2 = ext4_append(handle, dir, &block, &retval); |
@@ -1382,8 +1705,15 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1382 | top = data1 + len; | 1705 | top = data1 + len; |
1383 | while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top) | 1706 | while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top) |
1384 | de = de2; | 1707 | de = de2; |
1385 | de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de, | 1708 | de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) - |
1709 | (char *) de, | ||
1386 | blocksize); | 1710 | blocksize); |
1711 | |||
1712 | if (csum_size) { | ||
1713 | t = EXT4_DIRENT_TAIL(data1, blocksize); | ||
1714 | initialize_dirent_tail(t, blocksize); | ||
1715 | } | ||
1716 | |||
1387 | /* Initialize the root; the dot dirents already exist */ | 1717 | /* Initialize the root; the dot dirents already exist */ |
1388 | de = (struct ext4_dir_entry_2 *) (&root->dotdot); | 1718 | de = (struct ext4_dir_entry_2 *) (&root->dotdot); |
1389 | de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2), | 1719 | de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2), |
@@ -1408,8 +1738,8 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1408 | frame->bh = bh; | 1738 | frame->bh = bh; |
1409 | bh = bh2; | 1739 | bh = bh2; |
1410 | 1740 | ||
1411 | ext4_handle_dirty_metadata(handle, dir, frame->bh); | 1741 | ext4_handle_dirty_dx_node(handle, dir, frame->bh); |
1412 | ext4_handle_dirty_metadata(handle, dir, bh); | 1742 | ext4_handle_dirty_dirent_node(handle, dir, bh); |
1413 | 1743 | ||
1414 | de = do_split(handle,dir, &bh, frame, &hinfo, &retval); | 1744 | de = do_split(handle,dir, &bh, frame, &hinfo, &retval); |
1415 | if (!de) { | 1745 | if (!de) { |
@@ -1445,11 +1775,17 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1445 | struct inode *dir = dentry->d_parent->d_inode; | 1775 | struct inode *dir = dentry->d_parent->d_inode; |
1446 | struct buffer_head *bh; | 1776 | struct buffer_head *bh; |
1447 | struct ext4_dir_entry_2 *de; | 1777 | struct ext4_dir_entry_2 *de; |
1778 | struct ext4_dir_entry_tail *t; | ||
1448 | struct super_block *sb; | 1779 | struct super_block *sb; |
1449 | int retval; | 1780 | int retval; |
1450 | int dx_fallback=0; | 1781 | int dx_fallback=0; |
1451 | unsigned blocksize; | 1782 | unsigned blocksize; |
1452 | ext4_lblk_t block, blocks; | 1783 | ext4_lblk_t block, blocks; |
1784 | int csum_size = 0; | ||
1785 | |||
1786 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
1787 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1788 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
1453 | 1789 | ||
1454 | sb = dir->i_sb; | 1790 | sb = dir->i_sb; |
1455 | blocksize = sb->s_blocksize; | 1791 | blocksize = sb->s_blocksize; |
@@ -1468,6 +1804,11 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1468 | bh = ext4_bread(handle, dir, block, 0, &retval); | 1804 | bh = ext4_bread(handle, dir, block, 0, &retval); |
1469 | if(!bh) | 1805 | if(!bh) |
1470 | return retval; | 1806 | return retval; |
1807 | if (!buffer_verified(bh) && | ||
1808 | !ext4_dirent_csum_verify(dir, | ||
1809 | (struct ext4_dir_entry *)bh->b_data)) | ||
1810 | return -EIO; | ||
1811 | set_buffer_verified(bh); | ||
1471 | retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); | 1812 | retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); |
1472 | if (retval != -ENOSPC) { | 1813 | if (retval != -ENOSPC) { |
1473 | brelse(bh); | 1814 | brelse(bh); |
@@ -1484,7 +1825,13 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry, | |||
1484 | return retval; | 1825 | return retval; |
1485 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 1826 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1486 | de->inode = 0; | 1827 | de->inode = 0; |
1487 | de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize); | 1828 | de->rec_len = ext4_rec_len_to_disk(blocksize - csum_size, blocksize); |
1829 | |||
1830 | if (csum_size) { | ||
1831 | t = EXT4_DIRENT_TAIL(bh->b_data, blocksize); | ||
1832 | initialize_dirent_tail(t, blocksize); | ||
1833 | } | ||
1834 | |||
1488 | retval = add_dirent_to_buf(handle, dentry, inode, de, bh); | 1835 | retval = add_dirent_to_buf(handle, dentry, inode, de, bh); |
1489 | brelse(bh); | 1836 | brelse(bh); |
1490 | if (retval == 0) | 1837 | if (retval == 0) |
@@ -1516,6 +1863,11 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1516 | if (!(bh = ext4_bread(handle,dir, dx_get_block(frame->at), 0, &err))) | 1863 | if (!(bh = ext4_bread(handle,dir, dx_get_block(frame->at), 0, &err))) |
1517 | goto cleanup; | 1864 | goto cleanup; |
1518 | 1865 | ||
1866 | if (!buffer_verified(bh) && | ||
1867 | !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data)) | ||
1868 | goto journal_error; | ||
1869 | set_buffer_verified(bh); | ||
1870 | |||
1519 | BUFFER_TRACE(bh, "get_write_access"); | 1871 | BUFFER_TRACE(bh, "get_write_access"); |
1520 | err = ext4_journal_get_write_access(handle, bh); | 1872 | err = ext4_journal_get_write_access(handle, bh); |
1521 | if (err) | 1873 | if (err) |
@@ -1583,7 +1935,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1583 | dxtrace(dx_show_index("node", frames[1].entries)); | 1935 | dxtrace(dx_show_index("node", frames[1].entries)); |
1584 | dxtrace(dx_show_index("node", | 1936 | dxtrace(dx_show_index("node", |
1585 | ((struct dx_node *) bh2->b_data)->entries)); | 1937 | ((struct dx_node *) bh2->b_data)->entries)); |
1586 | err = ext4_handle_dirty_metadata(handle, dir, bh2); | 1938 | err = ext4_handle_dirty_dx_node(handle, dir, bh2); |
1587 | if (err) | 1939 | if (err) |
1588 | goto journal_error; | 1940 | goto journal_error; |
1589 | brelse (bh2); | 1941 | brelse (bh2); |
@@ -1609,7 +1961,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1609 | if (err) | 1961 | if (err) |
1610 | goto journal_error; | 1962 | goto journal_error; |
1611 | } | 1963 | } |
1612 | err = ext4_handle_dirty_metadata(handle, dir, frames[0].bh); | 1964 | err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); |
1613 | if (err) { | 1965 | if (err) { |
1614 | ext4_std_error(inode->i_sb, err); | 1966 | ext4_std_error(inode->i_sb, err); |
1615 | goto cleanup; | 1967 | goto cleanup; |
@@ -1641,12 +1993,17 @@ static int ext4_delete_entry(handle_t *handle, | |||
1641 | { | 1993 | { |
1642 | struct ext4_dir_entry_2 *de, *pde; | 1994 | struct ext4_dir_entry_2 *de, *pde; |
1643 | unsigned int blocksize = dir->i_sb->s_blocksize; | 1995 | unsigned int blocksize = dir->i_sb->s_blocksize; |
1996 | int csum_size = 0; | ||
1644 | int i, err; | 1997 | int i, err; |
1645 | 1998 | ||
1999 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
2000 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
2001 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
2002 | |||
1646 | i = 0; | 2003 | i = 0; |
1647 | pde = NULL; | 2004 | pde = NULL; |
1648 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2005 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1649 | while (i < bh->b_size) { | 2006 | while (i < bh->b_size - csum_size) { |
1650 | if (ext4_check_dir_entry(dir, NULL, de, bh, i)) | 2007 | if (ext4_check_dir_entry(dir, NULL, de, bh, i)) |
1651 | return -EIO; | 2008 | return -EIO; |
1652 | if (de == de_del) { | 2009 | if (de == de_del) { |
@@ -1667,7 +2024,7 @@ static int ext4_delete_entry(handle_t *handle, | |||
1667 | de->inode = 0; | 2024 | de->inode = 0; |
1668 | dir->i_version++; | 2025 | dir->i_version++; |
1669 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | 2026 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
1670 | err = ext4_handle_dirty_metadata(handle, dir, bh); | 2027 | err = ext4_handle_dirty_dirent_node(handle, dir, bh); |
1671 | if (unlikely(err)) { | 2028 | if (unlikely(err)) { |
1672 | ext4_std_error(dir->i_sb, err); | 2029 | ext4_std_error(dir->i_sb, err); |
1673 | return err; | 2030 | return err; |
@@ -1809,9 +2166,15 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
1809 | struct inode *inode; | 2166 | struct inode *inode; |
1810 | struct buffer_head *dir_block = NULL; | 2167 | struct buffer_head *dir_block = NULL; |
1811 | struct ext4_dir_entry_2 *de; | 2168 | struct ext4_dir_entry_2 *de; |
2169 | struct ext4_dir_entry_tail *t; | ||
1812 | unsigned int blocksize = dir->i_sb->s_blocksize; | 2170 | unsigned int blocksize = dir->i_sb->s_blocksize; |
2171 | int csum_size = 0; | ||
1813 | int err, retries = 0; | 2172 | int err, retries = 0; |
1814 | 2173 | ||
2174 | if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb, | ||
2175 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
2176 | csum_size = sizeof(struct ext4_dir_entry_tail); | ||
2177 | |||
1815 | if (EXT4_DIR_LINK_MAX(dir)) | 2178 | if (EXT4_DIR_LINK_MAX(dir)) |
1816 | return -EMLINK; | 2179 | return -EMLINK; |
1817 | 2180 | ||
@@ -1852,16 +2215,24 @@ retry: | |||
1852 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); | 2215 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); |
1853 | de = ext4_next_entry(de, blocksize); | 2216 | de = ext4_next_entry(de, blocksize); |
1854 | de->inode = cpu_to_le32(dir->i_ino); | 2217 | de->inode = cpu_to_le32(dir->i_ino); |
1855 | de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(1), | 2218 | de->rec_len = ext4_rec_len_to_disk(blocksize - |
2219 | (csum_size + EXT4_DIR_REC_LEN(1)), | ||
1856 | blocksize); | 2220 | blocksize); |
1857 | de->name_len = 2; | 2221 | de->name_len = 2; |
1858 | strcpy(de->name, ".."); | 2222 | strcpy(de->name, ".."); |
1859 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); | 2223 | ext4_set_de_type(dir->i_sb, de, S_IFDIR); |
1860 | set_nlink(inode, 2); | 2224 | set_nlink(inode, 2); |
2225 | |||
2226 | if (csum_size) { | ||
2227 | t = EXT4_DIRENT_TAIL(dir_block->b_data, blocksize); | ||
2228 | initialize_dirent_tail(t, blocksize); | ||
2229 | } | ||
2230 | |||
1861 | BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); | 2231 | BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); |
1862 | err = ext4_handle_dirty_metadata(handle, inode, dir_block); | 2232 | err = ext4_handle_dirty_dirent_node(handle, inode, dir_block); |
1863 | if (err) | 2233 | if (err) |
1864 | goto out_clear_inode; | 2234 | goto out_clear_inode; |
2235 | set_buffer_verified(dir_block); | ||
1865 | err = ext4_mark_inode_dirty(handle, inode); | 2236 | err = ext4_mark_inode_dirty(handle, inode); |
1866 | if (!err) | 2237 | if (!err) |
1867 | err = ext4_add_entry(handle, dentry, inode); | 2238 | err = ext4_add_entry(handle, dentry, inode); |
@@ -1911,6 +2282,14 @@ static int empty_dir(struct inode *inode) | |||
1911 | inode->i_ino); | 2282 | inode->i_ino); |
1912 | return 1; | 2283 | return 1; |
1913 | } | 2284 | } |
2285 | if (!buffer_verified(bh) && | ||
2286 | !ext4_dirent_csum_verify(inode, | ||
2287 | (struct ext4_dir_entry *)bh->b_data)) { | ||
2288 | EXT4_ERROR_INODE(inode, "checksum error reading directory " | ||
2289 | "lblock 0"); | ||
2290 | return -EIO; | ||
2291 | } | ||
2292 | set_buffer_verified(bh); | ||
1914 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2293 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1915 | de1 = ext4_next_entry(de, sb->s_blocksize); | 2294 | de1 = ext4_next_entry(de, sb->s_blocksize); |
1916 | if (le32_to_cpu(de->inode) != inode->i_ino || | 2295 | if (le32_to_cpu(de->inode) != inode->i_ino || |
@@ -1942,6 +2321,14 @@ static int empty_dir(struct inode *inode) | |||
1942 | offset += sb->s_blocksize; | 2321 | offset += sb->s_blocksize; |
1943 | continue; | 2322 | continue; |
1944 | } | 2323 | } |
2324 | if (!buffer_verified(bh) && | ||
2325 | !ext4_dirent_csum_verify(inode, | ||
2326 | (struct ext4_dir_entry *)bh->b_data)) { | ||
2327 | EXT4_ERROR_INODE(inode, "checksum error " | ||
2328 | "reading directory lblock 0"); | ||
2329 | return -EIO; | ||
2330 | } | ||
2331 | set_buffer_verified(bh); | ||
1945 | de = (struct ext4_dir_entry_2 *) bh->b_data; | 2332 | de = (struct ext4_dir_entry_2 *) bh->b_data; |
1946 | } | 2333 | } |
1947 | if (ext4_check_dir_entry(inode, NULL, de, bh, offset)) { | 2334 | if (ext4_check_dir_entry(inode, NULL, de, bh, offset)) { |
@@ -2010,7 +2397,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode) | |||
2010 | /* Insert this inode at the head of the on-disk orphan list... */ | 2397 | /* Insert this inode at the head of the on-disk orphan list... */ |
2011 | NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan); | 2398 | NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan); |
2012 | EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); | 2399 | EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); |
2013 | err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); | 2400 | err = ext4_handle_dirty_super_now(handle, sb); |
2014 | rc = ext4_mark_iloc_dirty(handle, inode, &iloc); | 2401 | rc = ext4_mark_iloc_dirty(handle, inode, &iloc); |
2015 | if (!err) | 2402 | if (!err) |
2016 | err = rc; | 2403 | err = rc; |
@@ -2083,7 +2470,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode) | |||
2083 | if (err) | 2470 | if (err) |
2084 | goto out_brelse; | 2471 | goto out_brelse; |
2085 | sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); | 2472 | sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); |
2086 | err = ext4_handle_dirty_metadata(handle, NULL, sbi->s_sbh); | 2473 | err = ext4_handle_dirty_super_now(handle, inode->i_sb); |
2087 | } else { | 2474 | } else { |
2088 | struct ext4_iloc iloc2; | 2475 | struct ext4_iloc iloc2; |
2089 | struct inode *i_prev = | 2476 | struct inode *i_prev = |
@@ -2442,6 +2829,11 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2442 | dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval); | 2829 | dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval); |
2443 | if (!dir_bh) | 2830 | if (!dir_bh) |
2444 | goto end_rename; | 2831 | goto end_rename; |
2832 | if (!buffer_verified(dir_bh) && | ||
2833 | !ext4_dirent_csum_verify(old_inode, | ||
2834 | (struct ext4_dir_entry *)dir_bh->b_data)) | ||
2835 | goto end_rename; | ||
2836 | set_buffer_verified(dir_bh); | ||
2445 | if (le32_to_cpu(PARENT_INO(dir_bh->b_data, | 2837 | if (le32_to_cpu(PARENT_INO(dir_bh->b_data, |
2446 | old_dir->i_sb->s_blocksize)) != old_dir->i_ino) | 2838 | old_dir->i_sb->s_blocksize)) != old_dir->i_ino) |
2447 | goto end_rename; | 2839 | goto end_rename; |
@@ -2472,7 +2864,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2472 | ext4_current_time(new_dir); | 2864 | ext4_current_time(new_dir); |
2473 | ext4_mark_inode_dirty(handle, new_dir); | 2865 | ext4_mark_inode_dirty(handle, new_dir); |
2474 | BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata"); | 2866 | BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata"); |
2475 | retval = ext4_handle_dirty_metadata(handle, new_dir, new_bh); | 2867 | retval = ext4_handle_dirty_dirent_node(handle, new_dir, new_bh); |
2476 | if (unlikely(retval)) { | 2868 | if (unlikely(retval)) { |
2477 | ext4_std_error(new_dir->i_sb, retval); | 2869 | ext4_std_error(new_dir->i_sb, retval); |
2478 | goto end_rename; | 2870 | goto end_rename; |
@@ -2526,7 +2918,8 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
2526 | PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) = | 2918 | PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) = |
2527 | cpu_to_le32(new_dir->i_ino); | 2919 | cpu_to_le32(new_dir->i_ino); |
2528 | BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); | 2920 | BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); |
2529 | retval = ext4_handle_dirty_metadata(handle, old_inode, dir_bh); | 2921 | retval = ext4_handle_dirty_dirent_node(handle, old_inode, |
2922 | dir_bh); | ||
2530 | if (retval) { | 2923 | if (retval) { |
2531 | ext4_std_error(old_dir->i_sb, retval); | 2924 | ext4_std_error(old_dir->i_sb, retval); |
2532 | goto end_rename; | 2925 | goto end_rename; |
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 59fa0be27251..7ea6cbb44121 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
@@ -161,6 +161,8 @@ static struct ext4_new_flex_group_data *alloc_flex_gd(unsigned long flexbg_size) | |||
161 | if (flex_gd == NULL) | 161 | if (flex_gd == NULL) |
162 | goto out3; | 162 | goto out3; |
163 | 163 | ||
164 | if (flexbg_size >= UINT_MAX / sizeof(struct ext4_new_flex_group_data)) | ||
165 | goto out2; | ||
164 | flex_gd->count = flexbg_size; | 166 | flex_gd->count = flexbg_size; |
165 | 167 | ||
166 | flex_gd->groups = kmalloc(sizeof(struct ext4_new_group_data) * | 168 | flex_gd->groups = kmalloc(sizeof(struct ext4_new_group_data) * |
@@ -796,7 +798,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode, | |||
796 | ext4_kvfree(o_group_desc); | 798 | ext4_kvfree(o_group_desc); |
797 | 799 | ||
798 | le16_add_cpu(&es->s_reserved_gdt_blocks, -1); | 800 | le16_add_cpu(&es->s_reserved_gdt_blocks, -1); |
799 | err = ext4_handle_dirty_metadata(handle, NULL, EXT4_SB(sb)->s_sbh); | 801 | err = ext4_handle_dirty_super_now(handle, sb); |
800 | if (err) | 802 | if (err) |
801 | ext4_std_error(sb, err); | 803 | ext4_std_error(sb, err); |
802 | 804 | ||
@@ -968,6 +970,8 @@ static void update_backups(struct super_block *sb, | |||
968 | goto exit_err; | 970 | goto exit_err; |
969 | } | 971 | } |
970 | 972 | ||
973 | ext4_superblock_csum_set(sb, (struct ext4_super_block *)data); | ||
974 | |||
971 | while ((group = ext4_list_backups(sb, &three, &five, &seven)) < last) { | 975 | while ((group = ext4_list_backups(sb, &three, &five, &seven)) < last) { |
972 | struct buffer_head *bh; | 976 | struct buffer_head *bh; |
973 | 977 | ||
@@ -1067,6 +1071,54 @@ static int ext4_add_new_descs(handle_t *handle, struct super_block *sb, | |||
1067 | return err; | 1071 | return err; |
1068 | } | 1072 | } |
1069 | 1073 | ||
1074 | static struct buffer_head *ext4_get_bitmap(struct super_block *sb, __u64 block) | ||
1075 | { | ||
1076 | struct buffer_head *bh = sb_getblk(sb, block); | ||
1077 | if (!bh) | ||
1078 | return NULL; | ||
1079 | |||
1080 | if (bitmap_uptodate(bh)) | ||
1081 | return bh; | ||
1082 | |||
1083 | lock_buffer(bh); | ||
1084 | if (bh_submit_read(bh) < 0) { | ||
1085 | unlock_buffer(bh); | ||
1086 | brelse(bh); | ||
1087 | return NULL; | ||
1088 | } | ||
1089 | unlock_buffer(bh); | ||
1090 | |||
1091 | return bh; | ||
1092 | } | ||
1093 | |||
1094 | static int ext4_set_bitmap_checksums(struct super_block *sb, | ||
1095 | ext4_group_t group, | ||
1096 | struct ext4_group_desc *gdp, | ||
1097 | struct ext4_new_group_data *group_data) | ||
1098 | { | ||
1099 | struct buffer_head *bh; | ||
1100 | |||
1101 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
1102 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
1103 | return 0; | ||
1104 | |||
1105 | bh = ext4_get_bitmap(sb, group_data->inode_bitmap); | ||
1106 | if (!bh) | ||
1107 | return -EIO; | ||
1108 | ext4_inode_bitmap_csum_set(sb, group, gdp, bh, | ||
1109 | EXT4_INODES_PER_GROUP(sb) / 8); | ||
1110 | brelse(bh); | ||
1111 | |||
1112 | bh = ext4_get_bitmap(sb, group_data->block_bitmap); | ||
1113 | if (!bh) | ||
1114 | return -EIO; | ||
1115 | ext4_block_bitmap_csum_set(sb, group, gdp, bh, | ||
1116 | EXT4_BLOCKS_PER_GROUP(sb) / 8); | ||
1117 | brelse(bh); | ||
1118 | |||
1119 | return 0; | ||
1120 | } | ||
1121 | |||
1070 | /* | 1122 | /* |
1071 | * ext4_setup_new_descs() will set up the group descriptor descriptors of a flex bg | 1123 | * ext4_setup_new_descs() will set up the group descriptor descriptors of a flex bg |
1072 | */ | 1124 | */ |
@@ -1093,18 +1145,24 @@ static int ext4_setup_new_descs(handle_t *handle, struct super_block *sb, | |||
1093 | */ | 1145 | */ |
1094 | gdb_bh = sbi->s_group_desc[gdb_num]; | 1146 | gdb_bh = sbi->s_group_desc[gdb_num]; |
1095 | /* Update group descriptor block for new group */ | 1147 | /* Update group descriptor block for new group */ |
1096 | gdp = (struct ext4_group_desc *)((char *)gdb_bh->b_data + | 1148 | gdp = (struct ext4_group_desc *)(gdb_bh->b_data + |
1097 | gdb_off * EXT4_DESC_SIZE(sb)); | 1149 | gdb_off * EXT4_DESC_SIZE(sb)); |
1098 | 1150 | ||
1099 | memset(gdp, 0, EXT4_DESC_SIZE(sb)); | 1151 | memset(gdp, 0, EXT4_DESC_SIZE(sb)); |
1100 | ext4_block_bitmap_set(sb, gdp, group_data->block_bitmap); | 1152 | ext4_block_bitmap_set(sb, gdp, group_data->block_bitmap); |
1101 | ext4_inode_bitmap_set(sb, gdp, group_data->inode_bitmap); | 1153 | ext4_inode_bitmap_set(sb, gdp, group_data->inode_bitmap); |
1154 | err = ext4_set_bitmap_checksums(sb, group, gdp, group_data); | ||
1155 | if (err) { | ||
1156 | ext4_std_error(sb, err); | ||
1157 | break; | ||
1158 | } | ||
1159 | |||
1102 | ext4_inode_table_set(sb, gdp, group_data->inode_table); | 1160 | ext4_inode_table_set(sb, gdp, group_data->inode_table); |
1103 | ext4_free_group_clusters_set(sb, gdp, | 1161 | ext4_free_group_clusters_set(sb, gdp, |
1104 | EXT4_B2C(sbi, group_data->free_blocks_count)); | 1162 | EXT4_B2C(sbi, group_data->free_blocks_count)); |
1105 | ext4_free_inodes_set(sb, gdp, EXT4_INODES_PER_GROUP(sb)); | 1163 | ext4_free_inodes_set(sb, gdp, EXT4_INODES_PER_GROUP(sb)); |
1106 | gdp->bg_flags = cpu_to_le16(*bg_flags); | 1164 | gdp->bg_flags = cpu_to_le16(*bg_flags); |
1107 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp); | 1165 | ext4_group_desc_csum_set(sb, group, gdp); |
1108 | 1166 | ||
1109 | err = ext4_handle_dirty_metadata(handle, NULL, gdb_bh); | 1167 | err = ext4_handle_dirty_metadata(handle, NULL, gdb_bh); |
1110 | if (unlikely(err)) { | 1168 | if (unlikely(err)) { |
@@ -1343,17 +1401,14 @@ static int ext4_setup_next_flex_gd(struct super_block *sb, | |||
1343 | (1 + ext4_bg_num_gdb(sb, group + i) + | 1401 | (1 + ext4_bg_num_gdb(sb, group + i) + |
1344 | le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; | 1402 | le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; |
1345 | group_data[i].free_blocks_count = blocks_per_group - overhead; | 1403 | group_data[i].free_blocks_count = blocks_per_group - overhead; |
1346 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | 1404 | if (ext4_has_group_desc_csum(sb)) |
1347 | EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) | ||
1348 | flex_gd->bg_flags[i] = EXT4_BG_BLOCK_UNINIT | | 1405 | flex_gd->bg_flags[i] = EXT4_BG_BLOCK_UNINIT | |
1349 | EXT4_BG_INODE_UNINIT; | 1406 | EXT4_BG_INODE_UNINIT; |
1350 | else | 1407 | else |
1351 | flex_gd->bg_flags[i] = EXT4_BG_INODE_ZEROED; | 1408 | flex_gd->bg_flags[i] = EXT4_BG_INODE_ZEROED; |
1352 | } | 1409 | } |
1353 | 1410 | ||
1354 | if (last_group == n_group && | 1411 | if (last_group == n_group && ext4_has_group_desc_csum(sb)) |
1355 | EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
1356 | EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) | ||
1357 | /* We need to initialize block bitmap of last group. */ | 1412 | /* We need to initialize block bitmap of last group. */ |
1358 | flex_gd->bg_flags[i - 1] &= ~EXT4_BG_BLOCK_UNINIT; | 1413 | flex_gd->bg_flags[i - 1] &= ~EXT4_BG_BLOCK_UNINIT; |
1359 | 1414 | ||
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 35b5954489ee..eb7aa3e4ef05 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -112,6 +112,48 @@ static struct file_system_type ext3_fs_type = { | |||
112 | #define IS_EXT3_SB(sb) (0) | 112 | #define IS_EXT3_SB(sb) (0) |
113 | #endif | 113 | #endif |
114 | 114 | ||
115 | static int ext4_verify_csum_type(struct super_block *sb, | ||
116 | struct ext4_super_block *es) | ||
117 | { | ||
118 | if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
119 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
120 | return 1; | ||
121 | |||
122 | return es->s_checksum_type == EXT4_CRC32C_CHKSUM; | ||
123 | } | ||
124 | |||
125 | static __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 | |||
137 | int 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 | |||
147 | void 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 | |||
115 | void *ext4_kvmalloc(size_t size, gfp_t flags) | 157 | void *ext4_kvmalloc(size_t size, gfp_t flags) |
116 | { | 158 | { |
117 | void *ret; | 159 | void *ret; |
@@ -497,6 +539,7 @@ void __ext4_error(struct super_block *sb, const char *function, | |||
497 | printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: comm %s: %pV\n", | 539 | printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: comm %s: %pV\n", |
498 | sb->s_id, function, line, current->comm, &vaf); | 540 | sb->s_id, function, line, current->comm, &vaf); |
499 | va_end(args); | 541 | va_end(args); |
542 | save_error_info(sb, function, line); | ||
500 | 543 | ||
501 | ext4_handle_error(sb); | 544 | ext4_handle_error(sb); |
502 | } | 545 | } |
@@ -905,6 +948,8 @@ static void ext4_put_super(struct super_block *sb) | |||
905 | unlock_super(sb); | 948 | unlock_super(sb); |
906 | kobject_put(&sbi->s_kobj); | 949 | kobject_put(&sbi->s_kobj); |
907 | wait_for_completion(&sbi->s_kobj_unregister); | 950 | wait_for_completion(&sbi->s_kobj_unregister); |
951 | if (sbi->s_chksum_driver) | ||
952 | crypto_free_shash(sbi->s_chksum_driver); | ||
908 | kfree(sbi->s_blockgroup_lock); | 953 | kfree(sbi->s_blockgroup_lock); |
909 | kfree(sbi); | 954 | kfree(sbi); |
910 | } | 955 | } |
@@ -1922,43 +1967,69 @@ failed: | |||
1922 | return 0; | 1967 | return 0; |
1923 | } | 1968 | } |
1924 | 1969 | ||
1925 | __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group, | 1970 | static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group, |
1926 | struct ext4_group_desc *gdp) | 1971 | struct ext4_group_desc *gdp) |
1927 | { | 1972 | { |
1973 | int offset; | ||
1928 | __u16 crc = 0; | 1974 | __u16 crc = 0; |
1975 | __le32 le_group = cpu_to_le32(block_group); | ||
1929 | 1976 | ||
1930 | if (sbi->s_es->s_feature_ro_compat & | 1977 | if ((sbi->s_es->s_feature_ro_compat & |
1931 | cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) { | 1978 | cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))) { |
1932 | int offset = offsetof(struct ext4_group_desc, bg_checksum); | 1979 | /* Use new metadata_csum algorithm */ |
1933 | __le32 le_group = cpu_to_le32(block_group); | 1980 | __u16 old_csum; |
1934 | 1981 | __u32 csum32; | |
1935 | crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); | 1982 | |
1936 | crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); | 1983 | old_csum = gdp->bg_checksum; |
1937 | crc = crc16(crc, (__u8 *)gdp, offset); | 1984 | gdp->bg_checksum = 0; |
1938 | offset += sizeof(gdp->bg_checksum); /* skip checksum */ | 1985 | csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group, |
1939 | /* for checksum of struct ext4_group_desc do the rest...*/ | 1986 | sizeof(le_group)); |
1940 | if ((sbi->s_es->s_feature_incompat & | 1987 | csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp, |
1941 | cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) && | 1988 | sbi->s_desc_size); |
1942 | offset < le16_to_cpu(sbi->s_es->s_desc_size)) | 1989 | gdp->bg_checksum = old_csum; |
1943 | crc = crc16(crc, (__u8 *)gdp + offset, | 1990 | |
1944 | le16_to_cpu(sbi->s_es->s_desc_size) - | 1991 | crc = csum32 & 0xFFFF; |
1945 | offset); | 1992 | goto out; |
1946 | } | 1993 | } |
1947 | 1994 | ||
1995 | /* old crc16 code */ | ||
1996 | offset = offsetof(struct ext4_group_desc, bg_checksum); | ||
1997 | |||
1998 | crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); | ||
1999 | crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); | ||
2000 | crc = crc16(crc, (__u8 *)gdp, offset); | ||
2001 | offset += sizeof(gdp->bg_checksum); /* skip checksum */ | ||
2002 | /* for checksum of struct ext4_group_desc do the rest...*/ | ||
2003 | if ((sbi->s_es->s_feature_incompat & | ||
2004 | cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) && | ||
2005 | offset < le16_to_cpu(sbi->s_es->s_desc_size)) | ||
2006 | crc = crc16(crc, (__u8 *)gdp + offset, | ||
2007 | le16_to_cpu(sbi->s_es->s_desc_size) - | ||
2008 | offset); | ||
2009 | |||
2010 | out: | ||
1948 | return cpu_to_le16(crc); | 2011 | return cpu_to_le16(crc); |
1949 | } | 2012 | } |
1950 | 2013 | ||
1951 | int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group, | 2014 | int ext4_group_desc_csum_verify(struct super_block *sb, __u32 block_group, |
1952 | struct ext4_group_desc *gdp) | 2015 | struct ext4_group_desc *gdp) |
1953 | { | 2016 | { |
1954 | if ((sbi->s_es->s_feature_ro_compat & | 2017 | if (ext4_has_group_desc_csum(sb) && |
1955 | cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) && | 2018 | (gdp->bg_checksum != ext4_group_desc_csum(EXT4_SB(sb), |
1956 | (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp))) | 2019 | block_group, gdp))) |
1957 | return 0; | 2020 | return 0; |
1958 | 2021 | ||
1959 | return 1; | 2022 | return 1; |
1960 | } | 2023 | } |
1961 | 2024 | ||
2025 | void ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group, | ||
2026 | struct ext4_group_desc *gdp) | ||
2027 | { | ||
2028 | if (!ext4_has_group_desc_csum(sb)) | ||
2029 | return; | ||
2030 | gdp->bg_checksum = ext4_group_desc_csum(EXT4_SB(sb), block_group, gdp); | ||
2031 | } | ||
2032 | |||
1962 | /* Called at mount-time, super-block is locked */ | 2033 | /* Called at mount-time, super-block is locked */ |
1963 | static int ext4_check_descriptors(struct super_block *sb, | 2034 | static int ext4_check_descriptors(struct super_block *sb, |
1964 | ext4_group_t *first_not_zeroed) | 2035 | ext4_group_t *first_not_zeroed) |
@@ -2013,7 +2084,7 @@ static int ext4_check_descriptors(struct super_block *sb, | |||
2013 | return 0; | 2084 | return 0; |
2014 | } | 2085 | } |
2015 | ext4_lock_group(sb, i); | 2086 | ext4_lock_group(sb, i); |
2016 | if (!ext4_group_desc_csum_verify(sbi, i, gdp)) { | 2087 | if (!ext4_group_desc_csum_verify(sb, i, gdp)) { |
2017 | ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " | 2088 | ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " |
2018 | "Checksum for group %u failed (%u!=%u)", | 2089 | "Checksum for group %u failed (%u!=%u)", |
2019 | i, le16_to_cpu(ext4_group_desc_csum(sbi, i, | 2090 | i, le16_to_cpu(ext4_group_desc_csum(sbi, i, |
@@ -2417,6 +2488,23 @@ static ssize_t sbi_ui_store(struct ext4_attr *a, | |||
2417 | return count; | 2488 | return count; |
2418 | } | 2489 | } |
2419 | 2490 | ||
2491 | static ssize_t trigger_test_error(struct ext4_attr *a, | ||
2492 | struct ext4_sb_info *sbi, | ||
2493 | const char *buf, size_t count) | ||
2494 | { | ||
2495 | int len = count; | ||
2496 | |||
2497 | if (!capable(CAP_SYS_ADMIN)) | ||
2498 | return -EPERM; | ||
2499 | |||
2500 | if (len && buf[len-1] == '\n') | ||
2501 | len--; | ||
2502 | |||
2503 | if (len) | ||
2504 | ext4_error(sbi->s_sb, "%.*s", len, buf); | ||
2505 | return count; | ||
2506 | } | ||
2507 | |||
2420 | #define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \ | 2508 | #define EXT4_ATTR_OFFSET(_name,_mode,_show,_store,_elname) \ |
2421 | static struct ext4_attr ext4_attr_##_name = { \ | 2509 | static struct ext4_attr ext4_attr_##_name = { \ |
2422 | .attr = {.name = __stringify(_name), .mode = _mode }, \ | 2510 | .attr = {.name = __stringify(_name), .mode = _mode }, \ |
@@ -2447,6 +2535,7 @@ EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs); | |||
2447 | EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request); | 2535 | EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request); |
2448 | EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); | 2536 | EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); |
2449 | EXT4_RW_ATTR_SBI_UI(max_writeback_mb_bump, s_max_writeback_mb_bump); | 2537 | EXT4_RW_ATTR_SBI_UI(max_writeback_mb_bump, s_max_writeback_mb_bump); |
2538 | EXT4_ATTR(trigger_fs_error, 0200, NULL, trigger_test_error); | ||
2450 | 2539 | ||
2451 | static struct attribute *ext4_attrs[] = { | 2540 | static struct attribute *ext4_attrs[] = { |
2452 | ATTR_LIST(delayed_allocation_blocks), | 2541 | ATTR_LIST(delayed_allocation_blocks), |
@@ -2461,6 +2550,7 @@ static struct attribute *ext4_attrs[] = { | |||
2461 | ATTR_LIST(mb_stream_req), | 2550 | ATTR_LIST(mb_stream_req), |
2462 | ATTR_LIST(mb_group_prealloc), | 2551 | ATTR_LIST(mb_group_prealloc), |
2463 | ATTR_LIST(max_writeback_mb_bump), | 2552 | ATTR_LIST(max_writeback_mb_bump), |
2553 | ATTR_LIST(trigger_fs_error), | ||
2464 | NULL, | 2554 | NULL, |
2465 | }; | 2555 | }; |
2466 | 2556 | ||
@@ -2957,6 +3047,44 @@ static void ext4_destroy_lazyinit_thread(void) | |||
2957 | kthread_stop(ext4_lazyinit_task); | 3047 | kthread_stop(ext4_lazyinit_task); |
2958 | } | 3048 | } |
2959 | 3049 | ||
3050 | static int set_journal_csum_feature_set(struct super_block *sb) | ||
3051 | { | ||
3052 | int ret = 1; | ||
3053 | int compat, incompat; | ||
3054 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
3055 | |||
3056 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
3057 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { | ||
3058 | /* journal checksum v2 */ | ||
3059 | compat = 0; | ||
3060 | incompat = JBD2_FEATURE_INCOMPAT_CSUM_V2; | ||
3061 | } else { | ||
3062 | /* journal checksum v1 */ | ||
3063 | compat = JBD2_FEATURE_COMPAT_CHECKSUM; | ||
3064 | incompat = 0; | ||
3065 | } | ||
3066 | |||
3067 | if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { | ||
3068 | ret = jbd2_journal_set_features(sbi->s_journal, | ||
3069 | compat, 0, | ||
3070 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | | ||
3071 | incompat); | ||
3072 | } else if (test_opt(sb, JOURNAL_CHECKSUM)) { | ||
3073 | ret = jbd2_journal_set_features(sbi->s_journal, | ||
3074 | compat, 0, | ||
3075 | incompat); | ||
3076 | jbd2_journal_clear_features(sbi->s_journal, 0, 0, | ||
3077 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); | ||
3078 | } else { | ||
3079 | jbd2_journal_clear_features(sbi->s_journal, | ||
3080 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, | ||
3081 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | | ||
3082 | JBD2_FEATURE_INCOMPAT_CSUM_V2); | ||
3083 | } | ||
3084 | |||
3085 | return ret; | ||
3086 | } | ||
3087 | |||
2960 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) | 3088 | static int ext4_fill_super(struct super_block *sb, void *data, int silent) |
2961 | { | 3089 | { |
2962 | char *orig_data = kstrdup(data, GFP_KERNEL); | 3090 | char *orig_data = kstrdup(data, GFP_KERNEL); |
@@ -2993,6 +3121,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
2993 | goto out_free_orig; | 3121 | goto out_free_orig; |
2994 | } | 3122 | } |
2995 | sb->s_fs_info = sbi; | 3123 | sb->s_fs_info = sbi; |
3124 | sbi->s_sb = sb; | ||
2996 | sbi->s_mount_opt = 0; | 3125 | sbi->s_mount_opt = 0; |
2997 | sbi->s_resuid = make_kuid(&init_user_ns, EXT4_DEF_RESUID); | 3126 | sbi->s_resuid = make_kuid(&init_user_ns, EXT4_DEF_RESUID); |
2998 | sbi->s_resgid = make_kgid(&init_user_ns, EXT4_DEF_RESGID); | 3127 | sbi->s_resgid = make_kgid(&init_user_ns, EXT4_DEF_RESGID); |
@@ -3032,13 +3161,54 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3032 | * Note: s_es must be initialized as soon as possible because | 3161 | * Note: s_es must be initialized as soon as possible because |
3033 | * some ext4 macro-instructions depend on its value | 3162 | * some ext4 macro-instructions depend on its value |
3034 | */ | 3163 | */ |
3035 | es = (struct ext4_super_block *) (((char *)bh->b_data) + offset); | 3164 | es = (struct ext4_super_block *) (bh->b_data + offset); |
3036 | sbi->s_es = es; | 3165 | sbi->s_es = es; |
3037 | sb->s_magic = le16_to_cpu(es->s_magic); | 3166 | sb->s_magic = le16_to_cpu(es->s_magic); |
3038 | if (sb->s_magic != EXT4_SUPER_MAGIC) | 3167 | if (sb->s_magic != EXT4_SUPER_MAGIC) |
3039 | goto cantfind_ext4; | 3168 | goto cantfind_ext4; |
3040 | sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written); | 3169 | sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written); |
3041 | 3170 | ||
3171 | /* Warn if metadata_csum and gdt_csum are both set. */ | ||
3172 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
3173 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && | ||
3174 | EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) | ||
3175 | ext4_warning(sb, KERN_INFO "metadata_csum and uninit_bg are " | ||
3176 | "redundant flags; please run fsck."); | ||
3177 | |||
3178 | /* Check for a known checksum algorithm */ | ||
3179 | if (!ext4_verify_csum_type(sb, es)) { | ||
3180 | ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with " | ||
3181 | "unknown checksum algorithm."); | ||
3182 | silent = 1; | ||
3183 | goto cantfind_ext4; | ||
3184 | } | ||
3185 | |||
3186 | /* Load the checksum driver */ | ||
3187 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
3188 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) { | ||
3189 | sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0); | ||
3190 | if (IS_ERR(sbi->s_chksum_driver)) { | ||
3191 | ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver."); | ||
3192 | ret = PTR_ERR(sbi->s_chksum_driver); | ||
3193 | sbi->s_chksum_driver = NULL; | ||
3194 | goto failed_mount; | ||
3195 | } | ||
3196 | } | ||
3197 | |||
3198 | /* Check superblock checksum */ | ||
3199 | if (!ext4_superblock_csum_verify(sb, es)) { | ||
3200 | ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with " | ||
3201 | "invalid superblock checksum. Run e2fsck?"); | ||
3202 | silent = 1; | ||
3203 | goto cantfind_ext4; | ||
3204 | } | ||
3205 | |||
3206 | /* Precompute checksum seed for all metadata */ | ||
3207 | if (EXT4_HAS_RO_COMPAT_FEATURE(sb, | ||
3208 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
3209 | sbi->s_csum_seed = ext4_chksum(sbi, ~0, es->s_uuid, | ||
3210 | sizeof(es->s_uuid)); | ||
3211 | |||
3042 | /* Set defaults before we parse the mount options */ | 3212 | /* Set defaults before we parse the mount options */ |
3043 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); | 3213 | def_mount_opts = le32_to_cpu(es->s_default_mount_opts); |
3044 | set_opt(sb, INIT_INODE_TABLE); | 3214 | set_opt(sb, INIT_INODE_TABLE); |
@@ -3200,7 +3370,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3200 | "Can't read superblock on 2nd try"); | 3370 | "Can't read superblock on 2nd try"); |
3201 | goto failed_mount; | 3371 | goto failed_mount; |
3202 | } | 3372 | } |
3203 | es = (struct ext4_super_block *)(((char *)bh->b_data) + offset); | 3373 | es = (struct ext4_super_block *)(bh->b_data + offset); |
3204 | sbi->s_es = es; | 3374 | sbi->s_es = es; |
3205 | if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) { | 3375 | if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) { |
3206 | ext4_msg(sb, KERN_ERR, | 3376 | ext4_msg(sb, KERN_ERR, |
@@ -3392,6 +3562,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3392 | GFP_KERNEL); | 3562 | GFP_KERNEL); |
3393 | if (sbi->s_group_desc == NULL) { | 3563 | if (sbi->s_group_desc == NULL) { |
3394 | ext4_msg(sb, KERN_ERR, "not enough memory"); | 3564 | ext4_msg(sb, KERN_ERR, "not enough memory"); |
3565 | ret = -ENOMEM; | ||
3395 | goto failed_mount; | 3566 | goto failed_mount; |
3396 | } | 3567 | } |
3397 | 3568 | ||
@@ -3449,6 +3620,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3449 | } | 3620 | } |
3450 | if (err) { | 3621 | if (err) { |
3451 | ext4_msg(sb, KERN_ERR, "insufficient memory"); | 3622 | ext4_msg(sb, KERN_ERR, "insufficient memory"); |
3623 | ret = err; | ||
3452 | goto failed_mount3; | 3624 | goto failed_mount3; |
3453 | } | 3625 | } |
3454 | 3626 | ||
@@ -3506,26 +3678,17 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3506 | goto no_journal; | 3678 | goto no_journal; |
3507 | } | 3679 | } |
3508 | 3680 | ||
3509 | if (ext4_blocks_count(es) > 0xffffffffULL && | 3681 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT) && |
3510 | !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0, | 3682 | !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0, |
3511 | JBD2_FEATURE_INCOMPAT_64BIT)) { | 3683 | JBD2_FEATURE_INCOMPAT_64BIT)) { |
3512 | ext4_msg(sb, KERN_ERR, "Failed to set 64-bit journal feature"); | 3684 | ext4_msg(sb, KERN_ERR, "Failed to set 64-bit journal feature"); |
3513 | goto failed_mount_wq; | 3685 | goto failed_mount_wq; |
3514 | } | 3686 | } |
3515 | 3687 | ||
3516 | if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { | 3688 | if (!set_journal_csum_feature_set(sb)) { |
3517 | jbd2_journal_set_features(sbi->s_journal, | 3689 | ext4_msg(sb, KERN_ERR, "Failed to set journal checksum " |
3518 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, | 3690 | "feature set"); |
3519 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); | 3691 | goto failed_mount_wq; |
3520 | } else if (test_opt(sb, JOURNAL_CHECKSUM)) { | ||
3521 | jbd2_journal_set_features(sbi->s_journal, | ||
3522 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, 0); | ||
3523 | jbd2_journal_clear_features(sbi->s_journal, 0, 0, | ||
3524 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); | ||
3525 | } else { | ||
3526 | jbd2_journal_clear_features(sbi->s_journal, | ||
3527 | JBD2_FEATURE_COMPAT_CHECKSUM, 0, | ||
3528 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); | ||
3529 | } | 3692 | } |
3530 | 3693 | ||
3531 | /* We have now updated the journal if required, so we can | 3694 | /* We have now updated the journal if required, so we can |
@@ -3606,7 +3769,8 @@ no_journal: | |||
3606 | goto failed_mount4; | 3769 | goto failed_mount4; |
3607 | } | 3770 | } |
3608 | 3771 | ||
3609 | ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY); | 3772 | if (ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY)) |
3773 | sb->s_flags |= MS_RDONLY; | ||
3610 | 3774 | ||
3611 | /* determine the minimum size of new large inodes, if present */ | 3775 | /* determine the minimum size of new large inodes, if present */ |
3612 | if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { | 3776 | if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { |
@@ -3641,7 +3805,7 @@ no_journal: | |||
3641 | } | 3805 | } |
3642 | 3806 | ||
3643 | ext4_ext_init(sb); | 3807 | ext4_ext_init(sb); |
3644 | err = ext4_mb_init(sb, needs_recovery); | 3808 | err = ext4_mb_init(sb); |
3645 | if (err) { | 3809 | if (err) { |
3646 | ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)", | 3810 | ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)", |
3647 | err); | 3811 | err); |
@@ -3724,6 +3888,8 @@ failed_mount2: | |||
3724 | brelse(sbi->s_group_desc[i]); | 3888 | brelse(sbi->s_group_desc[i]); |
3725 | ext4_kvfree(sbi->s_group_desc); | 3889 | ext4_kvfree(sbi->s_group_desc); |
3726 | failed_mount: | 3890 | failed_mount: |
3891 | if (sbi->s_chksum_driver) | ||
3892 | crypto_free_shash(sbi->s_chksum_driver); | ||
3727 | if (sbi->s_proc) { | 3893 | if (sbi->s_proc) { |
3728 | remove_proc_entry("options", sbi->s_proc); | 3894 | remove_proc_entry("options", sbi->s_proc); |
3729 | remove_proc_entry(sb->s_id, ext4_proc_root); | 3895 | remove_proc_entry(sb->s_id, ext4_proc_root); |
@@ -3847,7 +4013,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb, | |||
3847 | goto out_bdev; | 4013 | goto out_bdev; |
3848 | } | 4014 | } |
3849 | 4015 | ||
3850 | es = (struct ext4_super_block *) (((char *)bh->b_data) + offset); | 4016 | es = (struct ext4_super_block *) (bh->b_data + offset); |
3851 | if ((le16_to_cpu(es->s_magic) != EXT4_SUPER_MAGIC) || | 4017 | if ((le16_to_cpu(es->s_magic) != EXT4_SUPER_MAGIC) || |
3852 | !(le32_to_cpu(es->s_feature_incompat) & | 4018 | !(le32_to_cpu(es->s_feature_incompat) & |
3853 | EXT4_FEATURE_INCOMPAT_JOURNAL_DEV)) { | 4019 | EXT4_FEATURE_INCOMPAT_JOURNAL_DEV)) { |
@@ -4039,6 +4205,7 @@ static int ext4_commit_super(struct super_block *sb, int sync) | |||
4039 | &EXT4_SB(sb)->s_freeinodes_counter)); | 4205 | &EXT4_SB(sb)->s_freeinodes_counter)); |
4040 | sb->s_dirt = 0; | 4206 | sb->s_dirt = 0; |
4041 | BUFFER_TRACE(sbh, "marking dirty"); | 4207 | BUFFER_TRACE(sbh, "marking dirty"); |
4208 | ext4_superblock_csum_set(sb, es); | ||
4042 | mark_buffer_dirty(sbh); | 4209 | mark_buffer_dirty(sbh); |
4043 | if (sync) { | 4210 | if (sync) { |
4044 | error = sync_dirty_buffer(sbh); | 4211 | error = sync_dirty_buffer(sbh); |
@@ -4333,7 +4500,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
4333 | struct ext4_group_desc *gdp = | 4500 | struct ext4_group_desc *gdp = |
4334 | ext4_get_group_desc(sb, g, NULL); | 4501 | ext4_get_group_desc(sb, g, NULL); |
4335 | 4502 | ||
4336 | if (!ext4_group_desc_csum_verify(sbi, g, gdp)) { | 4503 | if (!ext4_group_desc_csum_verify(sb, g, gdp)) { |
4337 | ext4_msg(sb, KERN_ERR, | 4504 | ext4_msg(sb, KERN_ERR, |
4338 | "ext4_remount: Checksum for group %u failed (%u!=%u)", | 4505 | "ext4_remount: Checksum for group %u failed (%u!=%u)", |
4339 | g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)), | 4506 | g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)), |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index e88748e55c0f..e56c9ed7d6e3 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -122,6 +122,58 @@ const struct xattr_handler *ext4_xattr_handlers[] = { | |||
122 | NULL | 122 | NULL |
123 | }; | 123 | }; |
124 | 124 | ||
125 | static __le32 ext4_xattr_block_csum(struct inode *inode, | ||
126 | sector_t block_nr, | ||
127 | struct ext4_xattr_header *hdr) | ||
128 | { | ||
129 | struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); | ||
130 | struct ext4_inode_info *ei = EXT4_I(inode); | ||
131 | __u32 csum, old; | ||
132 | |||
133 | old = hdr->h_checksum; | ||
134 | hdr->h_checksum = 0; | ||
135 | if (le32_to_cpu(hdr->h_refcount) != 1) { | ||
136 | block_nr = cpu_to_le64(block_nr); | ||
137 | csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&block_nr, | ||
138 | sizeof(block_nr)); | ||
139 | } else | ||
140 | csum = ei->i_csum_seed; | ||
141 | csum = ext4_chksum(sbi, csum, (__u8 *)hdr, | ||
142 | EXT4_BLOCK_SIZE(inode->i_sb)); | ||
143 | hdr->h_checksum = old; | ||
144 | return cpu_to_le32(csum); | ||
145 | } | ||
146 | |||
147 | static int ext4_xattr_block_csum_verify(struct inode *inode, | ||
148 | sector_t block_nr, | ||
149 | struct ext4_xattr_header *hdr) | ||
150 | { | ||
151 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
152 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && | ||
153 | (hdr->h_checksum != ext4_xattr_block_csum(inode, block_nr, hdr))) | ||
154 | return 0; | ||
155 | return 1; | ||
156 | } | ||
157 | |||
158 | static void ext4_xattr_block_csum_set(struct inode *inode, | ||
159 | sector_t block_nr, | ||
160 | struct ext4_xattr_header *hdr) | ||
161 | { | ||
162 | if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | ||
163 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | ||
164 | return; | ||
165 | |||
166 | hdr->h_checksum = ext4_xattr_block_csum(inode, block_nr, hdr); | ||
167 | } | ||
168 | |||
169 | static inline int ext4_handle_dirty_xattr_block(handle_t *handle, | ||
170 | struct inode *inode, | ||
171 | struct buffer_head *bh) | ||
172 | { | ||
173 | ext4_xattr_block_csum_set(inode, bh->b_blocknr, BHDR(bh)); | ||
174 | return ext4_handle_dirty_metadata(handle, inode, bh); | ||
175 | } | ||
176 | |||
125 | static inline const struct xattr_handler * | 177 | static inline const struct xattr_handler * |
126 | ext4_xattr_handler(int name_index) | 178 | ext4_xattr_handler(int name_index) |
127 | { | 179 | { |
@@ -156,12 +208,22 @@ ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end) | |||
156 | } | 208 | } |
157 | 209 | ||
158 | static inline int | 210 | static inline int |
159 | ext4_xattr_check_block(struct buffer_head *bh) | 211 | ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh) |
160 | { | 212 | { |
213 | int error; | ||
214 | |||
215 | if (buffer_verified(bh)) | ||
216 | return 0; | ||
217 | |||
161 | if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || | 218 | if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || |
162 | BHDR(bh)->h_blocks != cpu_to_le32(1)) | 219 | BHDR(bh)->h_blocks != cpu_to_le32(1)) |
163 | return -EIO; | 220 | return -EIO; |
164 | return ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size); | 221 | if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh))) |
222 | return -EIO; | ||
223 | error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size); | ||
224 | if (!error) | ||
225 | set_buffer_verified(bh); | ||
226 | return error; | ||
165 | } | 227 | } |
166 | 228 | ||
167 | static inline int | 229 | static inline int |
@@ -224,7 +286,7 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, | |||
224 | goto cleanup; | 286 | goto cleanup; |
225 | ea_bdebug(bh, "b_count=%d, refcount=%d", | 287 | ea_bdebug(bh, "b_count=%d, refcount=%d", |
226 | atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); | 288 | atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); |
227 | if (ext4_xattr_check_block(bh)) { | 289 | if (ext4_xattr_check_block(inode, bh)) { |
228 | bad_block: | 290 | bad_block: |
229 | EXT4_ERROR_INODE(inode, "bad block %llu", | 291 | EXT4_ERROR_INODE(inode, "bad block %llu", |
230 | EXT4_I(inode)->i_file_acl); | 292 | EXT4_I(inode)->i_file_acl); |
@@ -369,7 +431,7 @@ ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) | |||
369 | goto cleanup; | 431 | goto cleanup; |
370 | ea_bdebug(bh, "b_count=%d, refcount=%d", | 432 | ea_bdebug(bh, "b_count=%d, refcount=%d", |
371 | atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); | 433 | atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); |
372 | if (ext4_xattr_check_block(bh)) { | 434 | if (ext4_xattr_check_block(inode, bh)) { |
373 | EXT4_ERROR_INODE(inode, "bad block %llu", | 435 | EXT4_ERROR_INODE(inode, "bad block %llu", |
374 | EXT4_I(inode)->i_file_acl); | 436 | EXT4_I(inode)->i_file_acl); |
375 | error = -EIO; | 437 | error = -EIO; |
@@ -492,7 +554,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, | |||
492 | if (ce) | 554 | if (ce) |
493 | mb_cache_entry_release(ce); | 555 | mb_cache_entry_release(ce); |
494 | unlock_buffer(bh); | 556 | unlock_buffer(bh); |
495 | error = ext4_handle_dirty_metadata(handle, inode, bh); | 557 | error = ext4_handle_dirty_xattr_block(handle, inode, bh); |
496 | if (IS_SYNC(inode)) | 558 | if (IS_SYNC(inode)) |
497 | ext4_handle_sync(handle); | 559 | ext4_handle_sync(handle); |
498 | dquot_free_block(inode, 1); | 560 | dquot_free_block(inode, 1); |
@@ -662,7 +724,7 @@ ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i, | |||
662 | ea_bdebug(bs->bh, "b_count=%d, refcount=%d", | 724 | ea_bdebug(bs->bh, "b_count=%d, refcount=%d", |
663 | atomic_read(&(bs->bh->b_count)), | 725 | atomic_read(&(bs->bh->b_count)), |
664 | le32_to_cpu(BHDR(bs->bh)->h_refcount)); | 726 | le32_to_cpu(BHDR(bs->bh)->h_refcount)); |
665 | if (ext4_xattr_check_block(bs->bh)) { | 727 | if (ext4_xattr_check_block(inode, bs->bh)) { |
666 | EXT4_ERROR_INODE(inode, "bad block %llu", | 728 | EXT4_ERROR_INODE(inode, "bad block %llu", |
667 | EXT4_I(inode)->i_file_acl); | 729 | EXT4_I(inode)->i_file_acl); |
668 | error = -EIO; | 730 | error = -EIO; |
@@ -725,9 +787,9 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
725 | if (error == -EIO) | 787 | if (error == -EIO) |
726 | goto bad_block; | 788 | goto bad_block; |
727 | if (!error) | 789 | if (!error) |
728 | error = ext4_handle_dirty_metadata(handle, | 790 | error = ext4_handle_dirty_xattr_block(handle, |
729 | inode, | 791 | inode, |
730 | bs->bh); | 792 | bs->bh); |
731 | if (error) | 793 | if (error) |
732 | goto cleanup; | 794 | goto cleanup; |
733 | goto inserted; | 795 | goto inserted; |
@@ -796,9 +858,9 @@ inserted: | |||
796 | ea_bdebug(new_bh, "reusing; refcount now=%d", | 858 | ea_bdebug(new_bh, "reusing; refcount now=%d", |
797 | le32_to_cpu(BHDR(new_bh)->h_refcount)); | 859 | le32_to_cpu(BHDR(new_bh)->h_refcount)); |
798 | unlock_buffer(new_bh); | 860 | unlock_buffer(new_bh); |
799 | error = ext4_handle_dirty_metadata(handle, | 861 | error = ext4_handle_dirty_xattr_block(handle, |
800 | inode, | 862 | inode, |
801 | new_bh); | 863 | new_bh); |
802 | if (error) | 864 | if (error) |
803 | goto cleanup_dquot; | 865 | goto cleanup_dquot; |
804 | } | 866 | } |
@@ -855,8 +917,8 @@ getblk_failed: | |||
855 | set_buffer_uptodate(new_bh); | 917 | set_buffer_uptodate(new_bh); |
856 | unlock_buffer(new_bh); | 918 | unlock_buffer(new_bh); |
857 | ext4_xattr_cache_insert(new_bh); | 919 | ext4_xattr_cache_insert(new_bh); |
858 | error = ext4_handle_dirty_metadata(handle, | 920 | error = ext4_handle_dirty_xattr_block(handle, |
859 | inode, new_bh); | 921 | inode, new_bh); |
860 | if (error) | 922 | if (error) |
861 | goto cleanup; | 923 | goto cleanup; |
862 | } | 924 | } |
@@ -1193,7 +1255,7 @@ retry: | |||
1193 | error = -EIO; | 1255 | error = -EIO; |
1194 | if (!bh) | 1256 | if (!bh) |
1195 | goto cleanup; | 1257 | goto cleanup; |
1196 | if (ext4_xattr_check_block(bh)) { | 1258 | if (ext4_xattr_check_block(inode, bh)) { |
1197 | EXT4_ERROR_INODE(inode, "bad block %llu", | 1259 | EXT4_ERROR_INODE(inode, "bad block %llu", |
1198 | EXT4_I(inode)->i_file_acl); | 1260 | EXT4_I(inode)->i_file_acl); |
1199 | error = -EIO; | 1261 | error = -EIO; |
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index 25b7387ff183..91f31ca7d9af 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h | |||
@@ -27,7 +27,9 @@ struct ext4_xattr_header { | |||
27 | __le32 h_refcount; /* reference count */ | 27 | __le32 h_refcount; /* reference count */ |
28 | __le32 h_blocks; /* number of disk blocks used */ | 28 | __le32 h_blocks; /* number of disk blocks used */ |
29 | __le32 h_hash; /* hash value of all attributes */ | 29 | __le32 h_hash; /* hash value of all attributes */ |
30 | __u32 h_reserved[4]; /* zero right now */ | 30 | __le32 h_checksum; /* crc32c(uuid+id+xattrblock) */ |
31 | /* id = inum if refcount=1, blknum otherwise */ | ||
32 | __u32 h_reserved[3]; /* zero right now */ | ||
31 | }; | 33 | }; |
32 | 34 | ||
33 | struct ext4_xattr_ibody_header { | 35 | struct ext4_xattr_ibody_header { |
diff --git a/fs/jbd2/Kconfig b/fs/jbd2/Kconfig index f32f346f4b0a..69a48c2944da 100644 --- a/fs/jbd2/Kconfig +++ b/fs/jbd2/Kconfig | |||
@@ -1,6 +1,8 @@ | |||
1 | config JBD2 | 1 | config JBD2 |
2 | tristate | 2 | tristate |
3 | select CRC32 | 3 | select CRC32 |
4 | select CRYPTO | ||
5 | select CRYPTO_CRC32C | ||
4 | help | 6 | help |
5 | This is a generic journaling layer for block devices that support | 7 | This is a generic journaling layer for block devices that support |
6 | both 32-bit and 64-bit block numbers. It is currently used by | 8 | both 32-bit and 64-bit block numbers. It is currently used by |
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index 840f70f50792..216f4299f65e 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c | |||
@@ -85,6 +85,24 @@ nope: | |||
85 | __brelse(bh); | 85 | __brelse(bh); |
86 | } | 86 | } |
87 | 87 | ||
88 | static void jbd2_commit_block_csum_set(journal_t *j, | ||
89 | struct journal_head *descriptor) | ||
90 | { | ||
91 | struct commit_header *h; | ||
92 | __u32 csum; | ||
93 | |||
94 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
95 | return; | ||
96 | |||
97 | h = (struct commit_header *)(jh2bh(descriptor)->b_data); | ||
98 | h->h_chksum_type = 0; | ||
99 | h->h_chksum_size = 0; | ||
100 | h->h_chksum[0] = 0; | ||
101 | csum = jbd2_chksum(j, j->j_csum_seed, jh2bh(descriptor)->b_data, | ||
102 | j->j_blocksize); | ||
103 | h->h_chksum[0] = cpu_to_be32(csum); | ||
104 | } | ||
105 | |||
88 | /* | 106 | /* |
89 | * Done it all: now submit the commit record. We should have | 107 | * Done it all: now submit the commit record. We should have |
90 | * cleaned up our previous buffers by now, so if we are in abort | 108 | * cleaned up our previous buffers by now, so if we are in abort |
@@ -128,6 +146,7 @@ static int journal_submit_commit_record(journal_t *journal, | |||
128 | tmp->h_chksum_size = JBD2_CRC32_CHKSUM_SIZE; | 146 | tmp->h_chksum_size = JBD2_CRC32_CHKSUM_SIZE; |
129 | tmp->h_chksum[0] = cpu_to_be32(crc32_sum); | 147 | tmp->h_chksum[0] = cpu_to_be32(crc32_sum); |
130 | } | 148 | } |
149 | jbd2_commit_block_csum_set(journal, descriptor); | ||
131 | 150 | ||
132 | JBUFFER_TRACE(descriptor, "submit commit block"); | 151 | JBUFFER_TRACE(descriptor, "submit commit block"); |
133 | lock_buffer(bh); | 152 | lock_buffer(bh); |
@@ -301,6 +320,44 @@ static void write_tag_block(int tag_bytes, journal_block_tag_t *tag, | |||
301 | tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1); | 320 | tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1); |
302 | } | 321 | } |
303 | 322 | ||
323 | static void jbd2_descr_block_csum_set(journal_t *j, | ||
324 | struct journal_head *descriptor) | ||
325 | { | ||
326 | struct jbd2_journal_block_tail *tail; | ||
327 | __u32 csum; | ||
328 | |||
329 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
330 | return; | ||
331 | |||
332 | tail = (struct jbd2_journal_block_tail *) | ||
333 | (jh2bh(descriptor)->b_data + j->j_blocksize - | ||
334 | sizeof(struct jbd2_journal_block_tail)); | ||
335 | tail->t_checksum = 0; | ||
336 | csum = jbd2_chksum(j, j->j_csum_seed, jh2bh(descriptor)->b_data, | ||
337 | j->j_blocksize); | ||
338 | tail->t_checksum = cpu_to_be32(csum); | ||
339 | } | ||
340 | |||
341 | static void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag, | ||
342 | struct buffer_head *bh, __u32 sequence) | ||
343 | { | ||
344 | struct page *page = bh->b_page; | ||
345 | __u8 *addr; | ||
346 | __u32 csum; | ||
347 | |||
348 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
349 | return; | ||
350 | |||
351 | sequence = cpu_to_be32(sequence); | ||
352 | addr = kmap_atomic(page, KM_USER0); | ||
353 | csum = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence, | ||
354 | sizeof(sequence)); | ||
355 | csum = jbd2_chksum(j, csum, addr + offset_in_page(bh->b_data), | ||
356 | bh->b_size); | ||
357 | kunmap_atomic(addr, KM_USER0); | ||
358 | |||
359 | tag->t_checksum = cpu_to_be32(csum); | ||
360 | } | ||
304 | /* | 361 | /* |
305 | * jbd2_journal_commit_transaction | 362 | * jbd2_journal_commit_transaction |
306 | * | 363 | * |
@@ -334,6 +391,10 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
334 | unsigned long first_block; | 391 | unsigned long first_block; |
335 | tid_t first_tid; | 392 | tid_t first_tid; |
336 | int update_tail; | 393 | int update_tail; |
394 | int csum_size = 0; | ||
395 | |||
396 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
397 | csum_size = sizeof(struct jbd2_journal_block_tail); | ||
337 | 398 | ||
338 | /* | 399 | /* |
339 | * First job: lock down the current transaction and wait for | 400 | * First job: lock down the current transaction and wait for |
@@ -627,7 +688,9 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
627 | 688 | ||
628 | tag = (journal_block_tag_t *) tagp; | 689 | tag = (journal_block_tag_t *) tagp; |
629 | write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr); | 690 | write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr); |
630 | tag->t_flags = cpu_to_be32(tag_flag); | 691 | tag->t_flags = cpu_to_be16(tag_flag); |
692 | jbd2_block_tag_csum_set(journal, tag, jh2bh(new_jh), | ||
693 | commit_transaction->t_tid); | ||
631 | tagp += tag_bytes; | 694 | tagp += tag_bytes; |
632 | space_left -= tag_bytes; | 695 | space_left -= tag_bytes; |
633 | 696 | ||
@@ -643,7 +706,7 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
643 | 706 | ||
644 | if (bufs == journal->j_wbufsize || | 707 | if (bufs == journal->j_wbufsize || |
645 | commit_transaction->t_buffers == NULL || | 708 | commit_transaction->t_buffers == NULL || |
646 | space_left < tag_bytes + 16) { | 709 | space_left < tag_bytes + 16 + csum_size) { |
647 | 710 | ||
648 | jbd_debug(4, "JBD2: Submit %d IOs\n", bufs); | 711 | jbd_debug(4, "JBD2: Submit %d IOs\n", bufs); |
649 | 712 | ||
@@ -651,8 +714,9 @@ void jbd2_journal_commit_transaction(journal_t *journal) | |||
651 | submitting the IOs. "tag" still points to | 714 | submitting the IOs. "tag" still points to |
652 | the last tag we set up. */ | 715 | the last tag we set up. */ |
653 | 716 | ||
654 | tag->t_flags |= cpu_to_be32(JBD2_FLAG_LAST_TAG); | 717 | tag->t_flags |= cpu_to_be16(JBD2_FLAG_LAST_TAG); |
655 | 718 | ||
719 | jbd2_descr_block_csum_set(journal, descriptor); | ||
656 | start_journal_io: | 720 | start_journal_io: |
657 | for (i = 0; i < bufs; i++) { | 721 | for (i = 0; i < bufs; i++) { |
658 | struct buffer_head *bh = wbuf[i]; | 722 | struct buffer_head *bh = wbuf[i]; |
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 1afb701622b0..e9a3c4c85594 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -97,6 +97,43 @@ EXPORT_SYMBOL(jbd2_inode_cache); | |||
97 | static void __journal_abort_soft (journal_t *journal, int errno); | 97 | static void __journal_abort_soft (journal_t *journal, int errno); |
98 | static int jbd2_journal_create_slab(size_t slab_size); | 98 | static int jbd2_journal_create_slab(size_t slab_size); |
99 | 99 | ||
100 | /* Checksumming functions */ | ||
101 | int jbd2_verify_csum_type(journal_t *j, journal_superblock_t *sb) | ||
102 | { | ||
103 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
104 | return 1; | ||
105 | |||
106 | return sb->s_checksum_type == JBD2_CRC32C_CHKSUM; | ||
107 | } | ||
108 | |||
109 | static __u32 jbd2_superblock_csum(journal_t *j, journal_superblock_t *sb) | ||
110 | { | ||
111 | __u32 csum, old_csum; | ||
112 | |||
113 | old_csum = sb->s_checksum; | ||
114 | sb->s_checksum = 0; | ||
115 | csum = jbd2_chksum(j, ~0, (char *)sb, sizeof(journal_superblock_t)); | ||
116 | sb->s_checksum = old_csum; | ||
117 | |||
118 | return cpu_to_be32(csum); | ||
119 | } | ||
120 | |||
121 | int jbd2_superblock_csum_verify(journal_t *j, journal_superblock_t *sb) | ||
122 | { | ||
123 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
124 | return 1; | ||
125 | |||
126 | return sb->s_checksum == jbd2_superblock_csum(j, sb); | ||
127 | } | ||
128 | |||
129 | void jbd2_superblock_csum_set(journal_t *j, journal_superblock_t *sb) | ||
130 | { | ||
131 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
132 | return; | ||
133 | |||
134 | sb->s_checksum = jbd2_superblock_csum(j, sb); | ||
135 | } | ||
136 | |||
100 | /* | 137 | /* |
101 | * Helper function used to manage commit timeouts | 138 | * Helper function used to manage commit timeouts |
102 | */ | 139 | */ |
@@ -1348,6 +1385,7 @@ static void jbd2_journal_update_sb_errno(journal_t *journal) | |||
1348 | jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", | 1385 | jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", |
1349 | journal->j_errno); | 1386 | journal->j_errno); |
1350 | sb->s_errno = cpu_to_be32(journal->j_errno); | 1387 | sb->s_errno = cpu_to_be32(journal->j_errno); |
1388 | jbd2_superblock_csum_set(journal, sb); | ||
1351 | read_unlock(&journal->j_state_lock); | 1389 | read_unlock(&journal->j_state_lock); |
1352 | 1390 | ||
1353 | jbd2_write_superblock(journal, WRITE_SYNC); | 1391 | jbd2_write_superblock(journal, WRITE_SYNC); |
@@ -1376,6 +1414,9 @@ static int journal_get_superblock(journal_t *journal) | |||
1376 | } | 1414 | } |
1377 | } | 1415 | } |
1378 | 1416 | ||
1417 | if (buffer_verified(bh)) | ||
1418 | return 0; | ||
1419 | |||
1379 | sb = journal->j_superblock; | 1420 | sb = journal->j_superblock; |
1380 | 1421 | ||
1381 | err = -EINVAL; | 1422 | err = -EINVAL; |
@@ -1413,6 +1454,43 @@ static int journal_get_superblock(journal_t *journal) | |||
1413 | goto out; | 1454 | goto out; |
1414 | } | 1455 | } |
1415 | 1456 | ||
1457 | if (JBD2_HAS_COMPAT_FEATURE(journal, JBD2_FEATURE_COMPAT_CHECKSUM) && | ||
1458 | JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) { | ||
1459 | /* Can't have checksum v1 and v2 on at the same time! */ | ||
1460 | printk(KERN_ERR "JBD: Can't enable checksumming v1 and v2 " | ||
1461 | "at the same time!\n"); | ||
1462 | goto out; | ||
1463 | } | ||
1464 | |||
1465 | if (!jbd2_verify_csum_type(journal, sb)) { | ||
1466 | printk(KERN_ERR "JBD: Unknown checksum type\n"); | ||
1467 | goto out; | ||
1468 | } | ||
1469 | |||
1470 | /* Load the checksum driver */ | ||
1471 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) { | ||
1472 | journal->j_chksum_driver = crypto_alloc_shash("crc32c", 0, 0); | ||
1473 | if (IS_ERR(journal->j_chksum_driver)) { | ||
1474 | printk(KERN_ERR "JBD: Cannot load crc32c driver.\n"); | ||
1475 | err = PTR_ERR(journal->j_chksum_driver); | ||
1476 | journal->j_chksum_driver = NULL; | ||
1477 | goto out; | ||
1478 | } | ||
1479 | } | ||
1480 | |||
1481 | /* Check superblock checksum */ | ||
1482 | if (!jbd2_superblock_csum_verify(journal, sb)) { | ||
1483 | printk(KERN_ERR "JBD: journal checksum error\n"); | ||
1484 | goto out; | ||
1485 | } | ||
1486 | |||
1487 | /* Precompute checksum seed for all metadata */ | ||
1488 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
1489 | journal->j_csum_seed = jbd2_chksum(journal, ~0, sb->s_uuid, | ||
1490 | sizeof(sb->s_uuid)); | ||
1491 | |||
1492 | set_buffer_verified(bh); | ||
1493 | |||
1416 | return 0; | 1494 | return 0; |
1417 | 1495 | ||
1418 | out: | 1496 | out: |
@@ -1564,6 +1642,8 @@ int jbd2_journal_destroy(journal_t *journal) | |||
1564 | iput(journal->j_inode); | 1642 | iput(journal->j_inode); |
1565 | if (journal->j_revoke) | 1643 | if (journal->j_revoke) |
1566 | jbd2_journal_destroy_revoke(journal); | 1644 | jbd2_journal_destroy_revoke(journal); |
1645 | if (journal->j_chksum_driver) | ||
1646 | crypto_free_shash(journal->j_chksum_driver); | ||
1567 | kfree(journal->j_wbuf); | 1647 | kfree(journal->j_wbuf); |
1568 | kfree(journal); | 1648 | kfree(journal); |
1569 | 1649 | ||
@@ -1653,6 +1733,10 @@ int jbd2_journal_check_available_features (journal_t *journal, unsigned long com | |||
1653 | int jbd2_journal_set_features (journal_t *journal, unsigned long compat, | 1733 | int jbd2_journal_set_features (journal_t *journal, unsigned long compat, |
1654 | unsigned long ro, unsigned long incompat) | 1734 | unsigned long ro, unsigned long incompat) |
1655 | { | 1735 | { |
1736 | #define INCOMPAT_FEATURE_ON(f) \ | ||
1737 | ((incompat & (f)) && !(sb->s_feature_incompat & cpu_to_be32(f))) | ||
1738 | #define COMPAT_FEATURE_ON(f) \ | ||
1739 | ((compat & (f)) && !(sb->s_feature_compat & cpu_to_be32(f))) | ||
1656 | journal_superblock_t *sb; | 1740 | journal_superblock_t *sb; |
1657 | 1741 | ||
1658 | if (jbd2_journal_check_used_features(journal, compat, ro, incompat)) | 1742 | if (jbd2_journal_check_used_features(journal, compat, ro, incompat)) |
@@ -1661,16 +1745,54 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat, | |||
1661 | if (!jbd2_journal_check_available_features(journal, compat, ro, incompat)) | 1745 | if (!jbd2_journal_check_available_features(journal, compat, ro, incompat)) |
1662 | return 0; | 1746 | return 0; |
1663 | 1747 | ||
1748 | /* Asking for checksumming v2 and v1? Only give them v2. */ | ||
1749 | if (incompat & JBD2_FEATURE_INCOMPAT_CSUM_V2 && | ||
1750 | compat & JBD2_FEATURE_COMPAT_CHECKSUM) | ||
1751 | compat &= ~JBD2_FEATURE_COMPAT_CHECKSUM; | ||
1752 | |||
1664 | jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n", | 1753 | jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n", |
1665 | compat, ro, incompat); | 1754 | compat, ro, incompat); |
1666 | 1755 | ||
1667 | sb = journal->j_superblock; | 1756 | sb = journal->j_superblock; |
1668 | 1757 | ||
1758 | /* If enabling v2 checksums, update superblock */ | ||
1759 | if (INCOMPAT_FEATURE_ON(JBD2_FEATURE_INCOMPAT_CSUM_V2)) { | ||
1760 | sb->s_checksum_type = JBD2_CRC32C_CHKSUM; | ||
1761 | sb->s_feature_compat &= | ||
1762 | ~cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM); | ||
1763 | |||
1764 | /* Load the checksum driver */ | ||
1765 | if (journal->j_chksum_driver == NULL) { | ||
1766 | journal->j_chksum_driver = crypto_alloc_shash("crc32c", | ||
1767 | 0, 0); | ||
1768 | if (IS_ERR(journal->j_chksum_driver)) { | ||
1769 | printk(KERN_ERR "JBD: Cannot load crc32c " | ||
1770 | "driver.\n"); | ||
1771 | journal->j_chksum_driver = NULL; | ||
1772 | return 0; | ||
1773 | } | ||
1774 | } | ||
1775 | |||
1776 | /* Precompute checksum seed for all metadata */ | ||
1777 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, | ||
1778 | JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
1779 | journal->j_csum_seed = jbd2_chksum(journal, ~0, | ||
1780 | sb->s_uuid, | ||
1781 | sizeof(sb->s_uuid)); | ||
1782 | } | ||
1783 | |||
1784 | /* If enabling v1 checksums, downgrade superblock */ | ||
1785 | if (COMPAT_FEATURE_ON(JBD2_FEATURE_COMPAT_CHECKSUM)) | ||
1786 | sb->s_feature_incompat &= | ||
1787 | ~cpu_to_be32(JBD2_FEATURE_INCOMPAT_CSUM_V2); | ||
1788 | |||
1669 | sb->s_feature_compat |= cpu_to_be32(compat); | 1789 | sb->s_feature_compat |= cpu_to_be32(compat); |
1670 | sb->s_feature_ro_compat |= cpu_to_be32(ro); | 1790 | sb->s_feature_ro_compat |= cpu_to_be32(ro); |
1671 | sb->s_feature_incompat |= cpu_to_be32(incompat); | 1791 | sb->s_feature_incompat |= cpu_to_be32(incompat); |
1672 | 1792 | ||
1673 | return 1; | 1793 | return 1; |
1794 | #undef COMPAT_FEATURE_ON | ||
1795 | #undef INCOMPAT_FEATURE_ON | ||
1674 | } | 1796 | } |
1675 | 1797 | ||
1676 | /* | 1798 | /* |
@@ -1975,10 +2097,16 @@ int jbd2_journal_blocks_per_page(struct inode *inode) | |||
1975 | */ | 2097 | */ |
1976 | size_t journal_tag_bytes(journal_t *journal) | 2098 | size_t journal_tag_bytes(journal_t *journal) |
1977 | { | 2099 | { |
2100 | journal_block_tag_t tag; | ||
2101 | size_t x = 0; | ||
2102 | |||
2103 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
2104 | x += sizeof(tag.t_checksum); | ||
2105 | |||
1978 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) | 2106 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) |
1979 | return JBD2_TAG_SIZE64; | 2107 | return x + JBD2_TAG_SIZE64; |
1980 | else | 2108 | else |
1981 | return JBD2_TAG_SIZE32; | 2109 | return x + JBD2_TAG_SIZE32; |
1982 | } | 2110 | } |
1983 | 2111 | ||
1984 | /* | 2112 | /* |
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index c1a03354a22f..0131e4362534 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c | |||
@@ -174,6 +174,25 @@ static int jread(struct buffer_head **bhp, journal_t *journal, | |||
174 | return 0; | 174 | return 0; |
175 | } | 175 | } |
176 | 176 | ||
177 | static int jbd2_descr_block_csum_verify(journal_t *j, | ||
178 | void *buf) | ||
179 | { | ||
180 | struct jbd2_journal_block_tail *tail; | ||
181 | __u32 provided, calculated; | ||
182 | |||
183 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
184 | return 1; | ||
185 | |||
186 | tail = (struct jbd2_journal_block_tail *)(buf + j->j_blocksize - | ||
187 | sizeof(struct jbd2_journal_block_tail)); | ||
188 | provided = tail->t_checksum; | ||
189 | tail->t_checksum = 0; | ||
190 | calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); | ||
191 | tail->t_checksum = provided; | ||
192 | |||
193 | provided = be32_to_cpu(provided); | ||
194 | return provided == calculated; | ||
195 | } | ||
177 | 196 | ||
178 | /* | 197 | /* |
179 | * Count the number of in-use tags in a journal descriptor block. | 198 | * Count the number of in-use tags in a journal descriptor block. |
@@ -186,6 +205,9 @@ static int count_tags(journal_t *journal, struct buffer_head *bh) | |||
186 | int nr = 0, size = journal->j_blocksize; | 205 | int nr = 0, size = journal->j_blocksize; |
187 | int tag_bytes = journal_tag_bytes(journal); | 206 | int tag_bytes = journal_tag_bytes(journal); |
188 | 207 | ||
208 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
209 | size -= sizeof(struct jbd2_journal_block_tail); | ||
210 | |||
189 | tagp = &bh->b_data[sizeof(journal_header_t)]; | 211 | tagp = &bh->b_data[sizeof(journal_header_t)]; |
190 | 212 | ||
191 | while ((tagp - bh->b_data + tag_bytes) <= size) { | 213 | while ((tagp - bh->b_data + tag_bytes) <= size) { |
@@ -193,10 +215,10 @@ static int count_tags(journal_t *journal, struct buffer_head *bh) | |||
193 | 215 | ||
194 | nr++; | 216 | nr++; |
195 | tagp += tag_bytes; | 217 | tagp += tag_bytes; |
196 | if (!(tag->t_flags & cpu_to_be32(JBD2_FLAG_SAME_UUID))) | 218 | if (!(tag->t_flags & cpu_to_be16(JBD2_FLAG_SAME_UUID))) |
197 | tagp += 16; | 219 | tagp += 16; |
198 | 220 | ||
199 | if (tag->t_flags & cpu_to_be32(JBD2_FLAG_LAST_TAG)) | 221 | if (tag->t_flags & cpu_to_be16(JBD2_FLAG_LAST_TAG)) |
200 | break; | 222 | break; |
201 | } | 223 | } |
202 | 224 | ||
@@ -353,6 +375,41 @@ static int calc_chksums(journal_t *journal, struct buffer_head *bh, | |||
353 | return 0; | 375 | return 0; |
354 | } | 376 | } |
355 | 377 | ||
378 | static int jbd2_commit_block_csum_verify(journal_t *j, void *buf) | ||
379 | { | ||
380 | struct commit_header *h; | ||
381 | __u32 provided, calculated; | ||
382 | |||
383 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
384 | return 1; | ||
385 | |||
386 | h = buf; | ||
387 | provided = h->h_chksum[0]; | ||
388 | h->h_chksum[0] = 0; | ||
389 | calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); | ||
390 | h->h_chksum[0] = provided; | ||
391 | |||
392 | provided = be32_to_cpu(provided); | ||
393 | return provided == calculated; | ||
394 | } | ||
395 | |||
396 | static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag, | ||
397 | void *buf, __u32 sequence) | ||
398 | { | ||
399 | __u32 provided, calculated; | ||
400 | |||
401 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
402 | return 1; | ||
403 | |||
404 | sequence = cpu_to_be32(sequence); | ||
405 | calculated = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&sequence, | ||
406 | sizeof(sequence)); | ||
407 | calculated = jbd2_chksum(j, calculated, buf, j->j_blocksize); | ||
408 | provided = be32_to_cpu(tag->t_checksum); | ||
409 | |||
410 | return provided == cpu_to_be32(calculated); | ||
411 | } | ||
412 | |||
356 | static int do_one_pass(journal_t *journal, | 413 | static int do_one_pass(journal_t *journal, |
357 | struct recovery_info *info, enum passtype pass) | 414 | struct recovery_info *info, enum passtype pass) |
358 | { | 415 | { |
@@ -366,6 +423,7 @@ static int do_one_pass(journal_t *journal, | |||
366 | int blocktype; | 423 | int blocktype; |
367 | int tag_bytes = journal_tag_bytes(journal); | 424 | int tag_bytes = journal_tag_bytes(journal); |
368 | __u32 crc32_sum = ~0; /* Transactional Checksums */ | 425 | __u32 crc32_sum = ~0; /* Transactional Checksums */ |
426 | int descr_csum_size = 0; | ||
369 | 427 | ||
370 | /* | 428 | /* |
371 | * First thing is to establish what we expect to find in the log | 429 | * First thing is to establish what we expect to find in the log |
@@ -451,6 +509,18 @@ static int do_one_pass(journal_t *journal, | |||
451 | 509 | ||
452 | switch(blocktype) { | 510 | switch(blocktype) { |
453 | case JBD2_DESCRIPTOR_BLOCK: | 511 | case JBD2_DESCRIPTOR_BLOCK: |
512 | /* Verify checksum first */ | ||
513 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, | ||
514 | JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
515 | descr_csum_size = | ||
516 | sizeof(struct jbd2_journal_block_tail); | ||
517 | if (descr_csum_size > 0 && | ||
518 | !jbd2_descr_block_csum_verify(journal, | ||
519 | bh->b_data)) { | ||
520 | err = -EIO; | ||
521 | goto failed; | ||
522 | } | ||
523 | |||
454 | /* If it is a valid descriptor block, replay it | 524 | /* If it is a valid descriptor block, replay it |
455 | * in pass REPLAY; if journal_checksums enabled, then | 525 | * in pass REPLAY; if journal_checksums enabled, then |
456 | * calculate checksums in PASS_SCAN, otherwise, | 526 | * calculate checksums in PASS_SCAN, otherwise, |
@@ -481,11 +551,11 @@ static int do_one_pass(journal_t *journal, | |||
481 | 551 | ||
482 | tagp = &bh->b_data[sizeof(journal_header_t)]; | 552 | tagp = &bh->b_data[sizeof(journal_header_t)]; |
483 | while ((tagp - bh->b_data + tag_bytes) | 553 | while ((tagp - bh->b_data + tag_bytes) |
484 | <= journal->j_blocksize) { | 554 | <= journal->j_blocksize - descr_csum_size) { |
485 | unsigned long io_block; | 555 | unsigned long io_block; |
486 | 556 | ||
487 | tag = (journal_block_tag_t *) tagp; | 557 | tag = (journal_block_tag_t *) tagp; |
488 | flags = be32_to_cpu(tag->t_flags); | 558 | flags = be16_to_cpu(tag->t_flags); |
489 | 559 | ||
490 | io_block = next_log_block++; | 560 | io_block = next_log_block++; |
491 | wrap(journal, next_log_block); | 561 | wrap(journal, next_log_block); |
@@ -516,6 +586,19 @@ static int do_one_pass(journal_t *journal, | |||
516 | goto skip_write; | 586 | goto skip_write; |
517 | } | 587 | } |
518 | 588 | ||
589 | /* Look for block corruption */ | ||
590 | if (!jbd2_block_tag_csum_verify( | ||
591 | journal, tag, obh->b_data, | ||
592 | be32_to_cpu(tmp->h_sequence))) { | ||
593 | brelse(obh); | ||
594 | success = -EIO; | ||
595 | printk(KERN_ERR "JBD: Invalid " | ||
596 | "checksum recovering " | ||
597 | "block %llu in log\n", | ||
598 | blocknr); | ||
599 | continue; | ||
600 | } | ||
601 | |||
519 | /* Find a buffer for the new | 602 | /* Find a buffer for the new |
520 | * data being restored */ | 603 | * data being restored */ |
521 | nbh = __getblk(journal->j_fs_dev, | 604 | nbh = __getblk(journal->j_fs_dev, |
@@ -650,6 +733,19 @@ static int do_one_pass(journal_t *journal, | |||
650 | } | 733 | } |
651 | crc32_sum = ~0; | 734 | crc32_sum = ~0; |
652 | } | 735 | } |
736 | if (pass == PASS_SCAN && | ||
737 | !jbd2_commit_block_csum_verify(journal, | ||
738 | bh->b_data)) { | ||
739 | info->end_transaction = next_commit_ID; | ||
740 | |||
741 | if (!JBD2_HAS_INCOMPAT_FEATURE(journal, | ||
742 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) { | ||
743 | journal->j_failed_commit = | ||
744 | next_commit_ID; | ||
745 | brelse(bh); | ||
746 | break; | ||
747 | } | ||
748 | } | ||
653 | brelse(bh); | 749 | brelse(bh); |
654 | next_commit_ID++; | 750 | next_commit_ID++; |
655 | continue; | 751 | continue; |
@@ -706,6 +802,25 @@ static int do_one_pass(journal_t *journal, | |||
706 | return err; | 802 | return err; |
707 | } | 803 | } |
708 | 804 | ||
805 | static int jbd2_revoke_block_csum_verify(journal_t *j, | ||
806 | void *buf) | ||
807 | { | ||
808 | struct jbd2_journal_revoke_tail *tail; | ||
809 | __u32 provided, calculated; | ||
810 | |||
811 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
812 | return 1; | ||
813 | |||
814 | tail = (struct jbd2_journal_revoke_tail *)(buf + j->j_blocksize - | ||
815 | sizeof(struct jbd2_journal_revoke_tail)); | ||
816 | provided = tail->r_checksum; | ||
817 | tail->r_checksum = 0; | ||
818 | calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); | ||
819 | tail->r_checksum = provided; | ||
820 | |||
821 | provided = be32_to_cpu(provided); | ||
822 | return provided == calculated; | ||
823 | } | ||
709 | 824 | ||
710 | /* Scan a revoke record, marking all blocks mentioned as revoked. */ | 825 | /* Scan a revoke record, marking all blocks mentioned as revoked. */ |
711 | 826 | ||
@@ -720,6 +835,9 @@ static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, | |||
720 | offset = sizeof(jbd2_journal_revoke_header_t); | 835 | offset = sizeof(jbd2_journal_revoke_header_t); |
721 | max = be32_to_cpu(header->r_count); | 836 | max = be32_to_cpu(header->r_count); |
722 | 837 | ||
838 | if (!jbd2_revoke_block_csum_verify(journal, header)) | ||
839 | return -EINVAL; | ||
840 | |||
723 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) | 841 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) |
724 | record_len = 8; | 842 | record_len = 8; |
725 | 843 | ||
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 6973705d6a3d..f30b80b4ce8b 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c | |||
@@ -578,6 +578,7 @@ static void write_one_revoke_record(journal_t *journal, | |||
578 | struct jbd2_revoke_record_s *record, | 578 | struct jbd2_revoke_record_s *record, |
579 | int write_op) | 579 | int write_op) |
580 | { | 580 | { |
581 | int csum_size = 0; | ||
581 | struct journal_head *descriptor; | 582 | struct journal_head *descriptor; |
582 | int offset; | 583 | int offset; |
583 | journal_header_t *header; | 584 | journal_header_t *header; |
@@ -592,9 +593,13 @@ static void write_one_revoke_record(journal_t *journal, | |||
592 | descriptor = *descriptorp; | 593 | descriptor = *descriptorp; |
593 | offset = *offsetp; | 594 | offset = *offsetp; |
594 | 595 | ||
596 | /* Do we need to leave space at the end for a checksum? */ | ||
597 | if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
598 | csum_size = sizeof(struct jbd2_journal_revoke_tail); | ||
599 | |||
595 | /* Make sure we have a descriptor with space left for the record */ | 600 | /* Make sure we have a descriptor with space left for the record */ |
596 | if (descriptor) { | 601 | if (descriptor) { |
597 | if (offset == journal->j_blocksize) { | 602 | if (offset >= journal->j_blocksize - csum_size) { |
598 | flush_descriptor(journal, descriptor, offset, write_op); | 603 | flush_descriptor(journal, descriptor, offset, write_op); |
599 | descriptor = NULL; | 604 | descriptor = NULL; |
600 | } | 605 | } |
@@ -631,6 +636,24 @@ static void write_one_revoke_record(journal_t *journal, | |||
631 | *offsetp = offset; | 636 | *offsetp = offset; |
632 | } | 637 | } |
633 | 638 | ||
639 | static void jbd2_revoke_csum_set(journal_t *j, | ||
640 | struct journal_head *descriptor) | ||
641 | { | ||
642 | struct jbd2_journal_revoke_tail *tail; | ||
643 | __u32 csum; | ||
644 | |||
645 | if (!JBD2_HAS_INCOMPAT_FEATURE(j, JBD2_FEATURE_INCOMPAT_CSUM_V2)) | ||
646 | return; | ||
647 | |||
648 | tail = (struct jbd2_journal_revoke_tail *) | ||
649 | (jh2bh(descriptor)->b_data + j->j_blocksize - | ||
650 | sizeof(struct jbd2_journal_revoke_tail)); | ||
651 | tail->r_checksum = 0; | ||
652 | csum = jbd2_chksum(j, j->j_csum_seed, jh2bh(descriptor)->b_data, | ||
653 | j->j_blocksize); | ||
654 | tail->r_checksum = cpu_to_be32(csum); | ||
655 | } | ||
656 | |||
634 | /* | 657 | /* |
635 | * Flush a revoke descriptor out to the journal. If we are aborting, | 658 | * Flush a revoke descriptor out to the journal. If we are aborting, |
636 | * this is a noop; otherwise we are generating a buffer which needs to | 659 | * this is a noop; otherwise we are generating a buffer which needs to |
@@ -652,6 +675,8 @@ static void flush_descriptor(journal_t *journal, | |||
652 | 675 | ||
653 | header = (jbd2_journal_revoke_header_t *) jh2bh(descriptor)->b_data; | 676 | header = (jbd2_journal_revoke_header_t *) jh2bh(descriptor)->b_data; |
654 | header->r_count = cpu_to_be32(offset); | 677 | header->r_count = cpu_to_be32(offset); |
678 | jbd2_revoke_csum_set(journal, descriptor); | ||
679 | |||
655 | set_buffer_jwrite(bh); | 680 | set_buffer_jwrite(bh); |
656 | BUFFER_TRACE(bh, "write"); | 681 | BUFFER_TRACE(bh, "write"); |
657 | set_buffer_dirty(bh); | 682 | set_buffer_dirty(bh); |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index ddcd3549c6c2..fb1ab9533b67 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -162,8 +162,8 @@ static int start_this_handle(journal_t *journal, handle_t *handle, | |||
162 | 162 | ||
163 | alloc_transaction: | 163 | alloc_transaction: |
164 | if (!journal->j_running_transaction) { | 164 | if (!journal->j_running_transaction) { |
165 | new_transaction = kmem_cache_alloc(transaction_cache, | 165 | new_transaction = kmem_cache_zalloc(transaction_cache, |
166 | gfp_mask | __GFP_ZERO); | 166 | gfp_mask); |
167 | if (!new_transaction) { | 167 | if (!new_transaction) { |
168 | /* | 168 | /* |
169 | * If __GFP_FS is not present, then we may be | 169 | * If __GFP_FS is not present, then we may be |
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index 912c30a8ddb1..f334c7fab967 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <linux/timer.h> | 32 | #include <linux/timer.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <crypto/hash.h> | ||
34 | #endif | 35 | #endif |
35 | 36 | ||
36 | #define journal_oom_retry 1 | 37 | #define journal_oom_retry 1 |
@@ -147,12 +148,24 @@ typedef struct journal_header_s | |||
147 | #define JBD2_CRC32_CHKSUM 1 | 148 | #define JBD2_CRC32_CHKSUM 1 |
148 | #define JBD2_MD5_CHKSUM 2 | 149 | #define JBD2_MD5_CHKSUM 2 |
149 | #define JBD2_SHA1_CHKSUM 3 | 150 | #define JBD2_SHA1_CHKSUM 3 |
151 | #define JBD2_CRC32C_CHKSUM 4 | ||
150 | 152 | ||
151 | #define JBD2_CRC32_CHKSUM_SIZE 4 | 153 | #define JBD2_CRC32_CHKSUM_SIZE 4 |
152 | 154 | ||
153 | #define JBD2_CHECKSUM_BYTES (32 / sizeof(u32)) | 155 | #define JBD2_CHECKSUM_BYTES (32 / sizeof(u32)) |
154 | /* | 156 | /* |
155 | * Commit block header for storing transactional checksums: | 157 | * Commit block header for storing transactional checksums: |
158 | * | ||
159 | * NOTE: If FEATURE_COMPAT_CHECKSUM (checksum v1) is set, the h_chksum* | ||
160 | * fields are used to store a checksum of the descriptor and data blocks. | ||
161 | * | ||
162 | * If FEATURE_INCOMPAT_CSUM_V2 (checksum v2) is set, then the h_chksum | ||
163 | * field is used to store crc32c(uuid+commit_block). Each journal metadata | ||
164 | * block gets its own checksum, and data block checksums are stored in | ||
165 | * journal_block_tag (in the descriptor). The other h_chksum* fields are | ||
166 | * not used. | ||
167 | * | ||
168 | * Checksum v1 and v2 are mutually exclusive features. | ||
156 | */ | 169 | */ |
157 | struct commit_header { | 170 | struct commit_header { |
158 | __be32 h_magic; | 171 | __be32 h_magic; |
@@ -175,13 +188,19 @@ struct commit_header { | |||
175 | typedef struct journal_block_tag_s | 188 | typedef struct journal_block_tag_s |
176 | { | 189 | { |
177 | __be32 t_blocknr; /* The on-disk block number */ | 190 | __be32 t_blocknr; /* The on-disk block number */ |
178 | __be32 t_flags; /* See below */ | 191 | __be16 t_checksum; /* truncated crc32c(uuid+seq+block) */ |
192 | __be16 t_flags; /* See below */ | ||
179 | __be32 t_blocknr_high; /* most-significant high 32bits. */ | 193 | __be32 t_blocknr_high; /* most-significant high 32bits. */ |
180 | } journal_block_tag_t; | 194 | } journal_block_tag_t; |
181 | 195 | ||
182 | #define JBD2_TAG_SIZE32 (offsetof(journal_block_tag_t, t_blocknr_high)) | 196 | #define JBD2_TAG_SIZE32 (offsetof(journal_block_tag_t, t_blocknr_high)) |
183 | #define JBD2_TAG_SIZE64 (sizeof(journal_block_tag_t)) | 197 | #define JBD2_TAG_SIZE64 (sizeof(journal_block_tag_t)) |
184 | 198 | ||
199 | /* Tail of descriptor block, for checksumming */ | ||
200 | struct jbd2_journal_block_tail { | ||
201 | __be32 t_checksum; /* crc32c(uuid+descr_block) */ | ||
202 | }; | ||
203 | |||
185 | /* | 204 | /* |
186 | * The revoke descriptor: used on disk to describe a series of blocks to | 205 | * The revoke descriptor: used on disk to describe a series of blocks to |
187 | * be revoked from the log | 206 | * be revoked from the log |
@@ -192,6 +211,10 @@ typedef struct jbd2_journal_revoke_header_s | |||
192 | __be32 r_count; /* Count of bytes used in the block */ | 211 | __be32 r_count; /* Count of bytes used in the block */ |
193 | } jbd2_journal_revoke_header_t; | 212 | } jbd2_journal_revoke_header_t; |
194 | 213 | ||
214 | /* Tail of revoke block, for checksumming */ | ||
215 | struct jbd2_journal_revoke_tail { | ||
216 | __be32 r_checksum; /* crc32c(uuid+revoke_block) */ | ||
217 | }; | ||
195 | 218 | ||
196 | /* Definitions for the journal tag flags word: */ | 219 | /* Definitions for the journal tag flags word: */ |
197 | #define JBD2_FLAG_ESCAPE 1 /* on-disk block is escaped */ | 220 | #define JBD2_FLAG_ESCAPE 1 /* on-disk block is escaped */ |
@@ -241,7 +264,10 @@ typedef struct journal_superblock_s | |||
241 | __be32 s_max_trans_data; /* Limit of data blocks per trans. */ | 264 | __be32 s_max_trans_data; /* Limit of data blocks per trans. */ |
242 | 265 | ||
243 | /* 0x0050 */ | 266 | /* 0x0050 */ |
244 | __u32 s_padding[44]; | 267 | __u8 s_checksum_type; /* checksum type */ |
268 | __u8 s_padding2[3]; | ||
269 | __u32 s_padding[42]; | ||
270 | __be32 s_checksum; /* crc32c(superblock) */ | ||
245 | 271 | ||
246 | /* 0x0100 */ | 272 | /* 0x0100 */ |
247 | __u8 s_users[16*48]; /* ids of all fs'es sharing the log */ | 273 | __u8 s_users[16*48]; /* ids of all fs'es sharing the log */ |
@@ -263,13 +289,15 @@ typedef struct journal_superblock_s | |||
263 | #define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001 | 289 | #define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001 |
264 | #define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002 | 290 | #define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002 |
265 | #define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004 | 291 | #define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004 |
292 | #define JBD2_FEATURE_INCOMPAT_CSUM_V2 0x00000008 | ||
266 | 293 | ||
267 | /* Features known to this kernel version: */ | 294 | /* Features known to this kernel version: */ |
268 | #define JBD2_KNOWN_COMPAT_FEATURES JBD2_FEATURE_COMPAT_CHECKSUM | 295 | #define JBD2_KNOWN_COMPAT_FEATURES JBD2_FEATURE_COMPAT_CHECKSUM |
269 | #define JBD2_KNOWN_ROCOMPAT_FEATURES 0 | 296 | #define JBD2_KNOWN_ROCOMPAT_FEATURES 0 |
270 | #define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE | \ | 297 | #define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE | \ |
271 | JBD2_FEATURE_INCOMPAT_64BIT | \ | 298 | JBD2_FEATURE_INCOMPAT_64BIT | \ |
272 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT) | 299 | JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | \ |
300 | JBD2_FEATURE_INCOMPAT_CSUM_V2) | ||
273 | 301 | ||
274 | #ifdef __KERNEL__ | 302 | #ifdef __KERNEL__ |
275 | 303 | ||
@@ -939,6 +967,12 @@ struct journal_s | |||
939 | * superblock pointer here | 967 | * superblock pointer here |
940 | */ | 968 | */ |
941 | void *j_private; | 969 | void *j_private; |
970 | |||
971 | /* Reference to checksum algorithm driver via cryptoapi */ | ||
972 | struct crypto_shash *j_chksum_driver; | ||
973 | |||
974 | /* Precomputed journal UUID checksum for seeding other checksums */ | ||
975 | __u32 j_csum_seed; | ||
942 | }; | 976 | }; |
943 | 977 | ||
944 | /* | 978 | /* |
@@ -1268,6 +1302,25 @@ static inline int jbd_space_needed(journal_t *journal) | |||
1268 | 1302 | ||
1269 | extern int jbd_blocks_per_page(struct inode *inode); | 1303 | extern int jbd_blocks_per_page(struct inode *inode); |
1270 | 1304 | ||
1305 | static inline u32 jbd2_chksum(journal_t *journal, u32 crc, | ||
1306 | const void *address, unsigned int length) | ||
1307 | { | ||
1308 | struct { | ||
1309 | struct shash_desc shash; | ||
1310 | char ctx[crypto_shash_descsize(journal->j_chksum_driver)]; | ||
1311 | } desc; | ||
1312 | int err; | ||
1313 | |||
1314 | desc.shash.tfm = journal->j_chksum_driver; | ||
1315 | desc.shash.flags = 0; | ||
1316 | *(u32 *)desc.ctx = crc; | ||
1317 | |||
1318 | err = crypto_shash_update(&desc.shash, address, length); | ||
1319 | BUG_ON(err); | ||
1320 | |||
1321 | return *(u32 *)desc.ctx; | ||
1322 | } | ||
1323 | |||
1271 | #ifdef __KERNEL__ | 1324 | #ifdef __KERNEL__ |
1272 | 1325 | ||
1273 | #define buffer_trace_init(bh) do {} while (0) | 1326 | #define buffer_trace_init(bh) do {} while (0) |
diff --git a/include/linux/jbd_common.h b/include/linux/jbd_common.h index 6230f8556a4e..6133679bc4c0 100644 --- a/include/linux/jbd_common.h +++ b/include/linux/jbd_common.h | |||
@@ -12,6 +12,7 @@ enum jbd_state_bits { | |||
12 | BH_State, /* Pins most journal_head state */ | 12 | BH_State, /* Pins most journal_head state */ |
13 | BH_JournalHead, /* Pins bh->b_private and jh->b_bh */ | 13 | BH_JournalHead, /* Pins bh->b_private and jh->b_bh */ |
14 | BH_Unshadow, /* Dummy bit, for BJ_Shadow wakeup filtering */ | 14 | BH_Unshadow, /* Dummy bit, for BJ_Shadow wakeup filtering */ |
15 | BH_Verified, /* Metadata block has been verified ok */ | ||
15 | BH_JBDPrivateStart, /* First bit available for private use by FS */ | 16 | BH_JBDPrivateStart, /* First bit available for private use by FS */ |
16 | }; | 17 | }; |
17 | 18 | ||
@@ -24,6 +25,7 @@ TAS_BUFFER_FNS(Revoked, revoked) | |||
24 | BUFFER_FNS(RevokeValid, revokevalid) | 25 | BUFFER_FNS(RevokeValid, revokevalid) |
25 | TAS_BUFFER_FNS(RevokeValid, revokevalid) | 26 | TAS_BUFFER_FNS(RevokeValid, revokevalid) |
26 | BUFFER_FNS(Freed, freed) | 27 | BUFFER_FNS(Freed, freed) |
28 | BUFFER_FNS(Verified, verified) | ||
27 | 29 | ||
28 | static inline struct buffer_head *jh2bh(struct journal_head *jh) | 30 | static inline struct buffer_head *jh2bh(struct journal_head *jh) |
29 | { | 31 | { |