xfs: refactor dquot iteration
[linux-2.6-block.git] / fs / xfs / scrub / quota.c
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. */
46 static inline uint
47 xfs_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. */
63 int
64 xfs_scrub_setup_quota(
65         struct xfs_scrub_context        *sc,
66         struct xfs_inode                *ip)
67 {
68         uint                            dqtype;
69
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 struct xfs_scrub_quota_info {
81         struct xfs_scrub_context        *sc;
82         xfs_dqid_t                      last_id;
83 };
84
85 /* Scrub the fields in an individual quota item. */
86 STATIC int
87 xfs_scrub_quota_item(
88         struct xfs_dquot                *dq,
89         uint                            dqtype,
90         void                            *priv)
91 {
92         struct xfs_scrub_quota_info     *sqi = priv;
93         struct xfs_scrub_context        *sc = sqi->sc;
94         struct xfs_mount                *mp = sc->mp;
95         struct xfs_disk_dquot           *d = &dq->q_core;
96         struct xfs_quotainfo            *qi = mp->m_quotainfo;
97         xfs_fileoff_t                   offset;
98         unsigned long long              bsoft;
99         unsigned long long              isoft;
100         unsigned long long              rsoft;
101         unsigned long long              bhard;
102         unsigned long long              ihard;
103         unsigned long long              rhard;
104         unsigned long long              bcount;
105         unsigned long long              icount;
106         unsigned long long              rcount;
107         xfs_ino_t                       fs_icount;
108         xfs_dqid_t                      id = be32_to_cpu(d->d_id);
109
110         /*
111          * Except for the root dquot, the actual dquot we got must either have
112          * the same or higher id as we saw before.
113          */
114         offset = id / qi->qi_dqperchunk;
115         if (id && id <= sqi->last_id)
116                 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
117
118         sqi->last_id = id;
119
120         /* Did we get the dquot type we wanted? */
121         if (dqtype != (d->d_flags & XFS_DQ_ALLTYPES))
122                 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
123
124         if (d->d_pad0 != cpu_to_be32(0) || d->d_pad != cpu_to_be16(0))
125                 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
126
127         /* Check the limits. */
128         bhard = be64_to_cpu(d->d_blk_hardlimit);
129         ihard = be64_to_cpu(d->d_ino_hardlimit);
130         rhard = be64_to_cpu(d->d_rtb_hardlimit);
131
132         bsoft = be64_to_cpu(d->d_blk_softlimit);
133         isoft = be64_to_cpu(d->d_ino_softlimit);
134         rsoft = be64_to_cpu(d->d_rtb_softlimit);
135
136         /*
137          * Warn if the hard limits are larger than the fs.
138          * Administrators can do this, though in production this seems
139          * suspect, which is why we flag it for review.
140          *
141          * Complain about corruption if the soft limit is greater than
142          * the hard limit.
143          */
144         if (bhard > mp->m_sb.sb_dblocks)
145                 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset);
146         if (bsoft > bhard)
147                 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
148
149         if (ihard > mp->m_maxicount)
150                 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset);
151         if (isoft > ihard)
152                 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
153
154         if (rhard > mp->m_sb.sb_rblocks)
155                 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset);
156         if (rsoft > rhard)
157                 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
158
159         /* Check the resource counts. */
160         bcount = be64_to_cpu(d->d_bcount);
161         icount = be64_to_cpu(d->d_icount);
162         rcount = be64_to_cpu(d->d_rtbcount);
163         fs_icount = percpu_counter_sum(&mp->m_icount);
164
165         /*
166          * Check that usage doesn't exceed physical limits.  However, on
167          * a reflink filesystem we're allowed to exceed physical space
168          * if there are no quota limits.
169          */
170         if (xfs_sb_version_hasreflink(&mp->m_sb)) {
171                 if (mp->m_sb.sb_dblocks < bcount)
172                         xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK,
173                                         offset);
174         } else {
175                 if (mp->m_sb.sb_dblocks < bcount)
176                         xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK,
177                                         offset);
178         }
179         if (icount > fs_icount || rcount > mp->m_sb.sb_rblocks)
180                 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
181
182         /*
183          * We can violate the hard limits if the admin suddenly sets a
184          * lower limit than the actual usage.  However, we flag it for
185          * admin review.
186          */
187         if (id != 0 && bhard != 0 && bcount > bhard)
188                 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset);
189         if (id != 0 && ihard != 0 && icount > ihard)
190                 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset);
191         if (id != 0 && rhard != 0 && rcount > rhard)
192                 xfs_scrub_fblock_set_warning(sc, XFS_DATA_FORK, offset);
193
194         return 0;
195 }
196
197 /* Scrub all of a quota type's items. */
198 int
199 xfs_scrub_quota(
200         struct xfs_scrub_context        *sc)
201 {
202         struct xfs_bmbt_irec            irec = { 0 };
203         struct xfs_scrub_quota_info     sqi;
204         struct xfs_mount                *mp = sc->mp;
205         struct xfs_inode                *ip;
206         struct xfs_quotainfo            *qi = mp->m_quotainfo;
207         xfs_fileoff_t                   max_dqid_off;
208         xfs_fileoff_t                   off = 0;
209         uint                            dqtype;
210         int                             nimaps;
211         int                             error = 0;
212
213         if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
214                 return -ENOENT;
215
216         mutex_lock(&qi->qi_quotaofflock);
217         dqtype = xfs_scrub_quota_to_dqtype(sc);
218         if (!xfs_this_quota_on(sc->mp, dqtype)) {
219                 error = -ENOENT;
220                 goto out_unlock_quota;
221         }
222
223         /* Attach to the quota inode and set sc->ip so that reporting works. */
224         ip = xfs_quota_inode(sc->mp, dqtype);
225         sc->ip = ip;
226
227         /* Look for problem extents. */
228         xfs_ilock(ip, XFS_ILOCK_EXCL);
229         if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) {
230                 xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino);
231                 goto out_unlock_inode;
232         }
233         max_dqid_off = ((xfs_dqid_t)-1) / qi->qi_dqperchunk;
234         while (1) {
235                 if (xfs_scrub_should_terminate(sc, &error))
236                         break;
237
238                 off = irec.br_startoff + irec.br_blockcount;
239                 nimaps = 1;
240                 error = xfs_bmapi_read(ip, off, -1, &irec, &nimaps,
241                                 XFS_BMAPI_ENTIRE);
242                 if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK, off,
243                                 &error))
244                         goto out_unlock_inode;
245                 if (!nimaps)
246                         break;
247                 if (irec.br_startblock == HOLESTARTBLOCK)
248                         continue;
249
250                 /* Check the extent record doesn't point to crap. */
251                 if (irec.br_startblock + irec.br_blockcount <=
252                     irec.br_startblock)
253                         xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK,
254                                         irec.br_startoff);
255                 if (!xfs_verify_fsbno(mp, irec.br_startblock) ||
256                     !xfs_verify_fsbno(mp, irec.br_startblock +
257                                         irec.br_blockcount - 1))
258                         xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK,
259                                         irec.br_startoff);
260
261                 /*
262                  * Unwritten extents or blocks mapped above the highest
263                  * quota id shouldn't happen.
264                  */
265                 if (isnullstartblock(irec.br_startblock) ||
266                     irec.br_startoff > max_dqid_off ||
267                     irec.br_startoff + irec.br_blockcount > max_dqid_off + 1)
268                         xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, off);
269         }
270         xfs_iunlock(ip, XFS_ILOCK_EXCL);
271         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
272                 goto out;
273
274         /* Check all the quota items. */
275         sqi.sc = sc;
276         sqi.last_id = 0;
277         error = xfs_qm_dqiterate(mp, dqtype, xfs_scrub_quota_item, &sqi);
278         if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK,
279                         sqi.last_id * qi->qi_dqperchunk, &error))
280                 goto out;
281
282 out:
283         /* We set sc->ip earlier, so make sure we clear it now. */
284         sc->ip = NULL;
285 out_unlock_quota:
286         mutex_unlock(&qi->qi_quotaofflock);
287         return error;
288
289 out_unlock_inode:
290         xfs_iunlock(ip, XFS_ILOCK_EXCL);
291         goto out;
292 }