2 * Copyright (C) 2017 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it would be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
22 #include "xfs_shared.h"
23 #include "xfs_format.h"
24 #include "xfs_trans_resv.h"
25 #include "xfs_mount.h"
26 #include "xfs_defer.h"
27 #include "xfs_btree.h"
29 #include "xfs_log_format.h"
30 #include "xfs_trans.h"
32 #include "xfs_inode.h"
33 #include "xfs_inode_fork.h"
34 #include "xfs_alloc.h"
36 #include "xfs_quota.h"
38 #include "xfs_dquot.h"
39 #include "xfs_dquot_item.h"
40 #include "scrub/xfs_scrub.h"
41 #include "scrub/scrub.h"
42 #include "scrub/common.h"
43 #include "scrub/trace.h"
45 /* Convert a scrub type code to a DQ flag, or return 0 if error. */
47 xfs_scrub_quota_to_dqtype(
48 struct xfs_scrub_context
*sc
)
50 switch (sc
->sm
->sm_type
) {
51 case XFS_SCRUB_TYPE_UQUOTA
:
53 case XFS_SCRUB_TYPE_GQUOTA
:
55 case XFS_SCRUB_TYPE_PQUOTA
:
62 /* Set us up to scrub a quota. */
64 xfs_scrub_setup_quota(
65 struct xfs_scrub_context
*sc
,
70 dqtype
= xfs_scrub_quota_to_dqtype(sc
);
73 if (!xfs_this_quota_on(sc
->mp
, dqtype
))
80 /* Scrub the fields in an individual quota item. */
83 struct xfs_scrub_context
*sc
,
88 struct xfs_mount
*mp
= sc
->mp
;
89 struct xfs_disk_dquot
*d
= &dq
->q_core
;
90 struct xfs_quotainfo
*qi
= mp
->m_quotainfo
;
92 unsigned long long bsoft
;
93 unsigned long long isoft
;
94 unsigned long long rsoft
;
95 unsigned long long bhard
;
96 unsigned long long ihard
;
97 unsigned long long rhard
;
98 unsigned long long bcount
;
99 unsigned long long icount
;
100 unsigned long long rcount
;
103 offset
= id
/ qi
->qi_dqperchunk
;
106 * We fed $id and DQNEXT into the xfs_qm_dqget call, which means
107 * that the actual dquot we got must either have the same id or
108 * the next higher id.
110 if (id
> be32_to_cpu(d
->d_id
))
111 xfs_scrub_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
113 /* Did we get the dquot type we wanted? */
114 if (dqtype
!= (d
->d_flags
& XFS_DQ_ALLTYPES
))
115 xfs_scrub_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
117 if (d
->d_pad0
!= cpu_to_be32(0) || d
->d_pad
!= cpu_to_be16(0))
118 xfs_scrub_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
120 /* Check the limits. */
121 bhard
= be64_to_cpu(d
->d_blk_hardlimit
);
122 ihard
= be64_to_cpu(d
->d_ino_hardlimit
);
123 rhard
= be64_to_cpu(d
->d_rtb_hardlimit
);
125 bsoft
= be64_to_cpu(d
->d_blk_softlimit
);
126 isoft
= be64_to_cpu(d
->d_ino_softlimit
);
127 rsoft
= be64_to_cpu(d
->d_rtb_softlimit
);
130 * Warn if the hard limits are larger than the fs.
131 * Administrators can do this, though in production this seems
132 * suspect, which is why we flag it for review.
134 * Complain about corruption if the soft limit is greater than
137 if (bhard
> mp
->m_sb
.sb_dblocks
)
138 xfs_scrub_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
140 xfs_scrub_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
142 if (ihard
> mp
->m_maxicount
)
143 xfs_scrub_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
145 xfs_scrub_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
147 if (rhard
> mp
->m_sb
.sb_rblocks
)
148 xfs_scrub_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
150 xfs_scrub_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
152 /* Check the resource counts. */
153 bcount
= be64_to_cpu(d
->d_bcount
);
154 icount
= be64_to_cpu(d
->d_icount
);
155 rcount
= be64_to_cpu(d
->d_rtbcount
);
156 fs_icount
= percpu_counter_sum(&mp
->m_icount
);
159 * Check that usage doesn't exceed physical limits. However, on
160 * a reflink filesystem we're allowed to exceed physical space
161 * if there are no quota limits.
163 if (xfs_sb_version_hasreflink(&mp
->m_sb
)) {
164 if (mp
->m_sb
.sb_dblocks
< bcount
)
165 xfs_scrub_fblock_set_warning(sc
, XFS_DATA_FORK
,
168 if (mp
->m_sb
.sb_dblocks
< bcount
)
169 xfs_scrub_fblock_set_corrupt(sc
, XFS_DATA_FORK
,
172 if (icount
> fs_icount
|| rcount
> mp
->m_sb
.sb_rblocks
)
173 xfs_scrub_fblock_set_corrupt(sc
, XFS_DATA_FORK
, offset
);
176 * We can violate the hard limits if the admin suddenly sets a
177 * lower limit than the actual usage. However, we flag it for
180 if (id
!= 0 && bhard
!= 0 && bcount
> bhard
)
181 xfs_scrub_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
182 if (id
!= 0 && ihard
!= 0 && icount
> ihard
)
183 xfs_scrub_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
184 if (id
!= 0 && rhard
!= 0 && rcount
> rhard
)
185 xfs_scrub_fblock_set_warning(sc
, XFS_DATA_FORK
, offset
);
188 /* Scrub all of a quota type's items. */
191 struct xfs_scrub_context
*sc
)
193 struct xfs_bmbt_irec irec
= { 0 };
194 struct xfs_mount
*mp
= sc
->mp
;
195 struct xfs_inode
*ip
;
196 struct xfs_quotainfo
*qi
= mp
->m_quotainfo
;
197 struct xfs_dquot
*dq
;
198 xfs_fileoff_t max_dqid_off
;
199 xfs_fileoff_t off
= 0;
205 if (!XFS_IS_QUOTA_RUNNING(mp
) || !XFS_IS_QUOTA_ON(mp
))
208 mutex_lock(&qi
->qi_quotaofflock
);
209 dqtype
= xfs_scrub_quota_to_dqtype(sc
);
210 if (!xfs_this_quota_on(sc
->mp
, dqtype
)) {
212 goto out_unlock_quota
;
215 /* Attach to the quota inode and set sc->ip so that reporting works. */
216 ip
= xfs_quota_inode(sc
->mp
, dqtype
);
219 /* Look for problem extents. */
220 xfs_ilock(ip
, XFS_ILOCK_EXCL
);
221 if (ip
->i_d
.di_flags
& XFS_DIFLAG_REALTIME
) {
222 xfs_scrub_ino_set_corrupt(sc
, sc
->ip
->i_ino
, NULL
);
223 goto out_unlock_inode
;
225 max_dqid_off
= ((xfs_dqid_t
)-1) / qi
->qi_dqperchunk
;
227 if (xfs_scrub_should_terminate(sc
, &error
))
230 off
= irec
.br_startoff
+ irec
.br_blockcount
;
232 error
= xfs_bmapi_read(ip
, off
, -1, &irec
, &nimaps
,
234 if (!xfs_scrub_fblock_process_error(sc
, XFS_DATA_FORK
, off
,
236 goto out_unlock_inode
;
239 if (irec
.br_startblock
== HOLESTARTBLOCK
)
242 /* Check the extent record doesn't point to crap. */
243 if (irec
.br_startblock
+ irec
.br_blockcount
<=
245 xfs_scrub_fblock_set_corrupt(sc
, XFS_DATA_FORK
,
247 if (!xfs_verify_fsbno(mp
, irec
.br_startblock
) ||
248 !xfs_verify_fsbno(mp
, irec
.br_startblock
+
249 irec
.br_blockcount
- 1))
250 xfs_scrub_fblock_set_corrupt(sc
, XFS_DATA_FORK
,
254 * Unwritten extents or blocks mapped above the highest
255 * quota id shouldn't happen.
257 if (isnullstartblock(irec
.br_startblock
) ||
258 irec
.br_startoff
> max_dqid_off
||
259 irec
.br_startoff
+ irec
.br_blockcount
> max_dqid_off
+ 1)
260 xfs_scrub_fblock_set_corrupt(sc
, XFS_DATA_FORK
, off
);
262 xfs_iunlock(ip
, XFS_ILOCK_EXCL
);
263 if (sc
->sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
)
266 /* Check all the quota items. */
267 while (id
< ((xfs_dqid_t
)-1ULL)) {
268 if (xfs_scrub_should_terminate(sc
, &error
))
271 error
= xfs_qm_dqget(mp
, NULL
, id
, dqtype
, XFS_QMOPT_DQNEXT
,
273 if (error
== -ENOENT
)
275 if (!xfs_scrub_fblock_process_error(sc
, XFS_DATA_FORK
,
276 id
* qi
->qi_dqperchunk
, &error
))
279 xfs_scrub_quota_item(sc
, dqtype
, dq
, id
);
281 id
= be32_to_cpu(dq
->q_core
.d_id
) + 1;
288 /* We set sc->ip earlier, so make sure we clear it now. */
291 mutex_unlock(&qi
->qi_quotaofflock
);
295 xfs_iunlock(ip
, XFS_ILOCK_EXCL
);