ChangeLog, journal.c, problem.c, problem.h, super.c:
super.c (release_inode_block, release_inode_blocks,
release_orphan_inodes): Add code to deal with truncating inodes which
are still in use (but which are on the orphan list because they need
truncation).
problem.c, problem.h: Rename PR_0_CLEAR_ORPHAN_INODE to
PR_0_ORPHAN_CLEAR_INODE, and remove PR_0_ORPHAN_INODE_INUSE.
journal.c (e2fsck_run_ext3_journal): Add i18n support, and print a
message when the journal is being recovered.
diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog
index 51b9e44..07fa523 100644
--- a/e2fsck/ChangeLog
+++ b/e2fsck/ChangeLog
@@ -1,5 +1,17 @@
2000-10-24 <tytso@snap.thunk.org>
+ * super.c (release_inode_block, release_inode_blocks,
+ release_orphan_inodes): Add code to deal with truncating
+ inodes which are still in use (but which are on the orphan
+ list because they need truncation).
+
+ * problem.c, problem.h: Rename PR_0_CLEAR_ORPHAN_INODE to
+ PR_0_ORPHAN_CLEAR_INODE, and remove
+ PR_0_ORPHAN_INODE_INUSE.
+
+ * journal.c (e2fsck_run_ext3_journal): Add i18n support, and print
+ a message when the journal is being recovered.
+
* pass1.c (e2fsck_pass1): Don't check the i_mode field for the
journal inode, if it is in use.
diff --git a/e2fsck/journal.c b/e2fsck/journal.c
index c9f67d0..8e318b0 100644
--- a/e2fsck/journal.c
+++ b/e2fsck/journal.c
@@ -594,9 +594,10 @@
io_manager io_ptr = ctx->fs->io->manager;
int blocksize = ctx->fs->blocksize;
errcode_t retval, recover_retval;
-
+
+ printf(_("%s: recovering journal\n"), ctx->device_name);
if (ctx->options & E2F_OPT_READONLY) {
- printf("%s: won't do journal recovery while read-only\n",
+ printf(_("%s: won't do journal recovery while read-only\n"),
ctx->device_name);
return EXT2_ET_FILE_RO;
}
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index bbfbb25..df87beb 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -230,8 +230,8 @@
PROMPT_CLEAR, PR_PREEN_OK|PR_PREEN_NOMSG },
/* Clearing orphan inode */
- { PR_0_CLEAR_ORPHAN_INODE,
- N_("Clearing @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
+ { PR_0_ORPHAN_CLEAR_INODE,
+ N_("%s @o @i %i (uid=%Iu, gid=%Ig, mode=%Im, size=%Is)\n"),
PROMPT_NONE, 0 },
/* Illegal block found in orphaned inode */
@@ -254,11 +254,6 @@
N_("@I @i %i in @o @i list.\n"),
PROMPT_NONE, 0 },
- /* Orphan inode has a non-zero link count */
- { PR_0_ORPHAN_INODE_INUSE,
- N_("@o @i %i has a non-zero link count.\n"),
- PROMPT_NONE, 0 },
-
/* Pass 1 errors */
/* Pass 1: Checking inodes, blocks, and sizes */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 60ca1d2..b432e64 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -128,7 +128,7 @@
#define PR_0_JOURNAL_RESET_PROMPT 0x000019
/* Clearing orphan inode */
-#define PR_0_CLEAR_ORPHAN_INODE 0x000020
+#define PR_0_ORPHAN_CLEAR_INODE 0x000020
/* Illegal block found in orphaned inode */
#define PR_0_ORPHAN_ILLEGAL_BLOCK_NUM 0x000021
@@ -142,9 +142,6 @@
/* Illegal inode in orphaned inode list */
#define PR_0_ORPHAN_ILLEGAL_INODE 0x000024
-/* Orphan inode has a non-zero link count */
-#define PR_0_ORPHAN_INODE_INUSE 0x000025
-
/*
* Pass 1 errors
*/
diff --git a/e2fsck/super.c b/e2fsck/super.c
index 7875dc1..05d898f 100644
--- a/e2fsck/super.c
+++ b/e2fsck/super.c
@@ -55,10 +55,15 @@
* helper function to release an inode
*/
struct process_block_struct {
- ino_t ino;
- e2fsck_t ctx;
+ e2fsck_t ctx;
+ char *buf;
struct problem_context *pctx;
- int abort;
+ int truncating;
+ int truncate_offset;
+ blk_t truncate_block;
+ int truncated_blocks;
+ int abort;
+ errcode_t errcode;
};
static int release_inode_block(ext2_filsys fs,
@@ -67,9 +72,10 @@
void *priv_data)
{
struct process_block_struct *pb;
- e2fsck_t ctx;
- struct problem_context *pctx;
- blk_t blk = *block_nr;
+ e2fsck_t ctx;
+ struct problem_context *pctx;
+ blk_t blk = *block_nr;
+ int retval = 0;
pb = (struct process_block_struct *) priv_data;
ctx = pb->ctx;
@@ -84,42 +90,110 @@
if ((blk < fs->super->s_first_data_block) ||
(blk >= fs->super->s_blocks_count)) {
fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
+ abort:
pb->abort = 1;
return BLOCK_ABORT;
}
if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
- pb->abort = 1;
- return BLOCK_ABORT;
+ goto abort;
+ }
+
+ /*
+ * If we are deleting an orphan, then we leave the fields alone.
+ * If we are truncating an orphan, then update the inode fields
+ * and clean up any partial block data.
+ */
+ if (pb->truncating) {
+ /*
+ * We only remove indirect blocks if they are
+ * completely empty.
+ */
+ if (blockcnt < 0) {
+ int i, limit;
+ blk_t *block_nr;
+
+ pb->errcode = io_channel_read_blk(fs->io, blk, 1,
+ pb->buf);
+ if (pb->errcode)
+ goto abort;
+
+ limit = fs->blocksize >> 2;
+ for (i = 0, block_nr = (blk_t *) pb->buf;
+ i < limit; i++, block_nr++)
+ if (*block_nr)
+ return 0;
+ }
+ /*
+ * We don't remove direct blocks until we've reached
+ * the truncation block.
+ */
+ if (blockcnt >= 0 && blockcnt < pb->truncate_block)
+ return 0;
+ /*
+ * If part of the last block needs truncating, we do
+ * it here.
+ */
+ if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
+ pb->errcode = io_channel_read_blk(fs->io, blk, 1,
+ pb->buf);
+ if (pb->errcode)
+ goto abort;
+ memset(pb->buf + pb->truncate_offset, 0,
+ fs->blocksize - pb->truncate_offset);
+ pb->errcode = io_channel_write_blk(fs->io, blk, 1,
+ pb->buf);
+ if (pb->errcode)
+ goto abort;
+ }
+ pb->truncated_blocks++;
+ *block_nr = 0;
+ retval |= BLOCK_CHANGED;
}
ext2fs_unmark_block_bitmap(fs->block_map, blk);
fs->group_desc[ext2fs_group_of_blk(fs, blk)].bg_free_blocks_count++;
fs->super->s_free_blocks_count++;
- return 0;
+ return retval;
}
/*
* This function releases an inode. Returns 1 if an inconsistency was
- * found.
+ * found. If the inode has a link count, then it is being truncated and
+ * not deleted.
*/
-static int release_inode_blocks(e2fsck_t ctx, ino_t ino, char* block_buf,
+static int release_inode_blocks(e2fsck_t ctx, ino_t ino,
+ struct ext2_inode *inode, char* block_buf,
struct problem_context *pctx)
{
- ext2_filsys fs = ctx->fs;
+ ext2_filsys fs = ctx->fs;
errcode_t retval;
struct process_block_struct pb;
- pb.ino = ino;
+ pb.buf = block_buf + 3 * ctx->fs->blocksize;
pb.ctx = ctx;
pb.abort = 0;
+ pb.errcode = 0;
pb.pctx = pctx;
- retval = ext2fs_block_iterate(fs, ino, 0, block_buf,
- release_inode_block, &pb);
+ if (inode->i_links_count) {
+ pb.truncating = 1;
+ pb.truncate_block = (blk_t)
+ ((((long long)inode->i_size_high << 32) +
+ inode->i_size + fs->blocksize - 1) /
+ fs->blocksize);
+ pb.truncate_offset = inode->i_size % fs->blocksize;
+ } else {
+ pb.truncating = 0;
+ pb.truncate_block = 0;
+ pb.truncate_offset = 0;
+ }
+ pb.truncated_blocks = 0;
+ retval = ext2fs_block_iterate(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
+ block_buf, release_inode_block, &pb);
if (retval) {
- com_err("delete_file", retval,
+ com_err("release_inode_blocks", retval,
_("while calling ext2fs_block_iterate for inode %d"),
ino);
return 1;
@@ -127,6 +201,13 @@
if (pb.abort)
return 1;
+ /* Refresh the inode since ext2fs_block_iterate may have changed it */
+ e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
+
+ if (pb.truncated_blocks)
+ inode->i_blocks -= pb.truncated_blocks *
+ (fs->blocksize / 512);
+
ext2fs_mark_bb_dirty(fs);
return 0;
}
@@ -162,22 +243,19 @@
return 1;
}
- block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
+ block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
"block interate buffer");
e2fsck_read_bitmaps(ctx);
while (ino) {
- e2fsck_read_inode(ctx, ino, &inode, "delete_file");
+ e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
clear_problem_context(&pctx);
pctx.ino = ino;
pctx.inode = &inode;
+ pctx.str = inode.i_links_count ? "Truncating" : "Clearing";
- fix_problem(ctx, PR_0_CLEAR_ORPHAN_INODE, &pctx);
+ fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
- if (inode.i_links_count) {
- fix_problem(ctx, PR_0_ORPHAN_INODE_INUSE, &pctx);
- goto abort;
- }
next_ino = inode.i_dtime;
if (next_ino &&
((next_ino < EXT2_FIRST_INODE(fs->super)) ||
@@ -187,20 +265,21 @@
goto abort;
}
- if (release_inode_blocks(ctx, ino, block_buf, &pctx))
+ if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
goto abort;
-
- inode.i_dtime = time(0);
- e2fsck_write_inode(ctx, ino, &inode, "delete_file");
- ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
- ext2fs_mark_ib_dirty(fs);
- group = ext2fs_group_of_ino(fs, ino);
- fs->group_desc[group].bg_free_inodes_count++;
- fs->super->s_free_inodes_count++;
- if (LINUX_S_ISDIR(inode.i_mode))
- fs->group_desc[group].bg_used_dirs_count--;
-
+ if (!inode.i_links_count) {
+ ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
+ ext2fs_mark_ib_dirty(fs);
+ group = ext2fs_group_of_ino(fs, ino);
+ fs->group_desc[group].bg_free_inodes_count++;
+ fs->super->s_free_inodes_count++;
+ if (LINUX_S_ISDIR(inode.i_mode))
+ fs->group_desc[group].bg_used_dirs_count--;
+
+ inode.i_dtime = time(0);
+ }
+ e2fsck_write_inode(ctx, ino, &inode, "delete_file");
ino = next_ino;
}
return 0;