1249259Sdim// SPDX-License-Identifier: GPL-2.0-or-later
2249259Sdim/*
3249259Sdim * Copyright (c) 2018-2024 Oracle.  All Rights Reserved.
4249259Sdim * Author: Darrick J. Wong <djwong@kernel.org>
5249259Sdim */
6249259Sdim#include "xfs.h"
7249259Sdim#include "xfs_fs.h"
8249259Sdim#include "xfs_shared.h"
9249259Sdim#include "xfs_format.h"
10249259Sdim#include "xfs_trans_resv.h"
11249259Sdim#include "xfs_mount.h"
12249259Sdim#include "xfs_defer.h"
13249259Sdim#include "xfs_btree.h"
14249259Sdim#include "xfs_bit.h"
15249259Sdim#include "xfs_log_format.h"
16249259Sdim#include "xfs_trans.h"
17249259Sdim#include "xfs_sb.h"
18249259Sdim#include "xfs_inode.h"
19249259Sdim#include "xfs_alloc.h"
20249259Sdim#include "xfs_ialloc.h"
21249259Sdim#include "xfs_rmap.h"
22249259Sdim#include "xfs_health.h"
23249259Sdim#include "scrub/xfs_scrub.h"
24249259Sdim#include "scrub/scrub.h"
25249259Sdim#include "scrub/common.h"
26249259Sdim#include "scrub/trace.h"
27249259Sdim#include "scrub/repair.h"
28249259Sdim#include "scrub/fscounters.h"
29249259Sdim
30249259Sdim/*
31249259Sdim * FS Summary Counters
32249259Sdim * ===================
33249259Sdim *
34249259Sdim * We correct errors in the filesystem summary counters by setting them to the
35249259Sdim * values computed during the obligatory scrub phase.  However, we must be
36249259Sdim * careful not to allow any other thread to change the counters while we're
37249259Sdim * computing and setting new values.  To achieve this, we freeze the
38249259Sdim * filesystem for the whole operation if the REPAIR flag is set.  The checking
39249259Sdim * function is stricter when we've frozen the fs.
40249259Sdim */
41249259Sdim
42249259Sdim/*
43249259Sdim * Reset the superblock counters.  Caller is responsible for freezing the
44249259Sdim * filesystem during the calculation and reset phases.
45249259Sdim */
46249259Sdimint
47249259Sdimxrep_fscounters(
48249259Sdim	struct xfs_scrub	*sc)
49249259Sdim{
50249259Sdim	struct xfs_mount	*mp = sc->mp;
51249259Sdim	struct xchk_fscounters	*fsc = sc->buf;
52249259Sdim
53249259Sdim	/*
54249259Sdim	 * Reinitialize the in-core counters from what we computed.  We froze
55249259Sdim	 * the filesystem, so there shouldn't be anyone else trying to modify
56249259Sdim	 * these counters.
57249259Sdim	 */
58249259Sdim	if (!fsc->frozen) {
59249259Sdim		ASSERT(fsc->frozen);
60249259Sdim		return -EFSCORRUPTED;
61249259Sdim	}
62249259Sdim
63249259Sdim	trace_xrep_reset_counters(mp, fsc);
64249259Sdim
65249259Sdim	percpu_counter_set(&mp->m_icount, fsc->icount);
66249259Sdim	percpu_counter_set(&mp->m_ifree, fsc->ifree);
67249259Sdim	percpu_counter_set(&mp->m_fdblocks, fsc->fdblocks);
68249259Sdim
69249259Sdim	/*
70249259Sdim	 * Online repair is only supported on v5 file systems, which require
71249259Sdim	 * lazy sb counters and thus no update of sb_fdblocks here.  But as of
72249259Sdim	 * now we don't support lazy counting sb_frextents yet, and thus need
73249259Sdim	 * to also update it directly here.  And for that we need to keep
74249259Sdim	 * track of the delalloc reservations separately, as they are are
75249259Sdim	 * subtracted from m_frextents, but not included in sb_frextents.
76249259Sdim	 */
77249259Sdim	percpu_counter_set(&mp->m_frextents,
78249259Sdim		fsc->frextents - fsc->frextents_delayed);
79249259Sdim	mp->m_sb.sb_frextents = fsc->frextents;
80249259Sdim
81249259Sdim	return 0;
82249259Sdim}
83249259Sdim