1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2017-2023 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <djwong@kernel.org>
8 #include "xfs_shared.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"
19 #include "scrub/scrub.h"
20 #include "scrub/common.h"
21 #include "scrub/quota.h"
23 /* Convert a scrub type code to a DQ flag, or return 0 if error. */
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
;
40 /* Set us up to scrub a quota. */
48 if (!XFS_IS_QUOTA_ON(sc
->mp
))
51 dqtype
= xchk_quota_to_dqtype(sc
);
55 if (!xfs_this_quota_on(sc
->mp
, dqtype
))
58 if (xchk_need_intent_drain(sc
))
59 xchk_fsgates_enable(sc
, XCHK_FSGATES_DRAIN
);
61 error
= xchk_setup_fs(sc
);
65 error
= xchk_install_live_inode(sc
, xfs_quota_inode(sc
->mp
, dqtype
));
69 xchk_ilock(sc
, XFS_ILOCK_EXCL
);
75 struct xchk_quota_info
{
80 /* There's a written block backing this dquot, right? */
87 struct xfs_bmbt_irec irec
;
88 struct xfs_mount
*mp
= sc
->mp
;
92 if (!xfs_verify_fileoff(mp
, offset
)) {
93 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
97 if (dq
->q_fileoffset
!= offset
) {
98 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
102 error
= xfs_bmapi_read(sc
->ip
, offset
, 1, &irec
, &nmaps
, 0);
107 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
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
);
121 /* Complain if a quota timer is incorrectly set. */
123 xchk_quota_item_timer(
124 struct xfs_scrub
*sc
,
125 xfs_fileoff_t offset
,
126 const struct xfs_dquot_res
*res
)
128 if ((res
->softlimit
&& res
->count
> res
->softlimit
) ||
129 (res
->hardlimit
&& res
->count
> res
->hardlimit
)) {
131 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
134 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
138 /* Scrub the fields in an individual quota item. */
141 struct xchk_quota_info
*sqi
,
142 struct xfs_dquot
*dq
)
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
;
151 if (xchk_should_terminate(sc
, &error
))
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
162 xchk_ilock(sc
, XFS_ILOCK_SHARED
);
166 * Except for the root dquot, the actual dquot we got must either have
167 * the same or higher id as we saw before.
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
);
173 sqi
->last_id
= dq
->q_id
;
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
))
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.
185 * Complain about corruption if the soft limit is greater than
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
);
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
);
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
);
203 /* Check the resource counts. */
204 fs_icount
= percpu_counter_sum(&mp
->m_icount
);
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.
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
,
216 if (mp
->m_sb
.sb_dblocks
< dq
->q_blk
.count
)
217 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
,
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
);
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
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
);
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
);
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
);
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
);
248 if (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
)
254 /* Check the quota's data fork. */
256 xchk_quota_data_fork(
257 struct xfs_scrub
*sc
)
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
;
266 /* Invoke the fork scrubber. */
267 error
= xchk_metadata_inode_forks(sc
);
268 if (error
|| (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
))
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
))
279 * delalloc/unwritten extents or blocks mapped above the highest
280 * quota id shouldn't happen.
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
,
294 /* Scrub all of a quota type's items. */
297 struct xfs_scrub
*sc
)
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
;
307 dqtype
= xchk_quota_to_dqtype(sc
);
309 /* Look for problem extents. */
310 error
= xchk_quota_data_fork(sc
);
313 if (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
)
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
321 xchk_iunlock(sc
, sc
->ilock_flags
);
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
);
331 if (error
== -ECANCELED
)
333 if (!xchk_fblock_process_error(sc
, XFS_DATA_FORK
,
334 sqi
.last_id
* qi
->qi_dqperchunk
, &error
))