aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/extents.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-06-01 13:12:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-06-01 13:12:15 -0400
commit4edebed86690eb8db9af3ab85baf4a34e73266cc (patch)
tree8ab144b08f490f239fa62be52470860c9311664d /fs/ext4/extents.c
parent51eab603f5c86dd1eae4c525df3e7f7eeab401d6 (diff)
parent5e44f8c374dc4f8eadf61cd18b2c0d46bc87c1b7 (diff)
Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull Ext4 updates from Theodore Ts'o: "The major new feature added in this update is Darrick J Wong's metadata checksum feature, which adds crc32 checksums to ext4's metadata fields. There is also the usual set of cleanups and bug fixes." * tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (44 commits) ext4: hole-punch use truncate_pagecache_range jbd2: use kmem_cache_zalloc wrapper instead of flag ext4: remove mb_groups before tearing down the buddy_cache ext4: add ext4_mb_unload_buddy in the error path ext4: don't trash state flags in EXT4_IOC_SETFLAGS ext4: let getattr report the right blocks in delalloc+bigalloc ext4: add missing save_error_info() to ext4_error() ext4: add debugging trigger for ext4_error() ext4: protect group inode free counting with group lock ext4: use consistent ssize_t type in ext4_file_write() ext4: fix format flag in ext4_ext_binsearch_idx() ext4: cleanup in ext4_discard_allocated_blocks() ext4: return ENOMEM when mounts fail due to lack of memory ext4: remove redundundant "(char *) bh->b_data" casts ext4: disallow hard-linked directory in ext4_lookup ext4: fix potential integer overflow in alloc_flex_gd() ext4: remove needs_recovery in ext4_mb_init() ext4: force ro mount if ext4_setup_super() fails ext4: fix potential NULL dereference in ext4_free_inodes_counts() ext4/jbd2: add metadata checksumming to the list of supported features ...
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r--fs/ext4/extents.c91
1 files changed, 79 insertions, 12 deletions
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
55static __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
67static 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
82static 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
55static int ext4_split_extent(handle_t *handle, 95static 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
396corrupted: 443corrupted:
@@ -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
462static 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
416static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) 483static 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 */