/* * Calculate the initial goal block to be roughly at the middle of the * filesystem. Pick a group that has the largest number of free * blocks. */ static blk64_t get_midpoint_journal_block(ext2_filsys fs) { dgrp_t group, start, end, i, log_flex; group = ext2fs_group_of_blk2(fs, (ext2fs_blocks_count(fs->super) - fs->super->s_first_data_block) / 2); log_flex = 1 << fs->super->s_log_groups_per_flex; if (fs->super->s_log_groups_per_flex && (group > log_flex)) { group = group & ~(log_flex - 1); while ((group < fs->group_desc_count) && ext2fs_bg_free_blocks_count(fs, group) == 0) group++; if (group == fs->group_desc_count) group = 0; start = group; } else start = (group > 0) ? group-1 : group; end = ((group+1) < fs->group_desc_count) ? group+1 : group; group = start; for (i = start + 1; i <= end; i++) if (ext2fs_bg_free_blocks_count(fs, i) > ext2fs_bg_free_blocks_count(fs, group)) group = i; return ext2fs_group_first_block2(fs, group); }
static void list_desc (ext2_filsys fs) { unsigned long i; blk64_t first_block, last_block; blk64_t super_blk, old_desc_blk, new_desc_blk; char *block_bitmap=NULL, *inode_bitmap=NULL; const char *units = _("blocks"); int inode_blocks_per_group, old_desc_blocks, reserved_gdt; int block_nbytes, inode_nbytes; int has_super; blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block); ext2_ino_t ino_itr = 1; errcode_t retval; if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, EXT4_FEATURE_RO_COMPAT_BIGALLOC)) units = _("clusters"); block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8; if (fs->block_map) block_bitmap = malloc(block_nbytes); if (fs->inode_map) inode_bitmap = malloc(inode_nbytes); inode_blocks_per_group = ((fs->super->s_inodes_per_group * EXT2_INODE_SIZE(fs->super)) + EXT2_BLOCK_SIZE(fs->super) - 1) / EXT2_BLOCK_SIZE(fs->super); reserved_gdt = fs->super->s_reserved_gdt_blocks; fputc('\n', stdout); first_block = fs->super->s_first_data_block; if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) old_desc_blocks = fs->super->s_first_meta_bg; else old_desc_blocks = fs->desc_blocks; for (i = 0; i < fs->group_desc_count; i++) { first_block = ext2fs_group_first_block2(fs, i); last_block = ext2fs_group_last_block2(fs, i); ext2fs_super_and_bgd_loc2(fs, i, &super_blk, &old_desc_blk, &new_desc_blk, 0); printf (_("Group %lu: (Blocks "), i); print_range(first_block, last_block); fputs(")", stdout); print_bg_opts(fs, i); if (ext2fs_has_group_desc_csum(fs)) { unsigned csum = ext2fs_bg_checksum(fs, i); unsigned exp_csum = ext2fs_group_desc_csum(fs, i); printf(_(" Checksum 0x%04x"), csum); if (csum != exp_csum) printf(_(" (EXPECTED 0x%04x)"), exp_csum); printf(_(", unused inodes %u\n"), ext2fs_bg_itable_unused(fs, i)); } has_super = ((i==0) || super_blk); if (has_super) { printf (_(" %s superblock at "), i == 0 ? _("Primary") : _("Backup")); print_number(super_blk); } if (old_desc_blk) { printf("%s", _(", Group descriptors at ")); print_range(old_desc_blk, old_desc_blk + old_desc_blocks - 1); if (reserved_gdt) { printf("%s", _("\n Reserved GDT blocks at ")); print_range(old_desc_blk + old_desc_blocks, old_desc_blk + old_desc_blocks + reserved_gdt - 1); } } else if (new_desc_blk) { fputc(has_super ? ',' : ' ', stdout); printf("%s", _(" Group descriptor at ")); print_number(new_desc_blk); has_super++; } if (has_super) fputc('\n', stdout); fputs(_(" Block bitmap at "), stdout); print_number(ext2fs_block_bitmap_loc(fs, i)); print_bg_rel_offset(fs, ext2fs_block_bitmap_loc(fs, i), 0, first_block, last_block); if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) printf(_(", csum 0x%08x"), ext2fs_block_bitmap_checksum(fs, i)); fputs(_(", Inode bitmap at "), stdout); print_number(ext2fs_inode_bitmap_loc(fs, i)); print_bg_rel_offset(fs, ext2fs_inode_bitmap_loc(fs, i), 0, first_block, last_block); if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) printf(_(", csum 0x%08x"), ext2fs_inode_bitmap_checksum(fs, i)); fputs(_("\n Inode table at "), stdout); print_range(ext2fs_inode_table_loc(fs, i), ext2fs_inode_table_loc(fs, i) + inode_blocks_per_group - 1); print_bg_rel_offset(fs, ext2fs_inode_table_loc(fs, i), 1, first_block, last_block); printf (_("\n %u free %s, %u free inodes, " "%u directories%s"), ext2fs_bg_free_blocks_count(fs, i), units, ext2fs_bg_free_inodes_count(fs, i), ext2fs_bg_used_dirs_count(fs, i), ext2fs_bg_itable_unused(fs, i) ? "" : "\n"); if (ext2fs_bg_itable_unused(fs, i)) printf (_(", %u unused inodes\n"), ext2fs_bg_itable_unused(fs, i)); if (block_bitmap) { fputs(_(" Free blocks: "), stdout); retval = ext2fs_get_block_bitmap_range2(fs->block_map, blk_itr, block_nbytes << 3, block_bitmap); if (retval) com_err("list_desc", retval, "while reading block bitmap"); else print_free(i, block_bitmap, fs->super->s_clusters_per_group, fs->super->s_first_data_block, EXT2FS_CLUSTER_RATIO(fs)); fputc('\n', stdout); blk_itr += fs->super->s_clusters_per_group; } if (inode_bitmap) { fputs(_(" Free inodes: "), stdout); retval = ext2fs_get_inode_bitmap_range2(fs->inode_map, ino_itr, inode_nbytes << 3, inode_bitmap); if (retval) com_err("list_desc", retval, "while reading inode bitmap"); else print_free(i, inode_bitmap, fs->super->s_inodes_per_group, 1, 1); fputc('\n', stdout); ino_itr += fs->super->s_inodes_per_group; } } if (block_bitmap) free(block_bitmap); if (inode_bitmap) free(inode_bitmap); }
/* * This function creates a journal using direct I/O routines. */ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, blk_t num_blocks, int flags) { char *buf; dgrp_t group, start, end, i, log_flex; errcode_t retval; struct ext2_inode inode; unsigned long long inode_size; struct mkjournal_struct es; if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags, &buf))) return retval; if ((retval = ext2fs_read_bitmaps(fs))) goto out2; if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) goto out2; if (inode.i_blocks > 0) { retval = EEXIST; goto out2; } es.num_blocks = num_blocks; es.newblocks = 0; es.buf = buf; es.err = 0; es.flags = flags; es.zero_count = 0; if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) { inode.i_flags |= EXT4_EXTENTS_FL; if ((retval = ext2fs_write_inode(fs, journal_ino, &inode))) goto out2; } /* * Set the initial goal block to be roughly at the middle of * the filesystem. Pick a group that has the largest number * of free blocks. */ group = ext2fs_group_of_blk2(fs, (ext2fs_blocks_count(fs->super) - fs->super->s_first_data_block) / 2); log_flex = 1 << fs->super->s_log_groups_per_flex; if (fs->super->s_log_groups_per_flex && (group > log_flex)) { group = group & ~(log_flex - 1); while ((group < fs->group_desc_count) && ext2fs_bg_free_blocks_count(fs, group) == 0) group++; if (group == fs->group_desc_count) group = 0; start = group; } else start = (group > 0) ? group-1 : group; end = ((group+1) < fs->group_desc_count) ? group+1 : group; group = start; for (i=start+1; i <= end; i++) if (ext2fs_bg_free_blocks_count(fs, i) > ext2fs_bg_free_blocks_count(fs, group)) group = i; es.goal = ext2fs_group_first_block2(fs, group); retval = ext2fs_block_iterate3(fs, journal_ino, BLOCK_FLAG_APPEND, 0, mkjournal_proc, &es); if (es.err) { retval = es.err; goto errout; } if (es.zero_count) { retval = ext2fs_zero_blocks2(fs, es.blk_to_zero, es.zero_count, 0, 0); if (retval) goto errout; } if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) goto errout; inode_size = (unsigned long long)fs->blocksize * num_blocks; inode.i_size = inode_size & 0xFFFFFFFF; inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF; if (ext2fs_needs_large_file_feature(inode_size)) fs->super->s_feature_ro_compat |= EXT2_FEATURE_RO_COMPAT_LARGE_FILE; ext2fs_iblk_add_blocks(fs, &inode, es.newblocks); inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0); inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) goto errout; retval = 0; memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); fs->super->s_jnl_blocks[15] = inode.i_size_high; fs->super->s_jnl_blocks[16] = inode.i_size; fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; ext2fs_mark_super_dirty(fs); errout: ext2fs_zero_blocks2(0, 0, 0, 0, 0); out2: ext2fs_free_mem(&buf); return retval; }
errcode_t online_resize_fs(ext2_filsys fs, const char *mtpt, blk64_t *new_size, int flags EXT2FS_ATTR((unused))) { #ifdef __linux__ struct ext2_new_group_input input; struct ext4_new_group_input input64; struct ext2_super_block *sb = fs->super; unsigned long new_desc_blocks; ext2_filsys new_fs; errcode_t retval; double percent; dgrp_t i; blk_t size; int fd, overhead; int use_old_ioctl = 1; int no_meta_bg_resize = 0; int no_resize_ioctl = 0; if (getenv("RESIZE2FS_KERNEL_VERSION")) { char *version_to_emulate = getenv("RESIZE2FS_KERNEL_VERSION"); int kvers = parse_version_number(version_to_emulate); if (kvers < VERSION_CODE(3, 7, 0)) no_meta_bg_resize = 1; if (kvers < VERSION_CODE(3, 3, 0)) no_resize_ioctl = 1; } if (ext2fs_has_feature_sparse_super2(fs->super) && (access("/sys/fs/ext4/features/sparse_super2", R_OK) != 0)) { com_err(program_name, 0, _("kernel does not support online " "resize with sparse_super2")); exit(1); } printf(_("Filesystem at %s is mounted on %s; " "on-line resizing required\n"), fs->device_name, mtpt); if (*new_size < ext2fs_blocks_count(sb)) { com_err(program_name, 0, _("On-line shrinking not supported")); exit(1); } /* * If the number of descriptor blocks is going to increase, * the on-line resizing inode must be present. */ new_desc_blocks = ext2fs_div_ceil( ext2fs_div64_ceil(*new_size - fs->super->s_first_data_block, EXT2_BLOCKS_PER_GROUP(fs->super)), EXT2_DESC_PER_BLOCK(fs->super)); printf("old_desc_blocks = %lu, new_desc_blocks = %lu\n", fs->desc_blocks, new_desc_blocks); /* * Do error checking to make sure the resize will be successful. */ if ((access("/sys/fs/ext4/features/meta_bg_resize", R_OK) != 0) || no_meta_bg_resize) { if (!ext2fs_has_feature_resize_inode(fs->super) && (new_desc_blocks != fs->desc_blocks)) { com_err(program_name, 0, _("Filesystem does not support online resizing")); exit(1); } if (ext2fs_has_feature_resize_inode(fs->super) && new_desc_blocks > (fs->desc_blocks + fs->super->s_reserved_gdt_blocks)) { com_err(program_name, 0, _("Not enough reserved gdt blocks for resizing")); exit(1); } if ((ext2fs_blocks_count(sb) > MAX_32_NUM) || (*new_size > MAX_32_NUM)) { com_err(program_name, 0, _("Kernel does not support resizing a file system this large")); exit(1); } } fd = open(mtpt, O_RDONLY); if (fd < 0) { com_err(program_name, errno, _("while trying to open mountpoint %s"), mtpt); exit(1); } if (no_resize_ioctl) { printf(_("Old resize interface requested.\n")); } else if (ioctl(fd, EXT4_IOC_RESIZE_FS, new_size)) { /* * If kernel does not support EXT4_IOC_RESIZE_FS, use the * old online resize. Note that the old approach does not * handle >32 bit file systems * * Sigh, if we are running a 32-bit binary on a 64-bit * kernel (which happens all the time on the MIPS * architecture in Debian, but can happen on other CPU * architectures as well) we will get EINVAL returned * when an ioctl doesn't exist, at least up to Linux * 3.1. See compat_sys_ioctl() in fs/compat_ioctl.c * in the kernel sources. This is probably a kernel * bug, but work around it here. */ if ((errno != ENOTTY) && (errno != EINVAL)) { if (errno == EPERM) com_err(program_name, 0, _("Permission denied to resize filesystem")); else com_err(program_name, errno, _("While checking for on-line resizing " "support")); exit(1); } } else { close(fd); return 0; } size = ext2fs_blocks_count(sb); if (ioctl(fd, EXT2_IOC_GROUP_EXTEND, &size)) { if (errno == EPERM) com_err(program_name, 0, _("Permission denied to resize filesystem")); else if (errno == ENOTTY) com_err(program_name, 0, _("Kernel does not support online resizing")); else com_err(program_name, errno, _("While checking for on-line resizing support")); exit(1); } percent = (ext2fs_r_blocks_count(sb) * 100.0) / ext2fs_blocks_count(sb); retval = ext2fs_read_bitmaps(fs); if (retval) { close(fd); return retval; } retval = ext2fs_dup_handle(fs, &new_fs); if (retval) { close(fd); return retval; } /* The current method of adding one block group at a time to a * mounted filesystem means it is impossible to accommodate the * flex_bg allocation method of placing the metadata together * in a single block group. For now we "fix" this issue by * using the traditional layout for new block groups, where * each block group is self-contained and contains its own * bitmap blocks and inode tables. This means we don't get * the layout advantages of flex_bg in the new block groups, * but at least it allows on-line resizing to function. */ ext2fs_clear_feature_flex_bg(new_fs->super); retval = adjust_fs_info(new_fs, fs, 0, *new_size); if (retval) { close(fd); return retval; } printf(_("Performing an on-line resize of %s to %llu (%dk) blocks.\n"), fs->device_name, *new_size, fs->blocksize / 1024); size = fs->group_desc_count * sb->s_blocks_per_group + sb->s_first_data_block; if (size > *new_size) size = *new_size; if (ioctl(fd, EXT2_IOC_GROUP_EXTEND, &size)) { com_err(program_name, errno, _("While trying to extend the last group")); exit(1); } for (i = fs->group_desc_count; i < new_fs->group_desc_count; i++) { overhead = (int) (2 + new_fs->inode_blocks_per_group); if (ext2fs_bg_has_super(new_fs, new_fs->group_desc_count - 1)) overhead += 1 + new_fs->desc_blocks + new_fs->super->s_reserved_gdt_blocks; input.group = i; input.block_bitmap = ext2fs_block_bitmap_loc(new_fs, i); input.inode_bitmap = ext2fs_inode_bitmap_loc(new_fs, i); input.inode_table = ext2fs_inode_table_loc(new_fs, i); input.blocks_count = ext2fs_group_blocks_count(new_fs, i); input.reserved_blocks = (blk_t) (percent * input.blocks_count / 100.0); #if 0 printf("new block bitmap is at 0x%04x\n", input.block_bitmap); printf("new inode bitmap is at 0x%04x\n", input.inode_bitmap); printf("new inode table is at 0x%04x-0x%04x\n", input.inode_table, input.inode_table + new_fs->inode_blocks_per_group-1); printf("new group has %u blocks\n", input.blocks_count); printf("new group will reserve %d blocks\n", input.reserved_blocks); printf("new group has %d free blocks\n", ext2fs_bg_free_blocks_count(new_fs, i), printf("new group has %d free inodes (%d blocks)\n", ext2fs_bg_free_inodes_count(new_fs, i), new_fs->inode_blocks_per_group); printf("Adding group #%d\n", input.group); #endif if (use_old_ioctl && ioctl(fd, EXT2_IOC_GROUP_ADD, &input) == 0) continue; else use_old_ioctl = 0; input64.group = input.group; input64.block_bitmap = input.block_bitmap; input64.inode_bitmap = input.inode_bitmap; input64.inode_table = input.inode_table; input64.blocks_count = input.blocks_count; input64.reserved_blocks = input.reserved_blocks; input64.unused = input.unused; if (ioctl(fd, EXT4_IOC_GROUP_ADD, &input64) < 0) { com_err(program_name, errno, _("While trying to add group #%d"), input.group); exit(1); } } ext2fs_free(new_fs); close(fd); return 0; #else printf(_("Filesystem at %s is mounted on %s, and on-line resizing is " "not supported on this system.\n"), fs->device_name, mtpt); exit(1); #endif }
/// readbitmap - cread and heck bitmap, reference dumpe2fs extern void readbitmap(char* device, image_head image_hdr, unsigned long* bitmap, int pui){ errcode_t retval; unsigned long group; unsigned long long current_block, block; unsigned long long free, gfree; char *block_bitmap=NULL; int block_nbytes; unsigned long long blk_itr; int bg_flags = 0; int start = 0; int bit_size = 1; int B_UN_INIT = 0; int ext4_gfree_mismatch = 0; log_mesg(2, 0, 0, fs_opt.debug, "%s: readbitmap %p\n", __FILE__, bitmap); fs_open(device); retval = ext2fs_read_bitmaps(fs); /// open extfs bitmap if (retval) log_mesg(0, 1, 1, fs_opt.debug, "%s: Couldn't find valid filesystem bitmap.\n", __FILE__); block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; if (fs->block_map) block_bitmap = malloc(block_nbytes); /// initial image bitmap as 1 (all block are used) memset(bitmap, 0xFF, sizeof(unsigned long)*LONGS(image_hdr.totalblock)); free = 0; current_block = 0; blk_itr = fs->super->s_first_data_block; /// init progress progress_bar prog; /// progress_bar structure defined in progress.h progress_init(&prog, start, image_hdr.totalblock, image_hdr.totalblock, BITMAP, bit_size); /// each group for (group = 0; group < fs->group_desc_count; group++) { gfree = 0; B_UN_INIT = 0; if (block_bitmap) { ext2fs_get_block_bitmap_range(fs->block_map, blk_itr, block_nbytes << 3, block_bitmap); if (fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM){ #ifdef EXTFS_1_41 bg_flags = fs->group_desc[group].bg_flags; #else bg_flags = ext2fs_bg_flags(fs, group); #endif if (bg_flags&EXT2_BG_BLOCK_UNINIT){ log_mesg(1, 0, 0, fs_opt.debug, "%s: BLOCK_UNINIT for group %lu\n", __FILE__, group); B_UN_INIT = 1; } else { log_mesg(2, 0, 0, fs_opt.debug, "%s: BLOCK_INIT for group %lu\n", __FILE__, group); } } /// each block in group for (block = 0; ((block < fs->super->s_blocks_per_group) && (current_block < (image_hdr.totalblock-1))); block++) { current_block = block + blk_itr; /// check block is used or not if ((!in_use (block_bitmap, block)) || (B_UN_INIT)) { free++; gfree++; pc_clear_bit(current_block, bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: free block %llu at group %lu init %i\n", __FILE__, current_block, group, (int)B_UN_INIT); } else { pc_set_bit(current_block, bitmap); log_mesg(3, 0, 0, fs_opt.debug, "%s: used block %llu at group %lu\n", __FILE__, current_block, group); } /// update progress update_pui(&prog, current_block, current_block, 0);//keep update } blk_itr += fs->super->s_blocks_per_group; } /// check free blocks in group #ifdef EXTFS_1_41 if (gfree != fs->group_desc[group].bg_free_blocks_count){ #else if (gfree != ext2fs_bg_free_blocks_count(fs, group)){ #endif if (!B_UN_INIT) log_mesg(0, 1, 1, fs_opt.debug, "%s: bitmap error at %lu group.\n", __FILE__, group); else ext4_gfree_mismatch = 1; } } /// check all free blocks in partition if (free != fs->super->s_free_blocks_count) { if ((fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM) && (ext4_gfree_mismatch)) log_mesg(1, 0, 0, fs_opt.debug, "%s: EXT4 bitmap metadata mismatch\n", __FILE__); else log_mesg(0, 1, 1, fs_opt.debug, "%s: bitmap free count err, free:%llu\n", __FILE__, free); } fs_close(); /// update progress update_pui(&prog, 1, 1, 1);//finish } /// get extfs type static int test_extfs_type(char* device){ int ext2 = 1; int ext3 = 2; int ext4 = 3; int device_type; fs_open(device); if(fs->super->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM){ log_mesg(1, 0, 0, fs_opt.debug, "%s: test feature as EXT4\n", __FILE__); device_type = ext4; } else if (fs->super->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL){ log_mesg(1, 0, 0, fs_opt.debug, "%s: test feature as EXT3\n", __FILE__); device_type = ext3; } else { log_mesg(1, 0, 0, fs_opt.debug, "%s: test feature as EXT2\n", __FILE__); device_type = ext2; } fs_close(); return device_type; }
static void check_block_bitmaps(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; blk64_t i; unsigned int *free_array; int group = 0; unsigned int blocks = 0; blk64_t free_blocks = 0; blk64_t first_free = ext2fs_blocks_count(fs->super); unsigned int group_free = 0; int actual, bitmap; struct problem_context pctx; int problem, save_problem, fixit, had_problem; errcode_t retval; int csum_flag; int skip_group = 0; int old_desc_blocks = 0; int count = 0; int cmp_block = 0; int redo_flag = 0; blk64_t super_blk, old_desc_blk, new_desc_blk; clear_problem_context(&pctx); free_array = (unsigned int *) e2fsck_allocate_memory(ctx, fs->group_desc_count * sizeof(unsigned int), "free block count array"); if ((B2C(fs->super->s_first_data_block) < ext2fs_get_block_bitmap_start2(ctx->block_found_map)) || (B2C(ext2fs_blocks_count(fs->super)-1) > ext2fs_get_block_bitmap_end2(ctx->block_found_map))) { pctx.num = 1; pctx.blk = B2C(fs->super->s_first_data_block); pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1); pctx.ino = ext2fs_get_block_bitmap_start2(ctx->block_found_map); pctx.ino2 = ext2fs_get_block_bitmap_end2(ctx->block_found_map); fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ goto errout; } if ((B2C(fs->super->s_first_data_block) < ext2fs_get_block_bitmap_start2(fs->block_map)) || (B2C(ext2fs_blocks_count(fs->super)-1) > ext2fs_get_block_bitmap_end2(fs->block_map))) { pctx.num = 2; pctx.blk = B2C(fs->super->s_first_data_block); pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1); pctx.ino = ext2fs_get_block_bitmap_start2(fs->block_map); pctx.ino2 = ext2fs_get_block_bitmap_end2(fs->block_map); fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ goto errout; } csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super, EXT4_FEATURE_RO_COMPAT_GDT_CSUM); redo_counts: had_problem = 0; save_problem = 0; pctx.blk = pctx.blk2 = NO_BLK; if (csum_flag && (ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT))) skip_group++; for (i = B2C(fs->super->s_first_data_block); i < ext2fs_blocks_count(fs->super); i += EXT2FS_CLUSTER_RATIO(fs)) { actual = ext2fs_fast_test_block_bitmap2(ctx->block_found_map, i); if (skip_group) { if ((B2C(i) - B2C(fs->super->s_first_data_block)) % fs->super->s_clusters_per_group == 0) { super_blk = 0; old_desc_blk = 0; new_desc_blk = 0; ext2fs_super_and_bgd_loc2(fs, group, &super_blk, &old_desc_blk, &new_desc_blk, 0); if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) old_desc_blocks = fs->super->s_first_meta_bg; else old_desc_blocks = fs->desc_blocks + fs->super->s_reserved_gdt_blocks; count = 0; cmp_block = fs->super->s_clusters_per_group; if (group == (int)fs->group_desc_count - 1) cmp_block = EXT2FS_NUM_B2C(fs, ext2fs_group_blocks_count(fs, group)); } bitmap = 0; if (EQ_CLSTR(i, super_blk) || (old_desc_blk && old_desc_blocks && GE_CLSTR(i, old_desc_blk) && LE_CLSTR(i, old_desc_blk + old_desc_blocks-1)) || (new_desc_blk && EQ_CLSTR(i, new_desc_blk)) || EQ_CLSTR(i, ext2fs_block_bitmap_loc(fs, group)) || EQ_CLSTR(i, ext2fs_inode_bitmap_loc(fs, group)) || (GE_CLSTR(i, ext2fs_inode_table_loc(fs, group)) && LE_CLSTR(i, (ext2fs_inode_table_loc(fs, group) + fs->inode_blocks_per_group - 1)))) { bitmap = 1; actual = (actual != 0); count++; cmp_block--; } else if ((EXT2FS_B2C(fs, i) - count - EXT2FS_B2C(fs, fs->super->s_first_data_block)) % fs->super->s_clusters_per_group == 0) { /* * When the compare data blocks in block bitmap * are 0, count the free block, * skip the current block group. */ if (ext2fs_test_block_bitmap_range2( ctx->block_found_map, EXT2FS_B2C(fs, i), cmp_block)) { /* * -1 means to skip the current block * group. */ blocks = fs->super->s_clusters_per_group - 1; group_free = cmp_block; free_blocks += cmp_block; /* * The current block group's last block * is set to i. */ i += EXT2FS_C2B(fs, cmp_block - 1); bitmap = 1; goto do_counts; } } } else if (redo_flag) bitmap = actual; else bitmap = ext2fs_fast_test_block_bitmap2(fs->block_map, i); if (!actual == !bitmap) goto do_counts; if (!actual && bitmap) { /* * Block not used, but marked in use in the bitmap. */ problem = PR_5_BLOCK_UNUSED; } else { /* * Block used, but not marked in use in the bitmap. */ problem = PR_5_BLOCK_USED; if (skip_group) { struct problem_context pctx2; pctx2.blk = i; pctx2.group = group; if (fix_problem(ctx, PR_5_BLOCK_UNINIT,&pctx2)){ ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); skip_group = 0; } } } if (pctx.blk == NO_BLK) { pctx.blk = pctx.blk2 = i; save_problem = problem; } else { if ((problem == save_problem) && (pctx.blk2 == i-1)) pctx.blk2++; else { print_bitmap_problem(ctx, save_problem, &pctx); pctx.blk = pctx.blk2 = i; save_problem = problem; } } ctx->flags |= E2F_FLAG_PROG_SUPPRESS; had_problem++; /* * If there a problem we should turn off the discard so we * do not compromise the filesystem. */ ctx->options &= ~E2F_OPT_DISCARD; do_counts: if (!bitmap) { group_free++; free_blocks++; if (first_free > i) first_free = i; } else if (i > first_free) { e2fsck_discard_blocks(ctx, first_free, (i - first_free)); first_free = ext2fs_blocks_count(fs->super); } blocks ++; if ((blocks == fs->super->s_clusters_per_group) || (EXT2FS_B2C(fs, i) == EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1))) { /* * If the last block of this group is free, then we can * discard it as well. */ if (!bitmap && i >= first_free) e2fsck_discard_blocks(ctx, first_free, (i - first_free) + 1); first_free = ext2fs_blocks_count(fs->super); free_array[group] = group_free; group ++; blocks = 0; group_free = 0; skip_group = 0; if (ctx->progress) if ((ctx->progress)(ctx, 5, group, fs->group_desc_count*2)) goto errout; if (csum_flag && (i != ext2fs_blocks_count(fs->super)-1) && ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)) skip_group++; } } if (pctx.blk != NO_BLK) print_bitmap_problem(ctx, save_problem, &pctx); if (had_problem) fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP); else fixit = -1; ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS; if (fixit == 1) { ext2fs_free_block_bitmap(fs->block_map); retval = ext2fs_copy_bitmap(ctx->block_found_map, &fs->block_map); if (retval) { clear_problem_context(&pctx); fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; goto errout; } ext2fs_set_bitmap_padding(fs->block_map); ext2fs_mark_bb_dirty(fs); /* Redo the counts */ blocks = 0; free_blocks = 0; group_free = 0; group = 0; memset(free_array, 0, fs->group_desc_count * sizeof(int)); redo_flag++; goto redo_counts; } else if (fixit == 0) ext2fs_unmark_valid(fs); for (i = 0; i < fs->group_desc_count; i++) { if (free_array[i] != ext2fs_bg_free_blocks_count(fs, i)) { pctx.group = i; pctx.blk = ext2fs_bg_free_blocks_count(fs, i); pctx.blk2 = free_array[i]; if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP, &pctx)) { ext2fs_bg_free_blocks_count_set(fs, i, free_array[i]); ext2fs_mark_super_dirty(fs); } else ext2fs_unmark_valid(fs); } } free_blocks = EXT2FS_C2B(fs, free_blocks); if (free_blocks != ext2fs_free_blocks_count(fs->super)) { pctx.group = 0; pctx.blk = ext2fs_free_blocks_count(fs->super); pctx.blk2 = free_blocks; if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) { ext2fs_free_blocks_count_set(fs->super, free_blocks); ext2fs_mark_super_dirty(fs); } } errout: ext2fs_free_mem(&free_array); }
errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, ext2fs_block_bitmap bmap) { errcode_t retval; blk64_t group_blk, start_blk, last_blk, new_blk; dgrp_t last_grp = 0; int rem_grps = 0, flexbg_size = 0; group_blk = ext2fs_group_first_block2(fs, group); last_blk = ext2fs_group_last_block2(fs, group); if (!bmap) bmap = fs->block_map; if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_FLEX_BG) && fs->super->s_log_groups_per_flex) { flexbg_size = 1 << fs->super->s_log_groups_per_flex; last_grp = group | (flexbg_size - 1); if (last_grp > fs->group_desc_count-1) last_grp = fs->group_desc_count-1; rem_grps = last_grp - group + 1; } /* * Allocate the block and inode bitmaps, if necessary */ if (fs->stride) { retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk, 1, bmap, &start_blk); if (retval) return retval; start_blk += fs->inode_blocks_per_group; start_blk += ((fs->stride * group) % (last_blk - start_blk + 1)); if (start_blk >= last_blk) start_blk = group_blk; } else start_blk = group_blk; if (flexbg_size) { blk64_t prev_block = 0; if (group % flexbg_size) prev_block = ext2fs_block_bitmap_loc(fs, group - 1) + 1; start_blk = flexbg_offset(fs, group, prev_block, bmap, rem_grps, 1); last_blk = ext2fs_group_last_block2(fs, last_grp); } if (!ext2fs_block_bitmap_loc(fs, group)) { retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk, 1, bmap, &new_blk); if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk, 1, bmap, &new_blk); if (retval) return retval; ext2fs_mark_block_bitmap2(bmap, new_blk); ext2fs_block_bitmap_loc_set(fs, group, new_blk); if (flexbg_size) { dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk); ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1); ext2fs_free_blocks_count_add(fs->super, -1); ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT); ext2fs_group_desc_csum_set(fs, gr); } } if (flexbg_size) { blk64_t prev_block = 0; if (group % flexbg_size) prev_block = ext2fs_inode_bitmap_loc(fs, group - 1) + 1; else prev_block = ext2fs_block_bitmap_loc(fs, group) + flexbg_size; start_blk = flexbg_offset(fs, group, prev_block, bmap, rem_grps, 1); last_blk = ext2fs_group_last_block2(fs, last_grp); } if (!ext2fs_inode_bitmap_loc(fs, group)) { retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk, 1, bmap, &new_blk); if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk, 1, bmap, &new_blk); if (retval) return retval; ext2fs_mark_block_bitmap2(bmap, new_blk); ext2fs_inode_bitmap_loc_set(fs, group, new_blk); if (flexbg_size) { dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk); ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1); ext2fs_free_blocks_count_add(fs->super, -1); ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT); ext2fs_group_desc_csum_set(fs, gr); } } /* * Allocate the inode table */ if (flexbg_size) { blk64_t prev_block = 0; if (group % flexbg_size) prev_block = ext2fs_inode_table_loc(fs, group - 1) + fs->inode_blocks_per_group; else prev_block = ext2fs_inode_bitmap_loc(fs, group) + flexbg_size; group_blk = flexbg_offset(fs, group, prev_block, bmap, rem_grps, fs->inode_blocks_per_group); last_blk = ext2fs_group_last_block2(fs, last_grp); } if (!ext2fs_inode_table_loc(fs, group)) { retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk, fs->inode_blocks_per_group, bmap, &new_blk); if (retval) return retval; if (flexbg_size) ext2fs_block_alloc_stats_range(fs, new_blk, fs->inode_blocks_per_group, +1); else ext2fs_mark_block_bitmap_range2(fs->block_map, new_blk, fs->inode_blocks_per_group); ext2fs_inode_table_loc_set(fs, group, new_blk); } ext2fs_group_desc_csum_set(fs, group); return 0; }
static void check_block_bitmaps(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; blk64_t i; unsigned int *free_array; dgrp_t g, group = 0; unsigned int blocks = 0; blk64_t free_blocks = 0; blk64_t first_free = ext2fs_blocks_count(fs->super); unsigned int group_free = 0; int actual, bitmap; struct problem_context pctx; problem_t problem, save_problem; int fixit, had_problem; errcode_t retval; int old_desc_blocks = 0; int count = 0; int cmp_block = 0; int redo_flag = 0; blk64_t super_blk, old_desc_blk, new_desc_blk; char *actual_buf, *bitmap_buf; actual_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize, "actual bitmap buffer"); bitmap_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize, "bitmap block buffer"); clear_problem_context(&pctx); free_array = (unsigned int *) e2fsck_allocate_memory(ctx, fs->group_desc_count * sizeof(unsigned int), "free block count array"); if ((B2C(fs->super->s_first_data_block) < ext2fs_get_block_bitmap_start2(ctx->block_found_map)) || (B2C(ext2fs_blocks_count(fs->super)-1) > ext2fs_get_block_bitmap_end2(ctx->block_found_map))) { pctx.num = 1; pctx.blk = B2C(fs->super->s_first_data_block); pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1); pctx.ino = ext2fs_get_block_bitmap_start2(ctx->block_found_map); pctx.ino2 = ext2fs_get_block_bitmap_end2(ctx->block_found_map); fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ goto errout; } if ((B2C(fs->super->s_first_data_block) < ext2fs_get_block_bitmap_start2(fs->block_map)) || (B2C(ext2fs_blocks_count(fs->super)-1) > ext2fs_get_block_bitmap_end2(fs->block_map))) { pctx.num = 2; pctx.blk = B2C(fs->super->s_first_data_block); pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1); pctx.ino = ext2fs_get_block_bitmap_start2(fs->block_map); pctx.ino2 = ext2fs_get_block_bitmap_end2(fs->block_map); fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ goto errout; } redo_counts: had_problem = 0; save_problem = 0; pctx.blk = pctx.blk2 = NO_BLK; for (i = B2C(fs->super->s_first_data_block); i < ext2fs_blocks_count(fs->super); i += EXT2FS_CLUSTER_RATIO(fs)) { int first_block_in_bg = (B2C(i) - B2C(fs->super->s_first_data_block)) % fs->super->s_clusters_per_group == 0; int n, nbytes = fs->super->s_clusters_per_group / 8; actual = ext2fs_fast_test_block_bitmap2(ctx->block_found_map, i); /* * Try to optimize pass5 by extracting a bitmap block * as expected from what we have on disk, and then * comparing the two. If they are identical, then * update the free block counts and go on to the next * block group. This is much faster than doing the * individual bit-by-bit comparison. The one downside * is that this doesn't work if we are asking e2fsck * to do a discard operation. */ if (!first_block_in_bg || (group == (int)fs->group_desc_count - 1) || (ctx->options & E2F_OPT_DISCARD)) goto no_optimize; retval = ext2fs_get_block_bitmap_range2(ctx->block_found_map, B2C(i), fs->super->s_clusters_per_group, actual_buf); if (retval) goto no_optimize; retval = ext2fs_get_block_bitmap_range2(fs->block_map, B2C(i), fs->super->s_clusters_per_group, bitmap_buf); if (retval) goto no_optimize; if (memcmp(actual_buf, bitmap_buf, nbytes) != 0) goto no_optimize; n = ext2fs_bitcount(actual_buf, nbytes); group_free = fs->super->s_clusters_per_group - n; free_blocks += group_free; i += EXT2FS_C2B(fs, fs->super->s_clusters_per_group - 1); goto next_group; no_optimize: if (redo_flag) bitmap = actual; else bitmap = ext2fs_fast_test_block_bitmap2(fs->block_map, i); if (!actual == !bitmap) goto do_counts; if (!actual && bitmap) { /* * Block not used, but marked in use in the bitmap. */ problem = PR_5_BLOCK_UNUSED; } else { /* * Block used, but not marked in use in the bitmap. */ problem = PR_5_BLOCK_USED; if (ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)) { struct problem_context pctx2; pctx2.blk = i; pctx2.group = group; if (fix_problem(ctx, PR_5_BLOCK_UNINIT, &pctx2)) ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); } } if (pctx.blk == NO_BLK) { pctx.blk = pctx.blk2 = i; save_problem = problem; } else { if ((problem == save_problem) && (pctx.blk2 == i - EXT2FS_CLUSTER_RATIO(fs))) pctx.blk2 += EXT2FS_CLUSTER_RATIO(fs); else { print_bitmap_problem(ctx, save_problem, &pctx); pctx.blk = pctx.blk2 = i; save_problem = problem; } } ctx->flags |= E2F_FLAG_PROG_SUPPRESS; had_problem++; /* * If there a problem we should turn off the discard so we * do not compromise the filesystem. */ ctx->options &= ~E2F_OPT_DISCARD; do_counts: if (!bitmap) { group_free++; free_blocks++; if (first_free > i) first_free = i; } else if (i > first_free) { e2fsck_discard_blocks(ctx, first_free, (i - first_free)); first_free = ext2fs_blocks_count(fs->super); } blocks ++; if ((blocks == fs->super->s_clusters_per_group) || (EXT2FS_B2C(fs, i) == EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1))) { /* * If the last block of this group is free, then we can * discard it as well. */ if (!bitmap && i >= first_free) e2fsck_discard_blocks(ctx, first_free, (i - first_free) + 1); next_group: first_free = ext2fs_blocks_count(fs->super); free_array[group] = group_free; group ++; blocks = 0; group_free = 0; if (ctx->progress) if ((ctx->progress)(ctx, 5, group, fs->group_desc_count*2)) goto errout; } } if (pctx.blk != NO_BLK) print_bitmap_problem(ctx, save_problem, &pctx); if (had_problem) fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP); else fixit = -1; ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS; if (fixit == 1) { ext2fs_free_block_bitmap(fs->block_map); retval = ext2fs_copy_bitmap(ctx->block_found_map, &fs->block_map); if (retval) { clear_problem_context(&pctx); fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; goto errout; } ext2fs_set_bitmap_padding(fs->block_map); ext2fs_mark_bb_dirty(fs); /* Redo the counts */ blocks = 0; free_blocks = 0; group_free = 0; group = 0; memset(free_array, 0, fs->group_desc_count * sizeof(int)); redo_flag++; goto redo_counts; } else if (fixit == 0) ext2fs_unmark_valid(fs); for (g = 0; g < fs->group_desc_count; g++) { if (free_array[g] != ext2fs_bg_free_blocks_count(fs, g)) { pctx.group = g; pctx.blk = ext2fs_bg_free_blocks_count(fs, g); pctx.blk2 = free_array[g]; if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP, &pctx)) { ext2fs_bg_free_blocks_count_set(fs, g, free_array[g]); ext2fs_mark_super_dirty(fs); } else ext2fs_unmark_valid(fs); } } free_blocks = EXT2FS_C2B(fs, free_blocks); if (free_blocks != ext2fs_free_blocks_count(fs->super)) { pctx.group = 0; pctx.blk = ext2fs_free_blocks_count(fs->super); pctx.blk2 = free_blocks; if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) { ext2fs_free_blocks_count_set(fs->super, free_blocks); ext2fs_mark_super_dirty(fs); } } errout: ext2fs_free_mem(&free_array); ext2fs_free_mem(&actual_buf); ext2fs_free_mem(&bitmap_buf); }
errcode_t online_resize_fs(ext2_filsys fs, const char *mtpt, blk64_t *new_size, int flags EXT2FS_ATTR((unused))) { #ifdef __linux__ struct ext2_new_group_input input; struct ext4_new_group_input input64; struct ext2_super_block *sb = fs->super; unsigned long new_desc_blocks; ext2_filsys new_fs; errcode_t retval; double percent; dgrp_t i; blk64_t size; int fd, overhead; int use_old_ioctl = 1; printf(_("Filesystem at %s is mounted on %s; " "on-line resizing required\n"), fs->device_name, mtpt); if (*new_size < ext2fs_blocks_count(sb)) { com_err(program_name, 0, _("On-line shrinking not supported")); exit(1); } /* * If the number of descriptor blocks is going to increase, * the on-line resizing inode must be present. */ new_desc_blocks = ext2fs_div_ceil( ext2fs_div64_ceil(*new_size - fs->super->s_first_data_block, EXT2_BLOCKS_PER_GROUP(fs->super)), EXT2_DESC_PER_BLOCK(fs->super)); printf("old desc_blocks = %lu, new_desc_blocks = %lu\n", fs->desc_blocks, new_desc_blocks); if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE) && new_desc_blocks != fs->desc_blocks) { com_err(program_name, 0, _("Filesystem does not support online resizing")); exit(1); } fd = open(mtpt, O_RDONLY); if (fd < 0) { com_err(program_name, errno, _("while trying to open mountpoint %s"), mtpt); exit(1); } size=ext2fs_blocks_count(sb); if (ioctl(fd, EXT2_IOC_GROUP_EXTEND, &size)) { if (errno == EPERM) com_err(program_name, 0, _("Permission denied to resize filesystem")); else if (errno == ENOTTY) com_err(program_name, 0, _("Kernel does not support online resizing")); else com_err(program_name, errno, _("While checking for on-line resizing support")); exit(1); } percent = (ext2fs_r_blocks_count(sb) * 100.0) / ext2fs_blocks_count(sb); retval = ext2fs_read_bitmaps(fs); if (retval) return retval; retval = ext2fs_dup_handle(fs, &new_fs); if (retval) return retval; /* The current method of adding one block group at a time to a * mounted filesystem means it is impossible to accomodate the * flex_bg allocation method of placing the metadata together * in a single block group. For now we "fix" this issue by * using the traditional layout for new block groups, where * each block group is self-contained and contains its own * bitmap blocks and inode tables. This means we don't get * the layout advantages of flex_bg in the new block groups, * but at least it allows on-line resizing to function. */ new_fs->super->s_feature_incompat &= ~EXT4_FEATURE_INCOMPAT_FLEX_BG; retval = adjust_fs_info(new_fs, fs, 0, *new_size); if (retval) return retval; printf(_("Performing an on-line resize of %s to %llu (%dk) blocks.\n"), fs->device_name, *new_size, fs->blocksize / 1024); size = fs->group_desc_count * sb->s_blocks_per_group + sb->s_first_data_block; if (size > *new_size) size = *new_size; if (ioctl(fd, EXT2_IOC_GROUP_EXTEND, &size)) { com_err(program_name, errno, _("While trying to extend the last group")); exit(1); } for (i = fs->group_desc_count; i < new_fs->group_desc_count; i++) { overhead = (int) (2 + new_fs->inode_blocks_per_group); if (ext2fs_bg_has_super(new_fs, new_fs->group_desc_count - 1)) overhead += 1 + new_fs->desc_blocks + new_fs->super->s_reserved_gdt_blocks; input.group = i; input.block_bitmap = ext2fs_block_bitmap_loc(new_fs, i); input.inode_bitmap = ext2fs_inode_bitmap_loc(new_fs, i); input.inode_table = ext2fs_inode_table_loc(new_fs, i); input.blocks_count = sb->s_blocks_per_group; if (i == new_fs->group_desc_count-1) { input.blocks_count = ext2fs_blocks_count(new_fs->super) - sb->s_first_data_block - (i * sb->s_blocks_per_group); } input.reserved_blocks = (blk_t) (percent * input.blocks_count / 100.0); #if 0 printf("new block bitmap is at 0x%04x\n", input.block_bitmap); printf("new inode bitmap is at 0x%04x\n", input.inode_bitmap); printf("new inode table is at 0x%04x-0x%04x\n", input.inode_table, input.inode_table + new_fs->inode_blocks_per_group-1); printf("new group has %u blocks\n", input.blocks_count); printf("new group will reserve %d blocks\n", input.reserved_blocks); printf("new group has %d free blocks\n", ext2fs_bg_free_blocks_count(new_fs, i), printf("new group has %d free inodes (%d blocks)\n", ext2fs_bg_free_inodes_count(new_fs, i), new_fs->inode_blocks_per_group); printf("Adding group #%d\n", input.group); #endif if (use_old_ioctl && ioctl(fd, EXT2_IOC_GROUP_ADD, &input) == 0) continue; else use_old_ioctl = 0; input64.group = input.group; input64.block_bitmap = input.block_bitmap; input64.inode_bitmap = input.inode_bitmap; input64.inode_table = input.inode_table; input64.blocks_count = input.blocks_count; input64.reserved_blocks = input.reserved_blocks; input64.unused = input.unused; if (ioctl(fd, EXT4_IOC_GROUP_ADD, &input64) < 0) { com_err(program_name, errno, _("While trying to add group #%d"), input.group); exit(1); } } ext2fs_free(new_fs); close(fd); return 0; #else printf(_("Filesystem at %s is mounted on %s, and on-line resizing is " "not supported on this system.\n"), fs->device_name, mtpt); exit(1); #endif }
} /* Helper function for remove_journal_inode */ static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), blk64_t ref_block EXT2FS_ATTR((unused)), int ref_offset EXT2FS_ATTR((unused)), void *private EXT2FS_ATTR((unused))) { blk64_t block; int group; block = *blocknr; ext2fs_unmark_block_bitmap2(fs->block_map, block); group = ext2fs_group_of_blk2(fs, block); ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) + 1); ext2fs_group_desc_csum_set(fs, group); ext2fs_free_blocks_count_add(fs->super, EXT2FS_CLUSTER_RATIO(fs)); return 0; } /* * Remove the journal inode from the filesystem */ static void remove_journal_inode(ext2_filsys fs) { struct ext2_inode inode; errcode_t retval; ino_t ino = fs->super->s_journal_inum; retval = ext2fs_read_inode(fs, ino, &inode);