]> asedeno.scripts.mit.edu Git - linux.git/blob - fs/xfs/scrub/quota.c
8e58ba8429464d7b57691fb06caf85eaaf6b13f6
[linux.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         /*
71          * If userspace gave us an AG number or inode data, they don't
72          * know what they're doing.  Get out.
73          */
74         if (sc->sm->sm_agno || sc->sm->sm_ino || sc->sm->sm_gen)
75                 return -EINVAL;
76
77         dqtype = xfs_scrub_quota_to_dqtype(sc);
78         if (dqtype == 0)
79                 return -EINVAL;
80         if (!xfs_this_quota_on(sc->mp, dqtype))
81                 return -ENOENT;
82         return 0;
83 }
84
85 /* Quotas. */
86
87 /* Scrub the fields in an individual quota item. */
88 STATIC void
89 xfs_scrub_quota_item(
90         struct xfs_scrub_context        *sc,
91         uint                            dqtype,
92         struct xfs_dquot                *dq,
93         xfs_dqid_t                      id)
94 {
95         struct xfs_mount                *mp = sc->mp;
96         struct xfs_disk_dquot           *d = &dq->q_core;
97         struct xfs_quotainfo            *qi = mp->m_quotainfo;
98         xfs_fileoff_t                   offset;
99         unsigned long long              bsoft;
100         unsigned long long              isoft;
101         unsigned long long              rsoft;
102         unsigned long long              bhard;
103         unsigned long long              ihard;
104         unsigned long long              rhard;
105         unsigned long long              bcount;
106         unsigned long long              icount;
107         unsigned long long              rcount;
108         xfs_ino_t                       fs_icount;
109
110         offset = id * qi->qi_dqperchunk;
111
112         /*
113          * We fed $id and DQNEXT into the xfs_qm_dqget call, which means
114          * that the actual dquot we got must either have the same id or
115          * the next higher id.
116          */
117         if (id > be32_to_cpu(d->d_id))
118                 xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, offset);
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
195 /* Scrub all of a quota type's items. */
196 int
197 xfs_scrub_quota(
198         struct xfs_scrub_context        *sc)
199 {
200         struct xfs_bmbt_irec            irec = { 0 };
201         struct xfs_mount                *mp = sc->mp;
202         struct xfs_inode                *ip;
203         struct xfs_quotainfo            *qi = mp->m_quotainfo;
204         struct xfs_dquot                *dq;
205         xfs_fileoff_t                   max_dqid_off;
206         xfs_fileoff_t                   off = 0;
207         xfs_dqid_t                      id = 0;
208         uint                            dqtype;
209         int                             nimaps;
210         int                             error;
211
212         if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp))
213                 return -ENOENT;
214
215         mutex_lock(&qi->qi_quotaofflock);
216         dqtype = xfs_scrub_quota_to_dqtype(sc);
217         if (!xfs_this_quota_on(sc->mp, dqtype)) {
218                 error = -ENOENT;
219                 goto out_unlock_quota;
220         }
221
222         /* Attach to the quota inode and set sc->ip so that reporting works. */
223         ip = xfs_quota_inode(sc->mp, dqtype);
224         sc->ip = ip;
225
226         /* Look for problem extents. */
227         xfs_ilock(ip, XFS_ILOCK_EXCL);
228         if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) {
229                 xfs_scrub_ino_set_corrupt(sc, sc->ip->i_ino, NULL);
230                 goto out_unlock_inode;
231         }
232         max_dqid_off = ((xfs_dqid_t)-1) / qi->qi_dqperchunk;
233         while (1) {
234                 if (xfs_scrub_should_terminate(sc, &error))
235                         break;
236
237                 off = irec.br_startoff + irec.br_blockcount;
238                 nimaps = 1;
239                 error = xfs_bmapi_read(ip, off, -1, &irec, &nimaps,
240                                 XFS_BMAPI_ENTIRE);
241                 if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK, off,
242                                 &error))
243                         goto out_unlock_inode;
244                 if (!nimaps)
245                         break;
246                 if (irec.br_startblock == HOLESTARTBLOCK)
247                         continue;
248
249                 /* Check the extent record doesn't point to crap. */
250                 if (irec.br_startblock + irec.br_blockcount <=
251                     irec.br_startblock)
252                         xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK,
253                                         irec.br_startoff);
254                 if (!xfs_verify_fsbno(mp, irec.br_startblock) ||
255                     !xfs_verify_fsbno(mp, irec.br_startblock +
256                                         irec.br_blockcount - 1))
257                         xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK,
258                                         irec.br_startoff);
259
260                 /*
261                  * Unwritten extents or blocks mapped above the highest
262                  * quota id shouldn't happen.
263                  */
264                 if (isnullstartblock(irec.br_startblock) ||
265                     irec.br_startoff > max_dqid_off ||
266                     irec.br_startoff + irec.br_blockcount > max_dqid_off + 1)
267                         xfs_scrub_fblock_set_corrupt(sc, XFS_DATA_FORK, off);
268         }
269         xfs_iunlock(ip, XFS_ILOCK_EXCL);
270         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
271                 goto out;
272
273         /* Check all the quota items. */
274         while (id < ((xfs_dqid_t)-1ULL)) {
275                 if (xfs_scrub_should_terminate(sc, &error))
276                         break;
277
278                 error = xfs_qm_dqget(mp, NULL, id, dqtype, XFS_QMOPT_DQNEXT,
279                                 &dq);
280                 if (error == -ENOENT)
281                         break;
282                 if (!xfs_scrub_fblock_process_error(sc, XFS_DATA_FORK,
283                                 id * qi->qi_dqperchunk, &error))
284                         break;
285
286                 xfs_scrub_quota_item(sc, dqtype, dq, id);
287
288                 id = be32_to_cpu(dq->q_core.d_id) + 1;
289                 xfs_qm_dqput(dq);
290                 if (!id)
291                         break;
292         }
293
294 out:
295         /* We set sc->ip earlier, so make sure we clear it now. */
296         sc->ip = NULL;
297 out_unlock_quota:
298         mutex_unlock(&qi->qi_quotaofflock);
299         return error;
300
301 out_unlock_inode:
302         xfs_iunlock(ip, XFS_ILOCK_EXCL);
303         goto out;
304 }