diff mbox

[04/18] e2fsck: fix rule-violating lblk->pblk mappings on bigalloc filesystems

Message ID 20140726003404.28334.18860.stgit@birch.djwong.org
State Accepted, archived
Headers show

Commit Message

Darrick Wong July 26, 2014, 12:34 a.m. UTC
As far as I can tell, logical block mappings on a bigalloc filesystem are
supposed to follow a few constraints:

 * The logical cluster offset must match the physical cluster offset.
 * A logical cluster may not map to multiple physical clusters.

Since the multiply-claimed block recovery code can be used to fix these
problems, teach e2fsck to find these transgressions and fix them.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 e2fsck/pass1.c              |   52 +++++++++++
 e2fsck/pass1b.c             |   42 ++++++++-
 e2fsck/problem.c            |    5 +
 e2fsck/problem.h            |    3 +
 tests/f_badcluster/expect   |  198 +++++++++++++++++++++++++++++++++++++++++++
 tests/f_badcluster/image.gz |  Bin
 tests/f_badcluster/name     |    2 
 tests/f_badcluster/script   |   25 +++++
 8 files changed, 320 insertions(+), 7 deletions(-)
 create mode 100644 tests/f_badcluster/expect
 create mode 100644 tests/f_badcluster/image.gz
 create mode 100644 tests/f_badcluster/name
 create mode 100644 tests/f_badcluster/script



--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Andreas Dilger July 26, 2014, 6:02 a.m. UTC | #1
Wouldn't it be possible to use this information to determine which
of the inodes sharing a duplicate mapped block is the right one
and which inode is the bad one?

Cheers, Andreas

