]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - lib/ext2fs/alloc.c
resize2fs: clear uninit BG if allocating from new group
[thirdparty/e2fsprogs.git] / lib / ext2fs / alloc.c
CommitLineData
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 42void 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 59static 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 86errcode_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
145errcode_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 180allocated:
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
191errcode_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
206errcode_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
239fail:
30fab293 240 return retval;
3839e657
TT
241}
242
8a5e1812
JS
243errcode_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
254errcode_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
290errcode_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 301void 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
318blk64_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
351no_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 */
374errcode_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 455allocated:
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
474fail:
475 retval = EXT2_ET_BLOCK_ALLOC_FAIL;
476errout:
477 return retval;
478}
479
647e8786
DW
480void 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
495errcode_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}