Line data Source code
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_format.h"
10 : #include "xfs_trans_resv.h"
11 : #include "xfs_mount.h"
12 : #include "xfs_log_format.h"
13 : #include "xfs_trans.h"
14 : #include "xfs_inode.h"
15 : #include "xfs_quota.h"
16 : #include "xfs_qm.h"
17 : #include "xfs_bmap.h"
18 : #include "scrub/scrub.h"
19 : #include "scrub/common.h"
20 : #include "scrub/quota.h"
21 :
22 : /* Convert a scrub type code to a DQ flag, or return 0 if error. */
23 : xfs_dqtype_t
24 2331 : xchk_quota_to_dqtype(
25 : struct xfs_scrub *sc)
26 : {
27 2331 : switch (sc->sm->sm_type) {
28 : case XFS_SCRUB_TYPE_UQUOTA:
29 : return XFS_DQTYPE_USER;
30 : case XFS_SCRUB_TYPE_GQUOTA:
31 : return XFS_DQTYPE_GROUP;
32 : case XFS_SCRUB_TYPE_PQUOTA:
33 : return XFS_DQTYPE_PROJ;
34 : default:
35 : return 0;
36 : }
37 : }
38 :
39 : /* Set us up to scrub a quota. */
40 : int
41 60915 : xchk_setup_quota(
42 : struct xfs_scrub *sc)
43 : {
44 60915 : xfs_dqtype_t dqtype;
45 60915 : int error;
46 :
47 60915 : if (!XFS_IS_QUOTA_ON(sc->mp))
48 : return -ENOENT;
49 :
50 55261 : dqtype = xchk_quota_to_dqtype(sc);
51 55263 : if (dqtype == 0)
52 : return -EINVAL;
53 :
54 55263 : if (!xfs_this_quota_on(sc->mp, dqtype))
55 : return -ENOENT;
56 :
57 55185 : if (xchk_need_intent_drain(sc))
58 0 : xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
59 :
60 55185 : error = xchk_setup_fs(sc);
61 55184 : if (error)
62 : return error;
63 :
64 55184 : error = xchk_install_live_inode(sc, xfs_quota_inode(sc->mp, dqtype));
65 55183 : if (error)
66 : return error;
67 :
68 55183 : xchk_ilock(sc, XFS_ILOCK_EXCL);
69 55183 : return 0;
70 : }
71 :
72 : /* Quotas. */
73 :
74 : struct xchk_quota_info {
75 : struct xfs_scrub *sc;
76 : xfs_dqid_t last_id;
77 : };
78 :
79 : /* Scrub the fields in an individual quota item. */
80 : STATIC int
81 55186 : xchk_quota_item(
82 : struct xfs_dquot *dq,
83 : xfs_dqtype_t dqtype,
84 : void *priv)
85 : {
86 55186 : struct xchk_quota_info *sqi = priv;
87 55186 : struct xfs_scrub *sc = sqi->sc;
88 55186 : struct xfs_mount *mp = sc->mp;
89 55186 : struct xfs_quotainfo *qi = mp->m_quotainfo;
90 55186 : xfs_fileoff_t offset;
91 55186 : xfs_ino_t fs_icount;
92 55186 : int error = 0;
93 :
94 55186 : if (xchk_should_terminate(sc, &error))
95 0 : return error;
96 :
97 : /*
98 : * Except for the root dquot, the actual dquot we got must either have
99 : * the same or higher id as we saw before.
100 : */
101 55186 : offset = dq->q_id / qi->qi_dqperchunk;
102 55186 : if (dq->q_id && dq->q_id <= sqi->last_id)
103 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
104 :
105 55186 : sqi->last_id = dq->q_id;
106 :
107 : /*
108 : * Warn if the hard limits are larger than the fs.
109 : * Administrators can do this, though in production this seems
110 : * suspect, which is why we flag it for review.
111 : *
112 : * Complain about corruption if the soft limit is greater than
113 : * the hard limit.
114 : */
115 55186 : if (dq->q_blk.hardlimit > mp->m_sb.sb_dblocks)
116 0 : xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
117 55186 : if (dq->q_blk.softlimit > dq->q_blk.hardlimit)
118 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
119 :
120 55186 : if (dq->q_ino.hardlimit > M_IGEO(mp)->maxicount)
121 0 : xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
122 55186 : if (dq->q_ino.softlimit > dq->q_ino.hardlimit)
123 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
124 :
125 55186 : if (dq->q_rtb.hardlimit > mp->m_sb.sb_rblocks)
126 0 : xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
127 55186 : if (dq->q_rtb.softlimit > dq->q_rtb.hardlimit)
128 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
129 :
130 : /* Check the resource counts. */
131 55186 : fs_icount = percpu_counter_sum(&mp->m_icount);
132 :
133 : /*
134 : * Check that usage doesn't exceed physical limits. However, on
135 : * a reflink filesystem we're allowed to exceed physical space
136 : * if there are no quota limits.
137 : */
138 55186 : if (xfs_has_reflink(mp)) {
139 55168 : if (mp->m_sb.sb_dblocks < dq->q_blk.count)
140 24 : xchk_fblock_set_warning(sc, XFS_DATA_FORK,
141 : offset);
142 : } else {
143 18 : if (mp->m_sb.sb_dblocks < dq->q_blk.count)
144 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
145 : offset);
146 : }
147 55186 : if (dq->q_ino.count > fs_icount || dq->q_rtb.count > mp->m_sb.sb_rblocks)
148 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
149 :
150 : /*
151 : * We can violate the hard limits if the admin suddenly sets a
152 : * lower limit than the actual usage. However, we flag it for
153 : * admin review.
154 : */
155 55186 : if (dq->q_id == 0)
156 55186 : goto out;
157 :
158 0 : if (dq->q_blk.hardlimit != 0 &&
159 0 : dq->q_blk.count > dq->q_blk.hardlimit)
160 0 : xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
161 :
162 0 : if (dq->q_ino.hardlimit != 0 &&
163 0 : dq->q_ino.count > dq->q_ino.hardlimit)
164 0 : xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
165 :
166 0 : if (dq->q_rtb.hardlimit != 0 &&
167 0 : dq->q_rtb.count > dq->q_rtb.hardlimit)
168 0 : xchk_fblock_set_warning(sc, XFS_DATA_FORK, offset);
169 :
170 0 : out:
171 55186 : if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
172 0 : return -ECANCELED;
173 :
174 : return 0;
175 : }
176 :
177 : /* Check the quota's data fork. */
178 : STATIC int
179 55182 : xchk_quota_data_fork(
180 : struct xfs_scrub *sc)
181 : {
182 55182 : struct xfs_bmbt_irec irec = { 0 };
183 55182 : struct xfs_iext_cursor icur;
184 55182 : struct xfs_quotainfo *qi = sc->mp->m_quotainfo;
185 55182 : struct xfs_ifork *ifp;
186 55182 : xfs_fileoff_t max_dqid_off;
187 55182 : int error = 0;
188 :
189 : /* Invoke the fork scrubber. */
190 55182 : error = xchk_metadata_inode_forks(sc);
191 55186 : if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
192 : return error;
193 :
194 : /* Check for data fork problems that apply only to quota files. */
195 55186 : max_dqid_off = ((xfs_dqid_t)-1) / qi->qi_dqperchunk;
196 55186 : ifp = xfs_ifork_ptr(sc->ip, XFS_DATA_FORK);
197 117683174 : for_each_xfs_iext(ifp, &icur, &irec) {
198 117632484 : if (xchk_should_terminate(sc, &error))
199 : break;
200 :
201 : /*
202 : * delalloc/unwritten extents or blocks mapped above the highest
203 : * quota id shouldn't happen.
204 : */
205 117627988 : if (!xfs_bmap_is_written_extent(&irec) ||
206 117627988 : irec.br_startoff > max_dqid_off ||
207 117627988 : irec.br_startoff + irec.br_blockcount - 1 > max_dqid_off) {
208 0 : xchk_fblock_set_corrupt(sc, XFS_DATA_FORK,
209 : irec.br_startoff);
210 0 : break;
211 : }
212 : }
213 :
214 55186 : return error;
215 : }
216 :
217 : /* Scrub all of a quota type's items. */
218 : int
219 55184 : xchk_quota(
220 : struct xfs_scrub *sc)
221 : {
222 55184 : struct xchk_quota_info sqi;
223 55184 : struct xfs_mount *mp = sc->mp;
224 55184 : struct xfs_quotainfo *qi = mp->m_quotainfo;
225 55184 : xfs_dqtype_t dqtype;
226 55184 : int error = 0;
227 :
228 55184 : dqtype = xchk_quota_to_dqtype(sc);
229 :
230 : /*
231 : * Look for problem extents. Leave the quota inode ILOCKd if we find
232 : * any.
233 : */
234 55184 : error = xchk_quota_data_fork(sc);
235 55186 : if (error)
236 0 : goto out;
237 55186 : if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
238 0 : goto out;
239 :
240 : /*
241 : * Check all the quota items. Now that we've checked the quota inode
242 : * data fork we have to drop ILOCK_EXCL to use the regular dquot
243 : * functions.
244 : */
245 55186 : xchk_iunlock(sc, sc->ilock_flags);
246 :
247 : /* Now look for things that the quota verifiers won't complain about. */
248 55186 : sqi.sc = sc;
249 55186 : sqi.last_id = 0;
250 55186 : error = xfs_qm_dqiterate(mp, dqtype, xchk_quota_item, &sqi);
251 55186 : if (error == -ECANCELED)
252 0 : error = 0;
253 55186 : if (!xchk_fblock_process_error(sc, XFS_DATA_FORK,
254 55186 : sqi.last_id * qi->qi_dqperchunk, &error))
255 : goto out;
256 :
257 55186 : out:
258 55186 : return error;
259 : }
|