From e8a3ee628ad693cbae231089b18886e6ba0e59d3 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 7 Jul 2001 11:12:50 -0400 Subject: [PATCH] Add code to check and fix incorrect reference counts in the extended attribute blocks. --- e2fsck/ChangeLog | 13 +++++++++++ e2fsck/pass1.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- e2fsck/problem.c | 17 +++++++++++++- e2fsck/problem.h | 9 ++++++++ 4 files changed, 104 insertions(+), 3 deletions(-) diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog index b24e806..1f6754d 100644 --- a/e2fsck/ChangeLog +++ b/e2fsck/ChangeLog @@ -1,3 +1,16 @@ +2001-07-07 Theodore Tso + + * pass1.c (adjust_extattr_refcount): Add new function which + adjusts the reference counts of extended attribute blocks + if needed, both up and down. + (e2fsck_pass1): If the refcount or refcount_extra + structure are present, call adjust_extattr_refcount(), + and free it afterwards. + + * problem.h, problem.c (PR_1_EXTATTR_READ_ABORT, + PR_1_EXTATTR_REFCOUNT, PR_1_EXTATTR_WRITE): Add new + problem codes. + 2001-07-02 Theodore Tso * pass1.c (e2fsck_pass1, check_ext_attr, check_blocks): Add diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index a9731c6..1ef4420 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -70,6 +70,8 @@ static void process_inodes(e2fsck_t ctx, char *block_buf); static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b); static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan, dgrp_t group, void * priv_data); +static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, + char *block_buf, int adjust_sign); /* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */ struct process_block_struct { @@ -623,6 +625,23 @@ void e2fsck_pass1(e2fsck_t ctx) ext2fs_close_inode_scan(scan); ehandler_operation(0); + /* + * If any extended attribute blocks' reference counts need to + * be adjusted, either up (ctx->refcount_extra), or down + * (ctx->refcount), then fix them. + */ + if (ctx->refcount) { + adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1); + ea_refcount_free(ctx->refcount); + ctx->refcount = 0; + } + if (ctx->refcount_extra) { + adjust_extattr_refcount(ctx, ctx->refcount_extra, + block_buf, +1); + ea_refcount_free(ctx->refcount_extra); + ctx->refcount_extra = 0; + } + if (ctx->invalid_bitmaps) handle_fs_bad_blocks(ctx); @@ -860,6 +879,52 @@ static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block) } /* + * Adjust the extended attribute block's reference counts at the end + * of pass 1, either by subtracting out references for EA blocks that + * are still referenced in ctx->refcount, or by adding references for + * EA blocks that had extra references as accounted for in + * ctx->refcount_extra. + */ +static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, + char *block_buf, int adjust_sign) +{ + struct ext2_ext_attr_header *header; + struct problem_context pctx; + ext2_filsys fs = ctx->fs; + errcode_t retval; + blk_t blk; + __u32 should_be; + int count; + + clear_problem_context(&pctx); + + ea_refcount_intr_begin(refcount); + while (1) { + if ((blk = ea_refcount_intr_next(refcount, &count)) == 0) + break; + pctx.blk = blk; + pctx.errcode = ext2fs_read_ext_attr(fs, blk, block_buf); + if (pctx.errcode) { + fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx); + return; + } + header = (struct ext2_ext_attr_header *) block_buf; + pctx.blkcount = header->h_refcount; + should_be = header->h_refcount + adjust_sign * count; + pctx.num = should_be; + if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) { + header->h_refcount = should_be; + pctx.errcode = ext2fs_write_ext_attr(fs, blk, + block_buf); + if (pctx.errcode) { + fix_problem(ctx, PR_1_EXTATTR_WRITE, &pctx); + continue; + } + } + } +} + +/* * Handle processing the extended attribute blocks */ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx, @@ -869,7 +934,7 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx, ext2_ino_t ino = pctx->ino; struct ext2_inode *inode = pctx->inode; blk_t blk; - static struct ext2_ext_attr_header *header; + struct ext2_ext_attr_header *header; int count; blk = inode->i_file_acl; @@ -941,7 +1006,6 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx, pctx->errcode = ext2fs_read_ext_attr(fs, blk, block_buf); if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx)) goto clear_extattr; - /* XXX what if read_ext_attr returns an error */ header = (struct ext2_ext_attr_header *) block_buf; if (header->h_magic != EXT2_EXT_ATTR_MAGIC) { diff --git a/e2fsck/problem.c b/e2fsck/problem.c index e5e62cf..4e13c53 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -577,11 +577,26 @@ static const struct e2fsck_problem problem_table[] = { N_("Error reading @a @b %b for @i %i. "), PROMPT_CLEAR, 0 }, - /* Invalid extended attribute block */ + /* Invalid extended attribute block */ { PR_1_BAD_EA_BLOCK, N_("@i %i has a bad @a @b %b. "), PROMPT_CLEAR, 0 }, + /* Error reading Extended Attribute block while fixing refcount */ + { PR_1_EXTATTR_READ_ABORT, + N_("Error reading @a @b %b (%m). "), + PROMPT_ABORT, 0 }, + + /* Extended attribute reference count incorrect */ + { PR_1_EXTATTR_REFCOUNT, + N_("@a @b %b has reference count %B, should be %N. "), + PROMPT_FIX, 0 }, + + /* Error writing Extended Attribute block while fixing refcount */ + { PR_1_EXTATTR_WRITE, + N_("Error writing @a @b %b (%m). "), + PROMPT_ABORT, 0 }, + /* Pass 1b errors */ /* Pass 1B: Rescan for duplicate/bad blocks */ diff --git a/e2fsck/problem.h b/e2fsck/problem.h index 7136381..aa2b706 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -336,6 +336,15 @@ struct problem_context { /* Invalid Extended Attribute block */ #define PR_1_BAD_EA_BLOCK 0x01003A +/* Error reading Extended Attribute block while fixing refcount -- abort */ +#define PR_1_EXTATTR_READ_ABORT 0x01003B + +/* Extended attribute reference count incorrect */ +#define PR_1_EXTATTR_REFCOUNT 0x01003C + +/* Error writing Extended Attribute block while fixing refcount */ +#define PR_1_EXTATTR_WRITE 0x01003D + /* * Pass 1b errors */ -- 1.8.3.1