]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - repair/phase3.c
xfs_repair: pass ops through during scan
[thirdparty/xfsprogs-dev.git] / repair / phase3.c
index 32e855cb516273fdee8481ffff51f4e68889ea11..161852e0bca642540efa411da9f6e711258df21c 100644 (file)
@@ -1,22 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
  * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-#include <libxfs.h>
+#include "libxfs.h"
+#include "threads.h"
+#include "prefetch.h"
 #include "avl.h"
 #include "globals.h"
 #include "agheader.h"
 #include "protos.h"
 #include "err_protos.h"
 #include "dinode.h"
-#include "threads.h"
 #include "progress.h"
-#include "prefetch.h"
-
-/*
- * walks an unlinked list, returns 1 on an error (bogus pointer) or
- * I/O error
- */
-int
-walk_unlinked_list(xfs_mount_t *mp, xfs_agnumber_t agno, xfs_agino_t start_ino)
-{
-       xfs_buf_t *bp;
-       xfs_dinode_t *dip;
-       xfs_agino_t current_ino = start_ino;
-       xfs_agblock_t agbno;
-       int state;
-
-       while (current_ino != NULLAGINO)  {
-               if (verify_aginum(mp, agno, current_ino))
-                       return(1);
-               if ((bp = get_agino_buf(mp, agno, current_ino, &dip)) == NULL)
-                       return(1);
-               /*
-                * if this looks like a decent inode, then continue
-                * following the unlinked pointers.  If not, bail.
-                */
-               if (verify_dinode(mp, dip, agno, current_ino) == 0)  {
-                       /*
-                        * check if the unlinked list points to an unknown
-                        * inode.  if so, put it on the uncertain inode list
-                        * and set block map appropriately.
-                        */
-                       if (find_inode_rec(agno, current_ino) == NULL)  {
-                               add_aginode_uncertain(agno, current_ino, 1);
-                               agbno = XFS_AGINO_TO_AGBNO(mp, current_ino);
-
-                               pthread_mutex_lock(&ag_locks[agno]);
-                               state = get_bmap(agno, agbno);
-                               switch (state) {
-                               case XR_E_BAD_STATE:
-                                       do_error(_(
-                                               "bad state in block map %d\n"),
-                                               state);
-                                       break;
-                               default:
-                                       /*
-                                        * the block looks like inodes
-                                        * so be conservative and try
-                                        * to scavenge what's in there.
-                                        * if what's there is completely
-                                        * bogus, it'll show up later
-                                        * and the inode will be trashed
-                                        * anyway, hopefully without
-                                        * losing too much other data
-                                        */
-                                       set_bmap(agno, agbno, XR_E_INO);
-                                       break;
-                               }
-                               pthread_mutex_unlock(&ag_locks[agno]);
-                       }
-                       current_ino = be32_to_cpu(dip->di_next_unlinked);
-               } else  {
-                       current_ino = NULLAGINO;;
-               }
-               libxfs_putbuf(bp);
-       }
-
-       return(0);
-}
+#include "bmap.h"
+#include "threads.h"
 
-void
-process_agi_unlinked(xfs_mount_t *mp, xfs_agnumber_t agno)
+static void
+process_agi_unlinked(
+       struct xfs_mount        *mp,
+       xfs_agnumber_t          agno)
 {
-       xfs_agnumber_t i;
-       xfs_buf_t *bp;
-       xfs_agi_t *agip;
-       int err = 0;
-       int agi_dirty = 0;
+       struct xfs_buf          *bp;
+       struct xfs_agi          *agip;
+       xfs_agnumber_t          i;
+       int                     agi_dirty = 0;
 
        bp = libxfs_readbuf(mp->m_dev,
                        XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
-                       mp->m_sb.sb_sectsize/BBSIZE, 0);
+                       mp->m_sb.sb_sectsize/BBSIZE, 0, &xfs_agi_buf_ops);
        if (!bp)
