diff options
Diffstat (limited to 'fs/ext4/ialloc.c')
| -rw-r--r-- | fs/ext4/ialloc.c | 85 |
1 files changed, 64 insertions, 21 deletions
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 409c2ee7750a..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); |
| @@ -808,8 +838,8 @@ got: | |||
| 808 | } | 838 | } |
| 809 | if (owner) { | 839 | if (owner) { |
| 810 | inode->i_mode = mode; | 840 | inode->i_mode = mode; |
| 811 | inode->i_uid = owner[0]; | 841 | i_uid_write(inode, owner[0]); |
| 812 | inode->i_gid = owner[1]; | 842 | i_gid_write(inode, owner[1]); |
| 813 | } else if (test_opt(sb, GRPID)) { | 843 | } else if (test_opt(sb, GRPID)) { |
| 814 | inode->i_mode = mode; | 844 | inode->i_mode = mode; |
| 815 | inode->i_uid = current_fsuid(); | 845 | inode->i_uid = current_fsuid(); |
| @@ -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, |
