~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/xfs/scrub/quotacheck_repair.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /*
  3  * Copyright (c) 2020-2024 Oracle.  All Rights Reserved.
  4  * Author: Darrick J. Wong <djwong@kernel.org>
  5  */
  6 #include "xfs.h"
  7 #include "xfs_fs.h"
  8 #include "xfs_shared.h"
  9 #include "xfs_format.h"
 10 #include "xfs_trans_resv.h"
 11 #include "xfs_mount.h"
 12 #include "xfs_log_format.h"
 13 #include "xfs_trans.h"
 14 #include "xfs_inode.h"
 15 #include "xfs_quota.h"
 16 #include "xfs_qm.h"
 17 #include "xfs_icache.h"
 18 #include "xfs_bmap_util.h"
 19 #include "xfs_iwalk.h"
 20 #include "xfs_ialloc.h"
 21 #include "xfs_sb.h"
 22 #include "scrub/scrub.h"
 23 #include "scrub/common.h"
 24 #include "scrub/repair.h"
 25 #include "scrub/xfile.h"
 26 #include "scrub/xfarray.h"
 27 #include "scrub/iscan.h"
 28 #include "scrub/quota.h"
 29 #include "scrub/quotacheck.h"
 30 #include "scrub/trace.h"
 31 
 32 /*
 33  * Live Quotacheck Repair
 34  * ======================
 35  *
 36  * Use the live quota counter information that we collected to replace the
 37  * counter values in the incore dquots.  A scrub->repair cycle should have left
 38  * the live data and hooks active, so this is safe so long as we make sure the
 39  * dquot is locked.
 40  */
 41 
 42 /* Commit new counters to a dquot. */
 43 static int
 44 xqcheck_commit_dquot(
 45         struct xqcheck          *xqc,
 46         xfs_dqtype_t            dqtype,
 47         struct xfs_dquot        *dq)
 48 {
 49         struct xqcheck_dquot    xcdq;
 50         struct xfarray          *counts = xqcheck_counters_for(xqc, dqtype);
 51         int64_t                 delta;
 52         bool                    dirty = false;
 53         int                     error = 0;
 54 
 55         /* Unlock the dquot just long enough to allocate a transaction. */
 56         xfs_dqunlock(dq);
 57         error = xchk_trans_alloc(xqc->sc, 0);
 58         xfs_dqlock(dq);
 59         if (error)
 60                 return error;
 61 
 62         xfs_trans_dqjoin(xqc->sc->tp, dq);
 63 
 64         if (xchk_iscan_aborted(&xqc->iscan)) {
 65                 error = -ECANCELED;
 66                 goto out_cancel;
 67         }
 68 
 69         mutex_lock(&xqc->lock);
 70         error = xfarray_load_sparse(counts, dq->q_id, &xcdq);
 71         if (error)
 72                 goto out_unlock;
 73 
 74         /* Adjust counters as needed. */
 75         delta = (int64_t)xcdq.icount - dq->q_ino.count;
 76         if (delta) {
 77                 dq->q_ino.reserved += delta;
 78                 dq->q_ino.count += delta;
 79                 dirty = true;
 80         }
 81 
 82         delta = (int64_t)xcdq.bcount - dq->q_blk.count;
 83         if (delta) {
 84                 dq->q_blk.reserved += delta;
 85                 dq->q_blk.count += delta;
 86                 dirty = true;
 87         }
 88 
 89         delta = (int64_t)xcdq.rtbcount - dq->q_rtb.count;
 90         if (delta) {
 91                 dq->q_rtb.reserved += delta;
 92                 dq->q_rtb.count += delta;
 93                 dirty = true;
 94         }
 95 
 96         xcdq.flags |= (XQCHECK_DQUOT_REPAIR_SCANNED | XQCHECK_DQUOT_WRITTEN);
 97         error = xfarray_store(counts, dq->q_id, &xcdq);
 98         if (error == -EFBIG) {
 99                 /*
100                  * EFBIG means we tried to store data at too high a byte offset
101                  * in the sparse array.  IOWs, we cannot complete the repair
102                  * and must cancel the whole operation.  This should never
103                  * happen, but we need to catch it anyway.
104                  */
105                 error = -ECANCELED;
106         }
107         mutex_unlock(&xqc->lock);
108         if (error || !dirty)
109                 goto out_cancel;
110 
111         trace_xrep_quotacheck_dquot(xqc->sc->mp, dq->q_type, dq->q_id);
112 
113         /* Commit the dirty dquot to disk. */
114         dq->q_flags |= XFS_DQFLAG_DIRTY;
115         if (dq->q_id)
116                 xfs_qm_adjust_dqtimers(dq);
117         xfs_trans_log_dquot(xqc->sc->tp, dq);
118 
119         /*
120          * Transaction commit unlocks the dquot, so we must re-lock it so that
121          * the caller can put the reference (which apparently requires a locked
122          * dquot).
123          */
124         error = xrep_trans_commit(xqc->sc);
125         xfs_dqlock(dq);
126         return error;
127 
128 out_unlock:
129         mutex_unlock(&xqc->lock);
130 out_cancel:
131         xchk_trans_cancel(xqc->sc);
132 
133         /* Re-lock the dquot so the caller can put the reference. */
134         xfs_dqlock(dq);
135         return error;
136 }
137 
138 /* Commit new quota counters for a particular quota type. */
139 STATIC int
140 xqcheck_commit_dqtype(
141         struct xqcheck          *xqc,
142         unsigned int            dqtype)
143 {
144         struct xchk_dqiter      cursor = { };
145         struct xqcheck_dquot    xcdq;
146         struct xfs_scrub        *sc = xqc->sc;
147         struct xfs_mount        *mp = sc->mp;
148         struct xfarray          *counts = xqcheck_counters_for(xqc, dqtype);
149         struct xfs_dquot        *dq;
150         xfarray_idx_t           cur = XFARRAY_CURSOR_INIT;
151         int                     error;
152 
153         /*
154          * Update the counters of every dquot that the quota file knows about.
155          */
156         xchk_dqiter_init(&cursor, sc, dqtype);
157         while ((error = xchk_dquot_iter(&cursor, &dq)) == 1) {
158                 error = xqcheck_commit_dquot(xqc, dqtype, dq);
159                 xfs_qm_dqput(dq);
160                 if (error)
161                         break;
162         }
163         if (error)
164                 return error;
165 
166         /*
167          * Make a second pass to deal with the dquots that we know about but
168          * the quota file previously did not know about.
169          */
170         mutex_lock(&xqc->lock);
171         while ((error = xfarray_iter(counts, &cur, &xcdq)) == 1) {
172                 xfs_dqid_t      id = cur - 1;
173 
174                 if (xcdq.flags & XQCHECK_DQUOT_REPAIR_SCANNED)
175                         continue;
176 
177                 mutex_unlock(&xqc->lock);
178 
179                 /*
180                  * Grab the dquot, allowing for dquot block allocation in a
181                  * separate transaction.  We committed the scrub transaction
182                  * in a previous step, so we will not be creating nested
183                  * transactions here.
184                  */
185                 error = xfs_qm_dqget(mp, id, dqtype, true, &dq);
186                 if (error)
187                         return error;
188 
189                 error = xqcheck_commit_dquot(xqc, dqtype, dq);
190                 xfs_qm_dqput(dq);
191                 if (error)
192                         return error;
193 
194                 mutex_lock(&xqc->lock);
195         }
196         mutex_unlock(&xqc->lock);
197 
198         return error;
199 }
200 
201 /* Figure out quota CHKD flags for the running quota types. */
202 static inline unsigned int
203 xqcheck_chkd_flags(
204         struct xfs_mount        *mp)
205 {
206         unsigned int            ret = 0;
207 
208         if (XFS_IS_UQUOTA_ON(mp))
209                 ret |= XFS_UQUOTA_CHKD;
210         if (XFS_IS_GQUOTA_ON(mp))
211                 ret |= XFS_GQUOTA_CHKD;
212         if (XFS_IS_PQUOTA_ON(mp))
213                 ret |= XFS_PQUOTA_CHKD;
214         return ret;
215 }
216 
217 /* Commit the new dquot counters. */
218 int
219 xrep_quotacheck(
220         struct xfs_scrub        *sc)
221 {
222         struct xqcheck          *xqc = sc->buf;
223         unsigned int            qflags = xqcheck_chkd_flags(sc->mp);
224         int                     error;
225 
226         /*
227          * Clear the CHKD flag for the running quota types and commit the scrub
228          * transaction so that we can allocate new quota block mappings if we
229          * have to.  If we crash after this point, the sb still has the CHKD
230          * flags cleared, so mount quotacheck will fix all of this up.
231          */
232         xrep_update_qflags(sc, qflags, 0);
233         error = xrep_trans_commit(sc);
234         if (error)
235                 return error;
236 
237         /* Commit the new counters to the dquots. */
238         if (xqc->ucounts) {
239                 error = xqcheck_commit_dqtype(xqc, XFS_DQTYPE_USER);
240                 if (error)
241                         return error;
242         }
243         if (xqc->gcounts) {
244                 error = xqcheck_commit_dqtype(xqc, XFS_DQTYPE_GROUP);
245                 if (error)
246                         return error;
247         }
248         if (xqc->pcounts) {
249                 error = xqcheck_commit_dqtype(xqc, XFS_DQTYPE_PROJ);
250                 if (error)
251                         return error;
252         }
253 
254         /* Set the CHKD flags now that we've fixed quota counts. */
255         error = xchk_trans_alloc(sc, 0);
256         if (error)
257                 return error;
258 
259         xrep_update_qflags(sc, 0, qflags);
260         return xrep_trans_commit(sc);
261 }
262 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php