diff options
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 91 |
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 | ||
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 */ |