]>
Commit | Line | Data |
---|---|---|
21c84b71 TT |
1 | /* |
2 | * alloc_tables.c --- Allocate tables for a newly initialized | |
3 | * filesystem. Used by mke2fs when initializing a filesystem | |
4 | * | |
5 | * Copyright (C) 1996 Theodore Ts'o. | |
6 | * | |
7 | * %Begin-Header% | |
543547a5 TT |
8 | * This file may be redistributed under the terms of the GNU Library |
9 | * General Public License, version 2. | |
21c84b71 TT |
10 | * %End-Header% |
11 | */ | |
12 | ||
d1154eb4 | 13 | #include "config.h" |
21c84b71 TT |
14 | #include <stdio.h> |
15 | #include <string.h> | |
4cbe8af4 | 16 | #if HAVE_UNISTD_H |
21c84b71 | 17 | #include <unistd.h> |
4cbe8af4 | 18 | #endif |
21c84b71 TT |
19 | #include <fcntl.h> |
20 | #include <time.h> | |
1d2ff46a | 21 | #if HAVE_SYS_STAT_H |
21c84b71 | 22 | #include <sys/stat.h> |
1d2ff46a TT |
23 | #endif |
24 | #if HAVE_SYS_TYPES_H | |
21c84b71 | 25 | #include <sys/types.h> |
1d2ff46a | 26 | #endif |
21c84b71 | 27 | |
b5abe6fa | 28 | #include "ext2_fs.h" |
21c84b71 | 29 | #include "ext2fs.h" |
95fd65bb | 30 | #include "ext2fsP.h" |
21c84b71 | 31 | |
9ba40002 TT |
32 | /* |
33 | * This routine searches for free blocks that can allocate a full | |
34 | * group of bitmaps or inode tables for a flexbg group. Returns the | |
35 | * block number with a correct offset were the bitmaps and inode | |
055866d8 | 36 | * tables can be allocated continuously and in order. |
9ba40002 | 37 | */ |
da3fc25b | 38 | static blk64_t flexbg_offset(ext2_filsys fs, dgrp_t group, blk64_t start_blk, |
25567a7b | 39 | ext2fs_block_bitmap bmap, int rem_grp, |
da3fc25b | 40 | int elem_size) |
9ba40002 | 41 | { |
25567a7b | 42 | int flexbg, flexbg_size, size; |
da3fc25b | 43 | blk64_t last_blk, first_free = 0; |
9ba40002 TT |
44 | dgrp_t last_grp; |
45 | ||
c4d2d43e TT |
46 | flexbg_size = 1 << fs->super->s_log_groups_per_flex; |
47 | flexbg = group / flexbg_size; | |
25567a7b | 48 | size = rem_grp * elem_size; |
9ba40002 | 49 | |
f7a51a12 AD |
50 | if (size > (int) (fs->super->s_blocks_per_group / 4)) |
51 | size = (int) fs->super->s_blocks_per_group / 4; | |
9ba40002 TT |
52 | |
53 | /* | |
f7a51a12 AD |
54 | * Don't do a long search if the previous block search is still valid, |
55 | * but skip minor obstructions such as group descriptor backups. | |
9ba40002 | 56 | */ |
d51072af | 57 | if (start_blk && start_blk < ext2fs_blocks_count(fs->super) && |
f7a51a12 AD |
58 | ext2fs_get_free_blocks2(fs, start_blk, start_blk + size, elem_size, |
59 | bmap, &first_free) == 0) | |
60 | return first_free; | |
9ba40002 | 61 | |
b49f78fe | 62 | start_blk = ext2fs_group_first_block2(fs, flexbg_size * flexbg); |
9ba40002 | 63 | last_grp = group | (flexbg_size - 1); |
25567a7b TT |
64 | if (last_grp > fs->group_desc_count-1) |
65 | last_grp = fs->group_desc_count-1; | |
b49f78fe | 66 | last_blk = ext2fs_group_last_block2(fs, last_grp); |
9ba40002 TT |
67 | |
68 | /* Find the first available block */ | |
25567a7b TT |
69 | if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, size, |
70 | bmap, &first_free) == 0) | |
71 | return first_free; | |
72 | ||
73 | if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, elem_size, | |
74 | bmap, &first_free) == 0) | |
9ba40002 TT |
75 | return first_free; |
76 | ||
25567a7b TT |
77 | if (ext2fs_get_free_blocks2(fs, 0, last_blk, elem_size, bmap, |
78 | &first_free) == 0) | |
9ba40002 TT |
79 | return first_free; |
80 | ||
81 | return first_free; | |
82 | } | |
83 | ||
2eb374c9 | 84 | errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, |
1e1da29f | 85 | ext2fs_block_bitmap bmap) |
21c84b71 TT |
86 | { |
87 | errcode_t retval; | |
fccdbac3 | 88 | blk64_t group_blk, start_blk, last_blk, new_blk; |
8895f43a | 89 | dgrp_t last_grp = 0; |
b1988056 | 90 | int rem_grps = 0, flexbg_size = 0, table_offset = 0; |
21c84b71 | 91 | |
b49f78fe TT |
92 | group_blk = ext2fs_group_first_block2(fs, group); |
93 | last_blk = ext2fs_group_last_block2(fs, group); | |
2ecc6fef | 94 | |
1e1da29f TT |
95 | if (!bmap) |
96 | bmap = fs->block_map; | |
9ba40002 | 97 | |
77b3e987 | 98 | if (ext2fs_has_feature_flex_bg(fs->super) && |
9ba40002 TT |
99 | fs->super->s_log_groups_per_flex) { |
100 | flexbg_size = 1 << fs->super->s_log_groups_per_flex; | |
101 | last_grp = group | (flexbg_size - 1); | |
25567a7b TT |
102 | if (last_grp > fs->group_desc_count-1) |
103 | last_grp = fs->group_desc_count-1; | |
104 | rem_grps = last_grp - group + 1; | |
9ba40002 | 105 | } |
efc6f628 | 106 | |
1e1da29f TT |
107 | /* |
108 | * Allocate the block and inode bitmaps, if necessary | |
109 | */ | |
ca74ecf3 | 110 | if (fs->stride && !flexbg_size) { |
da3fc25b TT |
111 | retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk, |
112 | 1, bmap, &start_blk); | |
bc2699f0 TT |
113 | if (retval) |
114 | return retval; | |
115 | start_blk += fs->inode_blocks_per_group; | |
1e1da29f | 116 | start_blk += ((fs->stride * group) % |
abf23439 ES |
117 | (last_blk - start_blk + 1)); |
118 | if (start_blk >= last_blk) | |
a29f4d30 | 119 | start_blk = group_blk; |
1e1da29f TT |
120 | } else |
121 | start_blk = group_blk; | |
122 | ||
9ba40002 | 123 | if (flexbg_size) { |
8f82ef98 VAH |
124 | blk64_t prev_block = 0; |
125 | ||
b1988056 | 126 | table_offset = flexbg_size; |
25567a7b TT |
127 | if (group % flexbg_size) |
128 | prev_block = ext2fs_block_bitmap_loc(fs, group - 1) + 1; | |
b1988056 TT |
129 | else if (last_grp == fs->group_desc_count-1) { |
130 | /* | |
131 | * If we are allocating for the last flex_bg | |
132 | * keep the metadata tables contiguous | |
133 | */ | |
134 | table_offset = last_grp & (flexbg_size - 1); | |
135 | if (table_offset == 0) | |
136 | table_offset = flexbg_size; | |
137 | else | |
138 | table_offset++; | |
139 | } | |
f7a51a12 AD |
140 | /* FIXME: Take backup group descriptor blocks into account |
141 | * if the flexbg allocations will grow to overlap them... */ | |
9ba40002 | 142 | start_blk = flexbg_offset(fs, group, prev_block, bmap, |
25567a7b | 143 | rem_grps, 1); |
b49f78fe | 144 | last_blk = ext2fs_group_last_block2(fs, last_grp); |
9ba40002 TT |
145 | } |
146 | ||
d7cca6b0 | 147 | if (!ext2fs_block_bitmap_loc(fs, group)) { |
da3fc25b TT |
148 | retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk, |
149 | 1, bmap, &new_blk); | |
efc6f628 | 150 | if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) |
da3fc25b | 151 | retval = ext2fs_get_free_blocks2(fs, group_blk, |
03673dbb | 152 | last_blk, 1, bmap, &new_blk); |
21c84b71 TT |
153 | if (retval) |
154 | return retval; | |
8f82ef98 | 155 | ext2fs_mark_block_bitmap2(bmap, new_blk); |
d7cca6b0 | 156 | ext2fs_block_bitmap_loc_set(fs, group, new_blk); |
9ba40002 | 157 | if (flexbg_size) { |
6493f8e8 | 158 | dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk); |
d7cca6b0 | 159 | ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1); |
4efbac6f | 160 | ext2fs_free_blocks_count_add(fs->super, -1); |
e633b58a | 161 | ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT); |
9ba40002 TT |
162 | ext2fs_group_desc_csum_set(fs, gr); |
163 | } | |
164 | } | |
165 | ||
166 | if (flexbg_size) { | |
d7cca6b0 | 167 | blk64_t prev_block = 0; |
25567a7b TT |
168 | if (group % flexbg_size) |
169 | prev_block = ext2fs_inode_bitmap_loc(fs, group - 1) + 1; | |
170 | else | |
171 | prev_block = ext2fs_block_bitmap_loc(fs, group) + | |
b1988056 | 172 | table_offset; |
f7a51a12 AD |
173 | /* FIXME: Take backup group descriptor blocks into account |
174 | * if the flexbg allocations will grow to overlap them... */ | |
9ba40002 | 175 | start_blk = flexbg_offset(fs, group, prev_block, bmap, |
25567a7b | 176 | rem_grps, 1); |
b49f78fe | 177 | last_blk = ext2fs_group_last_block2(fs, last_grp); |
1e1da29f | 178 | } |
21c84b71 | 179 | |
d7cca6b0 | 180 | if (!ext2fs_inode_bitmap_loc(fs, group)) { |
da3fc25b TT |
181 | retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk, |
182 | 1, bmap, &new_blk); | |
efc6f628 | 183 | if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) |
da3fc25b TT |
184 | retval = ext2fs_get_free_blocks2(fs, group_blk, |
185 | last_blk, 1, bmap, &new_blk); | |
21c84b71 TT |
186 | if (retval) |
187 | return retval; | |
8f82ef98 | 188 | ext2fs_mark_block_bitmap2(bmap, new_blk); |
d7cca6b0 | 189 | ext2fs_inode_bitmap_loc_set(fs, group, new_blk); |
9ba40002 | 190 | if (flexbg_size) { |
6493f8e8 | 191 | dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk); |
d7cca6b0 | 192 | ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1); |
4efbac6f | 193 | ext2fs_free_blocks_count_add(fs->super, -1); |
e633b58a | 194 | ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT); |
9ba40002 TT |
195 | ext2fs_group_desc_csum_set(fs, gr); |
196 | } | |
1e1da29f | 197 | } |
76dd5e5c TT |
198 | |
199 | /* | |
200 | * Allocate the inode table | |
201 | */ | |
9ba40002 | 202 | if (flexbg_size) { |
d7cca6b0 | 203 | blk64_t prev_block = 0; |
25567a7b TT |
204 | |
205 | if (group % flexbg_size) | |
206 | prev_block = ext2fs_inode_table_loc(fs, group - 1) + | |
207 | fs->inode_blocks_per_group; | |
208 | else | |
209 | prev_block = ext2fs_inode_bitmap_loc(fs, group) + | |
b1988056 | 210 | table_offset; |
25567a7b | 211 | |
f7a51a12 AD |
212 | /* FIXME: Take backup group descriptor blocks into account |
213 | * if the flexbg allocations will grow to overlap them... */ | |
9ba40002 | 214 | group_blk = flexbg_offset(fs, group, prev_block, bmap, |
25567a7b | 215 | rem_grps, fs->inode_blocks_per_group); |
b49f78fe | 216 | last_blk = ext2fs_group_last_block2(fs, last_grp); |
9ba40002 TT |
217 | } |
218 | ||
d7cca6b0 | 219 | if (!ext2fs_inode_table_loc(fs, group)) { |
da3fc25b | 220 | retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk, |
76dd5e5c TT |
221 | fs->inode_blocks_per_group, |
222 | bmap, &new_blk); | |
223 | if (retval) | |
224 | return retval; | |
0c12896e LC |
225 | |
226 | ext2fs_mark_block_bitmap_range2(bmap, | |
227 | new_blk, fs->inode_blocks_per_group); | |
228 | if (flexbg_size) { | |
229 | blk64_t num, blk; | |
230 | num = fs->inode_blocks_per_group; | |
231 | blk = new_blk; | |
232 | while (num) { | |
233 | int gr = ext2fs_group_of_blk2(fs, blk); | |
234 | last_blk = ext2fs_group_last_block2(fs, gr); | |
235 | blk64_t n = num; | |
236 | ||
237 | if (blk + num > last_blk) | |
238 | n = last_blk - blk + 1; | |
239 | ||
240 | ext2fs_bg_free_blocks_count_set(fs, gr, | |
241 | ext2fs_bg_free_blocks_count(fs, gr) - | |
242 | n/EXT2FS_CLUSTER_RATIO(fs)); | |
243 | ext2fs_bg_flags_clear(fs, gr, | |
244 | EXT2_BG_BLOCK_UNINIT); | |
245 | ext2fs_group_desc_csum_set(fs, gr); | |
246 | ext2fs_free_blocks_count_add(fs->super, -n); | |
247 | blk += n; | |
248 | num -= n; | |
249 | } | |
250 | } | |
d7cca6b0 | 251 | ext2fs_inode_table_loc_set(fs, group, new_blk); |
76dd5e5c | 252 | } |
d4f34d41 | 253 | ext2fs_group_desc_csum_set(fs, group); |
1e1da29f TT |
254 | return 0; |
255 | } | |
256 | ||
1e1da29f TT |
257 | errcode_t ext2fs_allocate_tables(ext2_filsys fs) |
258 | { | |
259 | errcode_t retval; | |
2eb374c9 | 260 | dgrp_t i; |
95fd65bb VAH |
261 | struct ext2fs_numeric_progress_struct progress; |
262 | ||
dfe74c5c TT |
263 | if (fs->progress_ops && fs->progress_ops->init) |
264 | (fs->progress_ops->init)(fs, &progress, NULL, | |
265 | fs->group_desc_count); | |
21c84b71 | 266 | |
1e1da29f | 267 | for (i = 0; i < fs->group_desc_count; i++) { |
dfe74c5c TT |
268 | if (fs->progress_ops && fs->progress_ops->update) |
269 | (fs->progress_ops->update)(fs, &progress, i); | |
1e1da29f TT |
270 | retval = ext2fs_allocate_group_table(fs, i, fs->block_map); |
271 | if (retval) | |
272 | return retval; | |
21c84b71 | 273 | } |
dfe74c5c TT |
274 | if (fs->progress_ops && fs->progress_ops->close) |
275 | (fs->progress_ops->close)(fs, &progress, NULL); | |
21c84b71 TT |
276 | return 0; |
277 | } | |
278 |