brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 20c4dae Raw
212 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2023 Oracle.  All Rights Reserved.4 * Author: Darrick J. Wong <djwong@kernel.org>5 */6#include "xfs.h"7#include "xfs_fs.h"8#include "xfs_shared.h"9#include "xfs_bit.h"10#include "xfs_format.h"11#include "xfs_trans_resv.h"12#include "xfs_mount.h"13#include "xfs_log_format.h"14#include "xfs_trans.h"15#include "xfs_inode.h"16#include "xfs_quota.h"17#include "xfs_qm.h"18#include "xfs_bmap.h"19#include "scrub/scrub.h"20#include "scrub/common.h"21#include "scrub/quota.h"22#include "scrub/trace.h"23 24/* Initialize a dquot iteration cursor. */25void26xchk_dqiter_init(27	struct xchk_dqiter	*cursor,28	struct xfs_scrub	*sc,29	xfs_dqtype_t		dqtype)30{31	cursor->sc = sc;32	cursor->bmap.br_startoff = NULLFILEOFF;33	cursor->dqtype = dqtype & XFS_DQTYPE_REC_MASK;34	cursor->quota_ip = xfs_quota_inode(sc->mp, cursor->dqtype);35	cursor->id = 0;36}37 38/*39 * Ensure that the cached data fork mapping for the dqiter cursor is fresh and40 * covers the dquot pointed to by the scan cursor.41 */42STATIC int43xchk_dquot_iter_revalidate_bmap(44	struct xchk_dqiter	*cursor)45{46	struct xfs_quotainfo	*qi = cursor->sc->mp->m_quotainfo;47	struct xfs_ifork	*ifp = xfs_ifork_ptr(cursor->quota_ip,48								XFS_DATA_FORK);49	xfs_fileoff_t		fileoff;50	xfs_dqid_t		this_id = cursor->id;51	int			nmaps = 1;52	int			error;53 54	fileoff = this_id / qi->qi_dqperchunk;55 56	/*57	 * If we have a mapping for cursor->id and it's still fresh, there's58	 * no need to reread the bmbt.59	 */60	if (cursor->bmap.br_startoff != NULLFILEOFF &&61	    cursor->if_seq == ifp->if_seq &&62	    cursor->bmap.br_startoff + cursor->bmap.br_blockcount > fileoff)63		return 0;64 65	/* Look up the data fork mapping for the dquot id of interest. */66	error = xfs_bmapi_read(cursor->quota_ip, fileoff,67			XFS_MAX_FILEOFF - fileoff, &cursor->bmap, &nmaps, 0);68	if (error)69		return error;70	if (!nmaps) {71		ASSERT(nmaps > 0);72		return -EFSCORRUPTED;73	}74	if (cursor->bmap.br_startoff > fileoff) {75		ASSERT(cursor->bmap.br_startoff == fileoff);76		return -EFSCORRUPTED;77	}78 79	cursor->if_seq = ifp->if_seq;80	trace_xchk_dquot_iter_revalidate_bmap(cursor, cursor->id);81	return 0;82}83 84/* Advance the dqiter cursor to the next non-sparse region of the quota file. */85STATIC int86xchk_dquot_iter_advance_bmap(87	struct xchk_dqiter	*cursor,88	uint64_t		*next_ondisk_id)89{90	struct xfs_quotainfo	*qi = cursor->sc->mp->m_quotainfo;91	struct xfs_ifork	*ifp = xfs_ifork_ptr(cursor->quota_ip,92								XFS_DATA_FORK);93	xfs_fileoff_t		fileoff;94	uint64_t		next_id;95	int			nmaps = 1;96	int			error;97 98	/* Find the dquot id for the next non-hole mapping. */99	do {100		fileoff = cursor->bmap.br_startoff + cursor->bmap.br_blockcount;101		if (fileoff > XFS_DQ_ID_MAX / qi->qi_dqperchunk) {102			/* The hole goes beyond the max dquot id, we're done */103			*next_ondisk_id = -1ULL;104			return 0;105		}106 107		error = xfs_bmapi_read(cursor->quota_ip, fileoff,108				XFS_MAX_FILEOFF - fileoff, &cursor->bmap,109				&nmaps, 0);110		if (error)111			return error;112		if (!nmaps) {113			/* Must have reached the end of the mappings. */114			*next_ondisk_id = -1ULL;115			return 0;116		}117		if (cursor->bmap.br_startoff > fileoff) {118			ASSERT(cursor->bmap.br_startoff == fileoff);119			return -EFSCORRUPTED;120		}121	} while (!xfs_bmap_is_real_extent(&cursor->bmap));122 123	next_id = cursor->bmap.br_startoff * qi->qi_dqperchunk;124	if (next_id > XFS_DQ_ID_MAX) {125		/* The hole goes beyond the max dquot id, we're done */126		*next_ondisk_id = -1ULL;127		return 0;128	}129 130	/* Propose jumping forward to the dquot in the next allocated block. */131	*next_ondisk_id = next_id;132	cursor->if_seq = ifp->if_seq;133	trace_xchk_dquot_iter_advance_bmap(cursor, *next_ondisk_id);134	return 0;135}136 137/*138 * Find the id of the next highest incore dquot.  Normally this will correspond139 * exactly with the quota file block mappings, but repair might have erased a140 * mapping because it was crosslinked; in that case, we need to re-allocate the141 * space so that we can reset q_blkno.142 */143STATIC void144xchk_dquot_iter_advance_incore(145	struct xchk_dqiter	*cursor,146	uint64_t		*next_incore_id)147{148	struct xfs_quotainfo	*qi = cursor->sc->mp->m_quotainfo;149	struct radix_tree_root	*tree = xfs_dquot_tree(qi, cursor->dqtype);150	struct xfs_dquot	*dq;151	unsigned int		nr_found;152 153	*next_incore_id = -1ULL;154 155	mutex_lock(&qi->qi_tree_lock);156	nr_found = radix_tree_gang_lookup(tree, (void **)&dq, cursor->id, 1);157	if (nr_found)158		*next_incore_id = dq->q_id;159	mutex_unlock(&qi->qi_tree_lock);160 161	trace_xchk_dquot_iter_advance_incore(cursor, *next_incore_id);162}163 164/*165 * Walk all incore dquots of this filesystem.  Caller must set *@cursorp to166 * zero before the first call, and must not hold the quota file ILOCK.167 * Returns 1 and a valid *@dqpp; 0 and *@dqpp == NULL when there are no more168 * dquots to iterate; or a negative errno.169 */170int171xchk_dquot_iter(172	struct xchk_dqiter	*cursor,173	struct xfs_dquot	**dqpp)174{175	struct xfs_mount	*mp = cursor->sc->mp;176	struct xfs_dquot	*dq = NULL;177	uint64_t		next_ondisk, next_incore = -1ULL;178	unsigned int		lock_mode;179	int			error = 0;180 181	if (cursor->id > XFS_DQ_ID_MAX)182		return 0;183	next_ondisk = cursor->id;184 185	/* Revalidate and/or advance the cursor. */186	lock_mode = xfs_ilock_data_map_shared(cursor->quota_ip);187	error = xchk_dquot_iter_revalidate_bmap(cursor);188	if (!error && !xfs_bmap_is_real_extent(&cursor->bmap))189		error = xchk_dquot_iter_advance_bmap(cursor, &next_ondisk);190	xfs_iunlock(cursor->quota_ip, lock_mode);191	if (error)192		return error;193 194	if (next_ondisk > cursor->id)195		xchk_dquot_iter_advance_incore(cursor, &next_incore);196 197	/* Pick the next dquot in the sequence and return it. */198	cursor->id = min(next_ondisk, next_incore);199	if (cursor->id > XFS_DQ_ID_MAX)200		return 0;201 202	trace_xchk_dquot_iter(cursor, cursor->id);203 204	error = xfs_qm_dqget(mp, cursor->id, cursor->dqtype, false, &dq);205	if (error)206		return error;207 208	cursor->id = dq->q_id + 1;209	*dqpp = dq;210	return 1;211}212