alloc.c revision b0ecb787ef9fde414791b644fa074450b28d4060
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 <stdio.h> 13#if HAVE_UNISTD_H 14#include <unistd.h> 15#endif 16#include <time.h> 17#include <string.h> 18#if HAVE_SYS_STAT_H 19#include <sys/stat.h> 20#endif 21#if HAVE_SYS_TYPES_H 22#include <sys/types.h> 23#endif 24 25#include "ext2_fs.h" 26#include "ext2fs.h" 27 28/* 29 * Check for uninit block bitmaps and deal with them appropriately 30 */ 31static void check_block_uninit(ext2_filsys fs, ext2fs_block_bitmap map, 32 dgrp_t group) 33{ 34 blk_t i; 35 blk64_t blk, super_blk, old_desc_blk, new_desc_blk; 36 int old_desc_blocks; 37 38 if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super, 39 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) || 40 !(ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT))) 41 return; 42 43 blk = (group * fs->super->s_blocks_per_group) + 44 fs->super->s_first_data_block; 45 46 ext2fs_super_and_bgd_loc2(fs, group, &super_blk, 47 &old_desc_blk, &new_desc_blk, 0); 48 49 if (fs->super->s_feature_incompat & 50 EXT2_FEATURE_INCOMPAT_META_BG) 51 old_desc_blocks = fs->super->s_first_meta_bg; 52 else 53 old_desc_blocks = fs->desc_blocks + fs->super->s_reserved_gdt_blocks; 54 55 for (i=0; i < fs->super->s_blocks_per_group; i++, blk++) 56 ext2fs_fast_unmark_block_bitmap2(map, blk); 57 58 for (i=0; i < fs->super->s_blocks_per_group; i++, blk++) { 59 if ((blk == super_blk) || 60 (old_desc_blk && old_desc_blocks && 61 (blk >= old_desc_blk) && 62 (blk < old_desc_blk + old_desc_blocks)) || 63 (new_desc_blk && (blk == new_desc_blk)) || 64 (blk == ext2fs_block_bitmap_loc(fs, group)) || 65 (blk == ext2fs_inode_bitmap_loc(fs, group)) || 66 (blk >= ext2fs_inode_table_loc(fs, group) && 67 (blk < ext2fs_inode_table_loc(fs, group) 68 + fs->inode_blocks_per_group))) 69 ext2fs_fast_mark_block_bitmap2(map, blk); 70 } 71 ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); 72 ext2fs_group_desc_csum_set(fs, group); 73} 74 75/* 76 * Check for uninit inode bitmaps and deal with them appropriately 77 */ 78static void check_inode_uninit(ext2_filsys fs, ext2fs_inode_bitmap map, 79 dgrp_t group) 80{ 81 ext2_ino_t i, ino; 82 83 if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super, 84 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) || 85 !(ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT))) 86 return; 87 88 ino = (group * fs->super->s_inodes_per_group) + 1; 89 for (i=0; i < fs->super->s_inodes_per_group; i++, ino++) 90 ext2fs_fast_unmark_inode_bitmap2(map, ino); 91 92 ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT); 93 check_block_uninit(fs, fs->block_map, group); 94} 95 96/* 97 * Right now, just search forward from the parent directory's block 98 * group to find the next free inode. 99 * 100 * Should have a special policy for directories. 101 */ 102errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, 103 int mode EXT2FS_ATTR((unused)), 104 ext2fs_inode_bitmap map, ext2_ino_t *ret) 105{ 106 ext2_ino_t dir_group = 0; 107 ext2_ino_t i; 108 ext2_ino_t start_inode; 109 110 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 111 112 if (!map) 113 map = fs->inode_map; 114 if (!map) 115 return EXT2_ET_NO_INODE_BITMAP; 116 117 if (dir > 0) 118 dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super); 119 120 start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->super)) + 1; 121 if (start_inode < EXT2_FIRST_INODE(fs->super)) 122 start_inode = EXT2_FIRST_INODE(fs->super); 123 if (start_inode > fs->super->s_inodes_count) 124 return EXT2_ET_INODE_ALLOC_FAIL; 125 i = start_inode; 126 127 do { 128 if (((i - 1) % EXT2_INODES_PER_GROUP(fs->super)) == 0) 129 check_inode_uninit(fs, map, (i - 1) / 130 EXT2_INODES_PER_GROUP(fs->super)); 131 132 if (!ext2fs_fast_test_inode_bitmap2(map, i)) 133 break; 134 i++; 135 if (i > fs->super->s_inodes_count) 136 i = EXT2_FIRST_INODE(fs->super); 137 } while (i != start_inode); 138 139 if (ext2fs_test_inode_bitmap2(map, i)) 140 return EXT2_ET_INODE_ALLOC_FAIL; 141 *ret = i; 142 return 0; 143} 144 145/* 146 * Stupid algorithm --- we now just search forward starting from the 147 * goal. Should put in a smarter one someday.... 148 */ 149errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal, 150 ext2fs_block_bitmap map, blk64_t *ret) 151{ 152 blk64_t i; 153 int c_ratio; 154 155 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 156 157 if (!map) 158 map = fs->block_map; 159 if (!map) 160 return EXT2_ET_NO_BLOCK_BITMAP; 161 if (!goal || (goal >= ext2fs_blocks_count(fs->super))) 162 goal = fs->super->s_first_data_block; 163 i = goal; 164 c_ratio = 1 << ext2fs_get_bitmap_granularity(map); 165 check_block_uninit(fs, map, 166 (i - fs->super->s_first_data_block) / 167 EXT2_BLOCKS_PER_GROUP(fs->super)); 168 do { 169 if (((i - fs->super->s_first_data_block) % 170 EXT2_BLOCKS_PER_GROUP(fs->super)) == 0) 171 check_block_uninit(fs, map, 172 (i - fs->super->s_first_data_block) / 173 EXT2_BLOCKS_PER_GROUP(fs->super)); 174 175 if (!ext2fs_fast_test_block_bitmap2(map, i)) { 176 *ret = i; 177 return 0; 178 } 179 i = (i + c_ratio) & ~(c_ratio - 1); 180 if (i >= ext2fs_blocks_count(fs->super)) 181 i = fs->super->s_first_data_block; 182 } while (i != goal); 183 return EXT2_ET_BLOCK_ALLOC_FAIL; 184} 185 186errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal, 187 ext2fs_block_bitmap map, blk_t *ret) 188{ 189 errcode_t retval; 190 blk64_t val; 191 retval = ext2fs_new_block2(fs, goal, map, &val); 192 if (!retval) 193 *ret = (blk_t) val; 194 return retval; 195} 196 197/* 198 * This function zeros out the allocated block, and updates all of the 199 * appropriate filesystem records. 200 */ 201errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal, 202 char *block_buf, blk64_t *ret) 203{ 204 errcode_t retval; 205 blk64_t block; 206 char *buf = 0; 207 208 if (!block_buf) { 209 retval = ext2fs_get_mem(fs->blocksize, &buf); 210 if (retval) 211 return retval; 212 block_buf = buf; 213 } 214 memset(block_buf, 0, fs->blocksize); 215 216 if (fs->get_alloc_block) { 217 retval = (fs->get_alloc_block)(fs, goal, &block); 218 if (retval) 219 goto fail; 220 } else { 221 if (!fs->block_map) { 222 retval = ext2fs_read_block_bitmap(fs); 223 if (retval) 224 goto fail; 225 } 226 227 retval = ext2fs_new_block2(fs, goal, 0, &block); 228 if (retval) 229 goto fail; 230 } 231 232 retval = io_channel_write_blk64(fs->io, block, 1, block_buf); 233 if (retval) 234 goto fail; 235 236 ext2fs_block_alloc_stats2(fs, block, +1); 237 *ret = block; 238 239fail: 240 if (buf) 241 ext2fs_free_mem(&buf); 242 return retval; 243} 244 245errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, 246 char *block_buf, blk_t *ret) 247{ 248 errcode_t retval; 249 blk64_t val; 250 retval = ext2fs_alloc_block2(fs, goal, block_buf, &val); 251 if (!retval) 252 *ret = (blk_t) val; 253 return retval; 254} 255 256errcode_t ext2fs_get_free_blocks2(ext2_filsys fs, blk64_t start, blk64_t finish, 257 int num, ext2fs_block_bitmap map, blk64_t *ret) 258{ 259 blk64_t b = start, c = 0; 260 int c_ratio; 261 262 EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); 263 264 if (!map) 265 map = fs->block_map; 266 if (!map) 267 return EXT2_ET_NO_BLOCK_BITMAP; 268 if (!b) 269 b = fs->super->s_first_data_block; 270 if (!finish) 271 finish = start; 272 if (!num) 273 num = 1; 274 c_ratio = 1 << ext2fs_get_bitmap_granularity(map); 275 b &= ~(c_ratio - 1); 276 finish &= ~(c_ratio -1); 277 do { 278 if (b+num-1 > ext2fs_blocks_count(fs->super)) 279 b = fs->super->s_first_data_block; 280 if (ext2fs_fast_test_block_bitmap_range2(map, b, num)) { 281 *ret = b; 282 return 0; 283 } 284 b += c_ratio; 285 } while (b != finish); 286 return EXT2_ET_BLOCK_ALLOC_FAIL; 287} 288 289errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish, 290 int num, ext2fs_block_bitmap map, blk_t *ret) 291{ 292 errcode_t retval; 293 blk64_t val; 294 retval = ext2fs_get_free_blocks2(fs, start, finish, num, map, &val); 295 if(!retval) 296 *ret = (blk_t) val; 297 return retval; 298} 299 300void ext2fs_set_alloc_block_callback(ext2_filsys fs, 301 errcode_t (*func)(ext2_filsys fs, 302 blk64_t goal, 303 blk64_t *ret), 304 errcode_t (**old)(ext2_filsys fs, 305 blk64_t goal, 306 blk64_t *ret)) 307{ 308 if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) 309 return; 310 311 if (old) 312 *old = fs->get_alloc_block; 313 314 fs->get_alloc_block = func; 315} 316