diff options
Diffstat (limited to 'fs/ext4/ialloc.c')
-rw-r--r-- | fs/ext4/ialloc.c | 81 |
1 files changed, 62 insertions, 19 deletions
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 9f9acac6c43f..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); |
@@ -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, |