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. */
25 switch (sc
->sm
->sm_type
) {
26 case XFS_SCRUB_TYPE_UQUOTA
:
28 case XFS_SCRUB_TYPE_GQUOTA
:
30 case XFS_SCRUB_TYPE_PQUOTA
:
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_disk_dquot
*d
= &dq
->q_core
;
83 struct xfs_quotainfo
*qi
= mp
->m_quotainfo
;
85 unsigned long long bsoft
;
86 unsigned long long isoft
;
87 unsigned long long rsoft
;
88 unsigned long long bhard
;
89 unsigned long long ihard
;
90 unsigned long long rhard
;
91 unsigned long long bcount
;
92 unsigned long long icount
;
93 unsigned long long rcount
;
95 xfs_dqid_t id
= be32_to_cpu(d
->d_id
);
98 if (xchk_should_terminate(sc
, &error
))
102 * Except for the root dquot, the actual dquot we got must either have
103 * the same or higher id as we saw before.
105 offset
= id
/ qi
->qi_dqperchunk
;
106 if (id
&& id
<= sqi
->last_id
)
107 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
111 /* Did we get the dquot type we wanted? */
112 if (dqtype
!= (d
->d_flags
& XFS_DQ_ALLTYPES
))
113 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
115 if (d
->d_pad0
!= cpu_to_be32(0) || d
->d_pad
!= cpu_to_be16(0))
116 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
118 /* Check the limits. */
119 bhard
= be64_to_cpu(d
->d_blk_hardlimit
);
120 ihard
= be64_to_cpu(d
->d_ino_hardlimit
);
121 rhard
= be64_to_cpu(d
->d_rtb_hardlimit
);
123 bsoft
= be64_to_cpu(d
->d_blk_softlimit
);
124 isoft
= be64_to_cpu(d
->d_ino_softlimit
);
125 rsoft
= be64_to_cpu(d
->d_rtb_softlimit
);
128 * Warn if the hard limits are larger than the fs.
129 * Administrators can do this, though in production this seems
130 * suspect, which is why we flag it for review.
132 * Complain about corruption if the soft limit is greater than
135 if (bhard
> mp
->m_sb
.sb_dblocks
)
136 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
138 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
140 if (ihard
> M_IGEO(mp
)->maxicount
)
141 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
143 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
145 if (rhard
> mp
->m_sb
.sb_rblocks
)
146 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
148 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
150 /* Check the resource counts. */
151 bcount
= be64_to_cpu(d
->d_bcount
);
152 icount
= be64_to_cpu(d
->d_icount
);
153 rcount
= be64_to_cpu(d
->d_rtbcount
);
154 fs_icount
= percpu_counter_sum(&mp
->m_icount
);
157 * Check that usage doesn't exceed physical limits. However, on
158 * a reflink filesystem we're allowed to exceed physical space
159 * if there are no quota limits.
161 if (xfs_sb_version_hasreflink(&mp
->m_sb
)) {
162 if (mp
->m_sb
.sb_dblocks
< bcount
)
163 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
,
166 if (mp
->m_sb
.sb_dblocks
< bcount
)
167 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
,
170 if (icount
> fs_icount
|| rcount
> mp
->m_sb
.sb_rblocks
)
171 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
174 * We can violate the hard limits if the admin suddenly sets a
175 * lower limit than the actual usage. However, we flag it for
178 if (id
!= 0 && bhard
!= 0 && bcount
> bhard
)
179 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
180 if (id
!= 0 && ihard
!= 0 && icount
> ihard
)
181 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
182 if (id
!= 0 && rhard
!= 0 && rcount
> rhard
)
183 xchk_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
185 if (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
)
186 return -EFSCORRUPTED
;
191 /* Check the quota's data fork. */
193 xchk_quota_data_fork(
194 struct xfs_scrub
*sc
)
196 struct xfs_bmbt_irec irec
= { 0 };
197 struct xfs_iext_cursor icur
;
198 struct xfs_quotainfo
*qi
= sc
->mp
->m_quotainfo
;
199 struct xfs_ifork
*ifp
;
200 xfs_fileoff_t max_dqid_off
;
203 /* Invoke the fork scrubber. */
204 error
= xchk_metadata_inode_forks(sc
);
205 if (error
|| (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
))
208 /* Check for data fork problems that apply only to quota files. */
209 max_dqid_off
= ((xfs_dqid_t
)-1) / qi
->qi_dqperchunk
;
210 ifp
= XFS_IFORK_PTR(sc
->ip
, XFS_DATA_FORK
);
211 for_each_xfs_iext(ifp
, &icur
, &irec
) {
212 if (xchk_should_terminate(sc
, &error
))
215 * delalloc extents or blocks mapped above the highest
216 * quota id shouldn't happen.
218 if (isnullstartblock(irec
.br_startblock
) ||
219 irec
.br_startoff
> max_dqid_off
||
220 irec
.br_startoff
+ irec
.br_blockcount
- 1 > max_dqid_off
) {
221 xchk_fblock_set_corrupt(sc
, XFS_DATA_FORK
,
230 /* Scrub all of a quota type's items. */
233 struct xfs_scrub
*sc
)
235 struct xchk_quota_info sqi
;
236 struct xfs_mount
*mp
= sc
->mp
;
237 struct xfs_quotainfo
*qi
= mp
->m_quotainfo
;
241 dqtype
= xchk_quota_to_dqtype(sc
);
243 /* Look for problem extents. */
244 error
= xchk_quota_data_fork(sc
);
247 if (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
)
251 * Check all the quota items. Now that we've checked the quota inode
252 * data fork we have to drop ILOCK_EXCL to use the regular dquot
255 xfs_iunlock(sc
->ip
, sc
->ilock_flags
);
259 error
= xfs_qm_dqiterate(mp
, dqtype
, xchk_quota_item
, &sqi
);
260 sc
->ilock_flags
= XFS_ILOCK_EXCL
;
261 xfs_ilock(sc
->ip
, sc
->ilock_flags
);
262 if (!xchk_fblock_process_error(sc
, XFS_DATA_FORK
,
263 sqi
.last_id
* qi
->qi_dqperchunk
, &error
))