1 /* 2 * alloc.c --- allocate new inodes, blocks for ext2fs 3 * 4 * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Library 8 * General Public License, version 2. 9 * %End-Header% 10 */ 11 12 #include "config.h" 13 #include <stdio.h> 14 #if HAVE_UNISTD_H 15 #include <unistd.h> 16 #endif 17 #include <time.h> 18 #include <string.h> 19 #if HAVE_SYS_STAT_H 20 #include <sys/stat.h> 21 #endif 22 #if HAVE_SYS_TYPES_H 23 #include <sys/types.h> 24 #endif 25 26 #include "ext2_fs.h" 27 #include "ext2fs.h" 28 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 39 /* 40 * Clear the uninit block bitmap flag if necessary 41 */ 42 void ext2fs_clear_block_uninit(ext2_filsys fs, dgrp_t group) 43 { 44 if (group >= fs->group_desc_count || 45 !ext2fs_has_group_desc_csum(fs) || 46 !(ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT))) 47 return; 48 49 /* uninit block bitmaps are now initialized in read_bitmaps() */ 50 51 ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); 52 ext2fs_group_desc_csum_set(fs, group); 53 ext2fs_mark_super_dirty(fs); 54 ext2fs_mark_bb_dirty(fs); 55 } 56 57 /* 58 * Check for uninit inode bitmaps and deal with them appropriately 59 */ 60 static void check_inode_uninit(ext2_filsys fs, ext2fs_inode_bitmap map, 61 dgrp_t group) 62 { 63 ext2_ino_t i, ino; 64 65 if (group >= fs->group_desc_count || 66 !ext2fs_has_group_desc_csum(fs) || 67 !(ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT))) 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++) 72 ext2fs_fast_unmark_inode_bitmap2(map, ino); 73 74 ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT); 75 /* Mimics what the kernel does */ 76 ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); 77 ext2fs_group_desc_csum_set(fs, group); 78 ext2fs_mark_ib_dirty(fs); 79 ext2fs_mark_super_dirty(fs); 80 } 81 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 */ 88 errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, 89 int mode EXT2FS_ATTR((unused)), 90 ext2fs_inode_bitmap map, ext2_ino_t *ret) 91 { 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; 96 97 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 98 99 if (!map) 100 map = fs->inode_map; 101 if (!map) 102 return EXT2_ET_NO_INODE_BITMAP; 103 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 } 108 if (start_inode < EXT2_FIRST_INODE(fs->super)) 109 start_inode = EXT2_FIRST_INODE(fs->super); 110 if (start_inode > fs->super->s_inodes_count) 111 return EXT2_ET_INODE_ALLOC_FAIL; 112 i = start_inode; 113 do { 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; 128 break; 129 } 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); 135 } while (i != start_inode); 136 137 if (ext2fs_test_inode_bitmap2(map, i)) 138 return EXT2_ET_INODE_ALLOC_FAIL; 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 */ 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) 150 { 151 errcode_t retval; 152 blk64_t b = 0; 153 errcode_t (*gab)(ext2_filsys fs, blk64_t goal, blk64_t *ret); 154 errcode_t (*gab2)(ext2_filsys, blk64_t, blk64_t *, 155 struct blk_alloc_ctx *); 156 157 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 158 159 if (!map) { 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 */ 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 } 179 } 180 if (!map) 181 map = fs->block_map; 182 if (!map) 183 return EXT2_ET_NO_BLOCK_BITMAP; 184 if (!goal || (goal >= ext2fs_blocks_count(fs->super))) 185 goal = fs->super->s_first_data_block; 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); 193 allocated: 194 if (retval == ENOENT) 195 return EXT2_ET_BLOCK_ALLOC_FAIL; 196 if (retval) 197 return retval; 198 199 ext2fs_clear_block_uninit(fs, ext2fs_group_of_blk2(fs, b)); 200 *ret = b; 201 return 0; 202 } 203 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 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 221 /* 222 * This function zeros out the allocated block, and updates all of the 223 * appropriate filesystem records. 224 */ 225 errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal, char *block_buf, 226 blk64_t *ret, struct blk_alloc_ctx *ctx) 227 { 228 errcode_t retval; 229 blk64_t block; 230 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) { 236 retval = (fs->get_alloc_block)(fs, goal, &block); 237 if (retval) 238 goto fail; 239 } else { 240 if (!fs->block_map) { 241 retval = ext2fs_read_block_bitmap(fs); 242 if (retval) 243 goto fail; 244 } 245 246 retval = ext2fs_new_block3(fs, goal, 0, &block, ctx); 247 if (retval) 248 goto fail; 249 } 250 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); 256 if (retval) 257 goto fail; 258 259 ext2fs_block_alloc_stats2(fs, block, +1); 260 *ret = block; 261 262 fail: 263 return retval; 264 } 265 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 272 errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, 273 char *block_buf, blk_t *ret) 274 { 275 errcode_t retval; 276 blk64_t ret64, goal64 = goal; 277 retval = ext2fs_alloc_block3(fs, goal64, block_buf, &ret64, NULL); 278 if (!retval) 279 *ret = (blk_t)ret64; 280 return retval; 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) 285 { 286 blk64_t b = start; 287 int c_ratio; 288 289 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 290 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; 301 c_ratio = 1 << ext2fs_get_bitmap_granularity(map); 302 b &= ~(c_ratio - 1); 303 finish &= ~(c_ratio -1); 304 do { 305 if (b + num - 1 >= ext2fs_blocks_count(fs->super)) { 306 if (finish > start) 307 return EXT2_ET_BLOCK_ALLOC_FAIL; 308 b = fs->super->s_first_data_block; 309 } 310 if (ext2fs_fast_test_block_bitmap_range2(map, b, num)) { 311 *ret = b; 312 return 0; 313 } 314 b += c_ratio; 315 } while (b != finish); 316 return EXT2_ET_BLOCK_ALLOC_FAIL; 317 } 318 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 330 void ext2fs_set_alloc_block_callback(ext2_filsys fs, 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 } 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 356 if (inode == NULL || ext2fs_inode_data_blocks2(fs, inode) == 0) 357 goto no_blocks; 358 359 if (inode->i_flags & EXT4_INLINE_DATA_FL) 360 goto no_blocks; 361 362 if (inode->i_flags & EXT4_EXTENTS_FL) { 363 err = ext2fs_extent_open2(fs, ino, inode, &handle); 364 if (err) 365 goto no_blocks; 366 err = ext2fs_extent_goto2(handle, 0, lblk); 367 if (err) 368 goto no_blocks; 369 err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); 370 if (err) 371 goto no_blocks; 372 ext2fs_extent_free(handle); 373 return extent.e_pblk + (lblk - extent.e_lblk); 374 } 375 376 /* block mapped file; see if block zero is mapped? */ 377 if (inode->i_block[0]) 378 return inode->i_block[0]; 379 380 no_blocks: 381 ext2fs_extent_free(handle); 382 log_flex = fs->super->s_log_groups_per_flex; 383 group = ext2fs_group_of_ino(fs, ino); 384 if (log_flex) 385 group = group & ~((1 << (log_flex)) - 1); 386 return ext2fs_group_first_block2(fs, group); 387 } 388 389 /* 390 * Starting at _goal_, scan around the filesystem to find a run of free blocks 391 * that's at least _len_ blocks long. Possible flags: 392 * - EXT2_NEWRANGE_EXACT_GOAL: The range of blocks must start at _goal_. 393 * - EXT2_NEWRANGE_MIN_LENGTH: do not return a allocation shorter than _len_. 394 * - EXT2_NEWRANGE_ZERO_BLOCKS: Zero blocks pblk to pblk+plen before returning. 395 * 396 * The starting block is returned in _pblk_ and the length is returned via 397 * _plen_. The blocks are not marked in the bitmap; the caller must mark 398 * however much of the returned run they actually use, hopefully via 399 * ext2fs_block_alloc_stats_range(). 400 * 401 * This function can return a range that is longer than what was requested. 402 */ 403 errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal, 404 blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk, 405 blk64_t *plen) 406 { 407 errcode_t retval; 408 blk64_t start, end, b; 409 int looped = 0; 410 blk64_t max_blocks = ext2fs_blocks_count(fs->super); 411 errcode_t (*nrf)(ext2_filsys fs, int flags, blk64_t goal, 412 blk64_t len, blk64_t *pblk, blk64_t *plen); 413 414 dbg_printf("%s: flags=0x%x goal=%llu len=%llu\n", __func__, flags, 415 goal, len); 416 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 417 if (len == 0 || (flags & ~EXT2_NEWRANGE_ALL_FLAGS)) 418 return EXT2_ET_INVALID_ARGUMENT; 419 420 if (!map && fs->new_range) { 421 /* 422 * In case there are clients out there whose new_range 423 * handlers call ext2fs_new_range with a NULL block map, 424 * temporarily swap out the function pointer so that we don't 425 * end up in an infinite loop. 426 */ 427 nrf = fs->new_range; 428 fs->new_range = NULL; 429 retval = nrf(fs, flags, goal, len, pblk, plen); 430 fs->new_range = nrf; 431 if (retval) 432 return retval; 433 start = *pblk; 434 end = *pblk + *plen; 435 goto allocated; 436 } 437 if (!map) 438 map = fs->block_map; 439 if (!map) 440 return EXT2_ET_NO_BLOCK_BITMAP; 441 if (!goal || goal >= ext2fs_blocks_count(fs->super)) 442 goal = fs->super->s_first_data_block; 443 444 start = goal; 445 while (!looped || start <= goal) { 446 retval = ext2fs_find_first_zero_block_bitmap2(map, start, 447 max_blocks - 1, 448 &start); 449 if (retval == ENOENT) { 450 /* 451 * If there are no free blocks beyond the starting 452 * point, try scanning the whole filesystem, unless the 453 * user told us only to allocate from _goal_, or if 454 * we're already scanning the whole filesystem. 455 */ 456 if (flags & EXT2_NEWRANGE_FIXED_GOAL || 457 start == fs->super->s_first_data_block) 458 goto fail; 459 start = fs->super->s_first_data_block; 460 continue; 461 } else if (retval) 462 goto errout; 463 464 if (flags & EXT2_NEWRANGE_FIXED_GOAL && start != goal) 465 goto fail; 466 467 b = min(start + len - 1, max_blocks - 1); 468 retval = ext2fs_find_first_set_block_bitmap2(map, start, b, 469 &end); 470 if (retval == ENOENT) 471 end = b + 1; 472 else if (retval) 473 goto errout; 474 475 if (!(flags & EXT2_NEWRANGE_MIN_LENGTH) || 476 (end - start) >= len) { 477 /* Success! */ 478 *pblk = start; 479 *plen = end - start; 480 dbg_printf("%s: new_range goal=%llu--%llu " 481 "blk=%llu--%llu %llu\n", 482 __func__, goal, goal + len - 1, 483 *pblk, *pblk + *plen - 1, *plen); 484 allocated: 485 for (b = start; b < end; 486 b += fs->super->s_blocks_per_group) 487 ext2fs_clear_block_uninit(fs, 488 ext2fs_group_of_blk2(fs, b)); 489 return 0; 490 } 491 492 if (flags & EXT2_NEWRANGE_FIXED_GOAL) 493 goto fail; 494 start = end; 495 if (start >= max_blocks) { 496 if (looped) 497 goto fail; 498 looped = 1; 499 start = fs->super->s_first_data_block; 500 } 501 } 502 503 fail: 504 retval = EXT2_ET_BLOCK_ALLOC_FAIL; 505 errout: 506 return retval; 507 } 508 509 void ext2fs_set_new_range_callback(ext2_filsys fs, 510 errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal, 511 blk64_t len, blk64_t *pblk, blk64_t *plen), 512 errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal, 513 blk64_t len, blk64_t *pblk, blk64_t *plen)) 514 { 515 if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) 516 return; 517 518 if (old) 519 *old = fs->new_range; 520 521 fs->new_range = func; 522 } 523 524 errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal, 525 blk_t len, blk64_t *ret) 526 { 527 int newr_flags = EXT2_NEWRANGE_MIN_LENGTH; 528 errcode_t retval; 529 blk64_t plen; 530 531 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 532 if (len == 0 || (flags & ~EXT2_ALLOCRANGE_ALL_FLAGS)) 533 return EXT2_ET_INVALID_ARGUMENT; 534 535 if (flags & EXT2_ALLOCRANGE_FIXED_GOAL) 536 newr_flags |= EXT2_NEWRANGE_FIXED_GOAL; 537 538 retval = ext2fs_new_range(fs, newr_flags, goal, len, NULL, ret, &plen); 539 if (retval) 540 return retval; 541 542 if (plen < len) 543 return EXT2_ET_BLOCK_ALLOC_FAIL; 544 545 if (flags & EXT2_ALLOCRANGE_ZERO_BLOCKS) { 546 retval = ext2fs_zero_blocks2(fs, *ret, len, NULL, NULL); 547 if (retval) 548 return retval; 549 } 550 551 ext2fs_block_alloc_stats_range(fs, *ret, len, +1); 552 return retval; 553 } 554