xref: /openbmc/linux/fs/xfs/scrub/quota.c (revision 752beb5e)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2017 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <darrick.wong@oracle.com>
5  */
6 #include "xfs.h"
7 #include "xfs_fs.h"
8 #include "xfs_shared.h"
9 #include "xfs_format.h"
10 #include "xfs_trans_resv.h"
11 #include "xfs_mount.h"
12 #include "xfs_defer.h"
13 #include "xfs_btree.h"
14 #include "xfs_bit.h"
15 #include "xfs_log_format.h"
16 #include "xfs_trans.h"
17 #include "xfs_sb.h"
18 #include "xfs_inode.h"
19 #include "xfs_inode_fork.h"
20 #include "xfs_alloc.h"
21 #include "xfs_bmap.h"
22 #include "xfs_quota.h"
23 #include "xfs_qm.h"
24 #include "xfs_dquot.h"
25 #include "xfs_dquot_item.h"
26 #include "scrub/xfs_scrub.h"
27 #include "scrub/scrub.h"
28 #include "scrub/common.h"
29 #include "scrub/trace.h"
30 
31 /* Convert a scrub type code to a DQ flag, or return 0 if error. */
32 static inline uint
33 xchk_quota_to_dqtype(
34 	struct xfs_scrub	*sc)
35 {
36 	switch (sc->sm->sm_type) {
37 	case XFS_SCRUB_TYPE_UQUOTA:
38 		return XFS_DQ_USER;
39 	case XFS_SCRUB_TYPE_GQUOTA:
40 		return XFS_DQ_GROUP;
41 	case XFS_SCRUB_TYPE_PQUOTA:
42 		return XFS_DQ_PROJ;
43 	default:
44 		return 0;
45 	}
46 }
47 
48 /* Set us up to scrub a quota. */
49 int
50 xchk_setup_quota(
51 	struct xfs_scrub	*sc,
52 	struct xfs_inode	*ip)
53 {
54 	uint			dqtype;
55 	int			error;
56 
57 	if (!XFS_IS_QUOTA_RUNNING(sc->mp) || !XFS_IS_QUOTA_ON(sc->mp))
58 		return -ENOENT;
59 
60 	dqtype = xchk_quota_to_dqtype(sc);
61 	if (dqtype == 0)
62 		return -EINVAL;
63 	sc->flags |= XCHK_HAS_QUOTAOFFLOCK;
64 	mutex_lock(&sc->mp->m_quotainfo->qi_quotaofflock);
65 	if (!xfs_this_quota_on(sc->mp, dqtype))
66 		return -ENOENT;
67 	error = xchk_setup_fs(sc, ip);
68 	if (error)
69 		return error;
70 	sc->ip = xfs_quota_inode(sc->mp, dqtype);
71 	xfs_ilock(sc->ip, XFS_ILOCK_EXCL);
72 	sc->ilock_flags = XFS_ILOCK_EXCL;
73 	return 0;
74 }
75 
76 /* Quotas. */
77 
78 struct xchk_quota_info {
79 	struct xfs_scrub	*sc;
80 	xfs_dqid_t		last_id;
81 };
82 
83 /* Scrub the fields in an individual quota item. */
84 STATIC int
85 xchk_quota_item(
86 	struct xfs_dquot	*dq,
87 	uint			dqtype,
88 	void			*priv)
89 {
90 	struct xchk_quota_info	*sqi = priv;
91 	struct xfs_scrub	*sc = sqi->sc;
92 	struct xfs_mount	*mp = sc->mp;
93 	struct xfs_disk_dquot	*d = &dq->q_core;
94 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
95 	xfs_fileoff_t		offset;
96 	unsigned long long	bsoft;
97 	unsigned long long	isoft;
98 	unsigned long long	rsoft;
99 	unsigned long long	bhard;
100 	unsigned long long	ihard;
101 	unsigned long long	rhard;
102 	unsigned long long	bcount;
103 	unsigned long long	icount;
104 	unsigned long long	rcount;
105 	xfs_ino_t		fs_icount;
106 	xfs_dqid_t		id = be32_to_cpu(d->d_id);
107 
108 	/*
109 	 * Except for the root dquot, the actual dquot we got must either have
110 	 * the same or higher id as we saw before.
111 	 */
112 	offset = id / qi->qi_dqperchunk;
113 	if (id && id <= sqi->last_id)
114 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
115 
116 	sqi->last_id = id;
117 
118 	/* Did we get the dquot type we wanted? */
119 	if (dqtype != (d->d_flags & XFS_DQ_ALLTYPES))
120 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
121 
122 	if (d->d_pad0 != cpu_to_be32(0) || d->d_pad != cpu_to_be16(0))
123 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
124 
125 	/* Check the limits. */
126 	bhard = be64_to_cpu(d->d_blk_hardlimit);
127 	ihard = be64_to_cpu(d->d_ino_hardlimit);
128 	rhard = be64_to_cpu(d->d_rtb_hardlimit);
129 
130 	bsoft = be64_to_cpu(d->d_blk_softlimit);
131 	isoft = be64_to_cpu(d->d_ino_softlimit);
132 	rsoft = be64_to_cpu(d->d_rtb_softlimit);
133 
134 	/*
135 	 * Warn if the hard limits are larger than the fs.
136 	 * Administrators can do this, though in production this seems
137 	 * suspect, which is why we flag it for review.
138 	 *
139 	 * Complain about corruption if the soft limit is greater than
140 	 * the hard limit.
141 	 */
142 	if (bhard > mp->m_sb.sb_dblocks)
143 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
144 	if (bsoft > bhard)
145 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
146 
147 	if (ihard > mp->m_maxicount)
148 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
149 	if (isoft > ihard)
150 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
151 
152 	if (rhard > mp->m_sb.sb_rblocks)
153 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
154 	if (rsoft > rhard)
155 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
156 
157 	/* Check the resource counts. */
158 	bcount = be64_to_cpu(d->d_bcount);
159 	icount = be64_to_cpu(d->d_icount);
160 	rcount = be64_to_cpu(d->d_rtbcount);
161 	fs_icount = percpu_counter_sum(&mp->m_icount);
162 
163 	/*
164 	 * Check that usage doesn't exceed physical limits.  However, on
165 	 * a reflink filesystem we're allowed to exceed physical space
166 	 * if there are no quota limits.
167 	 */
168 	if (xfs_sb_version_hasreflink(&mp->m_sb)) {
169 		if (mp->m_sb.sb_dblocks < bcount)
170 			xchk_fblock_set_warning(sc, XFS_DATA_FORK,
171 					offset);
172 	} else {
173 		if (mp->m_sb.sb_dblocks < bcount)
174 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
175 					offset);
176 	}
177 	if (icount > fs_icount || rcount > mp->m_sb.sb_rblocks)
178 		xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
179 
180 	/*
181 	 * We can violate the hard limits if the admin suddenly sets a
182 	 * lower limit than the actual usage.  However, we flag it for
183 	 * admin review.
184 	 */
185 	if (id != 0 && bhard != 0 && bcount > bhard)
186 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
187 	if (id != 0 && ihard != 0 && icount > ihard)
188 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
189 	if (id != 0 && rhard != 0 && rcount > rhard)
190 		xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
191 
192 	return 0;
193 }
194 
195 /* Check the quota's data fork. */
196 STATIC int
197 xchk_quota_data_fork(
198 	struct xfs_scrub	*sc)
199 {
200 	struct xfs_bmbt_irec	irec = { 0 };
201 	struct xfs_iext_cursor	icur;
202 	struct xfs_quotainfo	*qi = sc->mp->m_quotainfo;
203 	struct xfs_ifork	*ifp;
204 	xfs_fileoff_t		max_dqid_off;
205 	int			error = 0;
206 
207 	/* Invoke the fork scrubber. */
208 	error = xchk_metadata_inode_forks(sc);
209 	if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
210 		return error;
211 
212 	/* Check for data fork problems that apply only to quota files. */
213 	max_dqid_off = ((xfs_dqid_t)-1) / qi->qi_dqperchunk;
214 	ifp = XFS_IFORK_PTR(sc->ip, XFS_DATA_FORK);
215 	for_each_xfs_iext(ifp, &icur, &irec) {
216 		if (xchk_should_terminate(sc, &error))
217 			break;
218 		/*
219 		 * delalloc extents or blocks mapped above the highest
220 		 * quota id shouldn't happen.
221 		 */
222 		if (isnullstartblock(irec.br_startblock) ||
223 		    irec.br_startoff > max_dqid_off ||
224 		    irec.br_startoff + irec.br_blockcount - 1 > max_dqid_off) {
225 			xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
226 					irec.br_startoff);
227 			break;
228 		}
229 	}
230 
231 	return error;
232 }
233 
234 /* Scrub all of a quota type's items. */
235 int
236 xchk_quota(
237 	struct xfs_scrub	*sc)
238 {
239 	struct xchk_quota_info	sqi;
240 	struct xfs_mount	*mp = sc->mp;
241 	struct xfs_quotainfo	*qi = mp->m_quotainfo;
242 	uint			dqtype;
243 	int			error = 0;
244 
245 	dqtype = xchk_quota_to_dqtype(sc);
246 
247 	/* Look for problem extents. */
248 	error = xchk_quota_data_fork(sc);
249 	if (error)
250 		goto out;
251 	if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
252 		goto out;
253 
254 	/*
255 	 * Check all the quota items.  Now that we've checked the quota inode
256 	 * data fork we have to drop ILOCK_EXCL to use the regular dquot
257 	 * functions.
258 	 */
259 	xfs_iunlock(sc->ip, sc->ilock_flags);
260 	sc->ilock_flags = 0;
261 	sqi.sc = sc;
262 	sqi.last_id = 0;
263 	error = xfs_qm_dqiterate(mp, dqtype, xchk_quota_item, &sqi);
264 	sc->ilock_flags = XFS_ILOCK_EXCL;
265 	xfs_ilock(sc->ip, sc->ilock_flags);
266 	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK,
267 			sqi.last_id * qi->qi_dqperchunk, &error))
268 		goto out;
269 
270 out:
271 	return error;
272 }
273