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