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 
23 STATIC void
24 xlog_recover_dquot_ra_pass2(
25 	struct xlog			*log,
26 	struct xlog_recover_item	*item)
27 {
28 	struct xfs_mount	*mp = log->l_mp;
29 	struct xfs_disk_dquot	*recddq;
30 	struct xfs_dq_logformat	*dq_f;
31 	uint			type;
32 
33 	if (mp->m_qflags == 0)
34 		return;
35 
36 	recddq = item->ri_buf[1].i_addr;
37 	if (recddq == NULL)
38 		return;
39 	if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot))
40 		return;
41 
42 	type = recddq->d_flags & (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP);
43 	ASSERT(type);
44 	if (log->l_quotaoffs_flag & type)
45 		return;
46 
47 	dq_f = item->ri_buf[0].i_addr;
48 	ASSERT(dq_f);
49 	ASSERT(dq_f->qlf_len == 1);
50 
51 	xlog_buf_readahead(log, dq_f->qlf_blkno,
52 			XFS_FSB_TO_BB(mp, dq_f->qlf_len),
53 			&xfs_dquot_buf_ra_ops);
54 }
55 
56 /*
57  * Recover a dquot record
58  */
59 STATIC int
60 xlog_recover_dquot_commit_pass2(
61 	struct xlog			*log,
62 	struct list_head		*buffer_list,
63 	struct xlog_recover_item	*item,
64 	xfs_lsn_t			current_lsn)
65 {
66 	struct xfs_mount		*mp = log->l_mp;
67 	struct xfs_buf			*bp;
68 	struct xfs_disk_dquot		*ddq, *recddq;
69 	struct xfs_dq_logformat		*dq_f;
70 	xfs_failaddr_t			fa;
71 	int				error;
72 	uint				type;
73 
74 	/*
75 	 * Filesystems are required to send in quota flags at mount time.
76 	 */
77 	if (mp->m_qflags == 0)
78 		return 0;
79 
80 	recddq = item->ri_buf[1].i_addr;
81 	if (recddq == NULL) {
82 		xfs_alert(log->l_mp, "NULL dquot in %s.", __func__);
83 		return -EFSCORRUPTED;
84 	}
85 	if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) {
86 		xfs_alert(log->l_mp, "dquot too small (%d) in %s.",
87 			item->ri_buf[1].i_len, __func__);
88 		return -EFSCORRUPTED;
89 	}
90 
91 	/*
92 	 * This type of quotas was turned off, so ignore this record.
93 	 */
94 	type = recddq->d_flags & (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP);
95 	ASSERT(type);
96 	if (log->l_quotaoffs_flag & type)
97 		return 0;
98 
99 	/*
100 	 * At this point we know that quota was _not_ turned off.
101 	 * Since the mount flags are not indicating to us otherwise, this
102 	 * must mean that quota is on, and the dquot needs to be replayed.
103 	 * Remember that we may not have fully recovered the superblock yet,
104 	 * so we can't do the usual trick of looking at the SB quota bits.
105 	 *
106 	 * The other possibility, of course, is that the quota subsystem was
107 	 * removed since the last mount - ENOSYS.
108 	 */
109 	dq_f = item->ri_buf[0].i_addr;
110 	ASSERT(dq_f);
111 	fa = xfs_dquot_verify(mp, recddq, dq_f->qlf_id, 0);
112 	if (fa) {
113 		xfs_alert(mp, "corrupt dquot ID 0x%x in log at %pS",
114 				dq_f->qlf_id, fa);
115 		return -EFSCORRUPTED;
116 	}
117 	ASSERT(dq_f->qlf_len == 1);
118 
119 	/*
120 	 * At this point we are assuming that the dquots have been allocated
121 	 * and hence the buffer has valid dquots stamped in it. It should,
122 	 * therefore, pass verifier validation. If the dquot is bad, then the
123 	 * we'll return an error here, so we don't need to specifically check
124 	 * the dquot in the buffer after the verifier has run.
125 	 */
126 	error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno,
127 				   XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp,
128 				   &xfs_dquot_buf_ops);
129 	if (error)
130 		return error;
131 
132 	ASSERT(bp);
133 	ddq = xfs_buf_offset(bp, dq_f->qlf_boffset);
134 
135 	/*
136 	 * If the dquot has an LSN in it, recover the dquot only if it's less
137 	 * than the lsn of the transaction we are replaying.
138 	 */
139 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
140 		struct xfs_dqblk *dqb = (struct xfs_dqblk *)ddq;
141 		xfs_lsn_t	lsn = be64_to_cpu(dqb->dd_lsn);
142 
143 		if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
144 			goto out_release;
145 		}
146 	}
147 
148 	memcpy(ddq, recddq, item->ri_buf[1].i_len);
149 	if (xfs_sb_version_hascrc(&mp->m_sb)) {
150 		xfs_update_cksum((char *)ddq, sizeof(struct xfs_dqblk),
151 				 XFS_DQUOT_CRC_OFF);
152 	}
153 
154 	ASSERT(dq_f->qlf_size == 2);
155 	ASSERT(bp->b_mount == mp);
156 	bp->b_iodone = xlog_recover_iodone;
157 	xfs_buf_delwri_queue(bp, buffer_list);
158 
159 out_release:
160 	xfs_buf_relse(bp);
161 	return 0;
162 }
163 
164 const struct xlog_recover_item_ops xlog_dquot_item_ops = {
165 	.item_type		= XFS_LI_DQUOT,
166 	.ra_pass2		= xlog_recover_dquot_ra_pass2,
167 	.commit_pass2		= xlog_recover_dquot_commit_pass2,
168 };
169 
170 /*
171  * Recover QUOTAOFF records. We simply make a note of it in the xlog
172  * structure, so that we know not to do any dquot item or dquot buffer recovery,
173  * of that type.
174  */
175 STATIC int
176 xlog_recover_quotaoff_commit_pass1(
177 	struct xlog			*log,
178 	struct xlog_recover_item	*item)
179 {
180 	struct xfs_qoff_logformat	*qoff_f = item->ri_buf[0].i_addr;
181 	ASSERT(qoff_f);
182 
183 	/*
184 	 * The logitem format's flag tells us if this was user quotaoff,
185 	 * group/project quotaoff or both.
186 	 */
187 	if (qoff_f->qf_flags & XFS_UQUOTA_ACCT)
188 		log->l_quotaoffs_flag |= XFS_DQ_USER;
189 	if (qoff_f->qf_flags & XFS_PQUOTA_ACCT)
190 		log->l_quotaoffs_flag |= XFS_DQ_PROJ;
191 	if (qoff_f->qf_flags & XFS_GQUOTA_ACCT)
192 		log->l_quotaoffs_flag |= XFS_DQ_GROUP;
193 
194 	return 0;
195 }
196 
197 const struct xlog_recover_item_ops xlog_quotaoff_item_ops = {
198 	.item_type		= XFS_LI_QUOTAOFF,
199 	.commit_pass1		= xlog_recover_quotaoff_commit_pass1,
200 	/* nothing to commit in pass2 */
201 };
202