linux/fs/xfs/scrub/quotacheck.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (c) 2020-2024 Oracle.  All Rights Reserved.
 * Author: Darrick J. Wong <[email protected]>
 */
#include "xfs.h"
#include "xfs_fs.h"
#include "xfs_shared.h"
#include "xfs_format.h"
#include "xfs_trans_resv.h"
#include "xfs_mount.h"
#include "xfs_log_format.h"
#include "xfs_trans.h"
#include "xfs_inode.h"
#include "xfs_quota.h"
#include "xfs_qm.h"
#include "xfs_icache.h"
#include "xfs_bmap_util.h"
#include "xfs_ialloc.h"
#include "xfs_ag.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/repair.h"
#include "scrub/xfile.h"
#include "scrub/xfarray.h"
#include "scrub/iscan.h"
#include "scrub/quota.h"
#include "scrub/quotacheck.h"
#include "scrub/trace.h"

/*
 * Live Quotacheck
 * ===============
 *
 * Quota counters are "summary" metadata, in the sense that they are computed
 * as the summation of the block usage counts for every file on the filesystem.
 * Therefore, we compute the correct icount, bcount, and rtbcount values by
 * creating a shadow quota counter structure and walking every inode.
 */

/* Track the quota deltas for a dquot in a transaction. */
struct xqcheck_dqtrx {};

#define XQCHECK_MAX_NR_DQTRXS

/*
 * Track the quota deltas for all dquots attached to a transaction if the
 * quota deltas are being applied to an inode that we already scanned.
 */
struct xqcheck_dqacct {};

/* Free a shadow dquot accounting structure. */
static void
xqcheck_dqacct_free(
	void			*ptr,
	void			*arg)
{}

/* Set us up to scrub quota counters. */
int
xchk_setup_quotacheck(
	struct xfs_scrub	*sc)
{}

/*
 * Part 1: Collecting dquot resource usage counts.  For each xfs_dquot attached
 * to each inode, we create a shadow dquot, and compute the inode count and add
 * the data/rt block usage from what we see.
 *
 * To avoid false corruption reports in part 2, any failure in this part must
 * set the INCOMPLETE flag even when a negative errno is returned.  This care
 * must be taken with certain errno values (i.e. EFSBADCRC, EFSCORRUPTED,
 * ECANCELED) that are absorbed into a scrub state flag update by
 * xchk_*_process_error.  Scrub and repair share the same incore data
 * structures, so the INCOMPLETE flag is critical to prevent a repair based on
 * insufficient information.
 *
 * Because we are scanning a live filesystem, it's possible that another thread
 * will try to update the quota counters for an inode that we've already
 * scanned.  This will cause our counts to be incorrect.  Therefore, we hook
 * the live transaction code in two places: (1) when the callers update the
 * per-transaction dqtrx structure to log quota counter updates; and (2) when
 * transaction commit actually logs those updates to the incore dquot.  By
 * shadowing transaction updates in this manner, live quotacheck can ensure
 * by locking the dquot and the shadow structure that its own copies are not
 * out of date.  Because the hook code runs in a different process context from
 * the scrub code and the scrub state flags are not accessed atomically,
 * failures in the hook code must abort the iscan and the scrubber must notice
 * the aborted scan and set the incomplete flag.
 *
 * Note that we use srcu notifier hooks to minimize the overhead when live
 * quotacheck is /not/ running.
 */

/* Update an incore dquot counter information from a live update. */
static int
xqcheck_update_incore_counts(
	struct xqcheck		*xqc,
	struct xfarray		*counts,
	xfs_dqid_t		id,
	int64_t			inodes,
	int64_t			nblks,
	int64_t			rtblks)
{}

/* Decide if this is the shadow dquot accounting structure for a transaction. */
static int
xqcheck_dqacct_obj_cmpfn(
	struct rhashtable_compare_arg	*arg,
	const void			*obj)
{}

static const struct rhashtable_params xqcheck_dqacct_hash_params =;

/* Find a shadow dqtrx slot for the given dquot. */
STATIC struct xqcheck_dqtrx *
xqcheck_get_dqtrx(
	struct xqcheck_dqacct	*dqa,
	xfs_dqtype_t		q_type,
	xfs_dqid_t		q_id)
{}

/*
 * Create and fill out a quota delta tracking structure to shadow the updates
 * going on in the regular quota code.
 */
static int
xqcheck_mod_live_ino_dqtrx(
	struct notifier_block		*nb,
	unsigned long			action,
	void				*data)
{}

/*
 * Apply the transaction quota deltas to our shadow quota accounting info when
 * the regular quota code are doing the same.
 */
static int
xqcheck_apply_live_dqtrx(
	struct notifier_block		*nb,
	unsigned long			action,
	void				*data)
{}

/* Record this inode's quota usage in our shadow quota counter data. */
STATIC int
xqcheck_collect_inode(
	struct xqcheck		*xqc,
	struct xfs_inode	*ip)
{}

/* Walk all the allocated inodes and run a quota scan on them. */
STATIC int
xqcheck_collect_counts(
	struct xqcheck		*xqc)
{}

/*
 * Part 2: Comparing dquot resource counters.  Walk each xfs_dquot, comparing
 * the resource usage counters against our shadow dquots; and then walk each
 * shadow dquot (that wasn't covered in the first part), comparing it against
 * the xfs_dquot.
 */

/*
 * Check the dquot data against what we observed.  Caller must hold the dquot
 * lock.
 */
STATIC int
xqcheck_compare_dquot(
	struct xqcheck		*xqc,
	xfs_dqtype_t		dqtype,
	struct xfs_dquot	*dq)
{}

/*
 * Walk all the observed dquots, and make sure there's a matching incore
 * dquot and that its counts match ours.
 */
STATIC int
xqcheck_walk_observations(
	struct xqcheck		*xqc,
	xfs_dqtype_t		dqtype)
{}

/* Compare the quota counters we observed against the live dquots. */
STATIC int
xqcheck_compare_dqtype(
	struct xqcheck		*xqc,
	xfs_dqtype_t		dqtype)
{}

/* Tear down everything associated with a quotacheck. */
static void
xqcheck_teardown_scan(
	void			*priv)
{}

/*
 * Scan all inodes in the entire filesystem to generate quota counter data.
 * If the scan is successful, the quota data will be left alive for a repair.
 * If any error occurs, we'll tear everything down.
 */
STATIC int
xqcheck_setup_scan(
	struct xfs_scrub	*sc,
	struct xqcheck		*xqc)
{}

/* Scrub all counters for a given quota type. */
int
xchk_quotacheck(
	struct xfs_scrub	*sc)
{}