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

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

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ 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) 2023 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_bit.h"
 10 #include "xfs_format.h"
 11 #include "xfs_trans_resv.h"
 12 #include "xfs_mount.h"
 13 #include "xfs_log_format.h"
 14 #include "xfs_trans.h"
 15 #include "xfs_inode.h"
 16 #include "xfs_quota.h"
 17 #include "xfs_qm.h"
 18 #include "xfs_bmap.h"
 19 #include "scrub/scrub.h"
 20 #include "scrub/common.h"
 21 #include "scrub/quota.h"
 22 #include "scrub/trace.h"
 23 
 24 /* Initialize a dquot iteration cursor. */
 25 void
 26 xchk_dqiter_init(
 27         struct xchk_dqiter      *cursor,
 28         struct xfs_scrub        *sc,
 29         xfs_dqtype_t            dqtype)
 30 {
 31         cursor->sc = sc;
 32         cursor->bmap.br_startoff = NULLFILEOFF;
 33         cursor->dqtype = dqtype & XFS_DQTYPE_REC_MASK;
 34         cursor->quota_ip = xfs_quota_inode(sc->mp, cursor->dqtype);
 35         cursor->id = 0;
 36 }
 37 
 38 /*
 39  * Ensure that the cached data fork mapping for the dqiter cursor is fresh and
 40  * covers the dquot pointed to by the scan cursor.
 41  */
 42 STATIC int
 43 xchk_dquot_iter_revalidate_bmap(
 44         struct xchk_dqiter      *cursor)
 45 {
 46         struct xfs_quotainfo    *qi = cursor->sc->mp->m_quotainfo;
 47         struct xfs_ifork        *ifp = xfs_ifork_ptr(cursor->quota_ip,
 48                                                                 XFS_DATA_FORK);
 49         xfs_fileoff_t           fileoff;
 50         xfs_dqid_t              this_id = cursor->id;
 51         int                     nmaps = 1;
 52         int                     error;
 53 
 54         fileoff = this_id / qi->qi_dqperchunk;
 55 
 56         /*
 57          * If we have a mapping for cursor->id and it's still fresh, there's
 58          * no need to reread the bmbt.
 59          */
 60         if (cursor->bmap.br_startoff != NULLFILEOFF &&
 61             cursor->if_seq == ifp->if_seq &&
 62             cursor->bmap.br_startoff + cursor->bmap.br_blockcount > fileoff)
 63                 return 0;
 64 
 65         /* Look up the data fork mapping for the dquot id of interest. */
 66         error = xfs_bmapi_read(cursor->quota_ip, fileoff,
 67                         XFS_MAX_FILEOFF - fileoff, &cursor->bmap, &nmaps, 0);
 68         if (error)
 69                 return error;
 70         if (!nmaps) {
 71                 ASSERT(nmaps > 0);
 72                 return -EFSCORRUPTED;
 73         }
 74         if (cursor->bmap.br_startoff > fileoff) {
 75                 ASSERT(cursor->bmap.br_startoff == fileoff);
 76                 return -EFSCORRUPTED;
 77         }
 78 
 79         cursor->if_seq = ifp->if_seq;
 80         trace_xchk_dquot_iter_revalidate_bmap(cursor, cursor->id);
 81         return 0;
 82 }
 83 
 84 /* Advance the dqiter cursor to the next non-sparse region of the quota file. */
 85 STATIC int
 86 xchk_dquot_iter_advance_bmap(
 87         struct xchk_dqiter      *cursor,
 88         uint64_t                *next_ondisk_id)
 89 {
 90         struct xfs_quotainfo    *qi = cursor->sc->mp->m_quotainfo;
 91         struct xfs_ifork        *ifp = xfs_ifork_ptr(cursor->quota_ip,
 92                                                                 XFS_DATA_FORK);
 93         xfs_fileoff_t           fileoff;
 94         uint64_t                next_id;
 95         int                     nmaps = 1;
 96         int                     error;
 97 
 98         /* Find the dquot id for the next non-hole mapping. */
 99         do {
100                 fileoff = cursor->bmap.br_startoff + cursor->bmap.br_blockcount;
101                 if (fileoff > XFS_DQ_ID_MAX / qi->qi_dqperchunk) {
102                         /* The hole goes beyond the max dquot id, we're done */
103                         *next_ondisk_id = -1ULL;
104                         return 0;
105                 }
106 
107                 error = xfs_bmapi_read(cursor->quota_ip, fileoff,
108                                 XFS_MAX_FILEOFF - fileoff, &cursor->bmap,
109                                 &nmaps, 0);
110                 if (error)
111                         return error;
112                 if (!nmaps) {
113                         /* Must have reached the end of the mappings. */
114                         *next_ondisk_id = -1ULL;
115                         return 0;
116                 }
117                 if (cursor->bmap.br_startoff > fileoff) {
118                         ASSERT(cursor->bmap.br_startoff == fileoff);
119                         return -EFSCORRUPTED;
120                 }
121         } while (!xfs_bmap_is_real_extent(&cursor->bmap));
122 
123         next_id = cursor->bmap.br_startoff * qi->qi_dqperchunk;
124         if (next_id > XFS_DQ_ID_MAX) {
125                 /* The hole goes beyond the max dquot id, we're done */
126                 *next_ondisk_id = -1ULL;
127                 return 0;
128         }
129 
130         /* Propose jumping forward to the dquot in the next allocated block. */
131         *next_ondisk_id = next_id;
132         cursor->if_seq = ifp->if_seq;
133         trace_xchk_dquot_iter_advance_bmap(cursor, *next_ondisk_id);
134         return 0;
135 }
136 
137 /*
138  * Find the id of the next highest incore dquot.  Normally this will correspond
139  * exactly with the quota file block mappings, but repair might have erased a
140  * mapping because it was crosslinked; in that case, we need to re-allocate the
141  * space so that we can reset q_blkno.
142  */
143 STATIC void
144 xchk_dquot_iter_advance_incore(
145         struct xchk_dqiter      *cursor,
146         uint64_t                *next_incore_id)
147 {
148         struct xfs_quotainfo    *qi = cursor->sc->mp->m_quotainfo;
149         struct radix_tree_root  *tree = xfs_dquot_tree(qi, cursor->dqtype);
150         struct xfs_dquot        *dq;
151         unsigned int            nr_found;
152 
153         *next_incore_id = -1ULL;
154 
155         mutex_lock(&qi->qi_tree_lock);
156         nr_found = radix_tree_gang_lookup(tree, (void **)&dq, cursor->id, 1);
157         if (nr_found)
158                 *next_incore_id = dq->q_id;
159         mutex_unlock(&qi->qi_tree_lock);
160 
161         trace_xchk_dquot_iter_advance_incore(cursor, *next_incore_id);
162 }
163 
164 /*
165  * Walk all incore dquots of this filesystem.  Caller must set *@cursorp to
166  * zero before the first call, and must not hold the quota file ILOCK.
167  * Returns 1 and a valid *@dqpp; 0 and *@dqpp == NULL when there are no more
168  * dquots to iterate; or a negative errno.
169  */
170 int
171 xchk_dquot_iter(
172         struct xchk_dqiter      *cursor,
173         struct xfs_dquot        **dqpp)
174 {
175         struct xfs_mount        *mp = cursor->sc->mp;
176         struct xfs_dquot        *dq = NULL;
177         uint64_t                next_ondisk, next_incore = -1ULL;
178         unsigned int            lock_mode;
179         int                     error = 0;
180 
181         if (cursor->id > XFS_DQ_ID_MAX)
182                 return 0;
183         next_ondisk = cursor->id;
184 
185         /* Revalidate and/or advance the cursor. */
186         lock_mode = xfs_ilock_data_map_shared(cursor->quota_ip);
187         error = xchk_dquot_iter_revalidate_bmap(cursor);
188         if (!error && !xfs_bmap_is_real_extent(&cursor->bmap))
189                 error = xchk_dquot_iter_advance_bmap(cursor, &next_ondisk);
190         xfs_iunlock(cursor->quota_ip, lock_mode);
191         if (error)
192                 return error;
193 
194         if (next_ondisk > cursor->id)
195                 xchk_dquot_iter_advance_incore(cursor, &next_incore);
196 
197         /* Pick the next dquot in the sequence and return it. */
198         cursor->id = min(next_ondisk, next_incore);
199         if (cursor->id > XFS_DQ_ID_MAX)
200                 return 0;
201 
202         trace_xchk_dquot_iter(cursor, cursor->id);
203 
204         error = xfs_qm_dqget(mp, cursor->id, cursor->dqtype, false, &dq);
205         if (error)
206                 return error;
207 
208         cursor->id = dq->q_id + 1;
209         *dqpp = dq;
210         return 1;
211 }
212 

~ [ 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