aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2018-08-10 01:43:04 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2018-08-10 14:44:31 -0400
commit13942aa94a8b5df662d93c42c307b2f50cbe88b0 (patch)
tree38276489cfc812cd420471d86bc4cf1a245e7f65 /fs/xfs
parent0e93d3f43ec7d3308bff25ce1be81d46330168c9 (diff)
xfs: repair the AGI
Rebuild the AGI header items with some help from the rmapbt. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Brian Foster <bfoster@redhat.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/scrub/agheader_repair.c217
-rw-r--r--fs/xfs/scrub/repair.h2
-rw-r--r--fs/xfs/scrub/scrub.c2
3 files changed, 220 insertions, 1 deletions
diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
index 9ce302360bbb..f7568a4b5fe5 100644
--- a/fs/xfs/scrub/agheader_repair.c
+++ b/fs/xfs/scrub/agheader_repair.c
@@ -714,3 +714,220 @@ err:
714 xfs_bitmap_destroy(&agfl_extents); 714 xfs_bitmap_destroy(&agfl_extents);
715 return error; 715 return error;
716} 716}
717
718/* AGI */
719
720/*
721 * Offset within the xrep_find_ag_btree array for each btree type. Avoid the
722 * XFS_BTNUM_ names here to avoid creating a sparse array.
723 */
724enum {
725 XREP_AGI_INOBT = 0,
726 XREP_AGI_FINOBT,
727 XREP_AGI_END,
728 XREP_AGI_MAX
729};
730
731/*
732 * Given the inode btree roots described by *fab, find the roots, check them
733 * for sanity, and pass the root data back out via *fab.
734 */
735STATIC int
736xrep_agi_find_btrees(
737 struct xfs_scrub *sc,
738 struct xrep_find_ag_btree *fab)
739{
740 struct xfs_buf *agf_bp;
741 struct xfs_mount *mp = sc->mp;
742 int error;
743
744 /* Read the AGF. */
745 error = xfs_alloc_read_agf(mp, sc->tp, sc->sa.agno, 0, &agf_bp);
746 if (error)
747 return error;
748 if (!agf_bp)
749 return -ENOMEM;
750
751 /* Find the btree roots. */
752 error = xrep_find_ag_btree_roots(sc, agf_bp, fab, NULL);
753 if (error)
754 return error;
755
756 /* We must find the inobt root. */
757 if (!xrep_check_btree_root(sc, &fab[XREP_AGI_INOBT]))
758 return -EFSCORRUPTED;
759
760 /* We must find the finobt root if that feature is enabled. */
761 if (xfs_sb_version_hasfinobt(&mp->m_sb) &&
762 !xrep_check_btree_root(sc, &fab[XREP_AGI_FINOBT]))
763 return -EFSCORRUPTED;
764
765 return 0;
766}
767
768/*
769 * Reinitialize the AGI header, making an in-core copy of the old contents so
770 * that we know which in-core state needs to be reinitialized.
771 */
772STATIC void
773xrep_agi_init_header(
774 struct xfs_scrub *sc,
775 struct xfs_buf *agi_bp,
776 struct xfs_agi *old_agi)
777{
778 struct xfs_agi *agi = XFS_BUF_TO_AGI(agi_bp);
779 struct xfs_mount *mp = sc->mp;
780
781 memcpy(old_agi, agi, sizeof(*old_agi));
782 memset(agi, 0, BBTOB(agi_bp->b_length));
783 agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);
784 agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION);
785 agi->agi_seqno = cpu_to_be32(sc->sa.agno);
786 agi->agi_length = cpu_to_be32(xfs_ag_block_count(mp, sc->sa.agno));
787 agi->agi_newino = cpu_to_be32(NULLAGINO);
788 agi->agi_dirino = cpu_to_be32(NULLAGINO);
789 if (xfs_sb_version_hascrc(&mp->m_sb))
790 uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
791
792 /* We don't know how to fix the unlinked list yet. */
793 memcpy(&agi->agi_unlinked, &old_agi->agi_unlinked,
794 sizeof(agi->agi_unlinked));
795
796 /* Mark the incore AGF data stale until we're done fixing things. */
797 ASSERT(sc->sa.pag->pagi_init);
798 sc->sa.pag->pagi_init = 0;
799}
800
801/* Set btree root information in an AGI. */
802STATIC void
803xrep_agi_set_roots(
804 struct xfs_scrub *sc,
805 struct xfs_agi *agi,
806 struct xrep_find_ag_btree *fab)
807{
808 agi->agi_root = cpu_to_be32(fab[XREP_AGI_INOBT].root);
809 agi->agi_level = cpu_to_be32(fab[XREP_AGI_INOBT].height);
810
811 if (xfs_sb_version_hasfinobt(&sc->mp->m_sb)) {
812 agi->agi_free_root = cpu_to_be32(fab[XREP_AGI_FINOBT].root);
813 agi->agi_free_level = cpu_to_be32(fab[XREP_AGI_FINOBT].height);
814 }
815}
816
817/* Update the AGI counters. */
818STATIC int
819xrep_agi_calc_from_btrees(
820 struct xfs_scrub *sc,
821 struct xfs_buf *agi_bp)
822{
823 struct xfs_btree_cur *cur;
824 struct xfs_agi *agi = XFS_BUF_TO_AGI(agi_bp);
825 struct xfs_mount *mp = sc->mp;
826 xfs_agino_t count;
827 xfs_agino_t freecount;
828 int error;
829
830 cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp, sc->sa.agno,
831 XFS_BTNUM_INO);
832 error = xfs_ialloc_count_inodes(cur, &count, &freecount);
833 if (error)
834 goto err;
835 xfs_btree_del_cursor(cur, error);
836
837 agi->agi_count = cpu_to_be32(count);
838 agi->agi_freecount = cpu_to_be32(freecount);
839 return 0;
840err:
841 xfs_btree_del_cursor(cur, error);
842 return error;
843}
844
845/* Trigger reinitialization of the in-core data. */
846STATIC int
847xrep_agi_commit_new(
848 struct xfs_scrub *sc,
849 struct xfs_buf *agi_bp)
850{
851 struct xfs_perag *pag;
852 struct xfs_agi *agi = XFS_BUF_TO_AGI(agi_bp);
853
854 /* Trigger inode count recalculation */
855 xfs_force_summary_recalc(sc->mp);
856
857 /* Write this to disk. */
858 xfs_trans_buf_set_type(sc->tp, agi_bp, XFS_BLFT_AGI_BUF);
859 xfs_trans_log_buf(sc->tp, agi_bp, 0, BBTOB(agi_bp->b_length) - 1);
860
861 /* Now reinitialize the in-core counters if necessary. */
862 pag = sc->sa.pag;
863 pag->pagi_count = be32_to_cpu(agi->agi_count);
864 pag->pagi_freecount = be32_to_cpu(agi->agi_freecount);
865 pag->pagi_init = 1;
866
867 return 0;
868}
869
870/* Repair the AGI. */
871int
872xrep_agi(
873 struct xfs_scrub *sc)
874{
875 struct xrep_find_ag_btree fab[XREP_AGI_MAX] = {
876 [XREP_AGI_INOBT] = {
877 .rmap_owner = XFS_RMAP_OWN_INOBT,
878 .buf_ops = &xfs_inobt_buf_ops,
879 .magic = XFS_IBT_CRC_MAGIC,
880 },
881 [XREP_AGI_FINOBT] = {
882 .rmap_owner = XFS_RMAP_OWN_INOBT,
883 .buf_ops = &xfs_inobt_buf_ops,
884 .magic = XFS_FIBT_CRC_MAGIC,
885 },
886 [XREP_AGI_END] = {
887 .buf_ops = NULL
888 },
889 };
890 struct xfs_agi old_agi;
891 struct xfs_mount *mp = sc->mp;
892 struct xfs_buf *agi_bp;
893 struct xfs_agi *agi;
894 int error;
895
896 /* We require the rmapbt to rebuild anything. */
897 if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
898 return -EOPNOTSUPP;
899
900 xchk_perag_get(sc->mp, &sc->sa);
901 /*
902 * Make sure we have the AGI buffer, as scrub might have decided it
903 * was corrupt after xfs_ialloc_read_agi failed with -EFSCORRUPTED.
904 */
905 error = xfs_trans_read_buf(mp, sc->tp, mp->m_ddev_targp,
906 XFS_AG_DADDR(mp, sc->sa.agno, XFS_AGI_DADDR(mp)),
907 XFS_FSS_TO_BB(mp, 1), 0, &agi_bp, NULL);
908 if (error)
909 return error;
910 agi_bp->b_ops = &xfs_agi_buf_ops;
911 agi = XFS_BUF_TO_AGI(agi_bp);
912
913 /* Find the AGI btree roots. */
914 error = xrep_agi_find_btrees(sc, fab);
915 if (error)
916 return error;
917
918 /* Start rewriting the header and implant the btrees we found. */
919 xrep_agi_init_header(sc, agi_bp, &old_agi);
920 xrep_agi_set_roots(sc, agi, fab);
921 error = xrep_agi_calc_from_btrees(sc, agi_bp);
922 if (error)
923 goto out_revert;
924
925 /* Reinitialize in-core state. */
926 return xrep_agi_commit_new(sc, agi_bp);
927
928out_revert:
929 /* Mark the incore AGI state stale and revert the AGI. */
930 sc->sa.pag->pagi_init = 0;
931 memcpy(agi, &old_agi, sizeof(old_agi));
932 return error;
933}
diff --git a/fs/xfs/scrub/repair.h b/fs/xfs/scrub/repair.h
index 1d283360b5ab..9de321eee4ab 100644
--- a/fs/xfs/scrub/repair.h
+++ b/fs/xfs/scrub/repair.h
@@ -60,6 +60,7 @@ int xrep_probe(struct xfs_scrub *sc);
60int xrep_superblock(struct xfs_scrub *sc); 60int xrep_superblock(struct xfs_scrub *sc);
61int xrep_agf(struct xfs_scrub *sc); 61int xrep_agf(struct xfs_scrub *sc);
62int xrep_agfl(struct xfs_scrub *sc); 62int xrep_agfl(struct xfs_scrub *sc);
63int xrep_agi(struct xfs_scrub *sc);
63 64
64#else 65#else
65 66
@@ -85,6 +86,7 @@ xrep_calc_ag_resblks(
85#define xrep_superblock xrep_notsupported 86#define xrep_superblock xrep_notsupported
86#define xrep_agf xrep_notsupported 87#define xrep_agf xrep_notsupported
87#define xrep_agfl xrep_notsupported 88#define xrep_agfl xrep_notsupported
89#define xrep_agi xrep_notsupported
88 90
89#endif /* CONFIG_XFS_ONLINE_REPAIR */ 91#endif /* CONFIG_XFS_ONLINE_REPAIR */
90 92
diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c
index 2670f4cf62f4..4bfae1e61d30 100644
--- a/fs/xfs/scrub/scrub.c
+++ b/fs/xfs/scrub/scrub.c
@@ -226,7 +226,7 @@ static const struct xchk_meta_ops meta_scrub_ops[] = {
226 .type = ST_PERAG, 226 .type = ST_PERAG,
227 .setup = xchk_setup_fs, 227 .setup = xchk_setup_fs,
228 .scrub = xchk_agi, 228 .scrub = xchk_agi,
229 .repair = xrep_notsupported, 229 .repair = xrep_agi,
230 }, 230 },
231 [XFS_SCRUB_TYPE_BNOBT] = { /* bnobt */ 231 [XFS_SCRUB_TYPE_BNOBT] = { /* bnobt */
232 .type = ST_PERAG, 232 .type = ST_PERAG,