Merge tag 'iommu-updates-v4.17' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / fs / xfs / scrub / quota.c
CommitLineData
c2fc338c
DW
1/*
2 * Copyright (C) 2017 Oracle. All Rights Reserved.
3 *
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 *
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.
10 *
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.
15 *
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.
19 */
20#include "xfs.h"
21#include "xfs_fs.h"
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"
28#include "xfs_bit.h"
29#include "xfs_log_format.h"
30#include "xfs_trans.h"
31#include "xfs_sb.h"
32#include "xfs_inode.h"
33#include "xfs_inode_fork.h"
34#include "xfs_alloc.h"
35#include "xfs_bmap.h"
36#include "xfs_quota.h"
37#include "xfs_qm.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"
44
45/* Convert a scrub type code to a DQ flag, or return 0 if error. */
46static inline uint
47xfs_scrub_quota_to_dqtype(
48 struct xfs_scrub_context *sc)
49{
50 switch (sc->sm->sm_type) {
51 case XFS_SCRUB_TYPE_UQUOTA:
52 return XFS_DQ_USER;
53 case XFS_SCRUB_TYPE_GQUOTA:
54 return XFS_DQ_GROUP;
55 case XFS_SCRUB_TYPE_PQUOTA:
56 return XFS_DQ_PROJ;
57 default:
58 return 0;
59 }
60}
61
62/* Set us up to scrub a quota. */
63int
64xfs_scrub_setup_quota(
65 struct xfs_scrub_context *sc,
66 struct xfs_inode *ip)
67{
68 uint dqtype;
69
c2fc338c
DW
70 dqtype = xfs_scrub_quota_to_dqtype(sc);
71 if (dqtype == 0)
72 return -EINVAL;
73 if (!xfs_this_quota_on(sc->mp, dqtype))
74 return -ENOENT;
75 return 0;
76}
77
78/* Quotas. */
79
80/* Scrub the fields in an individual quota item. */
81STATIC void
82xfs_scrub_quota_item(
83 struct xfs_scrub_context *sc,
84 uint dqtype,
85 struct xfs_dquot *dq,
86 xfs_dqid_t id)
87{
88 struct xfs_mount *mp = sc->mp;
89 struct xfs_disk_dquot *d = &dq->q_core;
90 struct xfs_quotainfo *qi = mp->m_quotainfo;
91 xfs_fileoff_t offset;
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;
101 xfs_ino_t fs_icount;
102
712d361d 103 offset = id / qi->qi_dqperchunk;
c2fc338c
DW
104
105 /*
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.
109 */
110 if (id > be32_to_cpu(d->d_id))
111 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
112
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);
116
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);
119
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);
124
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);
128
129 /*
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.
133 *
134 * Complain about corruption if the soft limit is greater than
135 * the hard limit.
136 */
137 if (bhard > mp->m_sb.sb_dblocks)
138 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset);
139 if (bsoft > bhard)
140 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
141
142 if (ihard > mp->m_maxicount)
143 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset);
144 if (isoft > ihard)
145 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
146
147 if (rhard > mp->m_sb.sb_rblocks)
148 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset);
149 if (rsoft > rhard)
150 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
151
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);
157
158 /*
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.
162 */
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,
166 offset);
167 } else {
168 if (mp->m_sb.sb_dblocks < bcount)
169 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK,
170 offset);
171 }
172 if (icount > fs_icount || rcount > mp->m_sb.sb_rblocks)
173 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
174
175 /*
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
178 * admin review.
179 */
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);
186}
187
188/* Scrub all of a quota type's items. */
189int
190xfs_scrub_quota(
191 struct xfs_scrub_context *sc)
192{
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;
200 xfs_dqid_t id = 0;
201 uint dqtype;
202 int nimaps;
eda6bc27 203 int error = 0;
c2fc338c
DW
204
205 if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
206 return -ENOENT;
207
208 mutex_lock(&qi->qi_quotaofflock);
209 dqtype = xfs_scrub_quota_to_dqtype(sc);
210 if (!xfs_this_quota_on(sc->mp, dqtype)) {
211 error = -ENOENT;
212 goto out_unlock_quota;
213 }
214
215 /* Attach to the quota inode and set sc->ip so that reporting works. */
216 ip = xfs_quota_inode(sc->mp, dqtype);
217 sc->ip = ip;
218
219 /* Look for problem extents. */
220 xfs_ilock(ip, XFS_ILOCK_EXCL);
221 if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) {
7e56d9ea 222 xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino);
c2fc338c
DW
223 goto out_unlock_inode;
224 }
225 max_dqid_off = ((xfs_dqid_t)-1) / qi->qi_dqperchunk;
226 while (1) {
227 if (xfs_scrub_should_terminate(sc, &error))
228 break;
229
230 off = irec.br_startoff + irec.br_blockcount;
231 nimaps = 1;
232 error = xfs_bmapi_read(ip, off, -1, &irec, &nimaps,
233 XFS_BMAPI_ENTIRE);
234 if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK, off,
235 &error))
236 goto out_unlock_inode;
237 if (!nimaps)
238 break;
239 if (irec.br_startblock == HOLESTARTBLOCK)
240 continue;
241
242 /* Check the extent record doesn't point to crap. */
243 if (irec.br_startblock + irec.br_blockcount <=
244 irec.br_startblock)
245 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK,
246 irec.br_startoff);
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,
251 irec.br_startoff);
252
253 /*
254 * Unwritten extents or blocks mapped above the highest
255 * quota id shouldn't happen.
256 */
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);
261 }
262 xfs_iunlock(ip, XFS_ILOCK_EXCL);
263 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
264 goto out;
265
266 /* Check all the quota items. */
267 while (id < ((xfs_dqid_t)-1ULL)) {
268 if (xfs_scrub_should_terminate(sc, &error))
269 break;
270
271 error = xfs_qm_dqget(mp, NULL, id, dqtype, XFS_QMOPT_DQNEXT,
272 &dq);
273 if (error == -ENOENT)
274 break;
275 if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK,
276 id * qi->qi_dqperchunk, &error))
277 break;
278
279 xfs_scrub_quota_item(sc, dqtype, dq, id);
280
281 id = be32_to_cpu(dq->q_core.d_id) + 1;
282 xfs_qm_dqput(dq);
283 if (!id)
284 break;
285 }
286
287out:
288 /* We set sc->ip earlier, so make sure we clear it now. */
289 sc->ip = NULL;
290out_unlock_quota:
291 mutex_unlock(&qi->qi_quotaofflock);
292 return error;
293
294out_unlock_inode:
295 xfs_iunlock(ip, XFS_ILOCK_EXCL);
296 goto out;
297}