static errcode_t alloc_icount(ext2_filsys fs, int flags, ext2_icount_t *ret) { ext2_icount_t icount; errcode_t retval; *ret = 0; retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount); if (retval) return retval; memset(icount, 0, sizeof(struct ext2_icount)); retval = ext2fs_allocate_inode_bitmap(fs, 0, &icount->single); if (retval) goto errout; if (flags & EXT2_ICOUNT_OPT_INCREMENT) { retval = ext2fs_allocate_inode_bitmap(fs, 0, &icount->multiple); if (retval) goto errout; } else icount->multiple = 0; icount->magic = EXT2_ET_MAGIC_ICOUNT; icount->num_inodes = fs->super->s_inodes_count; *ret = icount; return 0; errout: ext2fs_free_icount(icount); return(retval); }
errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir, int flags, ext2_icount_t *ret) { ext2_icount_t icount; errcode_t retval; char *fn, uuid[40]; int fd; retval = alloc_icount(fs, flags, &icount); if (retval) return retval; retval = ext2fs_get_mem(strlen(tdb_dir) + 64, &fn); if (retval) goto errout; uuid_unparse(fs->super->s_uuid, uuid); sprintf(fn, "%s/%s-icount-XXXXXX", tdb_dir, uuid); fd = mkstemp(fn); icount->tdb_fn = fn; icount->tdb = tdb_open(fn, 0, TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT | O_TRUNC, 0600); if (icount->tdb) { close(fd); *ret = icount; return 0; } retval = errno; close(fd); errout: ext2fs_free_icount(icount); return(retval); }
void do_free_icount(int argc, char **argv) { if (check_icount(argv[0])) return; ext2fs_free_icount(test_icount); test_icount = 0; }
errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir, int flags, ext2_icount_t *ret) { ext2_icount_t icount; errcode_t retval; char *fn, uuid[40]; ext2_ino_t num_inodes; int fd; retval = alloc_icount(fs, flags, &icount); if (retval) return retval; retval = ext2fs_get_mem(strlen(tdb_dir) + 64, &fn); if (retval) goto errout; uuid_unparse(fs->super->s_uuid, uuid); sprintf(fn, "%s/%s-icount-XXXXXX", tdb_dir, uuid); fd = mkstemp(fn); if (fd < 0) return fd; /* * This is an overestimate of the size that we will need; the * ideal value is the number of used inodes with a count * greater than 1. OTOH the times when we really need this is * with the backup programs that use lots of hard links, in * which case the number of inodes in use approaches the ideal * value. */ num_inodes = fs->super->s_inodes_count - fs->super->s_free_inodes_count; icount->tdb_fn = fn; icount->tdb = tdb_open(fn, num_inodes, TDB_NOLOCK | TDB_NOSYNC, O_RDWR | O_CREAT | O_TRUNC, 0600); if (icount->tdb) { close(fd); *ret = icount; return 0; } retval = errno; close(fd); errout: ext2fs_free_icount(icount); return(retval); }
/* * This function resets an e2fsck context; it is called when e2fsck * needs to be restarted. */ errcode_t e2fsck_reset_context(e2fsck_t ctx) { ctx->flags = 0; ctx->lost_and_found = 0; ctx->bad_lost_and_found = 0; if (ctx->inode_used_map) { ext2fs_free_inode_bitmap(ctx->inode_used_map); ctx->inode_used_map = 0; } if (ctx->inode_dir_map) { ext2fs_free_inode_bitmap(ctx->inode_dir_map); ctx->inode_dir_map = 0; } if (ctx->inode_reg_map) { ext2fs_free_inode_bitmap(ctx->inode_reg_map); ctx->inode_reg_map = 0; } if (ctx->block_found_map) { ext2fs_free_block_bitmap(ctx->block_found_map); ctx->block_found_map = 0; } if (ctx->inode_link_info) { ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0; } if (ctx->journal_io) { if (ctx->fs && ctx->fs->io != ctx->journal_io) io_channel_close(ctx->journal_io); ctx->journal_io = 0; } if (ctx->fs && ctx->fs->dblist) { ext2fs_free_dblist(ctx->fs->dblist); ctx->fs->dblist = 0; } e2fsck_free_dir_info(ctx); #ifdef ENABLE_HTREE e2fsck_free_dx_dir_info(ctx); #endif if (ctx->refcount) { ea_refcount_free(ctx->refcount); ctx->refcount = 0; } if (ctx->refcount_extra) { ea_refcount_free(ctx->refcount_extra); ctx->refcount_extra = 0; } if (ctx->block_dup_map) { ext2fs_free_block_bitmap(ctx->block_dup_map); ctx->block_dup_map = 0; } if (ctx->block_ea_map) { ext2fs_free_block_bitmap(ctx->block_ea_map); ctx->block_ea_map = 0; } if (ctx->inode_bb_map) { ext2fs_free_inode_bitmap(ctx->inode_bb_map); ctx->inode_bb_map = 0; } if (ctx->inode_bad_map) { ext2fs_free_inode_bitmap(ctx->inode_bad_map); ctx->inode_bad_map = 0; } if (ctx->inode_imagic_map) { ext2fs_free_inode_bitmap(ctx->inode_imagic_map); ctx->inode_imagic_map = 0; } if (ctx->dirs_to_hash) { ext2fs_u32_list_free(ctx->dirs_to_hash); ctx->dirs_to_hash = 0; } /* * Clear the array of invalid meta-data flags */ if (ctx->invalid_inode_bitmap_flag) { ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag); ctx->invalid_inode_bitmap_flag = 0; } if (ctx->invalid_block_bitmap_flag) { ext2fs_free_mem(&ctx->invalid_block_bitmap_flag); ctx->invalid_block_bitmap_flag = 0; } if (ctx->invalid_inode_table_flag) { ext2fs_free_mem(&ctx->invalid_inode_table_flag); ctx->invalid_inode_table_flag = 0; } /* Clear statistic counters */ ctx->fs_directory_count = 0; ctx->fs_regular_count = 0; ctx->fs_blockdev_count = 0; ctx->fs_chardev_count = 0; ctx->fs_links_count = 0; ctx->fs_symlinks_count = 0; ctx->fs_fast_symlinks_count = 0; ctx->fs_fifo_count = 0; ctx->fs_total_count = 0; ctx->fs_badblocks_count = 0; ctx->fs_sockets_count = 0; ctx->fs_ind_count = 0; ctx->fs_dind_count = 0; ctx->fs_tind_count = 0; ctx->fs_fragmented = 0; ctx->large_files = 0; /* Reset the superblock to the user's requested value */ ctx->superblock = ctx->use_superblock; return 0; }
int run_test(int flags, int size, char *dir, struct test_program *prog) { errcode_t retval; ext2_icount_t icount; struct test_program *pc; __u16 result; int problem = 0; if (dir) { retval = ext2fs_create_icount_tdb(test_fs, dir, flags, &icount); if (retval) { com_err("run_test", retval, "while creating icount using tdb"); exit(1); } } else { retval = ext2fs_create_icount2(test_fs, flags, size, 0, &icount); if (retval) { com_err("run_test", retval, "while creating icount"); exit(1); } } for (pc = prog; pc->cmd != EXIT; pc++) { switch (pc->cmd) { case FETCH: printf("icount_fetch(%u) = ", pc->ino); break; case STORE: retval = ext2fs_icount_store(icount, pc->ino, pc->arg); if (retval) { com_err("run_test", retval, "while calling icount_store"); exit(1); } printf("icount_store(%u, %u) = ", pc->ino, pc->arg); break; case INCREMENT: retval = ext2fs_icount_increment(icount, pc->ino, 0); if (retval) { com_err("run_test", retval, "while calling icount_increment"); exit(1); } printf("icount_increment(%u) = ", pc->ino); break; case DECREMENT: retval = ext2fs_icount_decrement(icount, pc->ino, 0); if (retval) { com_err("run_test", retval, "while calling icount_decrement"); exit(1); } printf("icount_decrement(%u) = ", pc->ino); break; } retval = ext2fs_icount_fetch(icount, pc->ino, &result); if (retval) { com_err("run_test", retval, "while calling icount_fetch"); exit(1); } printf("%u (%s)\n", result, (result == pc->expected) ? "OK" : "NOT OK"); if (result != pc->expected) problem++; } printf("icount size is %u\n", ext2fs_get_icount_size(icount)); retval = ext2fs_icount_validate(icount, stdout); if (retval) { com_err("run_test", retval, "while calling icount_validate"); exit(1); } ext2fs_free_icount(icount); return problem; }
errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size, ext2_icount_t hint, ext2_icount_t *ret) { ext2_icount_t icount; errcode_t retval; size_t bytes; ext2_ino_t i; if (hint) { EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT); if (hint->size > size) size = (size_t) hint->size; } retval = alloc_icount(fs, flags, &icount); if (retval) return retval; if (size) { icount->size = size; } else { /* * Figure out how many special case inode counts we will * have. We know we will need one for each directory; * we also need to reserve some extra room for file links */ retval = ext2fs_get_num_dirs(fs, &icount->size); if (retval) goto errout; icount->size += fs->super->s_inodes_count / 50; } bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el)); #if 0 printf("Icount allocated %u entries, %d bytes.\n", icount->size, bytes); #endif retval = ext2fs_get_array(icount->size, sizeof(struct ext2_icount_el), &icount->list); if (retval) goto errout; memset(icount->list, 0, bytes); icount->count = 0; icount->cursor = 0; /* * Populate the sorted list with those entries which were * found in the hint icount (since those are ones which will * likely need to be in the sorted list this time around). */ if (hint) { for (i=0; i < hint->count; i++) icount->list[i].ino = hint->list[i].ino; icount->count = hint->count; } *ret = icount; return 0; errout: ext2fs_free_icount(icount); return(retval); }
void e2fsck_pass4(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; ext2_ino_t i; struct ext2_inode *inode; #ifdef RESOURCE_TRACK struct resource_track rtrack; #endif struct problem_context pctx; __u16 link_count, link_counted; char *buf = 0; dgrp_t group, maxgroup; init_resource_track(&rtrack, ctx->fs->io); #ifdef MTRACE mtrace_print("Pass 4"); #endif clear_problem_context(&pctx); if (!(ctx->options & E2F_OPT_PREEN)) fix_problem(ctx, PR_4_PASS_HEADER, &pctx); group = 0; maxgroup = fs->group_desc_count; if (ctx->progress) if ((ctx->progress)(ctx, 4, 0, maxgroup)) return; inode = e2fsck_allocate_memory(ctx, EXT2_INODE_SIZE(fs->super), "scratch inode"); /* Protect loop from wrap-around if s_inodes_count maxed */ for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) { int isdir; if (ctx->flags & E2F_FLAG_SIGNAL_MASK) goto errout; if ((i % fs->super->s_inodes_per_group) == 0) { group++; if (ctx->progress) if ((ctx->progress)(ctx, 4, group, maxgroup)) goto errout; } if (i == EXT2_BAD_INO || (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super))) continue; if (!(ext2fs_test_inode_bitmap2(ctx->inode_used_map, i)) || (ctx->inode_imagic_map && ext2fs_test_inode_bitmap2(ctx->inode_imagic_map, i)) || (ctx->inode_bb_map && ext2fs_test_inode_bitmap2(ctx->inode_bb_map, i))) continue; ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count); ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); if (link_counted == 0) { if (!buf) buf = e2fsck_allocate_memory(ctx, fs->blocksize, "bad_inode buffer"); if (e2fsck_process_bad_inode(ctx, 0, i, buf)) continue; if (disconnect_inode(ctx, i, inode)) continue; ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count); ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); } isdir = ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i); if (isdir && (link_counted > EXT2_LINK_MAX)) link_counted = 1; if (link_counted != link_count) { e2fsck_read_inode(ctx, i, inode, "pass4"); pctx.ino = i; pctx.inode = inode; if ((link_count != inode->i_links_count) && !isdir && (inode->i_links_count <= EXT2_LINK_MAX)) { pctx.num = link_count; fix_problem(ctx, PR_4_INCONSISTENT_COUNT, &pctx); } pctx.num = link_counted; /* i_link_count was previously exceeded, but no longer * is, fix this but don't consider it an error */ if ((isdir && link_counted > 1 && (inode->i_flags & EXT2_INDEX_FL) && link_count == 1 && !(ctx->options & E2F_OPT_NO)) || fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) { inode->i_links_count = link_counted; e2fsck_write_inode(ctx, i, inode, "pass4"); } } } ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0; ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0; ext2fs_free_inode_bitmap(ctx->inode_bb_map); ctx->inode_bb_map = 0; ext2fs_free_inode_bitmap(ctx->inode_imagic_map); ctx->inode_imagic_map = 0; errout: if (buf) ext2fs_free_mem(&buf); ext2fs_free_mem(&inode); print_resource_track(ctx, _("Pass 4"), &rtrack, ctx->fs->io); }
/* * This function resets an e2fsck context; it is called when e2fsck * needs to be restarted. */ errcode_t e2fsck_reset_context(e2fsck_t ctx) { int i; ctx->flags &= E2F_RESET_FLAGS; ctx->lost_and_found = 0; ctx->bad_lost_and_found = 0; if (ctx->inode_used_map) { ext2fs_free_inode_bitmap(ctx->inode_used_map); ctx->inode_used_map = 0; } if (ctx->inode_dir_map) { ext2fs_free_inode_bitmap(ctx->inode_dir_map); ctx->inode_dir_map = 0; } if (ctx->inode_reg_map) { ext2fs_free_inode_bitmap(ctx->inode_reg_map); ctx->inode_reg_map = 0; } if (ctx->block_found_map) { ext2fs_free_block_bitmap(ctx->block_found_map); ctx->block_found_map = 0; } if (ctx->inode_link_info) { ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0; } if (ctx->journal_io) { if (ctx->fs && ctx->fs->io != ctx->journal_io) io_channel_close(ctx->journal_io); ctx->journal_io = 0; } if (ctx->fs && ctx->fs->dblist) { ext2fs_free_dblist(ctx->fs->dblist); ctx->fs->dblist = 0; } e2fsck_free_dir_info(ctx); e2fsck_free_dx_dir_info(ctx); if (ctx->refcount) { ea_refcount_free(ctx->refcount); ctx->refcount = 0; } if (ctx->refcount_extra) { ea_refcount_free(ctx->refcount_extra); ctx->refcount_extra = 0; } if (ctx->block_dup_map) { ext2fs_free_block_bitmap(ctx->block_dup_map); ctx->block_dup_map = 0; } if (ctx->block_ea_map) { ext2fs_free_block_bitmap(ctx->block_ea_map); ctx->block_ea_map = 0; } if (ctx->block_metadata_map) { ext2fs_free_block_bitmap(ctx->block_metadata_map); ctx->block_metadata_map = 0; } if (ctx->inode_bb_map) { ext2fs_free_inode_bitmap(ctx->inode_bb_map); ctx->inode_bb_map = 0; } if (ctx->inode_bad_map) { ext2fs_free_inode_bitmap(ctx->inode_bad_map); ctx->inode_bad_map = 0; } if (ctx->inode_imagic_map) { ext2fs_free_inode_bitmap(ctx->inode_imagic_map); ctx->inode_imagic_map = 0; } if (ctx->dirs_to_hash) { ext2fs_u32_list_free(ctx->dirs_to_hash); ctx->dirs_to_hash = 0; } /* * Clear the array of invalid meta-data flags */ if (ctx->invalid_inode_bitmap_flag) { ext2fs_free_mem(&ctx->invalid_inode_bitmap_flag); ctx->invalid_inode_bitmap_flag = 0; } if (ctx->invalid_block_bitmap_flag) { ext2fs_free_mem(&ctx->invalid_block_bitmap_flag); ctx->invalid_block_bitmap_flag = 0; } if (ctx->invalid_inode_table_flag) { ext2fs_free_mem(&ctx->invalid_inode_table_flag); ctx->invalid_inode_table_flag = 0; } if (ctx->encrypted_dirs) { ext2fs_u32_list_free(ctx->encrypted_dirs); ctx->encrypted_dirs = 0; } if (ctx->inode_count) { ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0; } /* Clear statistic counters */ ctx->fs_directory_count = 0; ctx->fs_regular_count = 0; ctx->fs_blockdev_count = 0; ctx->fs_chardev_count = 0; ctx->fs_links_count = 0; ctx->fs_symlinks_count = 0; ctx->fs_fast_symlinks_count = 0; ctx->fs_fifo_count = 0; ctx->fs_total_count = 0; ctx->fs_badblocks_count = 0; ctx->fs_sockets_count = 0; ctx->fs_ind_count = 0; ctx->fs_dind_count = 0; ctx->fs_tind_count = 0; ctx->fs_fragmented = 0; ctx->fs_fragmented_dir = 0; ctx->large_files = 0; for (i=0; i < MAX_EXTENT_DEPTH_COUNT; i++) ctx->extent_depth_count[i] = 0; /* Reset the superblock to the user's requested value */ ctx->superblock = ctx->use_superblock; return 0; }
void e2fsck_pass4(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; ext2_ino_t i; struct ext2_inode inode; #ifdef RESOURCE_TRACK struct resource_track rtrack; #endif struct problem_context pctx; __u16 link_count, link_counted; char *buf = 0; int group, maxgroup; #ifdef RESOURCE_TRACK init_resource_track(&rtrack); #endif #ifdef MTRACE mtrace_print("Pass 4"); #endif clear_problem_context(&pctx); if (!(ctx->options & E2F_OPT_PREEN)) fix_problem(ctx, PR_4_PASS_HEADER, &pctx); group = 0; maxgroup = fs->group_desc_count; if (ctx->progress) if ((ctx->progress)(ctx, 4, 0, maxgroup)) return; /* Protect loop from wrap-around if s_inodes_count maxed */ for (i=1; i <= fs->super->s_inodes_count && i > 0; i++) { if (ctx->flags & E2F_FLAG_SIGNAL_MASK) goto errout; if ((i % fs->super->s_inodes_per_group) == 0) { group++; if (ctx->progress) if ((ctx->progress)(ctx, 4, group, maxgroup)) goto errout; } if (i == EXT2_BAD_INO || (i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super))) continue; if (!(ext2fs_test_inode_bitmap(ctx->inode_used_map, i)) || (ctx->inode_imagic_map && ext2fs_test_inode_bitmap(ctx->inode_imagic_map, i)) || (ctx->inode_bb_map && ext2fs_test_inode_bitmap(ctx->inode_bb_map, i))) continue; ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count); ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); if (link_counted == 0) { if (!buf) buf = e2fsck_allocate_memory(ctx, fs->blocksize, "bad_inode buffer"); if (e2fsck_process_bad_inode(ctx, 0, i, buf)) continue; if (disconnect_inode(ctx, i)) continue; ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count); ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); } if (link_counted != link_count) { e2fsck_read_inode(ctx, i, &inode, "pass4"); pctx.ino = i; pctx.inode = &inode; if (link_count != inode.i_links_count) { pctx.num = link_count; fix_problem(ctx, PR_4_INCONSISTENT_COUNT, &pctx); } pctx.num = link_counted; if (fix_problem(ctx, PR_4_BAD_REF_COUNT, &pctx)) { inode.i_links_count = link_counted; e2fsck_write_inode(ctx, i, &inode, "pass4"); } } } ext2fs_free_icount(ctx->inode_link_info); ctx->inode_link_info = 0; ext2fs_free_icount(ctx->inode_count); ctx->inode_count = 0; ext2fs_free_inode_bitmap(ctx->inode_bb_map); ctx->inode_bb_map = 0; ext2fs_free_inode_bitmap(ctx->inode_imagic_map); ctx->inode_imagic_map = 0; errout: if (buf) ext2fs_free_mem(&buf); #ifdef RESOURCE_TRACK if (ctx->options & E2F_OPT_TIME2) { e2fsck_clear_progbar(ctx); print_resource_track(_("Pass 4"), &rtrack); } #endif }