void e2fsck_read_bitmaps(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; errcode_t retval; const char *old_op; unsigned int save_type; if (ctx->invalid_bitmaps) { com_err(ctx->program_name, 0, _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"), ctx->device_name); fatal_error(ctx, 0); } old_op = ehandler_operation(_("reading inode and block bitmaps")); e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE, "fs_bitmaps", &save_type); ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; retval = ext2fs_read_bitmaps(fs); ctx->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS; fs->default_bitmap_type = save_type; ehandler_operation(old_op); if (retval) { com_err(ctx->program_name, retval, _("while retrying to read bitmaps for %s"), ctx->device_name); fatal_error(ctx, 0); } }
static void move_quota_inode(ext2_filsys fs, ext2_ino_t from_ino, ext2_ino_t to_ino, int qtype) { struct ext2_inode inode; char qf_name[QUOTA_NAME_LEN]; /* We need the inode bitmap to be loaded */ if (ext2fs_read_bitmaps(fs)) return; if (ext2fs_read_inode(fs, from_ino, &inode)) return; inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; inode.i_flags = EXT2_IMMUTABLE_FL; if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) inode.i_flags |= EXT4_EXTENTS_FL; ext2fs_write_new_inode(fs, to_ino, &inode); /* unlink the old inode */ quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); ext2fs_unlink(fs, EXT2_ROOT_INO, qf_name, from_ino, 0); ext2fs_inode_alloc_stats(fs, from_ino, -1); /* Clear out the original inode in the inode-table block. */ memset(&inode, 0, sizeof(struct ext2_inode)); ext2fs_write_inode(fs, from_ino, &inode); }
void * op_init (struct fuse_conn_info *conn) { errcode_t rc; struct fuse_context *cntx=fuse_get_context(); struct extfs_data *e2data=cntx->private_data; debugf("enter %s", e2data->device); rc = ext2fs_open(e2data->device, (e2data->readonly) ? 0 : EXT2_FLAG_RW, 0, 0, unix_io_manager, &e2data->e2fs); if (rc) { debugf("Error while trying to open %s", e2data->device); exit(1); } #if 1 if (e2data->readonly != 1) #endif rc = ext2fs_read_bitmaps(e2data->e2fs); if (rc) { debugf("Error while reading bitmaps"); ext2fs_close(e2data->e2fs); exit(1); } debugf("FileSystem %s", (e2data->e2fs->flags & EXT2_FLAG_RW) ? "Read&Write" : "ReadOnly"); debugf("leave"); return e2data; }
errcode_t quota_remove_inode(ext2_filsys fs, int qtype) { ext2_ino_t qf_ino; errcode_t retval; retval = ext2fs_read_bitmaps(fs); if (retval) { log_err("Couldn't read bitmaps: %s", error_message(retval)); return retval; } qf_ino = (qtype == USRQUOTA) ? fs->super->s_usr_quota_inum : fs->super->s_grp_quota_inum; quota_set_sb_inum(fs, 0, qtype); /* Truncate the inode only if its a reserved one. */ if (qf_ino < EXT2_FIRST_INODE(fs->super)) quota_inode_truncate(fs, qf_ino); ext2fs_mark_super_dirty(fs); fs->flags &= ~EXT2_FLAG_SUPER_ONLY; retval = ext2fs_write_bitmaps(fs); if (retval) { log_err("Couldn't write bitmaps: %s", error_message(retval)); return retval; } return 0; }
errcode_t quota_write_inode(quota_ctx_t qctx, int qtype) { int retval = 0, i; dict_t *dict; ext2_filsys fs; struct quota_handle *h = NULL; int fmt = QFMT_VFS_V1; if (!qctx) return 0; fs = qctx->fs; retval = ext2fs_get_mem(sizeof(struct quota_handle), &h); if (retval) { log_err("Unable to allocate quota handle", ""); goto out; } ext2fs_read_bitmaps(fs); for (i = 0; i < MAXQUOTAS; i++) { if ((qtype != -1) && (i != qtype)) continue; dict = qctx->quota_dict[i]; if (!dict) continue; retval = quota_file_create(h, fs, i, fmt); if (retval < 0) { log_err("Cannot initialize io on quotafile", ""); continue; } write_dquots(dict, h); retval = quota_file_close(h); if (retval < 0) { log_err("Cannot finish IO on new quotafile: %s", strerror(errno)); if (h->qh_qf.e2_file) ext2fs_file_close(h->qh_qf.e2_file); quota_inode_truncate(fs, h->qh_qf.ino); continue; } /* Set quota inode numbers in superblock. */ quota_set_sb_inum(fs, h->qh_qf.ino, i); ext2fs_mark_super_dirty(fs); ext2fs_mark_bb_dirty(fs); fs->flags &= ~EXT2_FLAG_SUPER_ONLY; } ext2fs_write_bitmaps(fs); out: if (h) ext2fs_free_mem(&h); return retval; }
static errcode_t ext3u_write_inode(ext2_filsys fs, ext2_ino_t undel_ino, int flags) { char *buf; errcode_t retval; struct ext2_inode inode; struct mk_ext3u_struct es; __u32 num_blocks = ext3u_fifo_reserved + ext3u_skip_reserved + ext3u_index_reserved + 1; if ((retval = ext3u_create_superblock(fs, flags, &buf))) return retval; if ((retval = ext2fs_read_bitmaps(fs))) return retval; if ((retval = ext2fs_read_inode(fs, undel_ino, &inode))) return retval; if (inode.i_blocks > 0) return EEXIST; es.goal = 0; es.num_blocks = num_blocks; es.newblocks = 0; es.buf = buf; es.err = 0; es.zero_count = 0; retval = ext2fs_block_iterate2(fs, undel_ino, BLOCK_FLAG_APPEND, 0, mk_ext3u_proc, &es); if (es.err) { retval = es.err; goto errout; } if (es.zero_count) { retval = ext2fs_zero_blocks(fs, es.blk_to_zero, es.zero_count, 0, 0); if (retval) goto errout; } if ((retval = ext2fs_read_inode(fs, undel_ino, &inode))) goto errout; inode.i_size += fs->blocksize * num_blocks; 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_inode(fs, undel_ino, &inode))) goto errout; retval = 0; errout: ext2fs_free_mem(&buf); return retval; }
/* * 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 size, int flags) { char *buf; errcode_t retval; struct ext2_inode inode; struct mkjournal_struct es; if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf))) return retval; if ((retval = ext2fs_read_bitmaps(fs))) return retval; if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) return retval; if (inode.i_blocks > 0) return EEXIST; es.num_blocks = size; es.newblocks = 0; es.buf = buf; es.err = 0; retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND, 0, mkjournal_proc, &es); if (es.err) { retval = es.err; goto errout; } if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) goto errout; inode.i_size += fs->blocksize * size; inode.i_blocks += (fs->blocksize / 512) * es.newblocks; inode.i_mtime = inode.i_ctime = time(0); inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; if ((retval = ext2fs_write_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[16] = inode.i_size; fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; ext2fs_mark_super_dirty(fs); errout: ext2fs_free_mem(&buf); return retval; }
errcode_t write_quota_inode(quota_ctx_t qctx, int qtype) { int retval, i; unsigned long qf_inums[MAXQUOTAS]; struct dquot *dquot; dict_t *dict; ext2_filsys fs; struct quota_handle *h; int fmt = QFMT_VFS_V1; if (!qctx) return; fs = qctx->fs; h = smalloc(sizeof(struct quota_handle)); ext2fs_read_bitmaps(fs); for (i = 0; i < MAXQUOTAS; i++) { if ((qtype != -1) && (i != qtype)) continue; dict = qctx->quota_dict[i]; if (!dict) continue; retval = new_io(h, fs, i, fmt); if (retval < 0) { log_err("Cannot initialize io on quotafile", ""); continue; } write_dquots(dict, h); retval = end_io(h); if (retval < 0) { log_err("Cannot finish IO on new quotafile: %s", strerror(errno)); if (h->qh_qf.e2_file) ext2fs_file_close(h->qh_qf.e2_file); truncate_quota_inode(fs, h->qh_qf.ino); continue; } /* Set quota inode numbers in superblock. */ set_sb_quota_inum(fs, h->qh_qf.ino, i); ext2fs_mark_super_dirty(fs); ext2fs_mark_bb_dirty(fs); fs->flags &= ~EXT2_FLAG_SUPER_ONLY; } ext2fs_write_bitmaps(fs); out: free(h); return retval; }
errcode_t quota_remove_inode(ext2_filsys fs, int qtype) { ext2_ino_t qf_ino; ext2fs_read_bitmaps(fs); qf_ino = (qtype == USRQUOTA) ? fs->super->s_usr_quota_inum : fs->super->s_grp_quota_inum; quota_set_sb_inum(fs, 0, qtype); /* Truncate the inode only if its a reserved one. */ if (qf_ino < EXT2_FIRST_INODE(fs->super)) quota_inode_truncate(fs, qf_ino); ext2fs_mark_super_dirty(fs); ext2fs_write_bitmaps(fs); return 0; }
int main(int argc, char **argv) { ext2_filsys fs; ext2fs_generic_bitmap bitmap; size_t size; ext2fs_open(argv[1], 0, 0, 0, unix_io_manager, &fs); ext2fs_read_bitmaps(fs); ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), &bitmap); memcpy(bitmap, fs->block_map, sizeof(struct ext2fs_struct_generic_bitmap)); size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1); printf("sBlock: %u\n", fs->blocksize); printf("sBitmap: %u\n", bitmap->real_end - bitmap->start + 1); printf("bitmap: "); fwrite(bitmap->bitmap, 1, size, stdout); ext2fs_close(fs); return 0; }
errcode_t quota_remove_inode(ext2_filsys fs, enum quota_type qtype) { ext2_ino_t qf_ino; errcode_t retval; retval = ext2fs_read_bitmaps(fs); if (retval) { log_debug("Couldn't read bitmaps: %s", error_message(retval)); return retval; } qf_ino = *quota_sb_inump(fs->super, qtype); if (qf_ino == 0) return 0; retval = quota_inode_truncate(fs, qf_ino); if (retval) return retval; if (qf_ino >= EXT2_FIRST_INODE(fs->super)) { struct ext2_inode inode; retval = ext2fs_read_inode(fs, qf_ino, &inode); if (!retval) { memset(&inode, 0, sizeof(struct ext2_inode)); ext2fs_write_inode(fs, qf_ino, &inode); } ext2fs_inode_alloc_stats2(fs, qf_ino, -1, 0); ext2fs_mark_ib_dirty(fs); } quota_set_sb_inum(fs, 0, qtype); ext2fs_mark_super_dirty(fs); fs->flags &= ~EXT2_FLAG_SUPER_ONLY; retval = ext2fs_write_bitmaps(fs); if (retval) { log_debug("Couldn't write bitmaps: %s", error_message(retval)); return retval; } return 0; }
static void move_quota_inode(ext2_filsys fs, ext2_ino_t from_ino, ext2_ino_t to_ino, enum quota_type qtype) { struct ext2_inode inode; errcode_t retval; char qf_name[QUOTA_NAME_LEN]; /* We need the inode bitmap to be loaded */ if (ext2fs_read_bitmaps(fs)) return; retval = ext2fs_read_inode(fs, from_ino, &inode); if (retval) { com_err("ext2fs_read_inode", retval, "%s", _("in move_quota_inode")); return; } inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; inode.i_flags = EXT2_IMMUTABLE_FL; if (ext2fs_has_feature_extents(fs->super)) inode.i_flags |= EXT4_EXTENTS_FL; retval = ext2fs_write_new_inode(fs, to_ino, &inode); if (retval) { com_err("ext2fs_write_new_inode", retval, "%s", _("in move_quota_inode")); return; } /* unlink the old inode */ quota_get_qf_name(qtype, QFMT_VFS_V1, qf_name); ext2fs_unlink(fs, EXT2_ROOT_INO, qf_name, from_ino, 0); ext2fs_inode_alloc_stats(fs, from_ino, -1); /* Clear out the original inode in the inode-table block. */ memset(&inode, 0, sizeof(struct ext2_inode)); ext2fs_write_inode(fs, from_ino, &inode); }
void e2fsck_read_bitmaps(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; errcode_t retval; if (ctx->invalid_bitmaps) { com_err(ctx->program_name, 0, _("e2fsck_read_bitmaps: illegal bitmap block(s) for %s"), ctx->device_name); fatal_error(ctx, 0); } ehandler_operation(_("reading inode and block bitmaps")); retval = ext2fs_read_bitmaps(fs); ehandler_operation(0); if (retval) { com_err(ctx->program_name, retval, _("while retrying to read bitmaps for %s"), ctx->device_name); fatal_error(ctx, 0); } }
/* * 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, blk64_t goal, int flags) { char *buf; 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; es.goal = (goal != ~0ULL) ? goal : get_midpoint_journal_block(fs); 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; } retval = ext2fs_block_iterate3(fs, journal_ino, BLOCK_FLAG_APPEND, 0, mkjournal_proc, &es); if (retval) goto out2; if (es.err) { retval = es.err; goto out2; } if (es.zero_count) { retval = ext2fs_zero_blocks2(fs, es.blk_to_zero, es.zero_count, 0, 0); if (retval) goto out2; } if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) goto out2; inode_size = (unsigned long long)fs->blocksize * num_blocks; 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; retval = ext2fs_inode_size_set(fs, &inode, inode_size); if (retval) goto out2; if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) goto out2; 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); out2: ext2fs_free_mem(&buf); return retval; }
/// 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; }
errcode_t quota_write_inode(quota_ctx_t qctx, unsigned int qtype_bits) { int retval = 0; enum quota_type qtype; dict_t *dict; ext2_filsys fs; struct quota_handle *h = NULL; int fmt = QFMT_VFS_V1; if (!qctx) return 0; fs = qctx->fs; retval = ext2fs_get_mem(sizeof(struct quota_handle), &h); if (retval) { log_debug("Unable to allocate quota handle: %s", error_message(retval)); goto out; } retval = ext2fs_read_bitmaps(fs); if (retval) { log_debug("Couldn't read bitmaps: %s", error_message(retval)); goto out; } for (qtype = 0; qtype < MAXQUOTAS; qtype++) { if (((1 << qtype) & qtype_bits) == 0) continue; dict = qctx->quota_dict[qtype]; if (!dict) continue; retval = quota_file_create(h, fs, qtype, fmt); if (retval) { log_debug("Cannot initialize io on quotafile: %s", error_message(retval)); goto out; } write_dquots(dict, h); retval = quota_file_close(qctx, h); if (retval) { log_debug("Cannot finish IO on new quotafile: %s", strerror(errno)); if (h->qh_qf.e2_file) ext2fs_file_close(h->qh_qf.e2_file); (void) quota_inode_truncate(fs, h->qh_qf.ino); goto out; } /* Set quota inode numbers in superblock. */ quota_set_sb_inum(fs, h->qh_qf.ino, qtype); ext2fs_mark_super_dirty(fs); ext2fs_mark_bb_dirty(fs); fs->flags &= ~EXT2_FLAG_SUPER_ONLY; } retval = ext2fs_write_bitmaps(fs); if (retval) { log_debug("Couldn't write bitmaps: %s", error_message(retval)); goto out; } out: if (h) ext2fs_free_mem(&h); 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 }
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 }
int main (int argc, char ** argv) { errcode_t retval; ext2_filsys fs; int print_badblocks = 0; blk64_t use_superblock = 0; int use_blocksize = 0; int image_dump = 0; int force = 0; int flags; int header_only = 0; int c; #ifdef ENABLE_NLS setlocale(LC_MESSAGES, ""); setlocale(LC_CTYPE, ""); bindtextdomain(NLS_CAT_NAME, LOCALEDIR); textdomain(NLS_CAT_NAME); set_com_err_gettext(gettext); #endif add_error_table(&et_ext2_error_table); fprintf (stderr, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION, E2FSPROGS_DATE); if (argc && *argv) program_name = *argv; while ((c = getopt (argc, argv, "bfhixVo:")) != EOF) { switch (c) { case 'b': print_badblocks++; break; case 'f': force++; break; case 'h': header_only++; break; case 'i': image_dump++; break; case 'o': parse_extended_opts(optarg, &use_superblock, &use_blocksize); break; case 'V': /* Print version number and exit */ fprintf(stderr, _("\tUsing %s\n"), error_message(EXT2_ET_BASE)); exit(0); case 'x': hex_format++; break; default: usage(); } } if (optind > argc - 1) usage(); device_name = argv[optind++]; flags = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS; if (force) flags |= EXT2_FLAG_FORCE; if (image_dump) flags |= EXT2_FLAG_IMAGE_FILE; if (use_superblock && !use_blocksize) { for (use_blocksize = EXT2_MIN_BLOCK_SIZE; use_blocksize <= EXT2_MAX_BLOCK_SIZE; use_blocksize *= 2) { retval = ext2fs_open (device_name, flags, use_superblock, use_blocksize, unix_io_manager, &fs); if (!retval) break; } } else retval = ext2fs_open (device_name, flags, use_superblock, use_blocksize, unix_io_manager, &fs); if (retval) { com_err (program_name, retval, _("while trying to open %s"), device_name); printf("%s", _("Couldn't find valid filesystem superblock.\n")); exit (1); } fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; if (fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) blocks64 = 1; if (print_badblocks) { list_bad_blocks(fs, 1); } else { list_super (fs->super); if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { print_journal_information(fs); ext2fs_close(fs); exit(0); } if ((fs->super->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && (fs->super->s_journal_inum != 0)) print_inline_journal_information(fs); list_bad_blocks(fs, 0); if (header_only) { ext2fs_close (fs); exit (0); } retval = ext2fs_read_bitmaps (fs); list_desc (fs); if (retval) { printf(_("\n%s: %s: error reading bitmaps: %s\n"), program_name, device_name, error_message(retval)); } } ext2fs_close (fs); remove_error_table(&et_ext2_error_table); exit (0); }
ext2_inode_t *ext2Create(ext2_vd *vd, const char *path, mode_t type, const char *target) { ext2_inode_t *dir_ni = NULL, *ni = NULL; char *dir = NULL; char *targetdir = NULL; char *name = NULL; ext2_ino_t newentry = 0; // Sanity check if (!vd || !vd->fs) { errno = ENODEV; return NULL; } if(!(vd->fs->flags & EXT2_FLAG_RW)) { errno = EACCES; return NULL; } // You cannot link between devices if(target) { if(vd != ext2GetVolume(target)) { errno = EXDEV; return NULL; } // Check if existing dir_ni = ext2OpenEntry(vd, target); if (dir_ni) { errno = EEXIST; goto cleanup; } targetdir = strdup(target); if (!targetdir) { errno = ENOMEM; goto cleanup; } target = ext2RealPath(target); } // Get the actual paths of the entry path = ext2RealPath(path); if (!path) goto cleanup; // Lock ext2Lock(vd); // Clean me // NOTE: this looks horrible right now and need a cleanup dir = strdup(path); if (!dir) { errno = ENOMEM; goto cleanup; } char * tmp_path = (targetdir && (type == S_IFLNK)) ? targetdir : dir; if (strrchr(tmp_path, '/') != NULL) { char * ptr = strrchr(tmp_path, '/'); name = strdup(ptr+1); *ptr = '\0'; } else name = strdup(tmp_path); // Open the entries parent directory dir_ni = ext2OpenEntry(vd, dir); if (!dir_ni) goto cleanup; // If not yet read, read the inode and block bitmap if((!vd->fs->inode_map || !vd->fs->block_map)) ext2fs_read_bitmaps(vd->fs); // Symbolic link if(type == S_IFLNK) { if (!target) { errno = EINVAL; goto cleanup; } newentry = ext2CreateSymlink(vd, path, targetdir, name, type); } // Directory else if(type == S_IFDIR) { newentry = ext2CreateMkDir(vd, dir_ni, LINUX_S_IFDIR | (0755 & ~vd->fs->umask), name); } // File else if(type == S_IFREG) { newentry = ext2CreateFile(vd, dir_ni, LINUX_S_IFREG | (0755 & ~vd->fs->umask), name); } // If the entry was created if (newentry != 0) { // Sync the entry to disc ext2Sync(vd, NULL); ni = ext2OpenEntry(vd, target ? target : path); } cleanup: if(dir_ni) ext2CloseEntry(vd, dir_ni); if(name) mem_free(name); if(dir) mem_free(dir); if(targetdir) mem_free(targetdir); // Unlock ext2Unlock(vd); return ni; }
/* * 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; }
/* * 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, blk64_t goal, int flags) { char *buf; errcode_t retval; struct ext2_inode inode; unsigned long long inode_size; int falloc_flags = EXT2_FALLOCATE_FORCE_INIT; blk64_t zblk; 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; } if (goal == ~0ULL) goal = get_midpoint_journal_block(fs); if (ext2fs_has_feature_extents(fs->super)) inode.i_flags |= EXT4_EXTENTS_FL; if (!(flags & EXT2_MKJOURNAL_LAZYINIT)) falloc_flags |= EXT2_FALLOCATE_ZERO_BLOCKS; inode_size = (unsigned long long)fs->blocksize * num_blocks; inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0); inode.i_links_count = 1; inode.i_mode = LINUX_S_IFREG | 0600; retval = ext2fs_inode_size_set(fs, &inode, inode_size); if (retval) goto out2; retval = ext2fs_fallocate(fs, falloc_flags, journal_ino, &inode, goal, 0, num_blocks); if (retval) goto out2; if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) goto out2; retval = ext2fs_bmap2(fs, journal_ino, &inode, NULL, 0, 0, NULL, &zblk); if (retval) goto out2; retval = io_channel_write_blk64(fs->io, zblk, 1, buf); if (retval) goto out2; 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); out2: ext2fs_free_mem(&buf); return retval; }
void e2fsck_move_ext3_journal(e2fsck_t ctx) { struct ext2_super_block *sb = ctx->fs->super; struct problem_context pctx; struct ext2_inode inode; ext2_filsys fs = ctx->fs; ext2_ino_t ino; errcode_t retval; const char * const * cpp; int group, mount_flags; clear_problem_context(&pctx); /* * If the filesystem is opened read-only, or there is no * journal, then do nothing. */ if ((ctx->options & E2F_OPT_READONLY) || (sb->s_journal_inum == 0) || !(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) return; /* * Read in the journal inode */ if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0) return; /* * If it's necessary to backup the journal inode, do so. */ if ((sb->s_jnl_backup_type == 0) || ((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) && memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) { if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) { memcpy(sb->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); sb->s_jnl_blocks[16] = inode.i_size; sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; ext2fs_mark_super_dirty(fs); fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; } } /* * If the journal is already the hidden inode, then do nothing */ if (sb->s_journal_inum == EXT2_JOURNAL_INO) return; /* * The journal inode had better have only one link and not be readable. */ if (inode.i_links_count != 1) return; /* * If the filesystem is mounted, or we can't tell whether * or not it's mounted, do nothing. */ retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags); if (retval || (mount_flags & EXT2_MF_MOUNTED)) return; /* * If we can't find the name of the journal inode, then do * nothing. */ for (cpp = journal_names; *cpp; cpp++) { retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp, strlen(*cpp), 0, &ino); if ((retval == 0) && (ino == sb->s_journal_inum)) break; } if (*cpp == 0) return; /* We need the inode bitmap to be loaded */ retval = ext2fs_read_bitmaps(fs); if (retval) return; pctx.str = *cpp; if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx)) return; /* * OK, we've done all the checks, let's actually move the * journal inode. Errors at this point mean we need to force * an ext2 filesystem check. */ if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0) goto err_out; if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0) goto err_out; sb->s_journal_inum = EXT2_JOURNAL_INO; ext2fs_mark_super_dirty(fs); fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; inode.i_links_count = 0; inode.i_dtime = ctx->now; if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0) goto err_out; group = ext2fs_group_of_ino(fs, ino); ext2fs_unmark_inode_bitmap(fs->inode_map, ino); ext2fs_mark_ib_dirty(fs); fs->group_desc[group].bg_free_inodes_count++; fs->super->s_free_inodes_count++; return; err_out: pctx.errcode = retval; fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx); fs->super->s_state &= ~EXT2_VALID_FS; ext2fs_mark_super_dirty(fs); return; }
errcode_t online_resize_fs(ext2_filsys fs, const char *mtpt, blk_t *new_size, int flags) { struct ext2_new_group_input input; struct ext2_super_block *sb = fs->super; ext2_filsys new_fs; errcode_t retval; dgrp_t i; blk_t size; int fd, r_frac, overhead; printf(_("Filesystem at %s is mounted on %s; " "on-line resizing required\n"), fs->device_name, mtpt); if (*new_size < sb->s_blocks_count) { printf(_("On-line shrinking from %u to %u not supported.\n"), sb->s_blocks_count, *new_size); 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=sb->s_blocks_count; 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, _("Filesystem does not support online resizing")); else com_err(program_name, errno, _("While checking for on-line resizing support")); exit(1); } r_frac = ((100 * sb->s_r_blocks_count) + sb->s_blocks_count-1) / sb->s_blocks_count; retval = ext2fs_read_bitmaps(fs); if (retval) return retval; retval = ext2fs_dup_handle(fs, &new_fs); if (retval) return retval; retval = adjust_fs_info(new_fs, fs, *new_size); if (retval) return retval; printf(_("Performing an on-line resize of %s to %d (%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 = new_fs->group_desc[i].bg_block_bitmap; input.inode_bitmap = new_fs->group_desc[i].bg_inode_bitmap; input.inode_table = new_fs->group_desc[i].bg_inode_table; input.blocks_count = sb->s_blocks_per_group; if (i == new_fs->group_desc_count-1) { input.blocks_count = new_fs->super->s_blocks_count - sb->s_first_data_block - (i * sb->s_blocks_per_group); } input.reserved_blocks = input.blocks_count * r_frac / 100; #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 %d blocks\n", input.blocks_count); printf("new group will reserve %d blocks\n", input.reserved_blocks); printf("new group has %d free blocks\n", new_fs->group_desc[i].bg_free_blocks_count); printf("new group has %d free inodes (%d blocks)\n", new_fs->group_desc[i].bg_free_inodes_count, new_fs->inode_blocks_per_group); printf("Adding group #%d\n", input.group); #endif if (ioctl(fd, EXT2_IOC_GROUP_ADD, &input) < 0) { com_err(program_name, errno, _("While trying to add group #%d"), input.group); exit(1); } } ext2fs_free(new_fs); close(fd); return 0; }