1169689Skan// SPDX-License-Identifier: GPL-2.0
2169689Skan/*
3171825Skan * Copyright (c) 2000-2006 Silicon Graphics, Inc.
4169689Skan * All Rights Reserved.
5169689Skan */
6169689Skan#include "xfs.h"
7169689Skan#include "xfs_fs.h"
8169689Skan#include "xfs_shared.h"
9169689Skan#include "xfs_format.h"
10169689Skan#include "xfs_log_format.h"
11169689Skan#include "xfs_trans_resv.h"
12169689Skan#include "xfs_mount.h"
13169689Skan#include "xfs_inode.h"
14169689Skan#include "xfs_quota.h"
15169689Skan#include "xfs_trans.h"
16169689Skan#include "xfs_buf_item.h"
17169689Skan#include "xfs_trans_priv.h"
18169689Skan#include "xfs_qm.h"
19169689Skan#include "xfs_log.h"
20169689Skan#include "xfs_log_priv.h"
21169689Skan#include "xfs_log_recover.h"
22169689Skan#include "xfs_error.h"
23169689Skan
24169689SkanSTATIC void
25169689Skanxlog_recover_dquot_ra_pass2(
26169689Skan	struct xlog			*log,
27169689Skan	struct xlog_recover_item	*item)
28169689Skan{
29169689Skan	struct xfs_mount	*mp = log->l_mp;
30169689Skan	struct xfs_disk_dquot	*recddq;
31169689Skan	struct xfs_dq_logformat	*dq_f;
32169689Skan	uint			type;
33169689Skan
34169689Skan	if (mp->m_qflags == 0)
35169689Skan		return;
36169689Skan
37169689Skan	recddq = item->ri_buf[1].i_addr;
38169689Skan	if (recddq == NULL)
39169689Skan		return;
40169689Skan	if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot))
41169689Skan		return;
42169689Skan
43169689Skan	type = recddq->d_type & XFS_DQTYPE_REC_MASK;
44169689Skan	ASSERT(type);
45169689Skan	if (log->l_quotaoffs_flag & type)
46169689Skan		return;
47169689Skan
48169689Skan	dq_f = item->ri_buf[0].i_addr;
49169689Skan	ASSERT(dq_f);
50169689Skan	ASSERT(dq_f->qlf_len == 1);
51169689Skan
52169689Skan	xlog_buf_readahead(log, dq_f->qlf_blkno,
53169689Skan			XFS_FSB_TO_BB(mp, dq_f->qlf_len),
54169689Skan			&xfs_dquot_buf_ra_ops);
55169689Skan}
56169689Skan
57169689Skan/*
58169689Skan * Recover a dquot record
59169689Skan */
60169689SkanSTATIC int
61169689Skanxlog_recover_dquot_commit_pass2(
62169689Skan	struct xlog			*log,
63169689Skan	struct list_head		*buffer_list,
64169689Skan	struct xlog_recover_item	*item,
65169689Skan	xfs_lsn_t			current_lsn)
66169689Skan{
67169689Skan	struct xfs_mount		*mp = log->l_mp;
68169689Skan	struct xfs_buf			*bp;
69169689Skan	struct xfs_dqblk		*dqb;
70169689Skan	struct xfs_disk_dquot		*ddq, *recddq;
71169689Skan	struct xfs_dq_logformat		*dq_f;
72169689Skan	xfs_failaddr_t			fa;
73169689Skan	int				error;
74169689Skan	uint				type;
75169689Skan
76169689Skan	/*
77169689Skan	 * Filesystems are required to send in quota flags at mount time.
78169689Skan	 */
79169689Skan	if (mp->m_qflags == 0)
80169689Skan		return 0;
81169689Skan
82169689Skan	recddq = item->ri_buf[1].i_addr;
83169689Skan	if (recddq == NULL) {
84169689Skan		xfs_alert(log->l_mp, "NULL dquot in %s.", __func__);
85169689Skan		return -EFSCORRUPTED;
86169689Skan	}
87169689Skan	if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) {
88169689Skan		xfs_alert(log->l_mp, "dquot too small (%d) in %s.",
89169689Skan			item->ri_buf[1].i_len, __func__);
90169689Skan		return -EFSCORRUPTED;
91169689Skan	}
92169689Skan
93169689Skan	/*
94169689Skan	 * This type of quotas was turned off, so ignore this record.
95169689Skan	 */
96169689Skan	type = recddq->d_type & XFS_DQTYPE_REC_MASK;
97169689Skan	ASSERT(type);
98169689Skan	if (log->l_quotaoffs_flag & type)
99169689Skan		return 0;
100169689Skan
101169689Skan	/*
102169689Skan	 * At this point we know that quota was _not_ turned off.
103169689Skan	 * Since the mount flags are not indicating to us otherwise, this
104169689Skan	 * must mean that quota is on, and the dquot needs to be replayed.
105169689Skan	 * Remember that we may not have fully recovered the superblock yet,
106169689Skan	 * so we can't do the usual trick of looking at the SB quota bits.
107169689Skan	 *
108169689Skan	 * The other possibility, of course, is that the quota subsystem was
109169689Skan	 * removed since the last mount - ENOSYS.
110169689Skan	 */
111169689Skan	dq_f = item->ri_buf[0].i_addr;
112169689Skan	ASSERT(dq_f);
113169689Skan	fa = xfs_dquot_verify(mp, recddq, dq_f->qlf_id);
114169689Skan	if (fa) {
115169689Skan		xfs_alert(mp, "corrupt dquot ID 0x%x in log at %pS",
116169689Skan				dq_f->qlf_id, fa);
117169689Skan		return -EFSCORRUPTED;
118169689Skan	}
119169689Skan	ASSERT(dq_f->qlf_len == 1);
120169689Skan
121169689Skan	/*
122169689Skan	 * At this point we are assuming that the dquots have been allocated
123169689Skan	 * and hence the buffer has valid dquots stamped in it. It should,
124169689Skan	 * therefore, pass verifier validation. If the dquot is bad, then the
125169689Skan	 * we'll return an error here, so we don't need to specifically check
126169689Skan	 * the dquot in the buffer after the verifier has run.
127169689Skan	 */
128169689Skan	error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno,
129169689Skan				   XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp,
130169689Skan				   &xfs_dquot_buf_ops);
131169689Skan	if (error)
132169689Skan		return error;
133169689Skan
134169689Skan	ASSERT(bp);
135169689Skan	dqb = xfs_buf_offset(bp, dq_f->qlf_boffset);
136169689Skan	ddq = &dqb->dd_diskdq;
137169689Skan
138169689Skan	/*
139169689Skan	 * If the dquot has an LSN in it, recover the dquot only if it's less
140169689Skan	 * than the lsn of the transaction we are replaying.
141169689Skan	 */
142169689Skan	if (xfs_has_crc(mp)) {
143169689Skan		xfs_lsn_t	lsn = be64_to_cpu(dqb->dd_lsn);
144169689Skan
145169689Skan		if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
146169689Skan			goto out_release;
147169689Skan		}
148169689Skan	}
149169689Skan
150169689Skan	memcpy(ddq, recddq, item->ri_buf[1].i_len);
151169689Skan	if (xfs_has_crc(mp)) {
152169689Skan		xfs_update_cksum((char *)dqb, sizeof(struct xfs_dqblk),
153169689Skan				 XFS_DQUOT_CRC_OFF);
154169689Skan	}
155169689Skan
156169689Skan	/* Validate the recovered dquot. */
157169689Skan	fa = xfs_dqblk_verify(log->l_mp, dqb, dq_f->qlf_id);
158169689Skan	if (fa) {
159169689Skan		XFS_CORRUPTION_ERROR("Bad dquot after recovery",
160169689Skan				XFS_ERRLEVEL_LOW, mp, dqb,
161169689Skan				sizeof(struct xfs_dqblk));
162169689Skan		xfs_alert(mp,
163169689Skan "Metadata corruption detected at %pS, dquot 0x%x",
164169689Skan				fa, dq_f->qlf_id);
165169689Skan		error = -EFSCORRUPTED;
166169689Skan		goto out_release;
167169689Skan	}
168169689Skan
169169689Skan	ASSERT(dq_f->qlf_size == 2);
170169689Skan	ASSERT(bp->b_mount == mp);
171169689Skan	bp->b_flags |= _XBF_LOGRECOVERY;
172169689Skan	xfs_buf_delwri_queue(bp, buffer_list);
173169689Skan
174169689Skanout_release:
175169689Skan	xfs_buf_relse(bp);
176169689Skan	return 0;
177169689Skan}
178169689Skan
179169689Skanconst struct xlog_recover_item_ops xlog_dquot_item_ops = {
180169689Skan	.item_type		= XFS_LI_DQUOT,
181169689Skan	.ra_pass2		= xlog_recover_dquot_ra_pass2,
182169689Skan	.commit_pass2		= xlog_recover_dquot_commit_pass2,
183169689Skan};
184169689Skan
185169689Skan/*
186169689Skan * Recover QUOTAOFF records. We simply make a note of it in the xlog
187169689Skan * structure, so that we know not to do any dquot item or dquot buffer recovery,
188169689Skan * of that type.
189169689Skan */
190169689SkanSTATIC int
191169689Skanxlog_recover_quotaoff_commit_pass1(
192169689Skan	struct xlog			*log,
193169689Skan	struct xlog_recover_item	*item)
194169689Skan{
195169689Skan	struct xfs_qoff_logformat	*qoff_f = item->ri_buf[0].i_addr;
196169689Skan	ASSERT(qoff_f);
197169689Skan
198169689Skan	/*
199169689Skan	 * The logitem format's flag tells us if this was user quotaoff,
200169689Skan	 * group/project quotaoff or both.
201169689Skan	 */
202169689Skan	if (qoff_f->qf_flags & XFS_UQUOTA_ACCT)
203169689Skan		log->l_quotaoffs_flag |= XFS_DQTYPE_USER;
204169689Skan	if (qoff_f->qf_flags & XFS_PQUOTA_ACCT)
205169689Skan		log->l_quotaoffs_flag |= XFS_DQTYPE_PROJ;
206169689Skan	if (qoff_f->qf_flags & XFS_GQUOTA_ACCT)
207169689Skan		log->l_quotaoffs_flag |= XFS_DQTYPE_GROUP;
208169689Skan
209169689Skan	return 0;
210169689Skan}
211169689Skan
212169689Skanconst struct xlog_recover_item_ops xlog_quotaoff_item_ops = {
213169689Skan	.item_type		= XFS_LI_QUOTAOFF,
214169689Skan	.commit_pass1		= xlog_recover_quotaoff_commit_pass1,
215169689Skan	/* nothing to commit in pass2 */
216169689Skan};
217169689Skan