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_defer.h"
13 #include "xfs_btree.h"
15 #include "xfs_log_format.h"
16 #include "xfs_trans.h"
18 #include "xfs_inode.h"
19 #include "xfs_inode_fork.h"
20 #include "xfs_alloc.h"
22 #include "xfs_quota.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"
31 /* Convert a scrub type code to a DQ flag, or return 0 if error. */
36 switch (sc
->sm
->sm_type
) {
37 case XFS_SCRUB_TYPE_UQUOTA
:
39 case XFS_SCRUB_TYPE_GQUOTA
:
41 case XFS_SCRUB_TYPE_PQUOTA
:
48 /* Set us up to scrub a quota. */
57 if (!XFS_IS_QUOTA_RUNNING(sc
->mp
) || !XFS_IS_QUOTA_ON(sc
->mp
))
60 dqtype
= xchk_quota_to_dqtype(sc
);
63 sc
->flags
|= XCHK_HAS_QUOTAOFFLOCK
;
64 mutex_lock(&sc
->mp
->m_quotainfo
->qi_quotaofflock
);
65 if (!xfs_this_quota_on(sc
->mp
, dqtype
))
67 error
= xchk_setup_fs(sc
, ip
);
70 sc
->ip
= xfs_quota_inode(sc
->mp
, dqtype
);
71 xfs_ilock(sc
->ip
, XFS_ILOCK_EXCL
);
72 sc
->ilock_flags
= XFS_ILOCK_EXCL
;
78 struct xchk_quota_info
{
83 /* Scrub the fields in an individual quota item. */
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
;
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
;
106 xfs_dqid_t id
= be32_to_cpu(d
->d_id
);
109 * Except for the root dquot, the actual dquot we got must either have
110 * the same or higher id as we saw before.
112 offset
= id
/ qi
->qi_dqperchunk
;
113 if (id
&& id
<= sqi
->last_id
)
114 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
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
);
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
);
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
);
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
);
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.
139 * Complain about corruption if the soft limit is greater than
142 if (bhard
> mp
->m_sb
.sb_dblocks
)
143 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
145 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
147 if (ihard
> mp
->m_maxicount
)
148 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
150 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
152 if (rhard
> mp
->m_sb
.sb_rblocks
)
153 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
155 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
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
);
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.
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
,
173 if (mp
->m_sb
.sb_dblocks
< bcount
)
174 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
,
177 if (icount
> fs_icount
|| rcount
> mp
->m_sb
.sb_rblocks
)
178 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
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
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
);
195 /* Check the quota's data fork. */
197 xchk_quota_data_fork(
198 struct xfs_scrub
*sc
)
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
;
207 /* Invoke the fork scrubber. */
208 error
= xchk_metadata_inode_forks(sc
);
209 if (error
|| (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
))
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
))
219 * delalloc extents or blocks mapped above the highest
220 * quota id shouldn't happen.
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
,
234 /* Scrub all of a quota type's items. */
237 struct xfs_scrub
*sc
)
239 struct xchk_quota_info sqi
;
240 struct xfs_mount
*mp
= sc
->mp
;
241 struct xfs_quotainfo
*qi
= mp
->m_quotainfo
;
245 dqtype
= xchk_quota_to_dqtype(sc
);
247 /* Look for problem extents. */
248 error
= xchk_quota_data_fork(sc
);
251 if (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
)
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
259 xfs_iunlock(sc
->ip
, sc
->ilock_flags
);
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
))