summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/tree-checker.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/tree-checker.c')
-rw-r--r--fs/btrfs/tree-checker.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index d7f4a3468945..ae4361cc6db5 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -678,6 +678,97 @@ static int check_dev_item(struct btrfs_fs_info *fs_info,
678 return 0; 678 return 0;
679} 679}
680 680
681/* Inode item error output has the same format as dir_item_err() */
682#define inode_item_err(fs_info, eb, slot, fmt, ...) \
683 dir_item_err(fs_info, eb, slot, fmt, __VA_ARGS__)
684
685static int check_inode_item(struct btrfs_fs_info *fs_info,
686 struct extent_buffer *leaf,
687 struct btrfs_key *key, int slot)
688{
689 struct btrfs_inode_item *iitem;
690 u64 super_gen = btrfs_super_generation(fs_info->super_copy);
691 u32 valid_mask = (S_IFMT | S_ISUID | S_ISGID | S_ISVTX | 0777);
692 u32 mode;
693
694 if ((key->objectid < BTRFS_FIRST_FREE_OBJECTID ||
695 key->objectid > BTRFS_LAST_FREE_OBJECTID) &&
696 key->objectid != BTRFS_ROOT_TREE_DIR_OBJECTID &&
697 key->objectid != BTRFS_FREE_INO_OBJECTID) {
698 generic_err(fs_info, leaf, slot,
699 "invalid key objectid: has %llu expect %llu or [%llu, %llu] or %llu",
700 key->objectid, BTRFS_ROOT_TREE_DIR_OBJECTID,
701 BTRFS_FIRST_FREE_OBJECTID,
702 BTRFS_LAST_FREE_OBJECTID,
703 BTRFS_FREE_INO_OBJECTID);
704 return -EUCLEAN;
705 }
706 if (key->offset != 0) {
707 inode_item_err(fs_info, leaf, slot,
708 "invalid key offset: has %llu expect 0",
709 key->offset);
710 return -EUCLEAN;
711 }
712 iitem = btrfs_item_ptr(leaf, slot, struct btrfs_inode_item);
713
714 /* Here we use super block generation + 1 to handle log tree */
715 if (btrfs_inode_generation(leaf, iitem) > super_gen + 1) {
716 inode_item_err(fs_info, leaf, slot,
717 "invalid inode generation: has %llu expect (0, %llu]",
718 btrfs_inode_generation(leaf, iitem),
719 super_gen + 1);
720 return -EUCLEAN;
721 }
722 /* Note for ROOT_TREE_DIR_ITEM, mkfs could set its transid 0 */
723 if (btrfs_inode_transid(leaf, iitem) > super_gen + 1) {
724 inode_item_err(fs_info, leaf, slot,
725 "invalid inode generation: has %llu expect [0, %llu]",
726 btrfs_inode_transid(leaf, iitem), super_gen + 1);
727 return -EUCLEAN;
728 }
729
730 /*
731 * For size and nbytes it's better not to be too strict, as for dir
732 * item its size/nbytes can easily get wrong, but doesn't affect
733 * anything in the fs. So here we skip the check.
734 */
735 mode = btrfs_inode_mode(leaf, iitem);
736 if (mode & ~valid_mask) {
737 inode_item_err(fs_info, leaf, slot,
738 "unknown mode bit detected: 0x%x",
739 mode & ~valid_mask);
740 return -EUCLEAN;
741 }
742
743 /*
744 * S_IFMT is not bit mapped so we can't completely rely on is_power_of_2,
745 * but is_power_of_2() can save us from checking FIFO/CHR/DIR/REG.
746 * Only needs to check BLK, LNK and SOCKS
747 */
748 if (!is_power_of_2(mode & S_IFMT)) {
749 if (!S_ISLNK(mode) && !S_ISBLK(mode) && !S_ISSOCK(mode)) {
750 inode_item_err(fs_info, leaf, slot,
751 "invalid mode: has 0%o expect valid S_IF* bit(s)",
752 mode & S_IFMT);
753 return -EUCLEAN;
754 }
755 }
756 if (S_ISDIR(mode) && btrfs_inode_nlink(leaf, iitem) > 1) {
757 inode_item_err(fs_info, leaf, slot,
758 "invalid nlink: has %u expect no more than 1 for dir",
759 btrfs_inode_nlink(leaf, iitem));
760 return -EUCLEAN;
761 }
762 if (btrfs_inode_flags(leaf, iitem) & ~BTRFS_INODE_FLAG_MASK) {
763 inode_item_err(fs_info, leaf, slot,
764 "unknown flags detected: 0x%llx",
765 btrfs_inode_flags(leaf, iitem) &
766 ~BTRFS_INODE_FLAG_MASK);
767 return -EUCLEAN;
768 }
769 return 0;
770}
771
681/* 772/*
682 * Common point to switch the item-specific validation. 773 * Common point to switch the item-specific validation.
683 */ 774 */
@@ -711,6 +802,9 @@ static int check_leaf_item(struct btrfs_fs_info *fs_info,
711 case BTRFS_DEV_ITEM_KEY: 802 case BTRFS_DEV_ITEM_KEY:
712 ret = check_dev_item(fs_info, leaf, key, slot); 803 ret = check_dev_item(fs_info, leaf, key, slot);
713 break; 804 break;
805 case BTRFS_INODE_ITEM_KEY:
806 ret = check_inode_item(fs_info, leaf, key, slot);
807 break;
714 } 808 }
715 return ret; 809 return ret;
716} 810}