diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2009-03-27 16:39:58 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2009-03-27 16:39:58 -0400 |
commit | 7a262f7c69163cd4811f2f838faef5c5b18439c9 (patch) | |
tree | 1d048ed0fa78d8d768c149cf414bd4325315f184 | |
parent | 56b19868aca856a7d7bf20c3a7a1030e4fd75b2b (diff) |
ext4: Validate extent details only when read from the disk
Make sure we validate extent details only when read from the disk.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Thiemo Nagel <thiemo.nagel@ph.tum.de>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r-- | fs/ext4/ext4_extents.h | 1 | ||||
-rw-r--r-- | fs/ext4/extents.c | 25 | ||||
-rw-r--r-- | fs/ext4/inode.c | 10 |
3 files changed, 29 insertions, 7 deletions
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index 18cb67b2cbbc..f0c3ec85bd48 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h | |||
@@ -241,5 +241,6 @@ extern int ext4_ext_search_left(struct inode *, struct ext4_ext_path *, | |||
241 | extern int ext4_ext_search_right(struct inode *, struct ext4_ext_path *, | 241 | extern int ext4_ext_search_right(struct inode *, struct ext4_ext_path *, |
242 | ext4_lblk_t *, ext4_fsblk_t *); | 242 | ext4_lblk_t *, ext4_fsblk_t *); |
243 | extern void ext4_ext_drop_refs(struct ext4_ext_path *); | 243 | extern void ext4_ext_drop_refs(struct ext4_ext_path *); |
244 | extern int ext4_ext_check_inode(struct inode *inode); | ||
244 | #endif /* _EXT4_EXTENTS */ | 245 | #endif /* _EXT4_EXTENTS */ |
245 | 246 | ||
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index ee40b7c52c8c..ac77d8b8251d 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -429,6 +429,11 @@ corrupted: | |||
429 | #define ext4_ext_check(inode, eh, depth) \ | 429 | #define ext4_ext_check(inode, eh, depth) \ |
430 | __ext4_ext_check(__func__, inode, eh, depth) | 430 | __ext4_ext_check(__func__, inode, eh, depth) |
431 | 431 | ||
432 | int ext4_ext_check_inode(struct inode *inode) | ||
433 | { | ||
434 | return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode)); | ||
435 | } | ||
436 | |||
432 | #ifdef EXT_DEBUG | 437 | #ifdef EXT_DEBUG |
433 | static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) | 438 | static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) |
434 | { | 439 | { |
@@ -631,9 +636,6 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block, | |||
631 | 636 | ||
632 | eh = ext_inode_hdr(inode); | 637 | eh = ext_inode_hdr(inode); |
633 | depth = ext_depth(inode); | 638 | depth = ext_depth(inode); |
634 | if (ext4_ext_check(inode, eh, depth)) | ||
635 | return ERR_PTR(-EIO); | ||
636 | |||
637 | 639 | ||
638 | /* account possible depth increase */ | 640 | /* account possible depth increase */ |
639 | if (!path) { | 641 | if (!path) { |
@@ -649,6 +651,8 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block, | |||
649 | i = depth; | 651 | i = depth; |
650 | /* walk through the tree */ | 652 | /* walk through the tree */ |
651 | while (i) { | 653 | while (i) { |
654 | int need_to_validate = 0; | ||
655 | |||
652 | ext_debug("depth %d: num %d, max %d\n", | 656 | ext_debug("depth %d: num %d, max %d\n", |
653 | ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); | 657 | ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); |
654 | 658 | ||
@@ -657,10 +661,17 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block, | |||
657 | path[ppos].p_depth = i; | 661 | path[ppos].p_depth = i; |
658 | path[ppos].p_ext = NULL; | 662 | path[ppos].p_ext = NULL; |
659 | 663 | ||
660 | bh = sb_bread(inode->i_sb, path[ppos].p_block); | 664 | bh = sb_getblk(inode->i_sb, path[ppos].p_block); |
661 | if (!bh) | 665 | if (unlikely(!bh)) |
662 | goto err; | 666 | goto err; |
663 | 667 | if (!bh_uptodate_or_lock(bh)) { | |
668 | if (bh_submit_read(bh) < 0) { | ||
669 | put_bh(bh); | ||
670 | goto err; | ||
671 | } | ||
672 | /* validate the extent entries */ | ||
673 | need_to_validate = 1; | ||
674 | } | ||
664 | eh = ext_block_hdr(bh); | 675 | eh = ext_block_hdr(bh); |
665 | ppos++; | 676 | ppos++; |
666 | BUG_ON(ppos > depth); | 677 | BUG_ON(ppos > depth); |
@@ -668,7 +679,7 @@ ext4_ext_find_extent(struct inode *inode, ext4_lblk_t block, | |||
668 | path[ppos].p_hdr = eh; | 679 | path[ppos].p_hdr = eh; |
669 | i--; | 680 | i--; |
670 | 681 | ||
671 | if (ext4_ext_check(inode, eh, i)) | 682 | if (need_to_validate && ext4_ext_check(inode, eh, i)) |
672 | goto err; | 683 | goto err; |
673 | } | 684 | } |
674 | 685 | ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 25811507d2b0..cd0399db0ef1 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -4345,6 +4345,16 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4345 | (__u64)(le32_to_cpu(raw_inode->i_version_hi)) << 32; | 4345 | (__u64)(le32_to_cpu(raw_inode->i_version_hi)) << 32; |
4346 | } | 4346 | } |
4347 | 4347 | ||
4348 | if (ei->i_flags & EXT4_EXTENTS_FL) { | ||
4349 | /* Validate extent which is part of inode */ | ||
4350 | ret = ext4_ext_check_inode(inode); | ||
4351 | if (ret) { | ||
4352 | brelse(bh); | ||
4353 | goto bad_inode; | ||
4354 | } | ||
4355 | |||
4356 | } | ||
4357 | |||
4348 | if (S_ISREG(inode->i_mode)) { | 4358 | if (S_ISREG(inode->i_mode)) { |
4349 | inode->i_op = &ext4_file_inode_operations; | 4359 | inode->i_op = &ext4_file_inode_operations; |
4350 | inode->i_fop = &ext4_file_operations; | 4360 | inode->i_fop = &ext4_file_operations; |