// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (c) 2021-2024 Oracle.  All Rights Reserved.
 * Author: Darrick J. Wong <djwong@kernel.org>
 */
#ifndef XFS_SCRUB_SCRUB_PRIVATE_H_
#define XFS_SCRUB_SCRUB_PRIVATE_H_

/* Shared code between scrub.c and repair.c. */

void xfrog_scrubv_from_item(struct xfrog_scrubv *scrubv,
		const struct scrub_item *sri);
void xfrog_scrubv_add_item(struct xfrog_scrubv *scrubv,
		const struct scrub_item *sri, unsigned int scrub_type,
		bool want_repair);
void xfrog_scrubv_add_barrier(struct xfrog_scrubv *scrubv);

struct scrubv_descr {
	struct xfrog_scrubv	*scrubv;
	int			idx;
};

#define SCRUBV_DESCR(sv)	{ .scrubv = (sv), .idx = -1 }

int format_scrubv_descr(struct scrub_ctx *ctx, char *buf, size_t buflen,
		void *where);

/* Predicates for scrub flag state. */

static inline bool is_corrupt(const struct xfs_scrub_vec *sv)
{
	return sv->sv_flags & XFS_SCRUB_OFLAG_CORRUPT;
}

static inline bool is_unoptimized(const struct xfs_scrub_vec *sv)
{
	return sv->sv_flags & XFS_SCRUB_OFLAG_PREEN;
}

static inline bool xref_failed(const struct xfs_scrub_vec *sv)
{
	return sv->sv_flags & XFS_SCRUB_OFLAG_XFAIL;
}

static inline bool xref_disagrees(const struct xfs_scrub_vec *sv)
{
	return sv->sv_flags & XFS_SCRUB_OFLAG_XCORRUPT;
}

static inline bool is_incomplete(const struct xfs_scrub_vec *sv)
{
	return sv->sv_flags & XFS_SCRUB_OFLAG_INCOMPLETE;
}

static inline bool is_suspicious(const struct xfs_scrub_vec *sv)
{
	return sv->sv_flags & XFS_SCRUB_OFLAG_WARNING;
}

/* Should we fix it? */
static inline bool needs_repair(const struct xfs_scrub_vec *sv)
{
	return is_corrupt(sv) || xref_disagrees(sv);
}

/*
 * We want to retry an operation if the kernel says it couldn't complete the
 * scan/repair; or if there were cross-referencing problems but the object was
 * not obviously corrupt.
 */
static inline bool want_retry(const struct xfs_scrub_vec *sv)
{
	return is_incomplete(sv) || (xref_disagrees(sv) && !is_corrupt(sv));
}

void scrub_warn_incomplete_scrub(struct scrub_ctx *ctx, struct descr *dsc,
		const struct xfs_scrub_vec *meta);

/* Scrub item functions */

static inline void
scrub_item_save_state(
	struct scrub_item		*sri,
	unsigned  int			scrub_type,
	unsigned  int			scrub_flags)
{
	sri->sri_state[scrub_type] = scrub_flags & SCRUB_ITEM_REPAIR_ANY;
	if (scrub_flags & SCRUB_ITEM_NEEDSREPAIR)
		sri->sri_inconsistent = true;
}

static inline void
scrub_item_clean_state(
	struct scrub_item		*sri,
	unsigned  int			scrub_type)
{
	sri->sri_state[scrub_type] = 0;
}

static inline bool
scrub_item_type_boosted(
	struct scrub_item		*sri,
	unsigned  int			scrub_type)
{
	return sri->sri_state[scrub_type] & SCRUB_ITEM_BOOST_REPAIR;
}

/* Decide if we want to retry this operation and update bookkeeping if yes. */
static inline bool
scrub_item_schedule_retry(struct scrub_item *sri, unsigned int scrub_type)
{
	if (sri->sri_tries[scrub_type] == 0)
		return false;
	sri->sri_tries[scrub_type]--;
	return true;
}

bool scrub_item_call_kernel_again(struct scrub_item *sri, uint8_t work_mask,
		const struct scrub_item *old);
bool scrub_item_schedule_work(struct scrub_item *sri, uint8_t state_flags,
		const unsigned int *schedule_deps);

#endif /* XFS_SCRUB_SCRUB_PRIVATE_H_ */
