]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
1 | /* |
2 | * alloc.c --- allocate new inodes, blocks for ext2fs | |
3 | * | |
21c84b71 TT |
4 | * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. |
5 | * | |
6 | * %Begin-Header% | |
543547a5 TT |
7 | * This file may be redistributed under the terms of the GNU Library |
8 | * General Public License, version 2. | |
21c84b71 | 9 | * %End-Header% |
3839e657 TT |
10 | */ |
11 | ||
d1154eb4 | 12 | #include "config.h" |
3839e657 | 13 | #include <stdio.h> |
4cbe8af4 | 14 | #if HAVE_UNISTD_H |
3839e657 | 15 | #include <unistd.h> |
4cbe8af4 | 16 | #endif |
3839e657 | 17 | #include <time.h> |
30fab293 | 18 | #include <string.h> |
1d2ff46a | 19 | #if HAVE_SYS_STAT_H |
3839e657 | 20 | #include <sys/stat.h> |
1d2ff46a TT |
21 | #endif |
22 | #if HAVE_SYS_TYPES_H | |
3839e657 | 23 | #include <sys/types.h> |
1d2ff46a | 24 | #endif |
3839e657 | 25 | |
b5abe6fa | 26 | #include "ext2_fs.h" |
3839e657 TT |
27 | #include "ext2fs.h" |
28 | ||
5a980264 DW |
29 | #define min(a, b) ((a) < (b) ? (a) : (b)) |
30 | ||
31 | #undef DEBUG | |
32 | ||
33 | #ifdef DEBUG | |
34 | # define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) | |
35 | #else | |
36 | # define dbg_printf(f, a...) | |
37 | #endif | |
38 | ||
c71d7813 | 39 | /* |
dd9aa132 | 40 | * Clear the uninit block bitmap flag if necessary |
c71d7813 | 41 | */ |
f3745728 | 42 | void ext2fs_clear_block_uninit(ext2_filsys fs, dgrp_t group) |
c71d7813 | 43 | { |
3888c1e8 TT |
44 | if (group >= fs->group_desc_count || |
45 | !ext2fs_has_group_desc_csum(fs) || | |
cd65a24e | 46 | !(ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT))) |
c71d7813 TT |
47 | return; |
48 | ||
8e44eb64 | 49 | /* uninit block bitmaps are now initialized in read_bitmaps() */ |
b0ecb787 | 50 | |
e633b58a | 51 | ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); |
c71d7813 | 52 | ext2fs_group_desc_csum_set(fs, group); |
538eb878 TT |
53 | ext2fs_mark_super_dirty(fs); |
54 | ext2fs_mark_bb_dirty(fs); | |
c71d7813 TT |
55 | } |
56 | ||
57 | /* | |
58 | * Check for uninit inode bitmaps and deal with them appropriately | |
59 | */ | |
03fa6f8a | 60 | static void check_inode_uninit(ext2_filsys fs, ext2fs_inode_bitmap map, |
c71d7813 TT |
61 | dgrp_t group) |
62 | { | |
03fa6f8a | 63 | ext2_ino_t i, ino; |
c71d7813 | 64 | |
3888c1e8 TT |
65 | if (group >= fs->group_desc_count || |
66 | !ext2fs_has_group_desc_csum(fs) || | |
cd65a24e | 67 | !(ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT))) |
c71d7813 TT |
68 | return; |
69 | ||
70 | ino = (group * fs->super->s_inodes_per_group) + 1; | |
71 | for (i=0; i < fs->super->s_inodes_per_group; i++, ino++) | |
8f82ef98 | 72 | ext2fs_fast_unmark_inode_bitmap2(map, ino); |
c71d7813 | 73 | |
e633b58a | 74 | ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT); |
dd9aa132 TT |
75 | /* Mimics what the kernel does */ |
76 | ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); | |
538eb878 TT |
77 | ext2fs_group_desc_csum_set(fs, group); |
78 | ext2fs_mark_ib_dirty(fs); | |
79 | ext2fs_mark_super_dirty(fs); | |
c71d7813 TT |
80 | } |
81 | ||
3839e657 TT |
82 | /* |
83 | * Right now, just search forward from the parent directory's block | |
84 | * group to find the next free inode. | |
85 | * | |
86 | * Should have a special policy for directories. | |
87 | */ | |
efc6f628 | 88 | errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, |
54434927 | 89 | int mode EXT2FS_ATTR((unused)), |
31dbecd4 | 90 | ext2fs_inode_bitmap map, ext2_ino_t *ret) |
3839e657 | 91 | { |
c1a1e7fc SL |
92 | ext2_ino_t start_inode = 0; |
93 | ext2_ino_t i, ino_in_group, upto, first_zero; | |
94 | errcode_t retval; | |
95 | dgrp_t group; | |
3839e657 | 96 | |
f3db3566 | 97 | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
efc6f628 | 98 | |
3839e657 TT |
99 | if (!map) |
100 | map = fs->inode_map; | |
101 | if (!map) | |
102 | return EXT2_ET_NO_INODE_BITMAP; | |
efc6f628 | 103 | |
c1a1e7fc SL |
104 | if (dir > 0) { |
105 | group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super); | |
106 | start_inode = (group * EXT2_INODES_PER_GROUP(fs->super)) + 1; | |
107 | } | |
7f88b043 TT |
108 | if (start_inode < EXT2_FIRST_INODE(fs->super)) |
109 | start_inode = EXT2_FIRST_INODE(fs->super); | |
a93d4069 TT |
110 | if (start_inode > fs->super->s_inodes_count) |
111 | return EXT2_ET_INODE_ALLOC_FAIL; | |
3839e657 | 112 | i = start_inode; |
3839e657 | 113 | do { |
c1a1e7fc SL |
114 | ino_in_group = (i - 1) % EXT2_INODES_PER_GROUP(fs->super); |
115 | group = (i - 1) / EXT2_INODES_PER_GROUP(fs->super); | |
116 | ||
117 | check_inode_uninit(fs, map, group); | |
118 | upto = i + (EXT2_INODES_PER_GROUP(fs->super) - ino_in_group); | |
119 | if (i < start_inode && upto >= start_inode) | |
120 | upto = start_inode - 1; | |
121 | if (upto > fs->super->s_inodes_count) | |
122 | upto = fs->super->s_inodes_count; | |
123 | ||
124 | retval = ext2fs_find_first_zero_inode_bitmap2(map, i, upto, | |
125 | &first_zero); | |
126 | if (retval == 0) { | |
127 | i = first_zero; | |
3839e657 | 128 | break; |
75556776 | 129 | } |
c1a1e7fc SL |
130 | if (retval != ENOENT) |
131 | return EXT2_ET_INODE_ALLOC_FAIL; | |
132 | i = upto + 1; | |
133 | if (i > fs->super->s_inodes_count) | |
134 | i = EXT2_FIRST_INODE(fs->super); | |
3839e657 | 135 | } while (i != start_inode); |
efc6f628 | 136 | |
8f82ef98 | 137 | if (ext2fs_test_inode_bitmap2(map, i)) |
1f0b6c1f | 138 | return EXT2_ET_INODE_ALLOC_FAIL; |
3839e657 TT |
139 | *ret = i; |
140 | return 0; | |
141 | } | |
142 | ||
143 | /* | |
144 | * Stupid algorithm --- we now just search forward starting from the | |
145 | * goal. Should put in a smarter one someday.... | |
146 | */ | |
3fc46996 AS |
147 | errcode_t ext2fs_new_block3(ext2_filsys fs, blk64_t goal, |
148 | ext2fs_block_bitmap map, blk64_t *ret, | |
149 | struct blk_alloc_ctx *ctx) | |
3839e657 | 150 | { |
424de6e8 | 151 | errcode_t retval; |
d8f401b1 | 152 | blk64_t b = 0; |
fae2467f | 153 | errcode_t (*gab)(ext2_filsys fs, blk64_t goal, blk64_t *ret); |
3fc46996 AS |
154 | errcode_t (*gab2)(ext2_filsys, blk64_t, blk64_t *, |
155 | struct blk_alloc_ctx *); | |
3839e657 | 156 | |
f3db3566 TT |
157 | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
158 | ||
3fc46996 | 159 | if (!map) { |
fae2467f DW |
160 | /* |
161 | * In case there are clients out there whose get_alloc_block | |
162 | * handlers call ext2fs_new_block2 with a NULL block map, | |
163 | * temporarily swap out the function pointer so that we don't | |
164 | * end up in an infinite loop. | |
165 | */ | |
3fc46996 AS |
166 | if (fs->get_alloc_block2) { |
167 | gab2 = fs->get_alloc_block2; | |
168 | fs->get_alloc_block2 = NULL; | |
169 | retval = gab2(fs, goal, &b, ctx); | |
170 | fs->get_alloc_block2 = gab2; | |
171 | goto allocated; | |
172 | } else if (fs->get_alloc_block) { | |
173 | gab = fs->get_alloc_block; | |
174 | fs->get_alloc_block = NULL; | |
175 | retval = gab(fs, goal, &b); | |
176 | fs->get_alloc_block = gab; | |
177 | goto allocated; | |
178 | } | |
fae2467f | 179 | } |
3839e657 TT |
180 | if (!map) |
181 | map = fs->block_map; | |
182 | if (!map) | |
183 | return EXT2_ET_NO_BLOCK_BITMAP; | |
4efbac6f | 184 | if (!goal || (goal >= ext2fs_blocks_count(fs->super))) |
a29f4d30 | 185 | goal = fs->super->s_first_data_block; |
424de6e8 TT |
186 | goal &= ~EXT2FS_CLUSTER_MASK(fs); |
187 | ||
188 | retval = ext2fs_find_first_zero_block_bitmap2(map, | |
189 | goal, ext2fs_blocks_count(fs->super) - 1, &b); | |
190 | if ((retval == ENOENT) && (goal != fs->super->s_first_data_block)) | |
191 | retval = ext2fs_find_first_zero_block_bitmap2(map, | |
192 | fs->super->s_first_data_block, goal - 1, &b); | |
fae2467f | 193 | allocated: |
424de6e8 TT |
194 | if (retval == ENOENT) |
195 | return EXT2_ET_BLOCK_ALLOC_FAIL; | |
196 | if (retval) | |
197 | return retval; | |
198 | ||
f3745728 | 199 | ext2fs_clear_block_uninit(fs, ext2fs_group_of_blk2(fs, b)); |
424de6e8 TT |
200 | *ret = b; |
201 | return 0; | |
c555aebd TT |
202 | } |
203 | ||
3fc46996 AS |
204 | errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal, |
205 | ext2fs_block_bitmap map, blk64_t *ret) | |
206 | { | |
207 | return ext2fs_new_block3(fs, goal, map, ret, NULL); | |
208 | } | |
209 | ||
8a5e1812 JS |
210 | errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal, |
211 | ext2fs_block_bitmap map, blk_t *ret) | |
212 | { | |
213 | errcode_t retval; | |
214 | blk64_t val; | |
215 | retval = ext2fs_new_block2(fs, goal, map, &val); | |
216 | if (!retval) | |
217 | *ret = (blk_t) val; | |
218 | return retval; | |
219 | } | |
220 | ||
c555aebd | 221 | /* |
30fab293 TT |
222 | * This function zeros out the allocated block, and updates all of the |
223 | * appropriate filesystem records. | |
c555aebd | 224 | */ |
3fc46996 AS |
225 | errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal, char *block_buf, |
226 | blk64_t *ret, struct blk_alloc_ctx *ctx) | |
c555aebd TT |
227 | { |
228 | errcode_t retval; | |
8a5e1812 | 229 | blk64_t block; |
30fab293 | 230 | |
3fc46996 AS |
231 | if (fs->get_alloc_block2) { |
232 | retval = (fs->get_alloc_block2)(fs, goal, &block, ctx); | |
233 | if (retval) | |
234 | goto fail; | |
235 | } else if (fs->get_alloc_block) { | |
8a5e1812 | 236 | retval = (fs->get_alloc_block)(fs, goal, &block); |
30fab293 TT |
237 | if (retval) |
238 | goto fail; | |
f5c562e2 TT |
239 | } else { |
240 | if (!fs->block_map) { | |
241 | retval = ext2fs_read_block_bitmap(fs); | |
242 | if (retval) | |
243 | goto fail; | |
244 | } | |
30fab293 | 245 | |
3fc46996 | 246 | retval = ext2fs_new_block3(fs, goal, 0, &block, ctx); |
f5c562e2 TT |
247 | if (retval) |
248 | goto fail; | |
249 | } | |
c555aebd | 250 | |
bc57b123 TT |
251 | if (block_buf) { |
252 | memset(block_buf, 0, fs->blocksize); | |
253 | retval = io_channel_write_blk64(fs->io, block, 1, block_buf); | |
254 | } else | |
255 | retval = ext2fs_zero_blocks2(fs, block, 1, NULL, NULL); | |
c555aebd | 256 | if (retval) |
30fab293 | 257 | goto fail; |
efc6f628 | 258 | |
8a5e1812 | 259 | ext2fs_block_alloc_stats2(fs, block, +1); |
30fab293 | 260 | *ret = block; |
30fab293 TT |
261 | |
262 | fail: | |
30fab293 | 263 | return retval; |
3839e657 TT |
264 | } |
265 | ||
3fc46996 AS |
266 | errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal, |
267 | char *block_buf, blk64_t *ret) | |
268 | { | |
269 | return ext2fs_alloc_block3(fs, goal, block_buf, ret, NULL); | |
270 | } | |
271 | ||
8a5e1812 JS |
272 | errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, |
273 | char *block_buf, blk_t *ret) | |
274 | { | |
275 | errcode_t retval; | |
3fc46996 AS |
276 | blk64_t ret64, goal64 = goal; |
277 | retval = ext2fs_alloc_block3(fs, goal64, block_buf, &ret64, NULL); | |
8a5e1812 | 278 | if (!retval) |
3fc46996 AS |
279 | *ret = (blk_t)ret64; |
280 | return retval; | |
8a5e1812 JS |
281 | } |
282 | ||
283 | errcode_t ext2fs_get_free_blocks2(ext2_filsys fs, blk64_t start, blk64_t finish, | |
284 | int num, ext2fs_block_bitmap map, blk64_t *ret) | |
3839e657 | 285 | { |
96367ad3 | 286 | blk64_t b = start; |
b0ecb787 | 287 | int c_ratio; |
3839e657 | 288 | |
f3db3566 TT |
289 | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); |
290 | ||
3839e657 TT |
291 | if (!map) |
292 | map = fs->block_map; | |
293 | if (!map) | |
294 | return EXT2_ET_NO_BLOCK_BITMAP; | |
295 | if (!b) | |
296 | b = fs->super->s_first_data_block; | |
297 | if (!finish) | |
298 | finish = start; | |
299 | if (!num) | |
300 | num = 1; | |
b0ecb787 TT |
301 | c_ratio = 1 << ext2fs_get_bitmap_granularity(map); |
302 | b &= ~(c_ratio - 1); | |
303 | finish &= ~(c_ratio -1); | |
3839e657 | 304 | do { |
203e13cf DW |
305 | if (b + num - 1 >= ext2fs_blocks_count(fs->super)) { |
306 | if (finish > start) | |
307 | return EXT2_ET_BLOCK_ALLOC_FAIL; | |
21c84b71 | 308 | b = fs->super->s_first_data_block; |
203e13cf | 309 | } |
8f82ef98 | 310 | if (ext2fs_fast_test_block_bitmap_range2(map, b, num)) { |
3839e657 TT |
311 | *ret = b; |
312 | return 0; | |
313 | } | |
b0ecb787 | 314 | b += c_ratio; |
3839e657 | 315 | } while (b != finish); |
1f0b6c1f | 316 | return EXT2_ET_BLOCK_ALLOC_FAIL; |
3839e657 TT |
317 | } |
318 | ||
8a5e1812 JS |
319 | errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish, |
320 | int num, ext2fs_block_bitmap map, blk_t *ret) | |
321 | { | |
322 | errcode_t retval; | |
323 | blk64_t val; | |
324 | retval = ext2fs_get_free_blocks2(fs, start, finish, num, map, &val); | |
325 | if(!retval) | |
326 | *ret = (blk_t) val; | |
327 | return retval; | |
328 | } | |
329 | ||
efc6f628 | 330 | void ext2fs_set_alloc_block_callback(ext2_filsys fs, |
f5c562e2 TT |
331 | errcode_t (*func)(ext2_filsys fs, |
332 | blk64_t goal, | |
333 | blk64_t *ret), | |
334 | errcode_t (**old)(ext2_filsys fs, | |
335 | blk64_t goal, | |
336 | blk64_t *ret)) | |
337 | { | |
338 | if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) | |
339 | return; | |
340 | ||
341 | if (old) | |
342 | *old = fs->get_alloc_block; | |
343 | ||
344 | fs->get_alloc_block = func; | |
345 | } | |
7b486ec0 DW |
346 | |
347 | blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino, | |
348 | struct ext2_inode *inode, blk64_t lblk) | |
349 | { | |
350 | dgrp_t group; | |
351 | __u8 log_flex; | |
352 | struct ext2fs_extent extent; | |
353 | ext2_extent_handle_t handle = NULL; | |
354 | errcode_t err; | |
355 | ||
cf0be234 TE |
356 | /* Make sure data stored in inode->i_block is neither fast symlink nor |
357 | * inline data. | |
358 | */ | |
359 | if (inode == NULL || ext2fs_is_fast_symlink(inode) || | |
360 | inode->i_flags & EXT4_INLINE_DATA_FL) | |
7b486ec0 DW |
361 | goto no_blocks; |
362 | ||
363 | if (inode->i_flags & EXT4_EXTENTS_FL) { | |
364 | err = ext2fs_extent_open2(fs, ino, inode, &handle); | |
365 | if (err) | |
366 | goto no_blocks; | |
367 | err = ext2fs_extent_goto2(handle, 0, lblk); | |
368 | if (err) | |
369 | goto no_blocks; | |
370 | err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); | |
371 | if (err) | |
372 | goto no_blocks; | |
373 | ext2fs_extent_free(handle); | |
374 | return extent.e_pblk + (lblk - extent.e_lblk); | |
375 | } | |
376 | ||
377 | /* block mapped file; see if block zero is mapped? */ | |
378 | if (inode->i_block[0]) | |
379 | return inode->i_block[0]; | |
380 | ||
381 | no_blocks: | |
382 | ext2fs_extent_free(handle); | |
383 | log_flex = fs->super->s_log_groups_per_flex; | |
384 | group = ext2fs_group_of_ino(fs, ino); | |
385 | if (log_flex) | |
386 | group = group & ~((1 << (log_flex)) - 1); | |
387 | return ext2fs_group_first_block2(fs, group); | |
388 | } | |
5a980264 DW |
389 | |
390 | /* | |
391 | * Starting at _goal_, scan around the filesystem to find a run of free blocks | |
392 | * that's at least _len_ blocks long. Possible flags: | |
393 | * - EXT2_NEWRANGE_EXACT_GOAL: The range of blocks must start at _goal_. | |
394 | * - EXT2_NEWRANGE_MIN_LENGTH: do not return a allocation shorter than _len_. | |
395 | * - EXT2_NEWRANGE_ZERO_BLOCKS: Zero blocks pblk to pblk+plen before returning. | |
396 | * | |
397 | * The starting block is returned in _pblk_ and the length is returned via | |
398 | * _plen_. The blocks are not marked in the bitmap; the caller must mark | |
399 | * however much of the returned run they actually use, hopefully via | |
400 | * ext2fs_block_alloc_stats_range(). | |
401 | * | |
402 | * This function can return a range that is longer than what was requested. | |
403 | */ | |
404 | errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal, | |
405 | blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk, | |
406 | blk64_t *plen) | |
407 | { | |
408 | errcode_t retval; | |
409 | blk64_t start, end, b; | |
410 | int looped = 0; | |
411 | blk64_t max_blocks = ext2fs_blocks_count(fs->super); | |
647e8786 DW |
412 | errcode_t (*nrf)(ext2_filsys fs, int flags, blk64_t goal, |
413 | blk64_t len, blk64_t *pblk, blk64_t *plen); | |
5a980264 DW |
414 | |
415 | dbg_printf("%s: flags=0x%x goal=%llu len=%llu\n", __func__, flags, | |
416 | goal, len); | |
417 | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | |
418 | if (len == 0 || (flags & ~EXT2_NEWRANGE_ALL_FLAGS)) | |
419 | return EXT2_ET_INVALID_ARGUMENT; | |
647e8786 DW |
420 | |
421 | if (!map && fs->new_range) { | |
422 | /* | |
423 | * In case there are clients out there whose new_range | |
424 | * handlers call ext2fs_new_range with a NULL block map, | |
425 | * temporarily swap out the function pointer so that we don't | |
426 | * end up in an infinite loop. | |
427 | */ | |
428 | nrf = fs->new_range; | |
429 | fs->new_range = NULL; | |
430 | retval = nrf(fs, flags, goal, len, pblk, plen); | |
431 | fs->new_range = nrf; | |
432 | if (retval) | |
433 | return retval; | |
434 | start = *pblk; | |
435 | end = *pblk + *plen; | |
436 | goto allocated; | |
437 | } | |
5a980264 DW |
438 | if (!map) |
439 | map = fs->block_map; | |
440 | if (!map) | |
441 | return EXT2_ET_NO_BLOCK_BITMAP; | |
442 | if (!goal || goal >= ext2fs_blocks_count(fs->super)) | |
443 | goal = fs->super->s_first_data_block; | |
444 | ||
445 | start = goal; | |
446 | while (!looped || start <= goal) { | |
447 | retval = ext2fs_find_first_zero_block_bitmap2(map, start, | |
448 | max_blocks - 1, | |
449 | &start); | |
450 | if (retval == ENOENT) { | |
451 | /* | |
452 | * If there are no free blocks beyond the starting | |
453 | * point, try scanning the whole filesystem, unless the | |
454 | * user told us only to allocate from _goal_, or if | |
455 | * we're already scanning the whole filesystem. | |
456 | */ | |
457 | if (flags & EXT2_NEWRANGE_FIXED_GOAL || | |
458 | start == fs->super->s_first_data_block) | |
459 | goto fail; | |
460 | start = fs->super->s_first_data_block; | |
461 | continue; | |
462 | } else if (retval) | |
463 | goto errout; | |
464 | ||
465 | if (flags & EXT2_NEWRANGE_FIXED_GOAL && start != goal) | |
466 | goto fail; | |
467 | ||
468 | b = min(start + len - 1, max_blocks - 1); | |
469 | retval = ext2fs_find_first_set_block_bitmap2(map, start, b, | |
470 | &end); | |
471 | if (retval == ENOENT) | |
472 | end = b + 1; | |
473 | else if (retval) | |
474 | goto errout; | |
475 | ||
476 | if (!(flags & EXT2_NEWRANGE_MIN_LENGTH) || | |
477 | (end - start) >= len) { | |
478 | /* Success! */ | |
479 | *pblk = start; | |
480 | *plen = end - start; | |
481 | dbg_printf("%s: new_range goal=%llu--%llu " | |
482 | "blk=%llu--%llu %llu\n", | |
483 | __func__, goal, goal + len - 1, | |
484 | *pblk, *pblk + *plen - 1, *plen); | |
647e8786 | 485 | allocated: |
5a980264 DW |
486 | for (b = start; b < end; |
487 | b += fs->super->s_blocks_per_group) | |
f3745728 | 488 | ext2fs_clear_block_uninit(fs, |
5a980264 DW |
489 | ext2fs_group_of_blk2(fs, b)); |
490 | return 0; | |
491 | } | |
492 | ||
493 | if (flags & EXT2_NEWRANGE_FIXED_GOAL) | |
494 | goto fail; | |
495 | start = end; | |
496 | if (start >= max_blocks) { | |
497 | if (looped) | |
498 | goto fail; | |
499 | looped = 1; | |
500 | start = fs->super->s_first_data_block; | |
501 | } | |
502 | } | |
503 | ||
504 | fail: | |
505 | retval = EXT2_ET_BLOCK_ALLOC_FAIL; | |
506 | errout: | |
507 | return retval; | |
508 | } | |
509 | ||
647e8786 DW |
510 | void ext2fs_set_new_range_callback(ext2_filsys fs, |
511 | errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal, | |
512 | blk64_t len, blk64_t *pblk, blk64_t *plen), | |
513 | errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal, | |
514 | blk64_t len, blk64_t *pblk, blk64_t *plen)) | |
515 | { | |
516 | if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) | |
517 | return; | |
518 | ||
519 | if (old) | |
520 | *old = fs->new_range; | |
521 | ||
522 | fs->new_range = func; | |
523 | } | |
524 | ||
5a980264 DW |
525 | errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal, |
526 | blk_t len, blk64_t *ret) | |
527 | { | |
528 | int newr_flags = EXT2_NEWRANGE_MIN_LENGTH; | |
529 | errcode_t retval; | |
530 | blk64_t plen; | |
531 | ||
532 | EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); | |
533 | if (len == 0 || (flags & ~EXT2_ALLOCRANGE_ALL_FLAGS)) | |
534 | return EXT2_ET_INVALID_ARGUMENT; | |
535 | ||
536 | if (flags & EXT2_ALLOCRANGE_FIXED_GOAL) | |
537 | newr_flags |= EXT2_NEWRANGE_FIXED_GOAL; | |
538 | ||
539 | retval = ext2fs_new_range(fs, newr_flags, goal, len, NULL, ret, &plen); | |
540 | if (retval) | |
541 | return retval; | |
542 | ||
543 | if (plen < len) | |
544 | return EXT2_ET_BLOCK_ALLOC_FAIL; | |
545 | ||
546 | if (flags & EXT2_ALLOCRANGE_ZERO_BLOCKS) { | |
547 | retval = ext2fs_zero_blocks2(fs, *ret, len, NULL, NULL); | |
548 | if (retval) | |
549 | return retval; | |
550 | } | |
551 | ||
552 | ext2fs_block_alloc_stats_range(fs, *ret, len, +1); | |
553 | return retval; | |
554 | } |