From: Madan Valluri Date: Thu, 20 Jul 2006 18:22:50 +0000 (+0000) Subject: This mod implements a new algorithm for phase7 which X-Git-Tag: v2.9.0~62 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2f07db3c4f5f706094f72c5e361396c1d991cb85;p=thirdparty%2Fxfsprogs-dev.git This mod implements a new algorithm for phase7 which makes use of the recently introduced prefetch framework. Instead of using the transaction framework one inode at a time, we read large chunks of inodes off the disk in chunks and compare the nlink count. This mod implements a new algorithm for phase7 which makes use of the recently introduced prefetch framework. Instead of using the transaction framework one inode at a time, we read large chunks of inodes off the disk in chunks and compare the nlink count. --- diff --git a/repair/phase7.c b/repair/phase7.c index 0f5fe5214..5f77a9c4e 100644 --- a/repair/phase7.c +++ b/repair/phase7.c @@ -25,6 +25,7 @@ #include "err_protos.h" #include "dinode.h" #include "versions.h" +#include "prefetch.h" /* dinoc is a pointer to the IN-CORE dinode core */ void @@ -57,6 +58,132 @@ _("nlinks %d will overflow v1 ino, ino %llu will be converted to version 2\n"), } } +void +phase7_alt_function(xfs_mount_t *mp, xfs_agnumber_t agno) +{ + register ino_tree_node_t *irec; + int j; + int dirty; + xfs_ino_t ino; + __uint32_t nrefs; + xfs_agblock_t agbno; + xfs_dinode_t *dip; + ino_tree_node_t *ino_ra; + xfs_buf_t *bp; + + if (verbose) + do_log(_(" - agno = %d\n"), agno); + + ino_ra = prefetch_inode_chunks(mp, agno, NULL); + + /* + * read on-disk inodes in chunks. then, + * look at each on-disk inode 1 at a time. + * if the number of links is bad, reset it. + */ + + irec = findfirst_inode_rec(agno); + + while (irec != NULL) { + + if (ino_ra && (irec->ino_startnum >= ino_ra->ino_startnum)) + ino_ra = prefetch_inode_chunks(mp, agno, ino_ra); + + agbno = XFS_AGINO_TO_AGBNO(mp, irec->ino_startnum); + bp = libxfs_readbuf(mp->m_dev, + XFS_AGB_TO_DADDR(mp, agno, agbno), + XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp)), 0); + if (bp == NULL) { + if (!no_modify) { + do_error( + _("cannot read inode %llu, disk block %lld, cnt %d\n"), + XFS_AGINO_TO_INO(mp, agno, irec->ino_startnum), + XFS_AGB_TO_DADDR(mp, agno, agbno), + (int)XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp))); + /* NOT REACHED */ + } + do_warn( + _("cannot read inode %llu, disk block %lld, cnt %d\n"), + XFS_AGINO_TO_INO(mp, agno, irec->ino_startnum), + XFS_AGB_TO_DADDR(mp, agno, agbno), + (int)XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp))); + + irec = next_ino_rec(irec); + continue; /* while */ + } + dirty = 0; + for (j = 0; j < XFS_INODES_PER_CHUNK; j++) { + assert(is_inode_confirmed(irec, j)); + + if (is_inode_free(irec, j)) + continue; + + assert(no_modify || is_inode_reached(irec, j)); + assert(no_modify || + is_inode_referenced(irec, j)); + + nrefs = num_inode_references(irec, j); + + ino = XFS_AGINO_TO_INO(mp, agno, + irec->ino_startnum + j); + + dip = (xfs_dinode_t *)(XFS_BUF_PTR(bp) + + (j << mp->m_sb.sb_inodelog)); + + /* Swap the fields we care about to native format */ + dip->di_core.di_magic = INT_GET(dip->di_core.di_magic, ARCH_CONVERT); + dip->di_core.di_nlink = INT_GET(dip->di_core.di_nlink, ARCH_CONVERT); + + if (dip->di_core.di_magic != XFS_DINODE_MAGIC) { + if (!no_modify) { + do_error( + _("ino: %llu, bad d_inode magic saw: (0x%x) expecting (0x%x)\n"), + ino, dip->di_core.di_magic, XFS_DINODE_MAGIC); + /* NOT REACHED */ + } + do_warn( + _("ino: %llu, bad d_inode magic saw: (0x%x) expecting (0x%x)\n"), + ino, dip->di_core.di_magic, XFS_DINODE_MAGIC); + continue; + } + /* + * compare and set links for all inodes + * but the lost+found inode. we keep + * that correct as we go. + */ + if (dip->di_core.di_nlink != nrefs) { + if (ino != orphanage_ino) { + set_nlinks(&dip->di_core, ino, + nrefs, &dirty); + } + } + + /* Swap the fields back */ + dip->di_core.di_magic = INT_GET(dip->di_core.di_magic, ARCH_CONVERT); + dip->di_core.di_nlink = INT_GET(dip->di_core.di_nlink, ARCH_CONVERT); + } + + if (dirty) + libxfs_writebuf(bp, 0); + else + libxfs_putbuf(bp); + + irec = next_ino_rec(irec); + } +} + +void +phase7_alt(xfs_mount_t *mp) +{ + int i; + + libxfs_bcache_purge(); + + for (i = 0; i < glob_agcount; i++) { + phase7_alt_function(mp, i); + } +} + void phase7(xfs_mount_t *mp) { @@ -75,6 +202,12 @@ phase7(xfs_mount_t *mp) else do_log(_("Phase 7 - verify link counts...\n")); + + if (do_prefetch) { + phase7_alt(mp); + return; + } + tp = libxfs_trans_alloc(mp, XFS_TRANS_REMOVE); error = libxfs_trans_reserve(tp, (no_modify ? 0 : 10),