/* * This function reserves the superblock and block group descriptors * for a given block group. It currently returns the number of free * blocks assuming that inode table and allocation bitmaps will be in * the group. This is not necessarily the case when the flex_bg * feature is enabled, so callers should take care! It was only * really intended for use by mke2fs, and even there it's not that * useful. In the future, when we redo this function for 64-bit block * numbers, we should probably return the number of blocks used by the * super block and group descriptors instead. * * See also the comment for ext2fs_super_and_bgd_loc() */ int ext2fs_reserve_super_and_bgd(ext2_filsys fs, dgrp_t group, ext2fs_block_bitmap bmap) { blk64_t super_blk, old_desc_blk, new_desc_blk; blk_t used_blks; int j, old_desc_blocks, num_blocks; ext2fs_super_and_bgd_loc2(fs, group, &super_blk, &old_desc_blk, &new_desc_blk, &used_blks); 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; if (super_blk || (group == 0)) ext2fs_mark_block_bitmap2(bmap, super_blk); if (old_desc_blk) { if (fs->super->s_reserved_gdt_blocks && fs->block_map == bmap) fs->group_desc[group].bg_flags &= ~EXT2_BG_BLOCK_UNINIT; for (j=0; j < old_desc_blocks; j++) if (old_desc_blk + j < fs->super->s_blocks_count) ext2fs_mark_block_bitmap2(bmap, old_desc_blk + j); } if (new_desc_blk) ext2fs_mark_block_bitmap2(bmap, new_desc_blk); if (group == fs->group_desc_count-1) { num_blocks = (fs->super->s_blocks_count - fs->super->s_first_data_block) % fs->super->s_blocks_per_group; if (!num_blocks) num_blocks = fs->super->s_blocks_per_group; } else num_blocks = fs->super->s_blocks_per_group; num_blocks -= 2 + fs->inode_blocks_per_group + used_blks; return num_blocks ; }
static int process_block(ext2_filsys fs, blk64_t *block_nr, e2_blkcnt_t blockcnt, blk64_t ref_block, int ref_offset, void *priv_data) { struct process_block_struct *pb; errcode_t retval; int ret; blk64_t block, orig; pb = (struct process_block_struct *) priv_data; block = orig = *block_nr; ret = 0; /* * Let's see if this is one which we need to relocate */ if (ext2fs_test_block_bitmap2(pb->reserve, block)) { do { if (++block >= ext2fs_blocks_count(fs->super)) block = fs->super->s_first_data_block; if (block == orig) { pb->error = EXT2_ET_BLOCK_ALLOC_FAIL; return BLOCK_ABORT; } } while (ext2fs_test_block_bitmap2(pb->reserve, block) || ext2fs_test_block_bitmap2(pb->alloc_map, block)); retval = io_channel_read_blk64(fs->io, orig, 1, pb->buf); if (retval) { pb->error = retval; return BLOCK_ABORT; } retval = io_channel_write_blk64(fs->io, block, 1, pb->buf); if (retval) { pb->error = retval; return BLOCK_ABORT; } *block_nr = block; ext2fs_mark_block_bitmap2(pb->alloc_map, block); ret = BLOCK_CHANGED; if (pb->flags & EXT2_BMOVE_DEBUG) printf("ino=%u, blockcnt=%lld, %llu->%llu\n", (unsigned) pb->ino, blockcnt, (unsigned long long) orig, (unsigned long long) block); } if (pb->add_dir) { retval = ext2fs_add_dir_block2(fs->dblist, pb->ino, block, blockcnt); if (retval) { pb->error = retval; ret |= BLOCK_ABORT; } } return ret; }
/* * This function reserves the superblock and block group descriptors * for a given block group. It currently returns the number of free * blocks assuming that inode table and allocation bitmaps will be in * the group. This is not necessarily the case when the flex_bg * feature is enabled, so callers should take care! It was only * really intended for use by mke2fs, and even there it's not that * useful. In the future, when we redo this function for 64-bit block * numbers, we should probably return the number of blocks used by the * super block and group descriptors instead. * * See also the comment for ext2fs_super_and_bgd_loc() */ int ext2fs_reserve_super_and_bgd(ext2_filsys fs, dgrp_t group, ext2fs_block_bitmap bmap) { blk64_t super_blk, old_desc_blk, new_desc_blk; blk_t used_blks; int j, old_desc_blocks, num_blocks; ext2fs_super_and_bgd_loc2(fs, group, &super_blk, &old_desc_blk, &new_desc_blk, &used_blks); 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; if (super_blk || (group == 0)) ext2fs_mark_block_bitmap2(bmap, super_blk); if ((group == 0) && (fs->blocksize == 1024) && EXT2FS_CLUSTER_RATIO(fs) > 1) ext2fs_mark_block_bitmap2(bmap, 0); if (old_desc_blk) { if (fs->super->s_reserved_gdt_blocks && fs->block_map == bmap) ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); for (j=0; j < old_desc_blocks; j++) if (old_desc_blk + j < ext2fs_blocks_count(fs->super)) ext2fs_mark_block_bitmap2(bmap, old_desc_blk + j); } if (new_desc_blk) ext2fs_mark_block_bitmap2(bmap, new_desc_blk); num_blocks = ext2fs_group_blocks_count(fs, group); num_blocks -= 2 + fs->inode_blocks_per_group + used_blks; return num_blocks ; }
static errcode_t mark_uninit_bg_group_blocks(ext2_filsys fs) { dgrp_t i; blk64_t blk; ext2fs_block_bitmap bmap = fs->block_map; for (i = 0; i < fs->group_desc_count; i++) { if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT)) continue; ext2fs_reserve_super_and_bgd(fs, i, bmap); /* * Mark the blocks used for the inode table */ blk = ext2fs_inode_table_loc(fs, i); if (blk) ext2fs_mark_block_bitmap_range2(bmap, blk, fs->inode_blocks_per_group); /* * Mark block used for the block bitmap */ blk = ext2fs_block_bitmap_loc(fs, i); if (blk) ext2fs_mark_block_bitmap2(bmap, blk); /* * Mark block used for the inode bitmap */ blk = ext2fs_inode_bitmap_loc(fs, i); if (blk) ext2fs_mark_block_bitmap2(bmap, blk); } return 0; }
static void check_block_end(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; blk64_t end, save_blocks_count, i; struct problem_context pctx; clear_problem_context(&pctx); end = ext2fs_get_block_bitmap_start2(fs->block_map) + ((blk64_t)EXT2_CLUSTERS_PER_GROUP(fs->super) * fs->group_desc_count) - 1; pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map, end, &save_blocks_count); if (pctx.errcode) { pctx.num = 3; fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ return; } if (save_blocks_count == end) return; /* Protect loop from wrap-around if end is maxed */ for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) { if (!ext2fs_test_block_bitmap2(fs->block_map, EXT2FS_C2B(fs, i))) { if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) { for (; i <= end; i++) ext2fs_mark_block_bitmap2(fs->block_map, EXT2FS_C2B(fs, i)); ext2fs_mark_bb_dirty(fs); } else ext2fs_unmark_valid(fs); break; } } pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map, save_blocks_count, 0); if (pctx.errcode) { pctx.num = 4; fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; /* fatal */ return; } }
errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, ext2fs_block_bitmap *bitmap) { ext2fs_block_bitmap cmap, bmap; errcode_t retval; blk64_t i, b_end, c_end; int n, ratio; bmap = *bitmap; if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(bmap)) return 0; /* Nothing to do */ retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap", &cmap); if (retval) return retval; i = bmap->start; b_end = bmap->end; bmap->end = bmap->real_end; c_end = cmap->end; cmap->end = cmap->real_end; n = 0; ratio = 1 << fs->cluster_ratio_bits; while (i < bmap->real_end) { if (ext2fs_test_block_bitmap2(bmap, i)) { ext2fs_mark_block_bitmap2(cmap, i); i += ratio - n; n = 0; continue; } i++; n++; if (n >= ratio) n = 0; } bmap->end = b_end; cmap->end = c_end; ext2fs_free_block_bitmap(bmap); *bitmap = cmap; return 0; }
void add_empty_dirblock(empty_dir_info edi, struct ext2_db_entry2 *db) { if (!edi || !db) return; if (db->ino == 11) return; /* Inode number 11 is usually lost+found */ printf(_("Empty directory block %u (#%d) in inode %u\n"), db->blk, db->blockcnt, db->ino); ext2fs_mark_block_bitmap2(edi->empty_dir_blocks, db->blk); if (ext2fs_test_inode_bitmap(edi->dir_map, db->ino)) return; ext2fs_mark_inode_bitmap(edi->dir_map, db->ino); ext2fs_add_dir_block2(edi->empty_dblist, db->ino, db->blk, db->blockcnt); }
static void iscan_test_read_blk64(unsigned long long block, int count, errcode_t err) { int i; if (first_no_comma) first_no_comma = 0; else printf(", "); if (count > 1) printf("%llu-%llu", block, block+count-1); else printf("%llu", block); for (i=0; i < count; i++, block++) { if (ext2fs_test_block_bitmap2(touched_map, block)) { printf("\nDuplicate block?!? --- %llu\n", block); failed++; first_no_comma = 1; } ext2fs_mark_block_bitmap2(touched_map, block); } }
void do_setb(int argc, char *argv[]) { unsigned int block, num; int err; int test_result, op_result; if (check_fs_open(argv[0])) return; if (argc != 2 && argc != 3) { com_err(argv[0], 0, "Usage: setb <block> [num]"); return; } block = parse_ulong(argv[1], argv[0], "block", &err); if (err) return; if (argc == 3) { num = parse_ulong(argv[2], argv[0], "num", &err); if (err) return; ext2fs_mark_block_bitmap_range2(test_fs->block_map, block, num); printf("Marking blocks %u to %u\n", block, block + num - 1); return; } test_result = ext2fs_test_block_bitmap2(test_fs->block_map, block); op_result = ext2fs_mark_block_bitmap2(test_fs->block_map, block); printf("Setting block %u, was %s before\n", block, op_result ? "set" : "clear"); if (!test_result != !op_result) com_err(argv[0], 0, "*ERROR* test_result different! (%d, %d)", test_result, op_result); }
/* * Verify the touched map */ static void check_map(void) { int i, j, first=1; blk64_t blk; for (i=0; test_vec[i]; i++) { if (ext2fs_test_block_bitmap2(touched_map, test_vec[i])) { printf("Bad block was touched --- %llu\n", test_vec[i]); failed++; first_no_comma = 1; } ext2fs_mark_block_bitmap2(touched_map, test_vec[i]); } for (i = 0; i < test_fs->group_desc_count; i++) { for (j=0, blk = ext2fs_inode_table_loc(test_fs, i); j < test_fs->inode_blocks_per_group; j++, blk++) { if (!ext2fs_test_block_bitmap2(touched_map, blk) && !ext2fs_test_block_bitmap2(bad_block_map, blk)) { printf("Missing block --- %llu\n", blk); failed++; } } } printf("Bad inodes: "); for (i=1; i <= test_fs->super->s_inodes_count; i++) { if (ext2fs_test_inode_bitmap2(bad_inode_map, i)) { if (first) first = 0; else printf(", "); printf("%u", i); } } printf("\n"); }
/* * This routine gets the lost_and_found inode, making it a directory * if necessary */ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) { ext2_filsys fs = ctx->fs; ext2_ino_t ino; blk64_t blk; errcode_t retval; struct ext2_inode inode; char * block; static const char name[] = "lost+found"; struct problem_context pctx; int will_rehash, flags; if (ctx->lost_and_found) return ctx->lost_and_found; clear_problem_context(&pctx); will_rehash = e2fsck_dir_will_be_rehashed(ctx, EXT2_ROOT_INO); if (will_rehash) { flags = ctx->fs->flags; ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; } retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino); if (will_rehash) ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); if (retval && !fix) return 0; if (!retval) { /* Lost+found shouldn't have inline data */ retval = ext2fs_read_inode(fs, ino, &inode); if (fix && retval) return 0; if (fix && (inode.i_flags & EXT4_INLINE_DATA_FL)) { if (!fix_problem(ctx, PR_3_LPF_INLINE_DATA, &pctx)) return 0; goto unlink; } if (fix && (inode.i_flags & EXT4_ENCRYPT_FL)) { if (!fix_problem(ctx, PR_3_LPF_ENCRYPTED, &pctx)) return 0; goto unlink; } if (ext2fs_check_directory(fs, ino) == 0) { ctx->lost_and_found = ino; return ino; } /* Lost+found isn't a directory! */ if (!fix) return 0; pctx.ino = ino; if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) return 0; unlink: /* OK, unlink the old /lost+found file. */ pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); if (pctx.errcode) { pctx.str = "ext2fs_unlink"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } (void) e2fsck_dir_info_set_parent(ctx, ino, 0); e2fsck_adjust_inode_count(ctx, ino, -1); /* * If the old lost+found was a directory, we've just * disconnected it from the directory tree, which * means we need to restart the directory tree scan. * The simplest way to do this is restart the whole * e2fsck operation. */ if (LINUX_S_ISDIR(inode.i_mode)) ctx->flags |= E2F_FLAG_RESTART; } else if (retval != EXT2_ET_FILE_NOT_FOUND) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); } if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) return 0; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ e2fsck_read_bitmaps(ctx); /* * First, find a free block */ if (ctx->lnf_repair_block) { blk = ctx->lnf_repair_block; ctx->lnf_repair_block = 0; goto skip_new_block; } retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval == EXT2_ET_BLOCK_ALLOC_FAIL && fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) { fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx); ctx->lost_and_found = EXT2_ROOT_INO; return 0; } if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); return 0; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); skip_new_block: ext2fs_block_alloc_stats2(fs, blk, +1); /* * Next find a free inode. */ retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, ctx->inode_used_map, &ino); if (retval == EXT2_ET_INODE_ALLOC_FAIL && fix_problem(ctx, PR_3_LPF_NO_SPACE, &pctx)) { fix_problem(ctx, PR_3_NO_SPACE_TO_RECOVER, &pctx); ctx->lost_and_found = EXT2_ROOT_INO; return 0; } if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); return 0; } ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); inode.i_mode = 040700; inode.i_size = fs->blocksize; inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; inode.i_links_count = 2; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; /* * Next, write out the inode. */ pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); if (pctx.errcode) { pctx.str = "ext2fs_write_inode"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Now let's create the actual data block for the inode. * Due to metadata_csum, the directory block MUST be written * after the inode is written to disk! */ retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); return 0; } retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); ext2fs_free_mem(&block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); return 0; } /* * Finally, create the directory link */ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); if (pctx.errcode == EXT2_ET_DIR_NO_SPACE) { pctx.errcode = ext2fs_expand_dir(fs, EXT2_ROOT_INO); if (pctx.errcode) goto link_error; pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); } if (pctx.errcode) { link_error: pctx.str = "ext2fs_link"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Miscellaneous bookkeeping that needs to be kept straight. */ e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); ext2fs_icount_store(ctx->inode_count, ino, 2); ext2fs_icount_store(ctx->inode_link_info, ino, 2); ctx->lost_and_found = ino; quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); quota_data_inodes(ctx->qctx, &inode, ino, +1); #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif return ino; }
/* * This routine gets the lost_and_found inode, making it a directory * if necessary */ ext2_ino_t e2fsck_get_lost_and_found(e2fsck_t ctx, int fix) { ext2_filsys fs = ctx->fs; ext2_ino_t ino; blk64_t blk; errcode_t retval; struct ext2_inode inode; char * block; static const char name[] = "lost+found"; struct problem_context pctx; if (ctx->lost_and_found) return ctx->lost_and_found; clear_problem_context(&pctx); retval = ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino); if (retval && !fix) return 0; if (!retval) { if (ext2fs_check_directory(fs, ino) == 0) { ctx->lost_and_found = ino; return ino; } /* Lost+found isn't a directory! */ if (!fix) return 0; pctx.ino = ino; if (!fix_problem(ctx, PR_3_LPF_NOTDIR, &pctx)) return 0; /* OK, unlink the old /lost+found file. */ pctx.errcode = ext2fs_unlink(fs, EXT2_ROOT_INO, name, ino, 0); if (pctx.errcode) { pctx.str = "ext2fs_unlink"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } (void) e2fsck_dir_info_set_parent(ctx, ino, 0); e2fsck_adjust_inode_count(ctx, ino, -1); } else if (retval != EXT2_ET_FILE_NOT_FOUND) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_FIND_LPF, &pctx); } if (!fix_problem(ctx, PR_3_NO_LF_DIR, 0)) return 0; /* * Read the inode and block bitmaps in; we'll be messing with * them. */ e2fsck_read_bitmaps(ctx); /* * First, find a free block */ retval = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_BLOCK, &pctx); return 0; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); ext2fs_block_alloc_stats2(fs, blk, +1); /* * Next find a free inode. */ retval = ext2fs_new_inode(fs, EXT2_ROOT_INO, 040700, ctx->inode_used_map, &ino); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_INODE, &pctx); return 0; } ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); ext2fs_inode_alloc_stats2(fs, ino, +1, 1); /* * Now let's create the actual data block for the inode */ retval = ext2fs_new_dir_block(fs, ino, EXT2_ROOT_INO, &block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_NEW_DIR_BLOCK, &pctx); return 0; } retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); ext2fs_free_mem(&block); if (retval) { pctx.errcode = retval; fix_problem(ctx, PR_3_ERR_LPF_WRITE_BLOCK, &pctx); return 0; } /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); inode.i_mode = 040700; inode.i_size = fs->blocksize; inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; inode.i_links_count = 2; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; /* * Next, write out the inode. */ pctx.errcode = ext2fs_write_new_inode(fs, ino, &inode); if (pctx.errcode) { pctx.str = "ext2fs_write_inode"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Finally, create the directory link */ pctx.errcode = ext2fs_link(fs, EXT2_ROOT_INO, name, ino, EXT2_FT_DIR); if (pctx.errcode) { pctx.str = "ext2fs_link"; fix_problem(ctx, PR_3_CREATE_LPF_ERROR, &pctx); return 0; } /* * Miscellaneous bookkeeping that needs to be kept straight. */ e2fsck_add_dir_info(ctx, ino, EXT2_ROOT_INO); e2fsck_adjust_inode_count(ctx, EXT2_ROOT_INO, 1); ext2fs_icount_store(ctx->inode_count, ino, 2); ext2fs_icount_store(ctx->inode_link_info, ino, 2); ctx->lost_and_found = ino; quota_data_add(ctx->qctx, &inode, ino, fs->blocksize); quota_data_inodes(ctx->qctx, &inode, ino, +1); #if 0 printf("/lost+found created; inode #%lu\n", ino); #endif return ino; }
/* * This makes sure the root inode is present; if not, we ask if the * user wants us to create it. Not creating it is a fatal error. */ static void check_root(e2fsck_t ctx) { ext2_filsys fs = ctx->fs; blk64_t blk; struct ext2_inode inode; char * block; struct problem_context pctx; clear_problem_context(&pctx); if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO)) { /* * If the root inode is not a directory, die here. The * user must have answered 'no' in pass1 when we * offered to clear it. */ if (!(ext2fs_test_inode_bitmap2(ctx->inode_dir_map, EXT2_ROOT_INO))) { fix_problem(ctx, PR_3_ROOT_NOT_DIR_ABORT, &pctx); ctx->flags |= E2F_FLAG_ABORT; } return; } if (!fix_problem(ctx, PR_3_NO_ROOT_INODE, &pctx)) { fix_problem(ctx, PR_3_NO_ROOT_INODE_ABORT, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } e2fsck_read_bitmaps(ctx); /* * First, find a free block */ pctx.errcode = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); if (pctx.errcode) { pctx.str = "ext2fs_new_block"; fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); ext2fs_mark_block_bitmap2(fs->block_map, blk); ext2fs_mark_bb_dirty(fs); /* * Now let's create the actual data block for the inode */ pctx.errcode = ext2fs_new_dir_block(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, &block); if (pctx.errcode) { pctx.str = "ext2fs_new_dir_block"; fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } pctx.errcode = ext2fs_write_dir_block4(fs, blk, block, 0, EXT2_ROOT_INO); if (pctx.errcode) { pctx.str = "ext2fs_write_dir_block"; fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } ext2fs_free_mem(&block); /* * Set up the inode structure */ memset(&inode, 0, sizeof(inode)); inode.i_mode = 040755; inode.i_size = fs->blocksize; inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now; inode.i_links_count = 2; ext2fs_iblk_set(fs, &inode, 1); inode.i_block[0] = blk; /* * Write out the inode. */ pctx.errcode = ext2fs_write_new_inode(fs, EXT2_ROOT_INO, &inode); if (pctx.errcode) { pctx.str = "ext2fs_write_inode"; fix_problem(ctx, PR_3_CREATE_ROOT_ERROR, &pctx); ctx->flags |= E2F_FLAG_ABORT; return; } /* * Miscellaneous bookkeeping... */ e2fsck_add_dir_info(ctx, EXT2_ROOT_INO, EXT2_ROOT_INO); ext2fs_icount_store(ctx->inode_count, EXT2_ROOT_INO, 2); ext2fs_icount_store(ctx->inode_link_info, EXT2_ROOT_INO, 2); ext2fs_mark_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO); ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, EXT2_ROOT_INO); ext2fs_mark_inode_bitmap2(fs->inode_map, EXT2_ROOT_INO); ext2fs_mark_ib_dirty(fs); }
static errcode_t undo_write_tdb(io_channel channel, unsigned long long block, int count) { int size, sz; unsigned long long block_num, backing_blk_num; errcode_t retval = 0; ext2_loff_t offset; struct undo_private_data *data; unsigned char *read_ptr; unsigned long long end_block; unsigned long long data_size; void *data_ptr; struct undo_key *key; __u32 blk_crc; data = (struct undo_private_data *) channel->private_data; if (data->undo_file == NULL) { /* * Transaction database not initialized */ return 0; } if (count == 1) size = channel->block_size; else { if (count < 0) size = -count; else size = count * channel->block_size; } retval = undo_setup_tdb(data); if (retval) return retval; /* * Data is stored in tdb database as blocks of tdb_data_size size * This helps in efficient lookup further. * * We divide the disk to blocks of tdb_data_size. */ offset = (block * channel->block_size) + data->offset ; block_num = offset / data->tdb_data_size; end_block = (offset + size - 1) / data->tdb_data_size; while (block_num <= end_block) { __u32 keysz; /* * Check if we have the record already */ if (ext2fs_test_block_bitmap2(data->written_block_map, block_num)) { /* Try the next block */ block_num++; continue; } ext2fs_mark_block_bitmap2(data->written_block_map, block_num); /* * Read one block using the backing I/O manager * The backing I/O manager block size may be * different from the tdb_data_size. * Also we need to recalcuate the block number with respect * to the backing I/O manager. */ offset = block_num * data->tdb_data_size; backing_blk_num = (offset - data->offset) / channel->block_size; count = data->tdb_data_size + ((offset - data->offset) % channel->block_size); retval = ext2fs_get_mem(count, &read_ptr); if (retval) { return retval; } memset(read_ptr, 0, count); actual_size = 0; if ((count % channel->block_size) == 0) sz = count / channel->block_size; else sz = -count; retval = io_channel_read_blk64(data->real, backing_blk_num, sz, read_ptr); if (retval) { if (retval != EXT2_ET_SHORT_READ) { free(read_ptr); return retval; } /* * short read so update the record size * accordingly */ data_size = actual_size; } else { data_size = data->tdb_data_size; } if (data_size == 0) { free(read_ptr); block_num++; continue; } dbg_printf("Read %llu bytes from FS block %llu (blk=%llu cnt=%u)\n", data_size, backing_blk_num, block, count); if ((data_size % data->undo_file->block_size) == 0) sz = data_size / data->undo_file->block_size; else sz = -actual_size; data_ptr = read_ptr + ((offset - data->offset) % data->undo_file->block_size); /* extend this key? */ if (data->keys_in_block) { key = data->keyb->keys + data->keys_in_block - 1; keysz = ext2fs_le32_to_cpu(key->size); } else { key = NULL; keysz = 0; } if (key != NULL && ext2fs_le64_to_cpu(key->fsblk) + ((keysz + data->tdb_data_size - 1) / data->tdb_data_size) == backing_blk_num && E2UNDO_MAX_EXTENT_BLOCKS * data->tdb_data_size > keysz + sz) { blk_crc = ext2fs_le32_to_cpu(key->blk_crc); blk_crc = ext2fs_crc32c_le(blk_crc, (unsigned char *)data_ptr, data_size); key->blk_crc = ext2fs_cpu_to_le32(blk_crc); key->size = ext2fs_cpu_to_le32(keysz + data_size); } else { data->num_keys++; key = data->keyb->keys + data->keys_in_block; data->keys_in_block++; key->fsblk = ext2fs_cpu_to_le64(backing_blk_num); blk_crc = ext2fs_crc32c_le(~0, (unsigned char *)data_ptr, data_size); key->blk_crc = ext2fs_cpu_to_le32(blk_crc); key->size = ext2fs_cpu_to_le32(data_size); } dbg_printf("Writing block %llu to offset %llu size %d key %zu\n", block_num, data->undo_blk_num, sz, data->num_keys - 1); retval = io_channel_write_blk64(data->undo_file, data->undo_blk_num, sz, data_ptr); if (retval) { free(read_ptr); return retval; } data->undo_blk_num++; free(read_ptr); /* Write out the key block */ retval = write_undo_indexes(data, 0); if (retval) return retval; /* Next block */ block_num++; } return retval; }
/* * This routine sanity checks the group descriptors */ errcode_t ext2fs_check_desc(ext2_filsys fs) { ext2fs_block_bitmap bmap; errcode_t retval; dgrp_t i; blk_t first_block = fs->super->s_first_data_block; blk_t last_block = fs->super->s_blocks_count-1; blk_t blk, b; int j; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); retval = ext2fs_allocate_block_bitmap(fs, "check_desc map", &bmap); if (retval) return retval; for (i = 0; i < fs->group_desc_count; i++) ext2fs_reserve_super_and_bgd(fs, i, bmap); for (i = 0; i < fs->group_desc_count; i++) { if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { first_block = ext2fs_group_first_block(fs, i); last_block = ext2fs_group_last_block(fs, i); if (i == (fs->group_desc_count - 1)) last_block = fs->super->s_blocks_count-1; } /* * Check to make sure the block bitmap for group is sane */ blk = fs->group_desc[i].bg_block_bitmap; if (blk < first_block || blk > last_block || ext2fs_test_block_bitmap2(bmap, blk)) { retval = EXT2_ET_GDESC_BAD_BLOCK_MAP; goto errout; } ext2fs_mark_block_bitmap2(bmap, blk); /* * Check to make sure the inode bitmap for group is sane */ blk = fs->group_desc[i].bg_inode_bitmap; if (blk < first_block || blk > last_block || ext2fs_test_block_bitmap2(bmap, blk)) { retval = EXT2_ET_GDESC_BAD_INODE_MAP; goto errout; } ext2fs_mark_block_bitmap2(bmap, blk); /* * Check to make sure the inode table for group is sane */ blk = fs->group_desc[i].bg_inode_table; if (blk < first_block || ((blk + fs->inode_blocks_per_group - 1) > last_block)) { retval = EXT2_ET_GDESC_BAD_INODE_TABLE; goto errout; } for (j = 0, b = blk; j < fs->inode_blocks_per_group; j++, b++) { if (ext2fs_test_block_bitmap2(bmap, b)) { retval = EXT2_ET_GDESC_BAD_INODE_TABLE; goto errout; } ext2fs_mark_block_bitmap2(bmap, b); } } errout: ext2fs_free_block_bitmap(bmap); return retval; }
/* * Setup the variables for doing the inode scan test. */ static void setup(void) { errcode_t retval; int i; struct ext2_super_block param; initialize_ext2_error_table(); memset(¶m, 0, sizeof(param)); ext2fs_blocks_count_set(¶m, 12000); test_io_cb_read_blk = iscan_test_read_blk; test_io_cb_read_blk64 = iscan_test_read_blk64; retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m, test_io_manager, &test_fs); if (retval) { com_err("setup", retval, "While initializing filesystem"); exit(1); } retval = ext2fs_allocate_tables(test_fs); if (retval) { com_err("setup", retval, "While allocating tables for test filesystem"); exit(1); } retval = ext2fs_allocate_block_bitmap(test_fs, "bad block map", &bad_block_map); if (retval) { com_err("setup", retval, "While allocating bad_block bitmap"); exit(1); } retval = ext2fs_allocate_block_bitmap(test_fs, "touched map", &touched_map); if (retval) { com_err("setup", retval, "While allocating touched block bitmap"); exit(1); } retval = ext2fs_allocate_inode_bitmap(test_fs, "bad inode map", &bad_inode_map); if (retval) { com_err("setup", retval, "While allocating bad inode bitmap"); exit(1); } retval = ext2fs_badblocks_list_create(&test_badblocks, 5); if (retval) { com_err("setup", retval, "while creating badblocks list"); exit(1); } for (i=0; test_vec[i]; i++) { retval = ext2fs_badblocks_list_add(test_badblocks, test_vec[i]); if (retval) { com_err("setup", retval, "while adding test vector %d", i); exit(1); } ext2fs_mark_block_bitmap2(bad_block_map, test_vec[i]); } test_fs->badblocks = test_badblocks; }
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; }
errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, ext2fs_block_bitmap bmap) { errcode_t retval; blk_t group_blk, start_blk, last_blk, new_blk, blk; dgrp_t last_grp = 0; int j, rem_grps = 0, flexbg_size = 0; group_blk = ext2fs_group_first_block(fs, group); last_blk = ext2fs_group_last_block(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); rem_grps = last_grp - group; if (last_grp > fs->group_desc_count) last_grp = fs->group_desc_count; } /* * Allocate the block and inode bitmaps, if necessary */ if (fs->stride) { retval = ext2fs_get_free_blocks(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 && fs->group_desc[group-1].bg_block_bitmap) prev_block = fs->group_desc[group-1].bg_block_bitmap; start_blk = flexbg_offset(fs, group, prev_block, bmap, 0, rem_grps, 1); last_blk = ext2fs_group_last_block(fs, last_grp); } if (!fs->group_desc[group].bg_block_bitmap) { retval = ext2fs_get_free_blocks(fs, start_blk, last_blk, 1, bmap, &new_blk); if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) retval = ext2fs_get_free_blocks(fs, group_blk, last_blk, 1, bmap, &new_blk); if (retval) return retval; ext2fs_mark_block_bitmap2(bmap, new_blk); fs->group_desc[group].bg_block_bitmap = new_blk; if (flexbg_size) { dgrp_t gr = ext2fs_group_of_blk(fs, new_blk); fs->group_desc[gr].bg_free_blocks_count--; fs->super->s_free_blocks_count--; fs->group_desc[gr].bg_flags &= ~EXT2_BG_BLOCK_UNINIT; ext2fs_group_desc_csum_set(fs, gr); } } if (flexbg_size) { blk_t prev_block = 0; if (group && fs->group_desc[group-1].bg_inode_bitmap) prev_block = fs->group_desc[group-1].bg_inode_bitmap; start_blk = flexbg_offset(fs, group, prev_block, bmap, flexbg_size, rem_grps, 1); last_blk = ext2fs_group_last_block(fs, last_grp); } if (!fs->group_desc[group].bg_inode_bitmap) { retval = ext2fs_get_free_blocks(fs, start_blk, last_blk, 1, bmap, &new_blk); if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) retval = ext2fs_get_free_blocks(fs, group_blk, last_blk, 1, bmap, &new_blk); if (retval) return retval; ext2fs_mark_block_bitmap2(bmap, new_blk); fs->group_desc[group].bg_inode_bitmap = new_blk; if (flexbg_size) { dgrp_t gr = ext2fs_group_of_blk(fs, new_blk); fs->group_desc[gr].bg_free_blocks_count--; fs->super->s_free_blocks_count--; fs->group_desc[gr].bg_flags &= ~EXT2_BG_BLOCK_UNINIT; ext2fs_group_desc_csum_set(fs, gr); } } /* * Allocate the inode table */ if (flexbg_size) { blk_t prev_block = 0; if (group && fs->group_desc[group-1].bg_inode_table) prev_block = fs->group_desc[group-1].bg_inode_table; group_blk = flexbg_offset(fs, group, prev_block, bmap, flexbg_size * 2, fs->inode_blocks_per_group * rem_grps, fs->inode_blocks_per_group); last_blk = ext2fs_group_last_block(fs, last_grp); } if (!fs->group_desc[group].bg_inode_table) { retval = ext2fs_get_free_blocks(fs, group_blk, last_blk, fs->inode_blocks_per_group, bmap, &new_blk); if (retval) return retval; for (j=0, blk = new_blk; j < fs->inode_blocks_per_group; j++, blk++) { ext2fs_mark_block_bitmap2(bmap, blk); if (flexbg_size) { dgrp_t gr = ext2fs_group_of_blk(fs, blk); fs->group_desc[gr].bg_free_blocks_count--; fs->super->s_free_blocks_count--; fs->group_desc[gr].bg_flags &= ~EXT2_BG_BLOCK_UNINIT; ext2fs_group_desc_csum_set(fs, gr); } } fs->group_desc[group].bg_inode_table = new_blk; } ext2fs_group_desc_csum_set(fs, group); return 0; }