diff options
Diffstat (limited to 'fs/ext4/balloc.c')
-rw-r--r-- | fs/ext4/balloc.c | 112 |
1 files changed, 109 insertions, 3 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index b74bf4368441..5927687b3e79 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/quotaops.h> | 20 | #include <linux/quotaops.h> |
21 | #include <linux/buffer_head.h> | 21 | #include <linux/buffer_head.h> |
22 | 22 | ||
23 | #include "group.h" | ||
23 | /* | 24 | /* |
24 | * balloc.c contains the blocks allocation and deallocation routines | 25 | * balloc.c contains the blocks allocation and deallocation routines |
25 | */ | 26 | */ |
@@ -42,6 +43,94 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, | |||
42 | 43 | ||
43 | } | 44 | } |
44 | 45 | ||
46 | /* Initializes an uninitialized block bitmap if given, and returns the | ||
47 | * number of blocks free in the group. */ | ||
48 | unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, | ||
49 | int block_group, struct ext4_group_desc *gdp) | ||
50 | { | ||
51 | unsigned long start; | ||
52 | int bit, bit_max; | ||
53 | unsigned free_blocks, group_blocks; | ||
54 | struct ext4_sb_info *sbi = EXT4_SB(sb); | ||
55 | |||
56 | if (bh) { | ||
57 | J_ASSERT_BH(bh, buffer_locked(bh)); | ||
58 | |||
59 | /* If checksum is bad mark all blocks used to prevent allocation | ||
60 | * essentially implementing a per-group read-only flag. */ | ||
61 | if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) { | ||
62 | ext4_error(sb, __FUNCTION__, | ||
63 | "Checksum bad for group %u\n", block_group); | ||
64 | gdp->bg_free_blocks_count = 0; | ||
65 | gdp->bg_free_inodes_count = 0; | ||
66 | gdp->bg_itable_unused = 0; | ||
67 | memset(bh->b_data, 0xff, sb->s_blocksize); | ||
68 | return 0; | ||
69 | } | ||
70 | memset(bh->b_data, 0, sb->s_blocksize); | ||
71 | } | ||
72 | |||
73 | /* Check for superblock and gdt backups in this group */ | ||
74 | bit_max = ext4_bg_has_super(sb, block_group); | ||
75 | |||
76 | if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) || | ||
77 | block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) * | ||
78 | sbi->s_desc_per_block) { | ||
79 | if (bit_max) { | ||
80 | bit_max += ext4_bg_num_gdb(sb, block_group); | ||
81 | bit_max += | ||
82 | le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks); | ||
83 | } | ||
84 | } else { /* For META_BG_BLOCK_GROUPS */ | ||
85 | int group_rel = (block_group - | ||
86 | le32_to_cpu(sbi->s_es->s_first_meta_bg)) % | ||
87 | EXT4_DESC_PER_BLOCK(sb); | ||
88 | if (group_rel == 0 || group_rel == 1 || | ||
89 | (group_rel == EXT4_DESC_PER_BLOCK(sb) - 1)) | ||
90 | bit_max += 1; | ||
91 | } | ||
92 | |||
93 | if (block_group == sbi->s_groups_count - 1) { | ||
94 | /* | ||
95 | * Even though mke2fs always initialize first and last group | ||
96 | * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need | ||
97 | * to make sure we calculate the right free blocks | ||
98 | */ | ||
99 | group_blocks = ext4_blocks_count(sbi->s_es) - | ||
100 | le32_to_cpu(sbi->s_es->s_first_data_block) - | ||
101 | (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count -1)); | ||
102 | } else { | ||
103 | group_blocks = EXT4_BLOCKS_PER_GROUP(sb); | ||
104 | } | ||
105 | |||
106 | free_blocks = group_blocks - bit_max; | ||
107 | |||
108 | if (bh) { | ||
109 | for (bit = 0; bit < bit_max; bit++) | ||
110 | ext4_set_bit(bit, bh->b_data); | ||
111 | |||
112 | start = block_group * EXT4_BLOCKS_PER_GROUP(sb) + | ||
113 | le32_to_cpu(sbi->s_es->s_first_data_block); | ||
114 | |||
115 | /* Set bits for block and inode bitmaps, and inode table */ | ||
116 | ext4_set_bit(ext4_block_bitmap(sb, gdp) - start, bh->b_data); | ||
117 | ext4_set_bit(ext4_inode_bitmap(sb, gdp) - start, bh->b_data); | ||
118 | for (bit = le32_to_cpu(gdp->bg_inode_table) - start, | ||
119 | bit_max = bit + sbi->s_itb_per_group; bit < bit_max; bit++) | ||
120 | ext4_set_bit(bit, bh->b_data); | ||
121 | |||
122 | /* | ||
123 | * Also if the number of blocks within the group is | ||
124 | * less than the blocksize * 8 ( which is the size | ||
125 | * of bitmap ), set rest of the block bitmap to 1 | ||
126 | */ | ||
127 | mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data); | ||
128 | } | ||
129 | |||
130 | return free_blocks - sbi->s_itb_per_group - 2; | ||
131 | } | ||
132 | |||
133 | |||
45 | /* | 134 | /* |
46 | * The free blocks are managed by bitmaps. A file system contains several | 135 | * The free blocks are managed by bitmaps. A file system contains several |
47 | * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap | 136 | * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap |
@@ -119,7 +208,7 @@ block_in_use(ext4_fsblk_t block, struct super_block *sb, unsigned char *map) | |||
119 | * | 208 | * |
120 | * Return buffer_head on success or NULL in case of failure. | 209 | * Return buffer_head on success or NULL in case of failure. |
121 | */ | 210 | */ |
122 | static struct buffer_head * | 211 | struct buffer_head * |
123 | read_block_bitmap(struct super_block *sb, unsigned int block_group) | 212 | read_block_bitmap(struct super_block *sb, unsigned int block_group) |
124 | { | 213 | { |
125 | int i; | 214 | int i; |
@@ -127,11 +216,24 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) | |||
127 | struct buffer_head * bh = NULL; | 216 | struct buffer_head * bh = NULL; |
128 | ext4_fsblk_t bitmap_blk; | 217 | ext4_fsblk_t bitmap_blk; |
129 | 218 | ||
130 | desc = ext4_get_group_desc (sb, block_group, NULL); | 219 | desc = ext4_get_group_desc(sb, block_group, NULL); |
131 | if (!desc) | 220 | if (!desc) |
132 | return NULL; | 221 | return NULL; |
133 | bitmap_blk = ext4_block_bitmap(sb, desc); | 222 | bitmap_blk = ext4_block_bitmap(sb, desc); |
134 | bh = sb_bread(sb, bitmap_blk); | 223 | if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { |
224 | bh = sb_getblk(sb, bitmap_blk); | ||
225 | if (!buffer_uptodate(bh)) { | ||
226 | lock_buffer(bh); | ||
227 | if (!buffer_uptodate(bh)) { | ||
228 | ext4_init_block_bitmap(sb, bh, block_group, | ||
229 | desc); | ||
230 | set_buffer_uptodate(bh); | ||
231 | } | ||
232 | unlock_buffer(bh); | ||
233 | } | ||
234 | } else { | ||
235 | bh = sb_bread(sb, bitmap_blk); | ||
236 | } | ||
135 | if (!bh) | 237 | if (!bh) |
136 | ext4_error (sb, __FUNCTION__, | 238 | ext4_error (sb, __FUNCTION__, |
137 | "Cannot read block bitmap - " | 239 | "Cannot read block bitmap - " |
@@ -627,6 +729,7 @@ do_more: | |||
627 | desc->bg_free_blocks_count = | 729 | desc->bg_free_blocks_count = |
628 | cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) + | 730 | cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) + |
629 | group_freed); | 731 | group_freed); |
732 | desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc); | ||
630 | spin_unlock(sb_bgl_lock(sbi, block_group)); | 733 | spin_unlock(sb_bgl_lock(sbi, block_group)); |
631 | percpu_counter_add(&sbi->s_freeblocks_counter, count); | 734 | percpu_counter_add(&sbi->s_freeblocks_counter, count); |
632 | 735 | ||
@@ -1685,8 +1788,11 @@ allocated: | |||
1685 | ret_block, goal_hits, goal_attempts); | 1788 | ret_block, goal_hits, goal_attempts); |
1686 | 1789 | ||
1687 | spin_lock(sb_bgl_lock(sbi, group_no)); | 1790 | spin_lock(sb_bgl_lock(sbi, group_no)); |
1791 | if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) | ||
1792 | gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); | ||
1688 | gdp->bg_free_blocks_count = | 1793 | gdp->bg_free_blocks_count = |
1689 | cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num); | 1794 | cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num); |
1795 | gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp); | ||
1690 | spin_unlock(sb_bgl_lock(sbi, group_no)); | 1796 | spin_unlock(sb_bgl_lock(sbi, group_no)); |
1691 | percpu_counter_sub(&sbi->s_freeblocks_counter, num); | 1797 | percpu_counter_sub(&sbi->s_freeblocks_counter, num); |
1692 | 1798 | ||