e2fsprogs/e2fsck/pass4.c

210 lines
6.0 KiB
C
Raw Normal View History

1997-04-26 17:21:57 +04:00
/*
* pass4.c -- pass #4 of e2fsck: Check reference counts
*
1997-04-29 20:15:03 +04:00
* Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
*
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Public
* License.
* %End-Header%
*
* Pass 4 frees the following data structures:
* - A bitmap of which inodes are in bad blocks. (inode_bb_map)
Many files: pass4.c (e2fsck_pass4): If an inode is set in the inode_imagic_map bitmap, don't check to see if it is disconnected from the inode tree (because it almost certainly will be). Free inode_imagic_map at the end of pass 4. pass2.c (check_dir_block, check_filetype): If the FILETYPE feature is set, check the directory entry's filetype information field, and fix/set it if necessary. (e2fsck_pass2): Free the inode_reg_map bitmap at the end of pass 2. pass1.c (e2fsck_pass1, alloc_imagic_map): Allocate and fill in information for inode_reg_map and inode_imagic_map, which indicates which inodes are regular files and AFS inodes, respectively. Since only the master superblock is written during a restart, force that superblock to be used after a restart; otherwise changes to the block group descriptors end up getting ignored. problem.c, problemP.h: If e2fsck is run -n, make def_yn variable be 0 for "no". Add support for a new flag, PR_NO_NOMSG, which supresses the problem message if e2fsck is run with the -n option. problem.c, problem.h (PR_2_SET_FILETYPE, PR_2_BAD_FILETYPE): Add new problem codes. message.c (expand_dirent_expression): Add support for %dt which prints the dirent type information. e2fsck.c (e2fsck_reset_context): Free new bitmaps (inode_reg_map and inode_imagic_map). e2fsck.h (e2fsck_t): Add new inode_reg_map and inode_magic_map to the context structure. ChangeLog, nt_io.c: nt_io.c: New file which supports I/O under Windows NT. ChangeLog, gen_uuid_nt.c: gen_uuid_nt.c: New file which creates a UUID under Windows NT. Many files: Add support for non-Unix compiles
1999-10-21 23:33:18 +04:00
* - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
1997-04-26 17:21:57 +04:00
*/
#include "config.h"
1997-04-26 17:21:57 +04:00
#include "e2fsck.h"
1997-04-29 20:15:03 +04:00
#include "problem.h"
#include <ext2fs/ext2_ext_attr.h>
1997-04-26 17:21:57 +04:00
1997-04-29 19:29:49 +04:00
/*
* This routine is called when an inode is not connected to the
* directory tree.
*
1997-04-29 19:29:49 +04:00
* This subroutine returns 1 then the caller shouldn't bother with the
* rest of the pass 4 tests.
*/
static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i,
struct ext2_inode_large *inode)
1997-04-29 19:29:49 +04:00
{
ext2_filsys fs = ctx->fs;
1997-04-29 20:15:03 +04:00
struct problem_context pctx;
__u32 eamagic = 0;
int extra_size = 0;
1997-04-29 19:29:49 +04:00
e2fsck_read_inode_full(ctx, i, EXT2_INODE(inode),
EXT2_INODE_SIZE(fs->super),
"pass4: disconnect_inode");
if (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
extra_size = inode->i_extra_isize;
1997-04-29 20:15:03 +04:00
clear_problem_context(&pctx);
pctx.ino = i;
pctx.inode = EXT2_INODE(inode);
if (EXT2_INODE_SIZE(fs->super) -EXT2_GOOD_OLD_INODE_SIZE -extra_size >0)
eamagic = *(__u32 *)(((char *)inode) +EXT2_GOOD_OLD_INODE_SIZE +
extra_size);
/*
* Offer to delete any zero-length files that does not have
* blocks. If there is an EA block, it might have useful
* information, so we won't prompt to delete it, but let it be
* reconnected to lost+found.
*/
if (!inode->i_blocks && eamagic != EXT2_EXT_ATTR_MAGIC &&
(LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISDIR(inode->i_mode))) {
if (fix_problem(ctx, PR_4_ZERO_LEN_INODE, &pctx)) {
e2fsck_clear_inode(ctx, i, EXT2_INODE(inode), 0,
1997-04-29 19:29:49 +04:00
"disconnect_inode");
/*
* Fix up the bitmaps...
*/
e2fsck_read_bitmaps(ctx);
ext2fs_inode_alloc_stats2(fs, i, -1,
LINUX_S_ISDIR(inode->i_mode));
quota_data_inodes(ctx->qctx, inode, i, -1);
1997-04-29 19:29:49 +04:00
return 0;
}
}
1997-04-29 19:29:49 +04:00
/*
* Prompt to reconnect.
*/
if (fix_problem(ctx, PR_4_UNATTACHED_INODE, &pctx)) {
if (e2fsck_reconnect_file(ctx, i))
1997-04-29 19:29:49 +04:00
ext2fs_unmark_valid(fs);
} else {
/*
* If we don't attach the inode, then skip the
* i_links_test since there's no point in trying to
* force i_links_count to zero.
*/
ext2fs_unmark_valid(fs);
return 1;
}
return 0;
}
void e2fsck_pass4(e2fsck_t ctx)
1997-04-26 17:21:57 +04:00
{
ext2_filsys fs = ctx->fs;
ext2_ino_t i;
struct ext2_inode_large *inode;
int inode_size = EXT2_INODE_SIZE(fs->super);
#ifdef RESOURCE_TRACK
1997-04-26 17:21:57 +04:00
struct resource_track rtrack;
#endif
1997-04-29 20:15:03 +04:00
struct problem_context pctx;
__u16 link_count, link_counted;
char *buf = 0;
dgrp_t group, maxgroup;
init_resource_track(&rtrack, ctx->fs->io);
1997-04-26 17:21:57 +04:00
#ifdef MTRACE
mtrace_print("Pass 4");
#endif
e2fsck: read-ahead metadata during passes 1, 2, and 4 e2fsck pass1 is modified to use the block group data prefetch function to try to fetch the inode tables into the pagecache before it is needed. We iterate through the blockgroups until we have enough inode tables that need reading such that we can issue readahead; then we sit and wait until the last inode table block read of the last group to start fetching the next bunch. pass2 is modified to use the dirblock prefetching function to prefetch the list of directory blocks that are assembled in pass1. We use the "iterate a subset of a dblist" and avoid copying the dblist. Directory blocks are fetched incrementally as we walk through the directory block list. In previous iterations of this patch we would free the directory blocks after processing, but the performance hit to e2fsck itself wasn't worth it. Furthermore, it is anticipated that most users will then mount the FS and start using the directories, so they may as well remain in the page cache. pass4 is modified to prefetch the block and inode bitmaps in anticipation of pass 5, because pass4 is entirely CPU bound. In general, these mechanisms can decrease fsck time by 10-40%, if the host system has sufficient memory and the storage system can provide a lot of IOPs. Pretty much any storage system capable of handling multiple IOs in-flight at any time will see a fairly large performance boost. (Single-issue USB mass storage disks seem to suffer badly.) By default, the readahead buffer size will be set to the size of a block group's inode table (which is 2MiB for a regular ext4 FS). The -E readahead_kb= option can be given to specify the amount of memory to use for readahead or zero to disable it entirely; or an option can be given in e2fsck.conf. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2015-04-21 05:27:19 +03:00
/*
* Since pass4 is mostly CPU bound, start readahead of bitmaps
* ahead of pass 5 if we haven't already loaded them.
*/
if (ctx->readahead_kb &&
(fs->block_map == NULL || fs->inode_map == NULL))
e2fsck_readahead(fs, E2FSCK_READA_BBITMAP |
E2FSCK_READA_IBITMAP,
0, fs->group_desc_count);
1997-04-26 17:21:57 +04:00
1997-04-29 20:15:03 +04:00
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, inode_size, "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 == quota_type2inum(PRJQUOTA, ctx->fs->super) ||
i == EXT2_BAD_INO ||
1997-04-26 18:48:50 +04:00
(i > EXT2_ROOT_INO && i < EXT2_FIRST_INODE(fs->super)))
1997-04-26 17:21:57 +04:00
continue;
if (!(ext2fs_test_inode_bitmap2(ctx->inode_used_map, i)) ||
Many files: pass4.c (e2fsck_pass4): If an inode is set in the inode_imagic_map bitmap, don't check to see if it is disconnected from the inode tree (because it almost certainly will be). Free inode_imagic_map at the end of pass 4. pass2.c (check_dir_block, check_filetype): If the FILETYPE feature is set, check the directory entry's filetype information field, and fix/set it if necessary. (e2fsck_pass2): Free the inode_reg_map bitmap at the end of pass 2. pass1.c (e2fsck_pass1, alloc_imagic_map): Allocate and fill in information for inode_reg_map and inode_imagic_map, which indicates which inodes are regular files and AFS inodes, respectively. Since only the master superblock is written during a restart, force that superblock to be used after a restart; otherwise changes to the block group descriptors end up getting ignored. problem.c, problemP.h: If e2fsck is run -n, make def_yn variable be 0 for "no". Add support for a new flag, PR_NO_NOMSG, which supresses the problem message if e2fsck is run with the -n option. problem.c, problem.h (PR_2_SET_FILETYPE, PR_2_BAD_FILETYPE): Add new problem codes. message.c (expand_dirent_expression): Add support for %dt which prints the dirent type information. e2fsck.c (e2fsck_reset_context): Free new bitmaps (inode_reg_map and inode_imagic_map). e2fsck.h (e2fsck_t): Add new inode_reg_map and inode_magic_map to the context structure. ChangeLog, nt_io.c: nt_io.c: New file which supports I/O under Windows NT. ChangeLog, gen_uuid_nt.c: gen_uuid_nt.c: New file which creates a UUID under Windows NT. Many files: Add support for non-Unix compiles
1999-10-21 23:33:18 +04:00
(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)))
1997-04-26 17:21:57 +04:00
continue;
ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count);
ext2fs_icount_fetch(ctx->inode_count, i, &link_counted);
1997-04-29 20:15:03 +04:00
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))
1997-04-29 18:53:37 +04:00
continue;
ext2fs_icount_fetch(ctx->inode_link_info, i,
&link_count);
ext2fs_icount_fetch(ctx->inode_count, i,
&link_counted);
1997-04-26 17:21:57 +04:00
}
isdir = ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i);
if (isdir && (link_counted > EXT2_LINK_MAX))
link_counted = 1;
1997-04-29 20:15:03 +04:00
if (link_counted != link_count) {
e2fsck_read_inode_full(ctx, i, EXT2_INODE(inode),
inode_size, "pass4");
1997-04-29 20:15:03 +04:00
pctx.ino = i;
pctx.inode = EXT2_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);
1997-04-26 17:21:57 +04:00
}
1997-04-29 20:15:03 +04:00
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_full(ctx, i,
EXT2_INODE(inode),
inode_size, "pass4");
1997-04-29 20:15:03 +04:00
}
1997-04-26 17:21:57 +04:00
}
}
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);
1997-04-26 17:21:57 +04:00
}