-               do_error(_("cannot read agi block %lld for ag %u\n"),
+               do_error(_("cannot read agi block %" PRId64 " for ag %u\n"),
                        XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), agno);
 
        agip = XFS_BUF_TO_AGI(bp);
 
-       ASSERT(no_modify || be32_to_cpu(agip->agi_seqno) == agno);
+       ASSERT(be32_to_cpu(agip->agi_seqno) == agno);
 
        for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++)  {
-               if (be32_to_cpu(agip->agi_unlinked[i]) != NULLAGINO)  {
-                       err += walk_unlinked_list(mp, agno,
-                                       be32_to_cpu(agip->agi_unlinked[i]));
-                       /*
-                        * clear the list
-                        */
-                       if (!no_modify)  {
-                               agip->agi_unlinked[i] = cpu_to_be32(NULLAGINO);
-                               agi_dirty = 1;
-                       }
+               if (agip->agi_unlinked[i] != cpu_to_be32(NULLAGINO)) {
+                       agip->agi_unlinked[i] = cpu_to_be32(NULLAGINO);
+                       agi_dirty = 1;
                }
        }
 
-       if (err)
-               do_warn(_("error following ag %d unlinked list\n"), agno);
-
-       ASSERT(agi_dirty == 0 || (agi_dirty && !no_modify));
-
-       if (agi_dirty && !no_modify)
+       if (agi_dirty)
                libxfs_writebuf(bp, 0);
        else
                libxfs_putbuf(bp);
@@ -141,7 +54,7 @@ process_agi_unlinked(xfs_mount_t *mp, xfs_agnumber_t agno)
 
 static void
 process_ag_func(
-       work_queue_t            *wq,
+       struct workqueue        *wq,
        xfs_agnumber_t          agno,
        void                    *arg)
 {
@@ -151,7 +64,8 @@ process_ag_func(
         */
        wait_for_inode_prefetch(arg);
        do_log(_("        - agno = %d\n"), agno);
-       process_aginodes(wq->mp, arg, agno, 1, 0, 1);
+       process_aginodes(wq->wq_ctx, arg, agno, 1, 0, 1);
+       blkmap_free_final();
        cleanup_inode_prefetch(arg);
 }
 
@@ -159,47 +73,36 @@ static void
 process_ags(
        xfs_mount_t             *mp)
 {
-       int                     i, j;
-       xfs_agnumber_t          agno;
-       work_queue_t            *queues;
-       prefetch_args_t         *pf_args[2];
+       do_inode_prefetch(mp, ag_stride, process_ag_func, false, false);
+}
 
-       queues = malloc(thread_count * sizeof(work_queue_t));
+static void
+do_uncertain_aginodes(
+       struct workqueue        *wq,
+       xfs_agnumber_t          agno,
+       void                    *arg)
+{
+       int                     *count = arg;
 
-       if (ag_stride) {
-               /*
-                * create one worker thread for each segment of the volume
-                */
-               for (i = 0, agno = 0; i < thread_count; i++) {
-                       create_work_queue(&queues[i], mp, 1);
-                       pf_args[0] = NULL;
-                       for (j = 0; j < ag_stride && agno < mp->m_sb.sb_agcount;
-                                       j++, agno++) {
-                               pf_args[0] = start_inode_prefetch(agno, 0, pf_args[0]);
-                               queue_work(&queues[i], process_ag_func, agno, pf_args[0]);
-                       }
-               }
-               /*
-                * wait for workers to complete
-                */
-               for (i = 0; i < thread_count; i++)
-                       destroy_work_queue(&queues[i]);
-       } else {
-               queues[0].mp = mp;
-               pf_args[0] = start_inode_prefetch(0, 0, NULL);
-               for (i = 0; i < mp->m_sb.sb_agcount; i++) {
-                       pf_args[(~i) & 1] = start_inode_prefetch(i + 1, 0,
-                                       pf_args[i & 1]);
-                       process_ag_func(&queues[0], i, pf_args[i & 1]);
-               }
-       }
-       free(queues);
+       *count = process_uncertain_aginodes(wq->wq_ctx, agno);
+
+#ifdef XR_INODE_TRACE
+       fprintf(stderr,
+               "\t\t phase 3 - ag %d process_uncertain_inodes returns %d\n",
+               *count, j);
+#endif
+
+       PROG_RPT_INC(prog_rpt_done[agno], 1);
 }
 
 void
-phase3(xfs_mount_t *mp)
+phase3(
+       struct xfs_mount *mp,
+       int             scan_threads)
 {
-       int                     i, j;
+       int                     i, j;
+       int                     *counts;
+       struct workqueue        wq;
 
        do_log(_("Phase 3 - for each AG...\n"));
        if (!no_modify)
@@ -207,16 +110,16 @@ phase3(xfs_mount_t *mp)
        else
                do_log(_("        - scan (but don't clear) agi unlinked lists...\n"));
 
-       set_progress_msg(PROG_FMT_AGI_UNLINKED, (__uint64_t) glob_agcount);
+       set_progress_msg(PROG_FMT_AGI_UNLINKED, (uint64_t) glob_agcount);
 
-       /*
-        * first, let's look at the possibly bogus inodes
-        */
+       /* first clear the agi unlinked AGI list */
+       if (!no_modify) {
+               for (i = 0; i < mp->m_sb.sb_agcount; i++)
+                       process_agi_unlinked(mp, i);
+       }
+
+       /* now look at possibly bogus inodes */
        for (i = 0; i < mp->m_sb.sb_agcount; i++)  {
-               /*
-                * walk unlinked list to add more potential inodes to list
-                */
-               process_agi_unlinked(mp, i);
                check_uncertain_aginodes(mp, i);
                PROG_RPT_INC(prog_rpt_done[i], 1);
        }
@@ -227,7 +130,7 @@ phase3(xfs_mount_t *mp)
        do_log(_(
            "        - process known inodes and perform inode discovery...\n"));
 
-       set_progress_msg(PROG_FMT_PROCESS_INO, (__uint64_t) mp->m_sb.sb_icount);
+       set_progress_msg(PROG_FMT_PROCESS_INO, (uint64_t) mp->m_sb.sb_icount);
 
        process_ags(mp);
 
@@ -237,21 +140,36 @@ phase3(xfs_mount_t *mp)
         * process newly discovered inode chunks
         */
        do_log(_("        - process newly discovered inodes...\n"));
-       set_progress_msg(PROG_FMT_NEW_INODES, (__uint64_t) glob_agcount);
+       set_progress_msg(PROG_FMT_NEW_INODES, (uint64_t) glob_agcount);
+
+       counts = calloc(sizeof(*counts), mp->m_sb.sb_agcount);
+       if (!counts) {
+               do_abort(_("no memory for uncertain inode counts\n"));
+               return;
+       }
+
        do  {
                /*
                 * have to loop until no ag has any uncertain
                 * inodes
                 */
                j = 0;
-               for (i = 0; i < mp->m_sb.sb_agcount; i++)  {
-                       j += process_uncertain_aginodes(mp, i);
-#ifdef XR_INODE_TRACE
-                       fprintf(stderr,
-                               "\t\t phase 3 - process_uncertain_inodes returns %d\n", j);
-#endif
-                       PROG_RPT_INC(prog_rpt_done[i], 1);
-               }
+               memset(counts, 0, mp->m_sb.sb_agcount * sizeof(*counts));
+
+               create_work_queue(&wq, mp, scan_threads);
+
+               for (i = 0; i < mp->m_sb.sb_agcount; i++)
+                       queue_work(&wq, do_uncertain_aginodes, i, &counts[i]);
+
+               destroy_work_queue(&wq);
+
+               /* tally up the counts */
+               for (i = 0; i < mp->m_sb.sb_agcount; i++)
+                       j += counts[i];
+
        } while (j != 0);
+
+       free(counts);
+
        print_final_rpt();
 }