brintos

brintos / linux-shallow public Read only

0
0
Text · 5.5 KiB · 2c2720c Raw
217 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2000-2006 Silicon Graphics, Inc.4 * All Rights Reserved.5 */6#include "xfs.h"7#include "xfs_fs.h"8#include "xfs_shared.h"9#include "xfs_format.h"10#include "xfs_log_format.h"11#include "xfs_trans_resv.h"12#include "xfs_mount.h"13#include "xfs_inode.h"14#include "xfs_quota.h"15#include "xfs_trans.h"16#include "xfs_buf_item.h"17#include "xfs_trans_priv.h"18#include "xfs_qm.h"19#include "xfs_log.h"20#include "xfs_log_priv.h"21#include "xfs_log_recover.h"22#include "xfs_error.h"23 24STATIC void25xlog_recover_dquot_ra_pass2(26	struct xlog			*log,27	struct xlog_recover_item	*item)28{29	struct xfs_mount	*mp = log->l_mp;30	struct xfs_disk_dquot	*recddq;31	struct xfs_dq_logformat	*dq_f;32	uint			type;33 34	if (mp->m_qflags == 0)35		return;36 37	recddq = item->ri_buf[1].i_addr;38	if (recddq == NULL)39		return;40	if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot))41		return;42 43	type = recddq->d_type & XFS_DQTYPE_REC_MASK;44	ASSERT(type);45	if (log->l_quotaoffs_flag & type)46		return;47 48	dq_f = item->ri_buf[0].i_addr;49	ASSERT(dq_f);50	ASSERT(dq_f->qlf_len == 1);51 52	xlog_buf_readahead(log, dq_f->qlf_blkno,53			XFS_FSB_TO_BB(mp, dq_f->qlf_len),54			&xfs_dquot_buf_ra_ops);55}56 57/*58 * Recover a dquot record59 */60STATIC int61xlog_recover_dquot_commit_pass2(62	struct xlog			*log,63	struct list_head		*buffer_list,64	struct xlog_recover_item	*item,65	xfs_lsn_t			current_lsn)66{67	struct xfs_mount		*mp = log->l_mp;68	struct xfs_buf			*bp;69	struct xfs_dqblk		*dqb;70	struct xfs_disk_dquot		*ddq, *recddq;71	struct xfs_dq_logformat		*dq_f;72	xfs_failaddr_t			fa;73	int				error;74	uint				type;75 76	/*77	 * Filesystems are required to send in quota flags at mount time.78	 */79	if (mp->m_qflags == 0)80		return 0;81 82	recddq = item->ri_buf[1].i_addr;83	if (recddq == NULL) {84		xfs_alert(log->l_mp, "NULL dquot in %s.", __func__);85		return -EFSCORRUPTED;86	}87	if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) {88		xfs_alert(log->l_mp, "dquot too small (%d) in %s.",89			item->ri_buf[1].i_len, __func__);90		return -EFSCORRUPTED;91	}92 93	/*94	 * This type of quotas was turned off, so ignore this record.95	 */96	type = recddq->d_type & XFS_DQTYPE_REC_MASK;97	ASSERT(type);98	if (log->l_quotaoffs_flag & type)99		return 0;100 101	/*102	 * At this point we know that quota was _not_ turned off.103	 * Since the mount flags are not indicating to us otherwise, this104	 * must mean that quota is on, and the dquot needs to be replayed.105	 * Remember that we may not have fully recovered the superblock yet,106	 * so we can't do the usual trick of looking at the SB quota bits.107	 *108	 * The other possibility, of course, is that the quota subsystem was109	 * removed since the last mount - ENOSYS.110	 */111	dq_f = item->ri_buf[0].i_addr;112	ASSERT(dq_f);113	fa = xfs_dquot_verify(mp, recddq, dq_f->qlf_id);114	if (fa) {115		xfs_alert(mp, "corrupt dquot ID 0x%x in log at %pS",116				dq_f->qlf_id, fa);117		return -EFSCORRUPTED;118	}119	ASSERT(dq_f->qlf_len == 1);120 121	/*122	 * At this point we are assuming that the dquots have been allocated123	 * and hence the buffer has valid dquots stamped in it. It should,124	 * therefore, pass verifier validation. If the dquot is bad, then the125	 * we'll return an error here, so we don't need to specifically check126	 * the dquot in the buffer after the verifier has run.127	 */128	error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno,129				   XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp,130				   &xfs_dquot_buf_ops);131	if (error)132		return error;133 134	ASSERT(bp);135	dqb = xfs_buf_offset(bp, dq_f->qlf_boffset);136	ddq = &dqb->dd_diskdq;137 138	/*139	 * If the dquot has an LSN in it, recover the dquot only if it's less140	 * than the lsn of the transaction we are replaying.141	 */142	if (xfs_has_crc(mp)) {143		xfs_lsn_t	lsn = be64_to_cpu(dqb->dd_lsn);144 145		if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {146			goto out_release;147		}148	}149 150	memcpy(ddq, recddq, item->ri_buf[1].i_len);151	if (xfs_has_crc(mp)) {152		xfs_update_cksum((char *)dqb, sizeof(struct xfs_dqblk),153				 XFS_DQUOT_CRC_OFF);154	}155 156	/* Validate the recovered dquot. */157	fa = xfs_dqblk_verify(log->l_mp, dqb, dq_f->qlf_id);158	if (fa) {159		XFS_CORRUPTION_ERROR("Bad dquot after recovery",160				XFS_ERRLEVEL_LOW, mp, dqb,161				sizeof(struct xfs_dqblk));162		xfs_alert(mp,163 "Metadata corruption detected at %pS, dquot 0x%x",164				fa, dq_f->qlf_id);165		error = -EFSCORRUPTED;166		goto out_release;167	}168 169	ASSERT(dq_f->qlf_size == 2);170	ASSERT(bp->b_mount == mp);171	bp->b_flags |= _XBF_LOGRECOVERY;172	xfs_buf_delwri_queue(bp, buffer_list);173 174out_release:175	xfs_buf_relse(bp);176	return 0;177}178 179const struct xlog_recover_item_ops xlog_dquot_item_ops = {180	.item_type		= XFS_LI_DQUOT,181	.ra_pass2		= xlog_recover_dquot_ra_pass2,182	.commit_pass2		= xlog_recover_dquot_commit_pass2,183};184 185/*186 * Recover QUOTAOFF records. We simply make a note of it in the xlog187 * structure, so that we know not to do any dquot item or dquot buffer recovery,188 * of that type.189 */190STATIC int191xlog_recover_quotaoff_commit_pass1(192	struct xlog			*log,193	struct xlog_recover_item	*item)194{195	struct xfs_qoff_logformat	*qoff_f = item->ri_buf[0].i_addr;196	ASSERT(qoff_f);197 198	/*199	 * The logitem format's flag tells us if this was user quotaoff,200	 * group/project quotaoff or both.201	 */202	if (qoff_f->qf_flags & XFS_UQUOTA_ACCT)203		log->l_quotaoffs_flag |= XFS_DQTYPE_USER;204	if (qoff_f->qf_flags & XFS_PQUOTA_ACCT)205		log->l_quotaoffs_flag |= XFS_DQTYPE_PROJ;206	if (qoff_f->qf_flags & XFS_GQUOTA_ACCT)207		log->l_quotaoffs_flag |= XFS_DQTYPE_GROUP;208 209	return 0;210}211 212const struct xlog_recover_item_ops xlog_quotaoff_item_ops = {213	.item_type		= XFS_LI_QUOTAOFF,214	.commit_pass1		= xlog_recover_quotaoff_commit_pass1,215	/* nothing to commit in pass2 */216};217