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