1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2017 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
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"
17 #include "scrub/scrub.h"
18 #include "scrub/common.h"
20 /* Convert a scrub type code to a DQ flag, or return 0 if error. */
21 static inline xfs_dqtype_t
25 switch (sc
->sm
->sm_type
) {
26 case XFS_SCRUB_TYPE_UQUOTA
:
27 return XFS_DQTYPE_USER
;
28 case XFS_SCRUB_TYPE_GQUOTA
:
29 return XFS_DQTYPE_GROUP
;
30 case XFS_SCRUB_TYPE_PQUOTA
:
31 return XFS_DQTYPE_PROJ
;
37 /* Set us up to scrub a quota. */
46 if (!XFS_IS_QUOTA_RUNNING(sc
->mp
) || !XFS_IS_QUOTA_ON(sc
->mp
))
49 dqtype
= xchk_quota_to_dqtype(sc
);
52 sc
->flags
|= XCHK_HAS_QUOTAOFFLOCK
;
53 mutex_lock(&sc
->mp
->m_quotainfo
->qi_quotaofflock
);
54 if (!xfs_this_quota_on(sc
->mp
, dqtype
))
56 error
= xchk_setup_fs(sc
, ip
);
59 sc
->ip
= xfs_quota_inode(sc
->mp
, dqtype
);
60 xfs_ilock(sc
->ip
, XFS_ILOCK_EXCL
);
61 sc
->ilock_flags
= XFS_ILOCK_EXCL
;
67 struct xchk_quota_info
{
72 /* Scrub the fields in an individual quota item. */
79 struct xchk_quota_info
*sqi
= priv
;
80 struct xfs_scrub
*sc
= sqi
->sc
;
81 struct xfs_mount
*mp
= sc
->mp
;
82 struct xfs_quotainfo
*qi
= mp
->m_quotainfo
;
87 if (xchk_should_terminate(sc
, &error
))
91 * Except for the root dquot, the actual dquot we got must either have
92 * the same or higher id as we saw before.
94 offset
= dq
->q_id
/ qi
->qi_dqperchunk
;
95 if (dq
->q_id
&& dq
->q_id
<= sqi
->last_id
)
96 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
98 sqi
->last_id
= dq
->q_id
;
101 * Warn if the hard limits are larger than the fs.
102 * Administrators can do this, though in production this seems
103 * suspect, which is why we flag it for review.
105 * Complain about corruption if the soft limit is greater than
108 if (dq
->q_blk
.hardlimit
> mp
->m_sb
.sb_dblocks
)
109 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
110 if (dq
->q_blk
.softlimit
> dq
->q_blk
.hardlimit
)
111 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
113 if (dq
->q_ino
.hardlimit
> M_IGEO(mp
)->maxicount
)
114 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
115 if (dq
->q_ino
.softlimit
> dq
->q_ino
.hardlimit
)
116 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
118 if (dq
->q_rtb
.hardlimit
> mp
->m_sb
.sb_rblocks
)
119 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
120 if (dq
->q_rtb
.softlimit
> dq
->q_rtb
.hardlimit
)
121 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
123 /* Check the resource counts. */
124 fs_icount
= percpu_counter_sum(&mp
->m_icount
);
127 * Check that usage doesn't exceed physical limits. However, on
128 * a reflink filesystem we're allowed to exceed physical space
129 * if there are no quota limits.
131 if (xfs_sb_version_hasreflink(&mp
->m_sb
)) {
132 if (mp
->m_sb
.sb_dblocks
< dq
->q_blk
.count
)
133 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
,
136 if (mp
->m_sb
.sb_dblocks
< dq
->q_blk
.count
)
137 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
,
140 if (dq
->q_ino
.count
> fs_icount
|| dq
->q_rtb
.count
> mp
->m_sb
.sb_rblocks
)
141 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
144 * We can violate the hard limits if the admin suddenly sets a
145 * lower limit than the actual usage. However, we flag it for
151 if (dq
->q_blk
.hardlimit
!= 0 &&
152 dq
->q_blk
.count
> dq
->q_blk
.hardlimit
)
153 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
155 if (dq
->q_ino
.hardlimit
!= 0 &&
156 dq
->q_ino
.count
> dq
->q_ino
.hardlimit
)
157 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
159 if (dq
->q_rtb
.hardlimit
!= 0 &&
160 dq
->q_rtb
.count
> dq
->q_rtb
.hardlimit
)
161 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
164 if (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
)
165 return -EFSCORRUPTED
;
170 /* Check the quota's data fork. */
172 xchk_quota_data_fork(
173 struct xfs_scrub
*sc
)
175 struct xfs_bmbt_irec irec
= { 0 };
176 struct xfs_iext_cursor icur
;
177 struct xfs_quotainfo
*qi
= sc
->mp
->m_quotainfo
;
178 struct xfs_ifork
*ifp
;
179 xfs_fileoff_t max_dqid_off
;
182 /* Invoke the fork scrubber. */
183 error
= xchk_metadata_inode_forks(sc
);
184 if (error
|| (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
))
187 /* Check for data fork problems that apply only to quota files. */
188 max_dqid_off
= ((xfs_dqid_t
)-1) / qi
->qi_dqperchunk
;
189 ifp
= XFS_IFORK_PTR(sc
->ip
, XFS_DATA_FORK
);
190 for_each_xfs_iext(ifp
, &icur
, &irec
) {
191 if (xchk_should_terminate(sc
, &error
))
194 * delalloc extents or blocks mapped above the highest
195 * quota id shouldn't happen.
197 if (isnullstartblock(irec
.br_startblock
) ||
198 irec
.br_startoff
> max_dqid_off
||
199 irec
.br_startoff
+ irec
.br_blockcount
- 1 > max_dqid_off
) {
200 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
,
209 /* Scrub all of a quota type's items. */
212 struct xfs_scrub
*sc
)
214 struct xchk_quota_info sqi
;
215 struct xfs_mount
*mp
= sc
->mp
;
216 struct xfs_quotainfo
*qi
= mp
->m_quotainfo
;
220 dqtype
= xchk_quota_to_dqtype(sc
);
222 /* Look for problem extents. */
223 error
= xchk_quota_data_fork(sc
);
226 if (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
)
230 * Check all the quota items. Now that we've checked the quota inode
231 * data fork we have to drop ILOCK_EXCL to use the regular dquot
234 xfs_iunlock(sc
->ip
, sc
->ilock_flags
);
238 error
= xfs_qm_dqiterate(mp
, dqtype
, xchk_quota_item
, &sqi
);
239 sc
->ilock_flags
= XFS_ILOCK_EXCL
;
240 xfs_ilock(sc
->ip
, sc
->ilock_flags
);
241 if (!xchk_fblock_process_error(sc
, XFS_DATA_FORK
,
242 sqi
.last_id
* qi
->qi_dqperchunk
, &error
))