File: [Development] / xfs-cmds / xfsprogs / repair / phase3.c (download)
Revision 1.16, Mon Sep 8 06:18:43 2008 UTC (9 years, 1 month ago) by bnaujok.longdrop.melbourne.sgi.com
Branch: MAIN
CVS Tags: HEAD Changes since 1.15: +6 -7
lines
Update xfsprogs to latest kernel headers and functions
Merge of master-melb:xfs-cmds:32070a by kenmcd.
|
/*
* 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 "avl.h"
#include "globals.h"
#include "agheader.h"
#include "incore.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]);
switch (state = get_agbno_state(mp,
agno, agbno)) {
case XR_E_UNKNOWN:
case XR_E_FREE:
case XR_E_FREE1:
set_agbno_state(mp, agno, agbno,
XR_E_INO);
break;
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_agbno_state(mp, 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);
}
void
process_agi_unlinked(xfs_mount_t *mp, xfs_agnumber_t agno)
{
xfs_agnumber_t i;
xfs_buf_t *bp;
xfs_agi_t *agip;
int err = 0;
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);
if (!bp)
do_error(_("cannot read agi block %lld 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);
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 (err)
do_warn(_("error following ag %d unlinked list\n"), agno);
ASSERT(agi_dirty == 0 || (agi_dirty && !no_modify));
if (agi_dirty && !no_modify)
libxfs_writebuf(bp, 0);
else
libxfs_putbuf(bp);
}
static void
process_ag_func(
work_queue_t *wq,
xfs_agnumber_t agno,
void *arg)
{
/*
* turn on directory processing (inode discovery) and
* attribute processing (extra_attr_check)
*/
wait_for_inode_prefetch(arg);
do_log(_(" - agno = %d\n"), agno);
process_aginodes(wq->mp, arg, agno, 1, 0, 1);
cleanup_inode_prefetch(arg);
}
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];
queues = malloc(thread_count * sizeof(work_queue_t));
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);
}
void
phase3(xfs_mount_t *mp)
{
int i, j;
do_log(_("Phase 3 - for each AG...\n"));
if (!no_modify)
do_log(_(" - scan and clear agi unlinked lists...\n"));
else
do_log(_(" - scan (but don't clear) agi unlinked lists...\n"));
set_progress_msg(PROG_FMT_AGI_UNLINKED, (__uint64_t) glob_agcount);
/*
* first, let's look at the 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);
}
print_final_rpt();
/* ok, now that the tree's ok, let's take a good look */
do_log(_(
" - process known inodes and perform inode discovery...\n"));
set_progress_msg(PROG_FMT_PROCESS_INO, (__uint64_t) mp->m_sb.sb_icount);
process_ags(mp);
print_final_rpt();
/*
* process newly discovered inode chunks
*/
do_log(_(" - process newly discovered inodes...\n"));
set_progress_msg(PROG_FMT_NEW_INODES, (__uint64_t) glob_agcount);
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);
}
} while (j != 0);
print_final_rpt();
}