xref: /linux/fs/xfs/scrub/quota.c (revision 20dfee95936413708701eb151f419597fdd9d948)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2017-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 
23 /* Convert a scrub type code to a DQ flag, or return 0 if error. */
24 xfs_dqtype_t
25 xchk_quota_to_dqtype(
26 	struct xfs_scrub	*sc)
27 {
28 	switch (sc->sm->sm_type) {
29 	case XFS_SCRUB_TYPE_UQUOTA:
30 		return XFS_DQTYPE_USER;
31 	case XFS_SCRUB_TYPE_GQUOTA:
32 		return XFS_DQTYPE_GROUP;
33 	case XFS_SCRUB_TYPE_PQUOTA:
34 		return XFS_DQTYPE_PROJ;
35 	default:
36 		return 0;
37 	}
38 }
39 
40 /* Set us up to scrub a quota. */
41 int
42 xchk_setup_quota(
43 	struct xfs_scrub	*sc)
44 {
45 	xfs_dqtype_t		dqtype;
46 	int			error;
47 
48 	if (!XFS_IS_QUOTA_ON(sc->mp))
49 		return -ENOENT;
50 
51 	dqtype = xchk_quota_to_dqtype(sc);
52 	if (dqtype == 0)
53 		return -EINVAL;
54 
55 	if (!xfs_this_quota_on(sc->mp, dqtype))
56 		return -ENOENT;
57 
58 	if (xchk_need_intent_drain(sc))
59 		xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
60 
61 	error = xchk_setup_fs(sc);
62 	if (error)
63 		return error;
64 
65 	error = xchk_install_live_inode(sc, xfs_quota_inode(sc->mp, dqtype));
66 	if (error)
67 		return error;
68 
69 	xchk_ilock(sc, XFS_ILOCK_EXCL);
70 	return 0;
71 }
72 
73 /* Quotas. */
74 
75 struct xchk_quota_info {
76 	struct xfs_scrub	*sc;
77 	xfs_dqid_t		last_id;
78 };
79 
80 /* There's a written block backing this dquot, right? */
81 STATIC int
82 xchk_quota_item_bmap(
83 	struct xfs_scrub	*sc,
84 	struct xfs_dquot	*dq,
85 	xfs_fileoff_t		offset)
86 {
87 	struct xfs_bmbt_irec	irec;
88 	struct xfs_mount	*mp = sc->mp;
89 	int			nmaps = 1;
90 	int			error;
91 
92 	if (!xfs_verify_fileoff(mp, offset)) {
93 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
94 		return 0;
95 	}
96 
97 	if (dq->q_fileoffset != offset) {
98 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
99 		return 0;
100 	}
101 
102 	error = xfs_bmapi_read(sc->ip, offset, 1, &irec, &nmaps, 0);
103 	if (error)
104 		return error;
105 
106 	if (nmaps != 1) {
107 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
108 		return 0;
109 	}
110 
111 	if (!xfs_verify_fsbno(mp, irec.br_startblock))
112 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
113 	if (XFS_FSB_TO_DADDR(mp, irec.br_startblock) != dq->q_blkno)
114 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
115 	if (!xfs_bmap_is_written_extent(&irec))
116 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
117 
118 	return 0;
119 }
120 
121 /* Complain if a quota timer is incorrectly set. */
122 static inline void
123 xchk_quota_item_timer(
124 	struct xfs_scrub		*sc,
125 	xfs_fileoff_t			offset,
126 	const struct xfs_dquot_res	*res)
127 {
128 	if ((res->softlimit && res->count > res->softlimit) ||
129 	    (res->hardlimit && res->count > res->hardlimit)) {
130 		if (!res->timer)
131 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
132 	} else {
133 		if (res->timer)
134 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
135 	}
136 }
137 
138 /* Scrub the fields in an individual quota item. */
139 STATIC int
140 xchk_quota_item(
141 	struct xchk_quota_info	*sqi,
142 	struct xfs_dquot	*dq)
143 {
144 	struct xfs_scrub	*sc = sqi->sc;
145 	struct xfs_mount	*mp = sc->mp;
146 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
147 	xfs_fileoff_t		offset;
148 	xfs_ino_t		fs_icount;
149 	int			error = 0;
150 
151 	if (xchk_should_terminate(sc, &error))
152 		return error;
153 
154 	/*
155 	 * We want to validate the bmap record for the storage backing this
156 	 * dquot, so we need to lock the dquot and the quota file.  For quota
157 	 * operations, the locking order is first the ILOCK and then the dquot.
158 	 * However, dqiterate gave us a locked dquot, so drop the dquot lock to
159 	 * get the ILOCK.
160 	 */
161 	xfs_dqunlock(dq);
162 	xchk_ilock(sc, XFS_ILOCK_SHARED);
163 	xfs_dqlock(dq);
164 
165 	/*
166 	 * Except for the root dquot, the actual dquot we got must either have
167 	 * the same or higher id as we saw before.
168 	 */
169 	offset = dq->q_id / qi->qi_dqperchunk;
170 	if (dq->q_id && dq->q_id <= sqi->last_id)
171 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
172 
173 	sqi->last_id = dq->q_id;
174 
175 	error = xchk_quota_item_bmap(sc, dq, offset);
176 	xchk_iunlock(sc, XFS_ILOCK_SHARED);
177 	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, offset, &error))
178 		return error;
179 
180 	/*
181 	 * Warn if the hard limits are larger than the fs.
182 	 * Administrators can do this, though in production this seems
183 	 * suspect, which is why we flag it for review.
184 	 *
185 	 * Complain about corruption if the soft limit is greater than
186 	 * the hard limit.
187 	 */
188 	if (dq->q_blk.hardlimit > mp->m_sb.sb_dblocks)
189 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
190 	if (dq->q_blk.softlimit > dq->q_blk.hardlimit)
191 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
192 
193 	if (dq->q_ino.hardlimit > M_IGEO(mp)->maxicount)
194 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
195 	if (dq->q_ino.softlimit > dq->q_ino.hardlimit)
196 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
197 
198 	if (dq->q_rtb.hardlimit > mp->m_sb.sb_rblocks)
199 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
200 	if (dq->q_rtb.softlimit > dq->q_rtb.hardlimit)
201 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
202 
203 	/* Check the resource counts. */
204 	fs_icount = percpu_counter_sum(&mp->m_icount);
205 
206 	/*
207 	 * Check that usage doesn't exceed physical limits.  However, on
208 	 * a reflink filesystem we're allowed to exceed physical space
209 	 * if there are no quota limits.
210 	 */
211 	if (xfs_has_reflink(mp)) {
212 		if (mp->m_sb.sb_dblocks < dq->q_blk.count)
213 			xchk_fblock_set_warning(sc, XFS_DATA_FORK,
214 					offset);
215 	} else {
216 		if (mp->m_sb.sb_dblocks < dq->q_blk.count)
217 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
218 					offset);
219 	}
220 	if (dq->q_ino.count > fs_icount || dq->q_rtb.count > mp->m_sb.sb_rblocks)
221 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
222 
223 	/*
224 	 * We can violate the hard limits if the admin suddenly sets a
225 	 * lower limit than the actual usage.  However, we flag it for
226 	 * admin review.
227 	 */
228 	if (dq->q_id == 0)
229 		goto out;
230 
231 	if (dq->q_blk.hardlimit != 0 &&
232 	    dq->q_blk.count > dq->q_blk.hardlimit)
233 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
234 
235 	if (dq->q_ino.hardlimit != 0 &&
236 	    dq->q_ino.count > dq->q_ino.hardlimit)
237 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
238 
239 	if (dq->q_rtb.hardlimit != 0 &&
240 	    dq->q_rtb.count > dq->q_rtb.hardlimit)
241 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
242 
243 	xchk_quota_item_timer(sc, offset, &dq->q_blk);
244 	xchk_quota_item_timer(sc, offset, &dq->q_ino);
245 	xchk_quota_item_timer(sc, offset, &dq->q_rtb);
246 
247 out:
248 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
249 		return -ECANCELED;
250 
251 	return 0;
252 }
253 
254 /* Check the quota's data fork. */
255 STATIC int
256 xchk_quota_data_fork(
257 	struct xfs_scrub	*sc)
258 {
259 	struct xfs_bmbt_irec	irec = { 0 };
260 	struct xfs_iext_cursor	icur;
261 	struct xfs_quotainfo	*qi = sc->mp->m_quotainfo;
262 	struct xfs_ifork	*ifp;
263 	xfs_fileoff_t		max_dqid_off;
264 	int			error = 0;
265 
266 	/* Invoke the fork scrubber. */
267 	error = xchk_metadata_inode_forks(sc);
268 	if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
269 		return error;
270 
271 	/* Check for data fork problems that apply only to quota files. */
272 	max_dqid_off = XFS_DQ_ID_MAX / qi->qi_dqperchunk;
273 	ifp = xfs_ifork_ptr(sc->ip, XFS_DATA_FORK);
274 	for_each_xfs_iext(ifp, &icur, &irec) {
275 		if (xchk_should_terminate(sc, &error))
276 			break;
277 
278 		/*
279 		 * delalloc/unwritten extents or blocks mapped above the highest
280 		 * quota id shouldn't happen.
281 		 */
282 		if (!xfs_bmap_is_written_extent(&irec) ||
283 		    irec.br_startoff > max_dqid_off ||
284 		    irec.br_startoff + irec.br_blockcount - 1 > max_dqid_off) {
285 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
286 					irec.br_startoff);
287 			break;
288 		}
289 	}
290 
291 	return error;
292 }
293 
294 /* Scrub all of a quota type's items. */
295 int
296 xchk_quota(
297 	struct xfs_scrub	*sc)
298 {
299 	struct xchk_dqiter	cursor = { };
300 	struct xchk_quota_info	sqi = { .sc = sc };
301 	struct xfs_mount	*mp = sc->mp;
302 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
303 	struct xfs_dquot	*dq;
304 	xfs_dqtype_t		dqtype;
305 	int			error = 0;
306 
307 	dqtype = xchk_quota_to_dqtype(sc);
308 
309 	/* Look for problem extents. */
310 	error = xchk_quota_data_fork(sc);
311 	if (error)
312 		goto out;
313 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
314 		goto out;
315 
316 	/*
317 	 * Check all the quota items.  Now that we've checked the quota inode
318 	 * data fork we have to drop ILOCK_EXCL to use the regular dquot
319 	 * functions.
320 	 */
321 	xchk_iunlock(sc, sc->ilock_flags);
322 
323 	/* Now look for things that the quota verifiers won't complain about. */
324 	xchk_dqiter_init(&cursor, sc, dqtype);
325 	while ((error = xchk_dquot_iter(&cursor, &dq)) == 1) {
326 		error = xchk_quota_item(&sqi, dq);
327 		xfs_qm_dqput(dq);
328 		if (error)
329 			break;
330 	}
331 	if (error == -ECANCELED)
332 		error = 0;
333 	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK,
334 			sqi.last_id * qi->qi_dqperchunk, &error))
335 		goto out;
336 
337 out:
338 	return error;
339 }
340