diff options
-rw-r--r-- | fs/ext4/balloc.c | 105 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 13 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 20 |
3 files changed, 66 insertions, 72 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 8573e2bfb78a..735d9fcc72e6 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -102,74 +102,73 @@ static unsigned int num_blocks_in_group(struct super_block *sb, | |||
102 | return EXT4_BLOCKS_PER_GROUP(sb); | 102 | return EXT4_BLOCKS_PER_GROUP(sb); |
103 | } | 103 | } |
104 | 104 | ||
105 | /* Initializes an uninitialized block bitmap if given, and returns the | 105 | /* Initializes an uninitialized block bitmap */ |
106 | * number of blocks free in the group. */ | 106 | void ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, |
107 | unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, | 107 | ext4_group_t block_group, |
108 | ext4_group_t block_group, struct ext4_group_desc *gdp) | 108 | struct ext4_group_desc *gdp) |
109 | { | 109 | { |
110 | unsigned int bit, bit_max = num_base_meta_blocks(sb, block_group); | 110 | unsigned int bit, bit_max = num_base_meta_blocks(sb, block_group); |
111 | ext4_group_t ngroups = ext4_get_groups_count(sb); | ||
112 | unsigned group_blocks = num_blocks_in_group(sb, block_group); | ||
113 | struct ext4_sb_info *sbi = EXT4_SB(sb); | 111 | struct ext4_sb_info *sbi = EXT4_SB(sb); |
114 | 112 | ext4_fsblk_t start, tmp; | |
115 | if (bh) { | 113 | int flex_bg = 0; |
116 | J_ASSERT_BH(bh, buffer_locked(bh)); | 114 | |
117 | 115 | J_ASSERT_BH(bh, buffer_locked(bh)); | |
118 | /* If checksum is bad mark all blocks used to prevent allocation | 116 | |
119 | * essentially implementing a per-group read-only flag. */ | 117 | /* If checksum is bad mark all blocks used to prevent allocation |
120 | if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { | 118 | * essentially implementing a per-group read-only flag. */ |
121 | ext4_error(sb, "Checksum bad for group %u", | 119 | if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { |
122 | block_group); | 120 | ext4_error(sb, "Checksum bad for group %u", block_group); |
123 | ext4_free_blks_set(sb, gdp, 0); | 121 | ext4_free_blks_set(sb, gdp, 0); |
124 | ext4_free_inodes_set(sb, gdp, 0); | 122 | ext4_free_inodes_set(sb, gdp, 0); |
125 | ext4_itable_unused_set(sb, gdp, 0); | 123 | ext4_itable_unused_set(sb, gdp, 0); |
126 | memset(bh->b_data, 0xff, sb->s_blocksize); | 124 | memset(bh->b_data, 0xff, sb->s_blocksize); |
127 | return 0; | 125 | return; |
128 | } | ||
129 | memset(bh->b_data, 0, sb->s_blocksize); | ||
130 | } | 126 | } |
127 | memset(bh->b_data, 0, sb->s_blocksize); | ||
131 | 128 | ||
132 | if (bh) { | 129 | for (bit = 0; bit < bit_max; bit++) |
133 | ext4_fsblk_t start, tmp; | 130 | ext4_set_bit(bit, bh->b_data); |
134 | int flex_bg = 0; | ||
135 | 131 | ||
136 | for (bit = 0; bit < bit_max; bit++) | 132 | start = ext4_group_first_block_no(sb, block_group); |
137 | ext4_set_bit(bit, bh->b_data); | ||
138 | 133 | ||
139 | start = ext4_group_first_block_no(sb, block_group); | 134 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) |
135 | flex_bg = 1; | ||
140 | 136 | ||
141 | if (EXT4_HAS_INCOMPAT_FEATURE(sb, | 137 | /* Set bits for block and inode bitmaps, and inode table */ |
142 | EXT4_FEATURE_INCOMPAT_FLEX_BG)) | 138 | tmp = ext4_block_bitmap(sb, gdp); |
143 | flex_bg = 1; | 139 | if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) |
140 | ext4_set_bit(tmp - start, bh->b_data); | ||
144 | 141 | ||
145 | /* Set bits for block and inode bitmaps, and inode table */ | 142 | tmp = ext4_inode_bitmap(sb, gdp); |
146 | tmp = ext4_block_bitmap(sb, gdp); | 143 | if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) |
147 | if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) | 144 | ext4_set_bit(tmp - start, bh->b_data); |
148 | ext4_set_bit(tmp - start, bh->b_data); | ||
149 | 145 | ||
150 | tmp = ext4_inode_bitmap(sb, gdp); | 146 | tmp = ext4_inode_table(sb, gdp); |
147 | for (; tmp < ext4_inode_table(sb, gdp) + | ||
148 | sbi->s_itb_per_group; tmp++) { | ||
151 | if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) | 149 | if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) |
152 | ext4_set_bit(tmp - start, bh->b_data); | 150 | ext4_set_bit(tmp - start, bh->b_data); |
153 | |||
154 | tmp = ext4_inode_table(sb, gdp); | ||
155 | for (; tmp < ext4_inode_table(sb, gdp) + | ||
156 | sbi->s_itb_per_group; tmp++) { | ||
157 | if (!flex_bg || | ||
158 | ext4_block_in_group(sb, tmp, block_group)) | ||
159 | ext4_set_bit(tmp - start, bh->b_data); | ||
160 | } | ||
161 | /* | ||
162 | * Also if the number of blocks within the group is | ||
163 | * less than the blocksize * 8 ( which is the size | ||
164 | * of bitmap ), set rest of the block bitmap to 1 | ||
165 | */ | ||
166 | ext4_mark_bitmap_end(group_blocks, sb->s_blocksize * 8, | ||
167 | bh->b_data); | ||
168 | } | 151 | } |
169 | return group_blocks - bit_max - | 152 | /* |
170 | ext4_group_used_meta_blocks(sb, block_group, gdp); | 153 | * Also if the number of blocks within the group is less than |
154 | * the blocksize * 8 ( which is the size of bitmap ), set rest | ||
155 | * of the block bitmap to 1 | ||
156 | */ | ||
157 | ext4_mark_bitmap_end(num_blocks_in_group(sb, block_group), | ||
158 | sb->s_blocksize * 8, bh->b_data); | ||
171 | } | 159 | } |
172 | 160 | ||
161 | /* Return the number of free blocks in a block group. It is used when | ||
162 | * the block bitmap is uninitialized, so we can't just count the bits | ||
163 | * in the bitmap. */ | ||
164 | unsigned ext4_free_blocks_after_init(struct super_block *sb, | ||
165 | ext4_group_t block_group, | ||
166 | struct ext4_group_desc *gdp) | ||
167 | { | ||
168 | return num_blocks_in_group(sb, block_group) - | ||
169 | num_base_meta_blocks(sb, block_group) - | ||
170 | ext4_group_used_meta_blocks(sb, block_group, gdp); | ||
171 | } | ||
173 | 172 | ||
174 | /* | 173 | /* |
175 | * The free blocks are managed by bitmaps. A file system contains several | 174 | * The free blocks are managed by bitmaps. A file system contains several |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index f7257aa6bf81..b0b7b67e439d 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -1763,12 +1763,13 @@ extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, | |||
1763 | extern int ext4_should_retry_alloc(struct super_block *sb, int *retries); | 1763 | extern int ext4_should_retry_alloc(struct super_block *sb, int *retries); |
1764 | struct buffer_head *ext4_read_block_bitmap(struct super_block *sb, | 1764 | struct buffer_head *ext4_read_block_bitmap(struct super_block *sb, |
1765 | ext4_group_t block_group); | 1765 | ext4_group_t block_group); |
1766 | extern unsigned ext4_init_block_bitmap(struct super_block *sb, | 1766 | extern void ext4_init_block_bitmap(struct super_block *sb, |
1767 | struct buffer_head *bh, | 1767 | struct buffer_head *bh, |
1768 | ext4_group_t group, | 1768 | ext4_group_t group, |
1769 | struct ext4_group_desc *desc); | 1769 | struct ext4_group_desc *desc); |
1770 | #define ext4_free_blocks_after_init(sb, group, desc) \ | 1770 | extern unsigned ext4_free_blocks_after_init(struct super_block *sb, |
1771 | ext4_init_block_bitmap(sb, NULL, group, desc) | 1771 | ext4_group_t block_group, |
1772 | struct ext4_group_desc *gdp); | ||
1772 | ext4_fsblk_t ext4_inode_to_goal_block(struct inode *); | 1773 | ext4_fsblk_t ext4_inode_to_goal_block(struct inode *); |
1773 | 1774 | ||
1774 | /* dir.c */ | 1775 | /* dir.c */ |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 9c63f273b550..b7a8130d0af4 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -816,7 +816,6 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode, | |||
816 | int ret2, err = 0; | 816 | int ret2, err = 0; |
817 | struct inode *ret; | 817 | struct inode *ret; |
818 | ext4_group_t i; | 818 | ext4_group_t i; |
819 | int free = 0; | ||
820 | static int once = 1; | 819 | static int once = 1; |
821 | ext4_group_t flex_group; | 820 | ext4_group_t flex_group; |
822 | 821 | ||
@@ -950,26 +949,21 @@ got: | |||
950 | goto fail; | 949 | goto fail; |
951 | } | 950 | } |
952 | 951 | ||
953 | free = 0; | 952 | BUFFER_TRACE(block_bitmap_bh, "dirty block bitmap"); |
954 | ext4_lock_group(sb, group); | 953 | err = ext4_handle_dirty_metadata(handle, NULL, block_bitmap_bh); |
954 | brelse(block_bitmap_bh); | ||
955 | |||
955 | /* recheck and clear flag under lock if we still need to */ | 956 | /* recheck and clear flag under lock if we still need to */ |
957 | ext4_lock_group(sb, group); | ||
956 | if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { | 958 | if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { |
957 | free = ext4_free_blocks_after_init(sb, group, gdp); | ||
958 | gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); | 959 | gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); |
959 | ext4_free_blks_set(sb, gdp, free); | 960 | ext4_free_blks_set(sb, gdp, |
961 | ext4_free_blocks_after_init(sb, group, gdp)); | ||
960 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group, | 962 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group, |
961 | gdp); | 963 | gdp); |
962 | } | 964 | } |
963 | ext4_unlock_group(sb, group); | 965 | ext4_unlock_group(sb, group); |
964 | 966 | ||
965 | /* Don't need to dirty bitmap block if we didn't change it */ | ||
966 | if (free) { | ||
967 | BUFFER_TRACE(block_bitmap_bh, "dirty block bitmap"); | ||
968 | err = ext4_handle_dirty_metadata(handle, | ||
969 | NULL, block_bitmap_bh); | ||
970 | } | ||
971 | |||
972 | brelse(block_bitmap_bh); | ||
973 | if (err) | 967 | if (err) |
974 | goto fail; | 968 | goto fail; |
975 | } | 969 | } |