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