> On Jul 25, 2014, at 18:34, "Darrick J. Wong" <darrick.wong@oracle.com> wrote:
> 
> As far as I can tell, logical block mappings on a bigalloc filesystem are
> supposed to follow a few constraints:
> 
> * The logical cluster offset must match the physical cluster offset.
> * A logical cluster may not map to multiple physical clusters.
> 
> Since the multiply-claimed block recovery code can be used to fix these
> problems, teach e2fsck to find these transgressions and fix them.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> ---
> e2fsck/pass1.c              |   52 +++++++++++
> e2fsck/pass1b.c             |   42 ++++++++-
> e2fsck/problem.c            |    5 +
> e2fsck/problem.h            |    3 +
> tests/f_badcluster/expect   |  198 +++++++++++++++++++++++++++++++++++++++++++
> tests/f_badcluster/image.gz |  Bin
> tests/f_badcluster/name     |    2 
> tests/f_badcluster/script   |   25 +++++
> 8 files changed, 320 insertions(+), 7 deletions(-)
> create mode 100644 tests/f_badcluster/expect
> create mode 100644 tests/f_badcluster/image.gz
> create mode 100644 tests/f_badcluster/name
> create mode 100644 tests/f_badcluster/script
> 
> 
> diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> index a6552e5..646ef8a 100644
> --- a/e2fsck/pass1.c
> +++ b/e2fsck/pass1.c
> @@ -1945,6 +1945,40 @@ void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
>    e2fsck_write_inode(ctx, ino, inode, source);
> }
> 
> +/*
> + * Use the multiple-blocks reclamation code to fix alignment problems in
> + * a bigalloc filesystem.  We want a logical cluster to map to *only* one
> + * physical cluster, and we want the block offsets within that cluster to
> + * line up.
> + */
> +static int has_unaligned_cluster_map(e2fsck_t ctx,
> +                     blk64_t last_pblk, e2_blkcnt_t last_lblk,
> +                     blk64_t pblk, blk64_t lblk)
> +{
> +    blk64_t cluster_mask;
> +
> +    if (!ctx->fs->cluster_ratio_bits)
> +        return 0;
> +    cluster_mask = EXT2FS_CLUSTER_MASK(ctx->fs);
> +
> +    /*
> +     * If the block in the logical cluster doesn't align with the block in
> +     * the physical cluster...
> +     */
> +    if ((lblk & cluster_mask) != (pblk & cluster_mask))
> +        return 1;
> +
> +    /*
> +     * If we cross a physical cluster boundary within a logical cluster...
> +     */
> +    if (last_pblk && (lblk & cluster_mask) != 0 &&
> +        EXT2FS_B2C(ctx->fs, lblk) == EXT2FS_B2C(ctx->fs, last_lblk) &&
> +        EXT2FS_B2C(ctx->fs, pblk) != EXT2FS_B2C(ctx->fs, last_pblk))
> +        return 1;
> +
> +    return 0;
> +}
> +
> static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
>                 struct process_block_struct *pb,
>                 blk64_t start_block, blk64_t end_block,
> @@ -2249,7 +2283,16 @@ alloc_later:
>                mark_block_used(ctx, blk);
>                pb->num_blocks++;
>            }
> -
> +            if (has_unaligned_cluster_map(ctx, pb->previous_block,
> +                              pb->last_block, blk,
> +                              blockcnt)) {
> +                pctx->blk = blockcnt;
> +                pctx->blk2 = blk;
> +                fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx);
> +                mark_block_used(ctx, blk);
> +                mark_block_used(ctx, blk);
> +            }
> +            pb->last_block = blockcnt;
>            pb->previous_block = blk;
> 
>            if (is_dir) {
> @@ -2815,6 +2858,13 @@ static int process_block(ext2_filsys fs,
>             ((unsigned) blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) {
>        mark_block_used(ctx, blk);
>        p->num_blocks++;
> +    } else if (has_unaligned_cluster_map(ctx, p->previous_block,
> +                         p->last_block, blk, blockcnt)) {
> +        pctx->blk = blockcnt;
> +        pctx->blk2 = blk;
> +        fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx);
> +        mark_block_used(ctx, blk);
> +        mark_block_used(ctx, blk);
>    }
>    if (blockcnt >= 0)
>        p->last_block = blockcnt;
> diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
> index 8d42d10..c0bfa07 100644
> --- a/e2fsck/pass1b.c
> +++ b/e2fsck/pass1b.c
> @@ -261,7 +261,7 @@ struct process_block_struct {
>    e2fsck_t    ctx;
>    ext2_ino_t    ino;
>    int        dup_blocks;
> -    blk64_t        cur_cluster;
> +    blk64_t        cur_cluster, phys_cluster;
>    blk64_t        last_blk;
>    struct ext2_inode *inode;
>    struct problem_context *pctx;
> @@ -317,6 +317,7 @@ static void pass1b(e2fsck_t ctx, char *block_buf)
>        pb.dup_blocks = 0;
>        pb.inode = &inode;
>        pb.cur_cluster = ~0;
> +        pb.phys_cluster = ~0;
>        pb.last_blk = 0;
>        pb.pctx->blk = pb.pctx->blk2 = 0;
> 
> @@ -360,7 +361,7 @@ static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
> {
>    struct process_block_struct *p;
>    e2fsck_t ctx;
> -    blk64_t    lc;
> +    blk64_t    lc, pc;
>    problem_t op;
> 
>    if (HOLE_BLKADDR(*block_nr))
> @@ -368,6 +369,7 @@ static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
>    p = (struct process_block_struct *) priv_data;
>    ctx = p->ctx;
>    lc = EXT2FS_B2C(fs, blockcnt);
> +    pc = EXT2FS_B2C(fs, *block_nr);
> 
>    if (!ext2fs_test_block_bitmap2(ctx->block_dup_map, *block_nr))
>        goto finish;
> @@ -389,11 +391,19 @@ static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
>    p->dup_blocks++;
>    ext2fs_mark_inode_bitmap2(inode_dup_map, p->ino);
> 
> -    if (blockcnt < 0 || lc != p->cur_cluster)
> +    /*
> +     * Qualifications for submitting a block for duplicate processing:
> +     * It's an extent/indirect block (and has a negative logical offset);
> +     * we've crossed a logical cluster boundary; or the physical cluster
> +     * suddenly changed, which indicates that blocks in a logical cluster
> +     * are mapped to multiple physical clusters.
> +     */
> +    if (blockcnt < 0 || lc != p->cur_cluster || pc != p->phys_cluster)
>        add_dupe(ctx, p->ino, EXT2FS_B2C(fs, *block_nr), p->inode);
> 
> finish:
>    p->cur_cluster = lc;
> +    p->phys_cluster = pc;
>    return 0;
> }
> 
> @@ -563,7 +573,11 @@ static void pass1d(e2fsck_t ctx, char *block_buf)
>            pctx.dir = t->dir;
>            fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
>        }
> -        if (file_ok) {
> +        /*
> +         * Even if the file shares blocks with itself, we still need to
> +         * clone the blocks.
> +         */
> +        if (file_ok && (meta_data ? shared_len+1 : shared_len) != 0) {
>            fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
>            continue;
>        }
> @@ -706,9 +720,10 @@ struct clone_struct {
>    errcode_t    errcode;
>    blk64_t        dup_cluster;
>    blk64_t        alloc_block;
> -    ext2_ino_t    dir;
> +    ext2_ino_t    dir, ino;
>    char    *buf;
>    e2fsck_t ctx;
> +    struct ext2_inode    *inode;
> };
> 
> static int clone_file_block(ext2_filsys fs,
> @@ -756,13 +771,26 @@ static int clone_file_block(ext2_filsys fs,
>            decrement_badcount(ctx, *block_nr, p);
> 
>        cs->dup_cluster = c;
> -
> +        /*
> +         * Let's try an implied cluster allocation.  If we get the same
> +         * cluster back, then we need to find a new block; otherwise,
> +         * we're merely fixing the problem of one logical cluster being
> +         * mapped to multiple physical clusters.
> +         */
> +        new_block = 0;
> +        retval = ext2fs_map_cluster_block(fs, cs->ino, cs->inode,
> +                          blockcnt, &new_block);
> +        if (retval == 0 && new_block != 0 &&
> +            EXT2FS_B2C(ctx->fs, new_block) !=
> +            EXT2FS_B2C(ctx->fs, *block_nr))
> +            goto cluster_alloc_ok;
>        retval = ext2fs_new_block2(fs, 0, ctx->block_found_map,
>                       &new_block);
>        if (retval) {
>            cs->errcode = retval;
>            return BLOCK_ABORT;
>        }
> +cluster_alloc_ok:
>        cs->alloc_block = new_block;
> 
>    got_block:
> @@ -817,6 +845,8 @@ static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino,
>    cs.dup_cluster = ~0;
>    cs.alloc_block = 0;
>    cs.ctx = ctx;
> +    cs.ino = ino;
> +    cs.inode = &dp->inode;
>    retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
>    if (retval)
>        return retval;
> diff --git a/e2fsck/problem.c b/e2fsck/problem.c
> index 60c02af..4da8ba8 100644
> --- a/e2fsck/problem.c
> +++ b/e2fsck/problem.c
> @@ -1048,6 +1048,11 @@ static struct e2fsck_problem problem_table[] = {
>      N_("@d @i %i has @x marked uninitialized at @b %c.  "),
>      PROMPT_FIX, PR_PREEN_OK },
> 
> +    /* Inode logical block (physical block ) is misaligned. */
> +    { PR_1_MISALIGNED_CLUSTER,
> +      N_("@i %i logical @b %b (physical @b %c) violates cluster allocation rules.\nWill fix in pass 1B.\n"),
> +      PROMPT_NONE, 0 },
> +
>    /* Pass 1b errors */
> 
>    /* Pass 1B: Rescan for duplicate/bad blocks */
> diff --git a/e2fsck/problem.h b/e2fsck/problem.h
> index 6cd3d50..80ef4a2 100644
> --- a/e2fsck/problem.h
> +++ b/e2fsck/problem.h
> @@ -609,6 +609,9 @@ struct problem_context {
> /* uninit directory block */
> #define PR_1_UNINIT_DBLOCK        0x010073
> 
> +/* Inode logical block is misaligned */
> +#define PR_1_MISALIGNED_CLUSTER        0x010074
> +
> /*
>  * Pass 1b errors
>  */
> diff --git a/tests/f_badcluster/expect b/tests/f_badcluster/expect
> new file mode 100644
> index 0000000..eb3bcf0
> --- /dev/null
> +++ b/tests/f_badcluster/expect
> @@ -0,0 +1,198 @@
> +Pass 1: Checking inodes, blocks, and sizes
> +Inode 12 logical block 2 (physical block 1154) violates cluster allocation rules.
> +Will fix in pass 1B.
> +Inode 12, i_blocks is 32, should be 64.  Fix? yes
> +
> +Inode 16 logical block 5 (physical block 1173) violates cluster allocation rules.
> +Will fix in pass 1B.
> +Inode 16, i_size is 3072, should be 6144.  Fix? yes
> +
> +Inode 16, i_blocks is 32, should be 64.  Fix? yes
> +
> +Inode 17 logical block 0 (physical block 1186) violates cluster allocation rules.
> +Will fix in pass 1B.
> +Inode 17 logical block 2 (physical block 1184) violates cluster allocation rules.
> +Will fix in pass 1B.
> +Inode 17, i_blocks is 32, should be 64.  Fix? yes
> +
> +Inode 18 logical block 3 (physical block 1201) violates cluster allocation rules.
> +Will fix in pass 1B.
> +Inode 18, i_blocks is 32, should be 64.  Fix? yes
> +
> +
> +Running additional passes to resolve blocks claimed by more than one inode...
> +Pass 1B: Rescanning for multiply-claimed blocks
> +Multiply-claimed block(s) in inode 12: 1154
> +Multiply-claimed block(s) in inode 13: 1152--1154
> +Multiply-claimed block(s) in inode 14: 1648--1650
> +Multiply-claimed block(s) in inode 15: 1650
> +Multiply-claimed block(s) in inode 16: 1173
> +Multiply-claimed block(s) in inode 17: 1186 1185 1184
> +Multiply-claimed block(s) in inode 18: 1201
> +Pass 1C: Scanning directories for inodes with multiply-claimed blocks
> +Pass 1D: Reconciling multiply-claimed blocks
> +(There are 7 inodes containing multiply-claimed blocks.)
> +
> +File /a (inode #12, mod time Tue Jun 17 08:00:50 2014) 
> +  has 1 multiply-claimed block(s), shared with 1 file(s):
> +    /b (inode #13, mod time Tue Jun 17 08:00:50 2014)
> +Clone multiply-claimed blocks? yes
> +
> +File /b (inode #13, mod time Tue Jun 17 08:00:50 2014) 
> +  has 1 multiply-claimed block(s), shared with 1 file(s):
> +    /a (inode #12, mod time Tue Jun 17 08:00:50 2014)
> +Multiply-claimed blocks already reassigned or cloned.
> +
> +File /c (inode #14, mod time Tue Jun 17 08:00:50 2014) 
> +  has 1 multiply-claimed block(s), shared with 1 file(s):
> +    /d (inode #15, mod time Tue Jun 17 08:00:50 2014)
> +Clone multiply-claimed blocks? yes
> +
> +File /d (inode #15, mod time Tue Jun 17 08:00:50 2014) 
> +  has 1 multiply-claimed block(s), shared with 1 file(s):
> +    /c (inode #14, mod time Tue Jun 17 08:00:50 2014)
> +Multiply-claimed blocks already reassigned or cloned.
> +
> +File /e (inode #16, mod time Tue Jun 17 08:00:50 2014) 
> +  has 1 multiply-claimed block(s), shared with 0 file(s):
> +Clone multiply-claimed blocks? yes
> +
> +File /f (inode #17, mod time Tue Jun 17 08:00:50 2014) 
> +  has 1 multiply-claimed block(s), shared with 0 file(s):
> +Clone multiply-claimed blocks? yes
> +
> +File /g (inode #18, mod time Tue Jun 17 08:00:50 2014) 
> +  has 1 multiply-claimed block(s), shared with 0 file(s):
> +Clone multiply-claimed blocks? yes
> +
> +Pass 2: Checking directory structure
> +Pass 3: Checking directory connectivity
> +Pass 4: Checking reference counts
> +Pass 5: Checking group summary information
> +Free blocks count wrong for group #0 (50, counted=47).
> +Fix? yes
> +
> +Free blocks count wrong (800, counted=752).
> +Fix? yes
> +
> +
> +test_fs: ***** FILE SYSTEM WAS MODIFIED *****
> +test_fs: 18/128 files (22.2% non-contiguous), 1296/2048 blocks
> +Pass 1: Checking inodes, blocks, and sizes
> +Inode 12, i_blocks is 64, should be 32.  Fix? yes
> +
> +Inode 16, i_blocks is 64, should be 32.  Fix? yes
> +
> +Inode 17, i_blocks is 64, should be 32.  Fix? yes
> +
> +Inode 18, i_blocks is 64, should be 32.  Fix? yes
> +
> +Pass 2: Checking directory structure
> +Pass 3: Checking directory connectivity
> +Pass 4: Checking reference counts
> +Pass 5: Checking group summary information
> +Block bitmap differences:  -(1168--1200)
> +Fix? yes
> +
> +Free blocks count wrong for group #0 (47, counted=50).
> +Fix? yes
> +
> +Free blocks count wrong (752, counted=800).
> +Fix? yes
> +
> +
> +test_fs: ***** FILE SYSTEM WAS MODIFIED *****
> +test_fs: 18/128 files (5.6% non-contiguous), 1248/2048 blocks
> +Pass 1: Checking inodes, blocks, and sizes
> +Pass 2: Checking directory structure
> +Pass 3: Checking directory connectivity
> +Pass 4: Checking reference counts
> +Pass 5: Checking group summary information
> +test_fs: 18/128 files (5.6% non-contiguous), 1248/2048 blocks
> +debugfs:  stat /a
> +Inode: 12   Type: regular    Mode:  0644   Flags: 0x80000
> +Generation: 1117152157    Version: 0x00000001
> +User:     0   Group:     0   Size: 3072
> +File ACL: 0    Directory ACL: 0
> +Links: 1   Blockcount: 32
> +Fragment:  Address: 0    Number: 0    Size: 0
> +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +EXTENTS:
> +(0-1):1136-1137, (2):1138
> +debugfs:  stat /b
> +Inode: 13   Type: regular    Mode:  0644   Flags: 0x80000
> +Generation: 1117152158    Version: 0x00000001
> +User:     0   Group:     0   Size: 3072
> +File ACL: 0    Directory ACL: 0
> +Links: 1   Blockcount: 32
> +Fragment:  Address: 0    Number: 0    Size: 0
> +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +EXTENTS:
> +(0-2):1152-1154
> +debugfs:  stat /c
> +Inode: 14   Type: regular    Mode:  0644   Flags: 0x80000
> +Generation: 1117152159    Version: 0x00000001
> +User:     0   Group:     0   Size: 3072
> +File ACL: 0    Directory ACL: 0
> +Links: 1   Blockcount: 32
> +Fragment:  Address: 0    Number: 0    Size: 0
> +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +EXTENTS:
> +(0-1):1216-1217, (2):1218
> +debugfs:  stat /d
> +Inode: 15   Type: regular    Mode:  0644   Flags: 0x0
> +Generation: 1117152160    Version: 0x00000001
> +User:     0   Group:     0   Size: 3072
> +File ACL: 0    Directory ACL: 0
> +Links: 1   Blockcount: 32
> +Fragment:  Address: 0    Number: 0    Size: 0
> +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +BLOCKS:
> +(TIND):1650
> +TOTAL: 1
> +
> +debugfs:  stat /e
> +Inode: 16   Type: regular    Mode:  0644   Flags: 0x80000
> +Generation: 1117152161    Version: 0x00000001
> +User:     0   Group:     0   Size: 6144
> +File ACL: 0    Directory ACL: 0
> +Links: 1   Blockcount: 32
> +Fragment:  Address: 0    Number: 0    Size: 0
> +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +EXTENTS:
> +(0-2):1664-1666, (5):1669
> +debugfs:  stat /f
> +Inode: 17   Type: regular    Mode:  0644   Flags: 0x80000
> +Generation: 1117152162    Version: 0x00000001
> +User:     0   Group:     0   Size: 3072
> +File ACL: 0    Directory ACL: 0
> +Links: 1   Blockcount: 32
> +Fragment:  Address: 0    Number: 0    Size: 0
> +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +EXTENTS:
> +(0):1232, (1):1233, (2):1234
> +debugfs:  stat /g
> +Inode: 18   Type: regular    Mode:  0644   Flags: 0x80000
> +Generation: 1117152163    Version: 0x00000001
> +User:     0   Group:     0   Size: 3072
> +File ACL: 0    Directory ACL: 0
> +Links: 1   Blockcount: 32
> +Fragment:  Address: 0    Number: 0    Size: 0
> +ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
> +EXTENTS:
> +(0-2):1680-1682, (3):1683
> +debugfs:  
> \ No newline at end of file
> diff --git a/tests/f_badcluster/image.gz b/tests/f_badcluster/image.gz
> new file mode 100644
> index 0000000000000000000000000000000000000000..e02ee1866868361e6e82bfbe29982365b2e3aa55
> GIT binary patch
> literal 3131
> zcmeH`eNfVO9LF)YGArHAl6flRwbV_eOvC0A4VPY_dFBj}kaU;3`An&ypmc4h9VhIf
> zG;+!qGBs1@gsG+2gU*y0Y50JcUV;y)D1xAjhu^x}b(h}$+@E~@_&j|7`F=jH&*u%L
> z*?=Z=?ARUF%2(nv2aF3y#X5Z+g%u<)LiS(y@}tx>cPz)&G0Qe&A*OK@Raq{8^q_F-
> zbB{#>iF|Dz=b)|E490O%W`;sOzn*Dtd$W+q>f!h2aWn3xA)rK!kjYY12Cz2VS^ia?
> zJKzn{oZ*j8$vKNhzKW^O#IziXdU8FzD*|<eD@NYnUd~^Sa_N2j2lXf(hj_l!WF(Xz
> z^@k=+XFN;5_JiKlfolqV3uj7S$m~OhGOU?ARvy2Z3xiBLmvwf9s?~oQZlIxv;1!zu
> zbzM+@IZwGj2G3`h`BuLoys*(veF#j!uuCmX7XnXQP{(9>l8|3~Qb0L3W_@O8Bou2S
> z#LwPyeSHU4SGh|_3O@<jVw-ulMAQSCYtw-BmUoczrKImN`3b_5sj-MBHFstycPr9Q
> zyDc_LT!%)FD#_s5hLIl5UXnDPD@{u}7ViyT0SH2%u*0u$j#2PSivDR6be36cLR7JI
> z>P9Io$LN#}Hy;+P)k<}%cC(5=1%>EC`mJ`K9DhLsMXNnTY7b5%xHS-GMy*X>nRI$s
> zn4{EJv>{B*zOB8Z6U4SCeQg`RoRS%(Z&ez2MRsCB5pII*p9!eO5eo6@SX?5Fv~;uk
> zMYgdE|JNdavOxx(M+a9JGE#v?A50YtD7>vh#2-d%9rOK)Okcl?dlmE3Udha-PBwlx
> zw<*_LcZb-D6dfZP2dfe{<%37d#Ki?z2z!rK7Yx~>r3c$JM1<s%-6TO8VzA^PvIA2p
> zr@^=X@pVnNrWr5+)70e+;E{U_fA>jX*E;3D-245!%MWU2YQwru2>?*S{bGVA^+1FB
> z8-;3y!|ILos18QJB|+U;YN8OP0+aw@s+)wy9IvNaJ!a&tRX-rM!{|#hNL**Yt+QAN
> zJh9_Kysv$_Bh~mb8`5JR&ddJMoa1}#T#i6&vzy$;rqF-rzqsGWd$8<0N-IB0;jPp~
> z22J;hV9a6Hf&ScQfGR<EF*<B2wZ4daZ;nx^i0)Iqacq`d{&rb6l&4^4_yVusv+Swi
> z1ak*`wtFPmFfS9Bu<1ZooEm+61;F<$9g=?5M=jQYQ<c*bH6}vQ?^dJ9a3$sY-ekEM
> zucY8tA{+GF>N<>h`Nd1)Ci8h@bC`iSpmOlA7MwV}^GPJS^lC&^e~*O6GRb2rQ1h+d
> zB*q7XIxlAAlVK8>hUhH`Qg4!ZahPpe$wQ2fuN{FV4;STob=J3cl1ux;sphvTO-et5
> za=9(yX3Y%vwwp~zE$z|267_p4(cyK{(@S=d<tY<GLiz(@c9y?d_xCfA^QuQ;p;6U-
> zgkHj3QM@#;1&o%EeQo}R%l?CeiQ{1XPRZF1iUXvrAI<|wei)IyMDNH*+K}a%dA%B_
> zeZmRAs#0yds@p(lDKZT^e7?L|o5?bXMz^W(-3eHtg@A>Cg@A>Cg@A>?|4(4iWQ{Gq
> K#Rh>6g8l&!3vo*T
> 
> literal 0
> HcmV?d00001
> 
> diff --git a/tests/f_badcluster/name b/tests/f_badcluster/name
> new file mode 100644
> index 0000000..266f81c
> --- /dev/null
> +++ b/tests/f_badcluster/name
> @@ -0,0 +1,2 @@
> +test alignment problems with bigalloc clusters
> +
> diff --git a/tests/f_badcluster/script b/tests/f_badcluster/script
> new file mode 100644
> index 0000000..ba6b248
> --- /dev/null
> +++ b/tests/f_badcluster/script
> @@ -0,0 +1,25 @@
> +if test -x $DEBUGFS_EXE; then
> +    IMAGE=$test_dir/../f_badcluster/image.gz
> +    OUT=$test_name.log
> +    EXP=$test_dir/expect
> +    gzip -d < $IMAGE > $TMPFILE
> +    ../misc/tune2fs -L test_fs $TMPFILE
> +    ../e2fsck/e2fsck -fy $TMPFILE > $OUT
> +    ../e2fsck/e2fsck -fy $TMPFILE >> $OUT
> +    ../e2fsck/e2fsck -fy $TMPFILE >> $OUT
> +    for i in a b c d e f g; do echo "stat /$i"; done | $DEBUGFS_EXE $TMPFILE >> $OUT
> +
> +    cmp -s $OUT $EXP
> +    status=$?
> +
> +    if [ "$status" = 0 ]; then
> +        echo "$test_name: $test_description: ok"
> +        touch $test_name.ok
> +    else
> +        echo "$test_name: $test_description: failed"
> +        diff $DIFF_OPTS $EXP $OUT > $test_name.failed
> +        rm -f $test_name.tmp
> +    fi
> +else
> +    echo "$test_name: skipped"
> +fi
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Theodore Ts'o July 26, 2014, 8:27 p.m. UTC | #2
On Sat, Jul 26, 2014 at 12:02:10AM -0600, Andreas Dilger wrote:
> Wouldn't it be possible to use this information to determine which
> of the inodes sharing a duplicate mapped block is the right one
> and which inode is the bad one?

Yes, although I'm not sure it's worth the effort.  Putting in more
intelligent hueristics for using the metadata checksums will help all
file systems, and not just bigalloc file systems --- and I think it
would be easier.

> On Jul 25, 2014, at 18:34, "Darrick J. Wong" <darrick.wong@oracle.com> wrote:
> 
> As far as I can tell, logical block mappings on a bigalloc filesystem are
> supposed to follow a few constraints:
> 
> * The logical cluster offset must match the physical cluster offset.
> * A logical cluster may not map to multiple physical clusters.
> 
> Since the multiply-claimed block recovery code can be used to fix these
> problems, teach e2fsck to find these transgressions and fix them.
> 
> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>

Thanks, applied, but a couple of tips about writing test scripts.

You originally had this:

	../misc/tune2fs -L test_fs $TMPFILE
	../e2fsck/e2fsck -fy $TMPFILE > $OUT
	../e2fsck/e2fsck -fy $TMPFILE >> $OUT
	../e2fsck/e2fsck -fy $TMPFILE >> $OUT

This spits out the version numbers to stderr, which is ugly.  I fixed
up the binary image file to have the test_fs label, and I changed the
lines above to:

	$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed > $OUT
	$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT
	$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT

The advantage of doing things this way is that any errors get captured
in the log file.  Also, if the user has requested valgrind be used,
that gets reflected in the value of $FSCK.

Cheers,

					- Ted
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Darrick Wong July 28, 2014, 8:28 a.m. UTC | #3
On Sat, Jul 26, 2014 at 04:27:28PM -0400, Theodore Ts'o wrote:
> On Sat, Jul 26, 2014 at 12:02:10AM -0600, Andreas Dilger wrote:
> > Wouldn't it be possible to use this information to determine which
> > of the inodes sharing a duplicate mapped block is the right one
> > and which inode is the bad one?
> 
> Yes, although I'm not sure it's worth the effort.  Putting in more
> intelligent hueristics for using the metadata checksums will help all
> file systems, and not just bigalloc file systems --- and I think it
> would be easier.
> 
> > On Jul 25, 2014, at 18:34, "Darrick J. Wong" <darrick.wong@oracle.com> wrote:
> > 
> > As far as I can tell, logical block mappings on a bigalloc filesystem are
> > supposed to follow a few constraints:
> > 
> > * The logical cluster offset must match the physical cluster offset.
> > * A logical cluster may not map to multiple physical clusters.
> > 
> > Since the multiply-claimed block recovery code can be used to fix these
> > problems, teach e2fsck to find these transgressions and fix them.
> > 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Thanks, applied, but a couple of tips about writing test scripts.
> 
> You originally had this:
> 
> 	../misc/tune2fs -L test_fs $TMPFILE
> 	../e2fsck/e2fsck -fy $TMPFILE > $OUT
> 	../e2fsck/e2fsck -fy $TMPFILE >> $OUT
> 	../e2fsck/e2fsck -fy $TMPFILE >> $OUT
> 
> This spits out the version numbers to stderr, which is ugly.  I fixed
> up the binary image file to have the test_fs label, and I changed the
> lines above to:
> 
> 	$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed > $OUT
> 	$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT
> 	$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT
> 
> The advantage of doing things this way is that any errors get captured
> in the log file.  Also, if the user has requested valgrind be used,
> that gets reflected in the value of $FSCK.

Got it, thanks.  I'll do that next time.

--D
> 
> Cheers,
> 
> 					- Ted
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Darrick Wong July 28, 2014, 5:55 p.m. UTC | #4
On Sat, Jul 26, 2014 at 04:27:28PM -0400, Theodore Ts'o wrote:
> On Sat, Jul 26, 2014 at 12:02:10AM -0600, Andreas Dilger wrote:
> > Wouldn't it be possible to use this information to determine which
> > of the inodes sharing a duplicate mapped block is the right one
> > and which inode is the bad one?
> 
> Yes, although I'm not sure it's worth the effort.  Putting in more
> intelligent hueristics for using the metadata checksums will help all
> file systems, and not just bigalloc file systems --- and I think it
> would be easier.
> 
> > On Jul 25, 2014, at 18:34, "Darrick J. Wong" <darrick.wong@oracle.com> wrote:
> > 
> > As far as I can tell, logical block mappings on a bigalloc filesystem are
> > supposed to follow a few constraints:
> > 
> > * The logical cluster offset must match the physical cluster offset.
> > * A logical cluster may not map to multiple physical clusters.
> > 
> > Since the multiply-claimed block recovery code can be used to fix these
> > problems, teach e2fsck to find these transgressions and fix them.
> > 
> > Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
> Thanks, applied, but a couple of tips about writing test scripts.
> 
> You originally had this:
> 
> 	../misc/tune2fs -L test_fs $TMPFILE
> 	../e2fsck/e2fsck -fy $TMPFILE > $OUT
> 	../e2fsck/e2fsck -fy $TMPFILE >> $OUT
> 	../e2fsck/e2fsck -fy $TMPFILE >> $OUT
> 
> This spits out the version numbers to stderr, which is ugly.  I fixed
> up the binary image file to have the test_fs label, and I changed the
> lines above to:
> 
> 	$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed > $OUT
> 	$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT
> 	$FSCK -fy $TMPFILE 2>&1 | sed -f $cmd_dir/filter.sed >> $OUT
> 
> The advantage of doing things this way is that any errors get captured
> in the log file.  Also, if the user has requested valgrind be used,
> that gets reflected in the value of $FSCK.

Hmm... the f_badcluster test seems to be missing from -maint and -next.
Did it get lost in the merge?

--D
> 
> Cheers,
> 
> 					- Ted
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Theodore Ts'o July 28, 2014, 7:32 p.m. UTC | #5
On Mon, Jul 28, 2014 at 10:55:54AM -0700, Darrick J. Wong wrote:
> 
> Hmm... the f_badcluster test seems to be missing from -maint and -next.
> Did it get lost in the merge?

Oh, whoops.  It's in my tree, but I forgot to "git add" the directory.
(Because of some patch conflicts that caused "git am" to be unhappy, I
ended up having to apply the patch manually.)

I'll fix it up and push it out.

						- Ted
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index a6552e5..646ef8a 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -1945,6 +1945,40 @@  void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
 	e2fsck_write_inode(ctx, ino, inode, source);
 }
 
+/*
+ * Use the multiple-blocks reclamation code to fix alignment problems in
+ * a bigalloc filesystem.  We want a logical cluster to map to *only* one
+ * physical cluster, and we want the block offsets within that cluster to
+ * line up.
+ */
+static int has_unaligned_cluster_map(e2fsck_t ctx,
+				     blk64_t last_pblk, e2_blkcnt_t last_lblk,
+				     blk64_t pblk, blk64_t lblk)
+{
+	blk64_t cluster_mask;
+
+	if (!ctx->fs->cluster_ratio_bits)
+		return 0;
+	cluster_mask = EXT2FS_CLUSTER_MASK(ctx->fs);
+
+	/*
+	 * If the block in the logical cluster doesn't align with the block in
+	 * the physical cluster...
+	 */
+	if ((lblk & cluster_mask) != (pblk & cluster_mask))
+		return 1;
+
+	/*
+	 * If we cross a physical cluster boundary within a logical cluster...
+	 */
+	if (last_pblk && (lblk & cluster_mask) != 0 &&
+	    EXT2FS_B2C(ctx->fs, lblk) == EXT2FS_B2C(ctx->fs, last_lblk) &&
+	    EXT2FS_B2C(ctx->fs, pblk) != EXT2FS_B2C(ctx->fs, last_pblk))
+		return 1;
+
+	return 0;
+}
+
 static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
 			     struct process_block_struct *pb,
 			     blk64_t start_block, blk64_t end_block,
@@ -2249,7 +2283,16 @@  alloc_later:
 				mark_block_used(ctx, blk);
 				pb->num_blocks++;
 			}
-
+			if (has_unaligned_cluster_map(ctx, pb->previous_block,
+						      pb->last_block, blk,
+						      blockcnt)) {
+				pctx->blk = blockcnt;
+				pctx->blk2 = blk;
+				fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx);
+				mark_block_used(ctx, blk);
+				mark_block_used(ctx, blk);
+			}
+			pb->last_block = blockcnt;
 			pb->previous_block = blk;
 
 			if (is_dir) {
@@ -2815,6 +2858,13 @@  static int process_block(ext2_filsys fs,
 		     ((unsigned) blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) {
 		mark_block_used(ctx, blk);
 		p->num_blocks++;
+	} else if (has_unaligned_cluster_map(ctx, p->previous_block,
+					     p->last_block, blk, blockcnt)) {
+		pctx->blk = blockcnt;
+		pctx->blk2 = blk;
+		fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx);
+		mark_block_used(ctx, blk);
+		mark_block_used(ctx, blk);
 	}
 	if (blockcnt >= 0)
 		p->last_block = blockcnt;
diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
index 8d42d10..c0bfa07 100644
--- a/e2fsck/pass1b.c
+++ b/e2fsck/pass1b.c
@@ -261,7 +261,7 @@  struct process_block_struct {
 	e2fsck_t	ctx;
 	ext2_ino_t	ino;
 	int		dup_blocks;
-	blk64_t		cur_cluster;
+	blk64_t		cur_cluster, phys_cluster;
 	blk64_t		last_blk;
 	struct ext2_inode *inode;
 	struct problem_context *pctx;
@@ -317,6 +317,7 @@  static void pass1b(e2fsck_t ctx, char *block_buf)
 		pb.dup_blocks = 0;
 		pb.inode = &inode;
 		pb.cur_cluster = ~0;
+		pb.phys_cluster = ~0;
 		pb.last_blk = 0;
 		pb.pctx->blk = pb.pctx->blk2 = 0;
 
@@ -360,7 +361,7 @@  static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
 {
 	struct process_block_struct *p;
 	e2fsck_t ctx;
-	blk64_t	lc;
+	blk64_t	lc, pc;
 	problem_t op;
 
 	if (HOLE_BLKADDR(*block_nr))
@@ -368,6 +369,7 @@  static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
 	p = (struct process_block_struct *) priv_data;
 	ctx = p->ctx;
 	lc = EXT2FS_B2C(fs, blockcnt);
+	pc = EXT2FS_B2C(fs, *block_nr);
 
 	if (!ext2fs_test_block_bitmap2(ctx->block_dup_map, *block_nr))
 		goto finish;
@@ -389,11 +391,19 @@  static int process_pass1b_block(ext2_filsys fs EXT2FS_ATTR((unused)),
 	p->dup_blocks++;
 	ext2fs_mark_inode_bitmap2(inode_dup_map, p->ino);
 
-	if (blockcnt < 0 || lc != p->cur_cluster)
+	/*
+	 * Qualifications for submitting a block for duplicate processing:
+	 * It's an extent/indirect block (and has a negative logical offset);
+	 * we've crossed a logical cluster boundary; or the physical cluster
+	 * suddenly changed, which indicates that blocks in a logical cluster
+	 * are mapped to multiple physical clusters.
+	 */
+	if (blockcnt < 0 || lc != p->cur_cluster || pc != p->phys_cluster)
 		add_dupe(ctx, p->ino, EXT2FS_B2C(fs, *block_nr), p->inode);
 
 finish:
 	p->cur_cluster = lc;
+	p->phys_cluster = pc;
 	return 0;
 }
 
@@ -563,7 +573,11 @@  static void pass1d(e2fsck_t ctx, char *block_buf)
 			pctx.dir = t->dir;
 			fix_problem(ctx, PR_1D_DUP_FILE_LIST, &pctx);
 		}
-		if (file_ok) {
+		/*
+		 * Even if the file shares blocks with itself, we still need to
+		 * clone the blocks.
+		 */
+		if (file_ok && (meta_data ? shared_len+1 : shared_len) != 0) {
 			fix_problem(ctx, PR_1D_DUP_BLOCKS_DEALT, &pctx);
 			continue;
 		}
@@ -706,9 +720,10 @@  struct clone_struct {
 	errcode_t	errcode;
 	blk64_t		dup_cluster;
 	blk64_t		alloc_block;
-	ext2_ino_t	dir;
+	ext2_ino_t	dir, ino;
 	char	*buf;
 	e2fsck_t ctx;
+	struct ext2_inode	*inode;
 };
 
 static int clone_file_block(ext2_filsys fs,
@@ -756,13 +771,26 @@  static int clone_file_block(ext2_filsys fs,
 			decrement_badcount(ctx, *block_nr, p);
 
 		cs->dup_cluster = c;
-
+		/*
+		 * Let's try an implied cluster allocation.  If we get the same
+		 * cluster back, then we need to find a new block; otherwise,
+		 * we're merely fixing the problem of one logical cluster being
+		 * mapped to multiple physical clusters.
+		 */
+		new_block = 0;
+		retval = ext2fs_map_cluster_block(fs, cs->ino, cs->inode,
+						  blockcnt, &new_block);
+		if (retval == 0 && new_block != 0 &&
+		    EXT2FS_B2C(ctx->fs, new_block) !=
+		    EXT2FS_B2C(ctx->fs, *block_nr))
+			goto cluster_alloc_ok;
 		retval = ext2fs_new_block2(fs, 0, ctx->block_found_map,
 					   &new_block);
 		if (retval) {
 			cs->errcode = retval;
 			return BLOCK_ABORT;
 		}
+cluster_alloc_ok:
 		cs->alloc_block = new_block;
 
 	got_block:
@@ -817,6 +845,8 @@  static errcode_t clone_file(e2fsck_t ctx, ext2_ino_t ino,
 	cs.dup_cluster = ~0;
 	cs.alloc_block = 0;
 	cs.ctx = ctx;
+	cs.ino = ino;
+	cs.inode = &dp->inode;
 	retval = ext2fs_get_mem(fs->blocksize, &cs.buf);
 	if (retval)
 		return retval;
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 60c02af..4da8ba8 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1048,6 +1048,11 @@  static struct e2fsck_problem problem_table[] = {
 	  N_("@d @i %i has @x marked uninitialized at @b %c.  "),
 	  PROMPT_FIX, PR_PREEN_OK },
 
+	/* Inode logical block (physical block ) is misaligned. */
+	{ PR_1_MISALIGNED_CLUSTER,
+	  N_("@i %i logical @b %b (physical @b %c) violates cluster allocation rules.\nWill fix in pass 1B.\n"),
+	  PROMPT_NONE, 0 },
+
 	/* Pass 1b errors */
 
 	/* Pass 1B: Rescan for duplicate/bad blocks */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 6cd3d50..80ef4a2 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -609,6 +609,9 @@  struct problem_context {
 /* uninit directory block */
 #define PR_1_UNINIT_DBLOCK		0x010073
 
+/* Inode logical block is misaligned */
+#define PR_1_MISALIGNED_CLUSTER		0x010074
+
 /*
  * Pass 1b errors
  */
diff --git a/tests/f_badcluster/expect b/tests/f_badcluster/expect
new file mode 100644
index 0000000..eb3bcf0
--- /dev/null
+++ b/tests/f_badcluster/expect
@@ -0,0 +1,198 @@ 
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 logical block 2 (physical block 1154) violates cluster allocation rules.
+Will fix in pass 1B.
+Inode 12, i_blocks is 32, should be 64.  Fix? yes
+
+Inode 16 logical block 5 (physical block 1173) violates cluster allocation rules.
+Will fix in pass 1B.
+Inode 16, i_size is 3072, should be 6144.  Fix? yes
+
+Inode 16, i_blocks is 32, should be 64.  Fix? yes
+
+Inode 17 logical block 0 (physical block 1186) violates cluster allocation rules.
+Will fix in pass 1B.
+Inode 17 logical block 2 (physical block 1184) violates cluster allocation rules.
+Will fix in pass 1B.
+Inode 17, i_blocks is 32, should be 64.  Fix? yes
+
+Inode 18 logical block 3 (physical block 1201) violates cluster allocation rules.
+Will fix in pass 1B.
+Inode 18, i_blocks is 32, should be 64.  Fix? yes
+
+
+Running additional passes to resolve blocks claimed by more than one inode...
+Pass 1B: Rescanning for multiply-claimed blocks
+Multiply-claimed block(s) in inode 12: 1154
+Multiply-claimed block(s) in inode 13: 1152--1154
+Multiply-claimed block(s) in inode 14: 1648--1650
+Multiply-claimed block(s) in inode 15: 1650
+Multiply-claimed block(s) in inode 16: 1173
+Multiply-claimed block(s) in inode 17: 1186 1185 1184
+Multiply-claimed block(s) in inode 18: 1201
+Pass 1C: Scanning directories for inodes with multiply-claimed blocks
+Pass 1D: Reconciling multiply-claimed blocks
+(There are 7 inodes containing multiply-claimed blocks.)
+
+File /a (inode #12, mod time Tue Jun 17 08:00:50 2014) 
+  has 1 multiply-claimed block(s), shared with 1 file(s):
+	/b (inode #13, mod time Tue Jun 17 08:00:50 2014)
+Clone multiply-claimed blocks? yes
+
+File /b (inode #13, mod time Tue Jun 17 08:00:50 2014) 
+  has 1 multiply-claimed block(s), shared with 1 file(s):
+	/a (inode #12, mod time Tue Jun 17 08:00:50 2014)
+Multiply-claimed blocks already reassigned or cloned.
+
+File /c (inode #14, mod time Tue Jun 17 08:00:50 2014) 
+  has 1 multiply-claimed block(s), shared with 1 file(s):
+	/d (inode #15, mod time Tue Jun 17 08:00:50 2014)
+Clone multiply-claimed blocks? yes
+
+File /d (inode #15, mod time Tue Jun 17 08:00:50 2014) 
+  has 1 multiply-claimed block(s), shared with 1 file(s):
+	/c (inode #14, mod time Tue Jun 17 08:00:50 2014)
+Multiply-claimed blocks already reassigned or cloned.
+
+File /e (inode #16, mod time Tue Jun 17 08:00:50 2014) 
+  has 1 multiply-claimed block(s), shared with 0 file(s):
+Clone multiply-claimed blocks? yes
+
+File /f (inode #17, mod time Tue Jun 17 08:00:50 2014) 
+  has 1 multiply-claimed block(s), shared with 0 file(s):
+Clone multiply-claimed blocks? yes
+
+File /g (inode #18, mod time Tue Jun 17 08:00:50 2014) 
+  has 1 multiply-claimed block(s), shared with 0 file(s):
+Clone multiply-claimed blocks? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Free blocks count wrong for group #0 (50, counted=47).
+Fix? yes
+
+Free blocks count wrong (800, counted=752).
+Fix? yes
+
+
+test_fs: ***** FILE SYSTEM WAS MODIFIED *****
+test_fs: 18/128 files (22.2% non-contiguous), 1296/2048 blocks
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12, i_blocks is 64, should be 32.  Fix? yes
+
+Inode 16, i_blocks is 64, should be 32.  Fix? yes
+
+Inode 17, i_blocks is 64, should be 32.  Fix? yes
+
+Inode 18, i_blocks is 64, should be 32.  Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+Block bitmap differences:  -(1168--1200)
+Fix? yes
+
+Free blocks count wrong for group #0 (47, counted=50).
+Fix? yes
+
+Free blocks count wrong (752, counted=800).
+Fix? yes
+
+
+test_fs: ***** FILE SYSTEM WAS MODIFIED *****
+test_fs: 18/128 files (5.6% non-contiguous), 1248/2048 blocks
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_fs: 18/128 files (5.6% non-contiguous), 1248/2048 blocks
+debugfs:  stat /a
+Inode: 12   Type: regular    Mode:  0644   Flags: 0x80000
+Generation: 1117152157    Version: 0x00000001
+User:     0   Group:     0   Size: 3072
+File ACL: 0    Directory ACL: 0
+Links: 1   Blockcount: 32
+Fragment:  Address: 0    Number: 0    Size: 0
+ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+EXTENTS:
+(0-1):1136-1137, (2):1138
+debugfs:  stat /b
+Inode: 13   Type: regular    Mode:  0644   Flags: 0x80000
+Generation: 1117152158    Version: 0x00000001
+User:     0   Group:     0   Size: 3072
+File ACL: 0    Directory ACL: 0
+Links: 1   Blockcount: 32
+Fragment:  Address: 0    Number: 0    Size: 0
+ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+EXTENTS:
+(0-2):1152-1154
+debugfs:  stat /c
+Inode: 14   Type: regular    Mode:  0644   Flags: 0x80000
+Generation: 1117152159    Version: 0x00000001
+User:     0   Group:     0   Size: 3072
+File ACL: 0    Directory ACL: 0
+Links: 1   Blockcount: 32
+Fragment:  Address: 0    Number: 0    Size: 0
+ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+EXTENTS:
+(0-1):1216-1217, (2):1218
+debugfs:  stat /d
+Inode: 15   Type: regular    Mode:  0644   Flags: 0x0
+Generation: 1117152160    Version: 0x00000001
+User:     0   Group:     0   Size: 3072
+File ACL: 0    Directory ACL: 0
+Links: 1   Blockcount: 32
+Fragment:  Address: 0    Number: 0    Size: 0
+ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+BLOCKS:
+(TIND):1650
+TOTAL: 1
+
+debugfs:  stat /e
+Inode: 16   Type: regular    Mode:  0644   Flags: 0x80000
+Generation: 1117152161    Version: 0x00000001
+User:     0   Group:     0   Size: 6144
+File ACL: 0    Directory ACL: 0
+Links: 1   Blockcount: 32
+Fragment:  Address: 0    Number: 0    Size: 0
+ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+EXTENTS:
+(0-2):1664-1666, (5):1669
+debugfs:  stat /f
+Inode: 17   Type: regular    Mode:  0644   Flags: 0x80000
+Generation: 1117152162    Version: 0x00000001
+User:     0   Group:     0   Size: 3072
+File ACL: 0    Directory ACL: 0
+Links: 1   Blockcount: 32
+Fragment:  Address: 0    Number: 0    Size: 0
+ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+EXTENTS:
+(0):1232, (1):1233, (2):1234
+debugfs:  stat /g
+Inode: 18   Type: regular    Mode:  0644   Flags: 0x80000
+Generation: 1117152163    Version: 0x00000001
+User:     0   Group:     0   Size: 3072
+File ACL: 0    Directory ACL: 0
+Links: 1   Blockcount: 32
+Fragment:  Address: 0    Number: 0    Size: 0
+ctime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+atime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+mtime: 0x539ff5b2 -- Tue Jun 17 08:00:50 2014
+EXTENTS:
+(0-2):1680-1682, (3):1683
+debugfs:  
\ No newline at end of file
diff --git a/tests/f_badcluster/image.gz b/tests/f_badcluster/image.gz
new file mode 100644
index 0000000000000000000000000000000000000000..e02ee1866868361e6e82bfbe29982365b2e3aa55
GIT binary patch
literal 3131
zcmeH`eNfVO9LF)YGArHAl6flRwbV_eOvC0A4VPY_dFBj}kaU;3`An&ypmc4h9VhIf
zG;+!qGBs1@gsG+2gU*y0Y50JcUV;y)D1xAjhu^x}b(h}$+@E~@_&j|7`F=jH&*u%L
z*?=Z=?ARUF%2(nv2aF3y#X5Z+g%u<)LiS(y@}tx>cPz)&G0Qe&A*OK@Raq{8^q_F-
zbB{#>iF|Dz=b)|E490O%W`;sOzn*Dtd$W+q>f!h2aWn3xA)rK!kjYY12Cz2VS^ia?
zJKzn{oZ*j8$vKNhzKW^O#IziXdU8FzD*|<eD@NYnUd~^Sa_N2j2lXf(hj_l!WF(Xz
z^@k=+XFN;5_JiKlfolqV3uj7S$m~OhGOU?ARvy2Z3xiBLmvwf9s?~oQZlIxv;1!zu
zbzM+@IZwGj2G3`h`BuLoys*(veF#j!uuCmX7XnXQP{(9>l8|3~Qb0L3W_@O8Bou2S
z#LwPyeSHU4SGh|_3O@<jVw-ulMAQSCYtw-BmUoczrKImN`3b_5sj-MBHFstycPr9Q
zyDc_LT!%)FD#_s5hLIl5UXnDPD@{u}7ViyT0SH2%u*0u$j#2PSivDR6be36cLR7JI
z>P9Io$LN#}Hy;+P)k<}%cC(5=1%>EC`mJ`K9DhLsMXNnTY7b5%xHS-GMy*X>nRI$s
zn4{EJv>{B*zOB8Z6U4SCeQg`RoRS%(Z&ez2MRsCB5pII*p9!eO5eo6@SX?5Fv~;uk
zMYgdE|JNdavOxx(M+a9JGE#v?A50YtD7>vh#2-d%9rOK)Okcl?dlmE3Udha-PBwlx
zw<*_LcZb-D6dfZP2dfe{<%37d#Ki?z2z!rK7Yx~>r3c$JM1<s%-6TO8VzA^PvIA2p
zr@^=X@pVnNrWr5+)70e+;E{U_fA>jX*E;3D-245!%MWU2YQwru2>?*S{bGVA^+1FB
z8-;3y!|ILos18QJB|+U;YN8OP0+aw@s+)wy9IvNaJ!a&tRX-rM!{|#hNL**Yt+QAN
zJh9_Kysv$_Bh~mb8`5JR&ddJMoa1}#T#i6&vzy$;rqF-rzqsGWd$8<0N-IB0;jPp~
z22J;hV9a6Hf&ScQfGR<EF*<B2wZ4daZ;nx^i0)Iqacq`d{&rb6l&4^4_yVusv+Swi
z1ak*`wtFPmFfS9Bu<1ZooEm+61;F<$9g=?5M=jQYQ<c*bH6}vQ?^dJ9a3$sY-ekEM
zucY8tA{+GF>N<>h`Nd1)Ci8h@bC`iSpmOlA7MwV}^GPJS^lC&^e~*O6GRb2rQ1h+d
zB*q7XIxlAAlVK8>hUhH`Qg4!ZahPpe$wQ2fuN{FV4;STob=J3cl1ux;sphvTO-et5
za=9(yX3Y%vwwp~zE$z|267_p4(cyK{(@S=d<tY<GLiz(@c9y?d_xCfA^QuQ;p;6U-
zgkHj3QM@#;1&o%EeQo}R%l?CeiQ{1XPRZF1iUXvrAI<|wei)IyMDNH*+K}a%dA%B_
zeZmRAs#0yds@p(lDKZT^e7?L|o5?bXMz^W(-3eHtg@A>Cg@A>Cg@A>?|4(4iWQ{Gq
K#Rh>6g8l&!3vo*T

literal 0
HcmV?d00001

diff --git a/tests/f_badcluster/name b/tests/f_badcluster/name
new file mode 100644
index 0000000..266f81c
--- /dev/null
+++ b/tests/f_badcluster/name
@@ -0,0 +1,2 @@ 
+test alignment problems with bigalloc clusters
+
diff --git a/tests/f_badcluster/script b/tests/f_badcluster/script
new file mode 100644
index 0000000..ba6b248
--- /dev/null
+++ b/tests/f_badcluster/script
@@ -0,0 +1,25 @@ 
+if test -x $DEBUGFS_EXE; then
+	IMAGE=$test_dir/../f_badcluster/image.gz
+	OUT=$test_name.log
+	EXP=$test_dir/expect
+	gzip -d < $IMAGE > $TMPFILE
+	../misc/tune2fs -L test_fs $TMPFILE
+	../e2fsck/e2fsck -fy $TMPFILE > $OUT
+	../e2fsck/e2fsck -fy $TMPFILE >> $OUT
+	../e2fsck/e2fsck -fy $TMPFILE >> $OUT
+	for i in a b c d e f g; do echo "stat /$i"; done | $DEBUGFS_EXE $TMPFILE >> $OUT
+
+	cmp -s $OUT $EXP
+	status=$?
+
+	if [ "$status" = 0 ]; then
+		echo "$test_name: $test_description: ok"
+		touch $test_name.ok
+	else
+		echo "$test_name: $test_description: failed"
+		diff $DIFF_OPTS $EXP $OUT > $test_name.failed
+		rm -f $test_name.tmp
+	fi
+else
+	echo "$test_name: skipped"
+fi