Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  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 void
 25xlog_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 record
 59 */
 60STATIC int
 61xlog_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, this
104	 * 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 was
109	 * 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 allocated
123	 * and hence the buffer has valid dquots stamped in it. It should,
124	 * therefore, pass verifier validation. If the dquot is bad, then the
125	 * we'll return an error here, so we don't need to specifically check
126	 * 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 less
140	 * 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 xlog
187 * structure, so that we know not to do any dquot item or dquot buffer recovery,
188 * of that type.
189 */
190STATIC int
191xlog_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};