847c6f83610214f13f1ce195d79453ab6eea7baf
[platform/kernel/linux-starfive.git] / fs / xfs / scrub / reap.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2022-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_format.h"
10 #include "xfs_trans_resv.h"
11 #include "xfs_mount.h"
12 #include "xfs_btree.h"
13 #include "xfs_log_format.h"
14 #include "xfs_trans.h"
15 #include "xfs_sb.h"
16 #include "xfs_inode.h"
17 #include "xfs_alloc.h"
18 #include "xfs_alloc_btree.h"
19 #include "xfs_ialloc.h"
20 #include "xfs_ialloc_btree.h"
21 #include "xfs_rmap.h"
22 #include "xfs_rmap_btree.h"
23 #include "xfs_refcount_btree.h"
24 #include "xfs_extent_busy.h"
25 #include "xfs_ag.h"
26 #include "xfs_ag_resv.h"
27 #include "xfs_quota.h"
28 #include "xfs_qm.h"
29 #include "xfs_bmap.h"
30 #include "scrub/scrub.h"
31 #include "scrub/common.h"
32 #include "scrub/trace.h"
33 #include "scrub/repair.h"
34 #include "scrub/bitmap.h"
35 #include "scrub/reap.h"
36
37 /*
38  * Disposal of Blocks from Old Metadata
39  *
40  * Now that we've constructed a new btree to replace the damaged one, we want
41  * to dispose of the blocks that (we think) the old btree was using.
42  * Previously, we used the rmapbt to collect the extents (bitmap) with the
43  * rmap owner corresponding to the tree we rebuilt, collected extents for any
44  * blocks with the same rmap owner that are owned by another data structure
45  * (sublist), and subtracted sublist from bitmap.  In theory the extents
46  * remaining in bitmap are the old btree's blocks.
47  *
48  * Unfortunately, it's possible that the btree was crosslinked with other
49  * blocks on disk.  The rmap data can tell us if there are multiple owners, so
50  * if the rmapbt says there is an owner of this block other than @oinfo, then
51  * the block is crosslinked.  Remove the reverse mapping and continue.
52  *
53  * If there is one rmap record, we can free the block, which removes the
54  * reverse mapping but doesn't add the block to the free space.  Our repair
55  * strategy is to hope the other metadata objects crosslinked on this block
56  * will be rebuilt (atop different blocks), thereby removing all the cross
57  * links.
58  *
59  * If there are no rmap records at all, we also free the block.  If the btree
60  * being rebuilt lives in the free space (bnobt/cntbt/rmapbt) then there isn't
61  * supposed to be a rmap record and everything is ok.  For other btrees there
62  * had to have been an rmap entry for the block to have ended up on @bitmap,
63  * so if it's gone now there's something wrong and the fs will shut down.
64  *
65  * Note: If there are multiple rmap records with only the same rmap owner as
66  * the btree we're trying to rebuild and the block is indeed owned by another
67  * data structure with the same rmap owner, then the block will be in sublist
68  * and therefore doesn't need disposal.  If there are multiple rmap records
69  * with only the same rmap owner but the block is not owned by something with
70  * the same rmap owner, the block will be freed.
71  *
72  * The caller is responsible for locking the AG headers for the entire rebuild
73  * operation so that nothing else can sneak in and change the AG state while
74  * we're not looking.  We must also invalidate any buffers associated with
75  * @bitmap.
76  */
77
78 /* Information about reaping extents after a repair. */
79 struct xrep_reap_state {
80         struct xfs_scrub                *sc;
81
82         /* Reverse mapping owner and metadata reservation type. */
83         const struct xfs_owner_info     *oinfo;
84         enum xfs_ag_resv_type           resv;
85
86         /* Number of deferred reaps attached to the current transaction. */
87         unsigned int                    deferred;
88 };
89
90 /* Put a block back on the AGFL. */
91 STATIC int
92 xrep_put_freelist(
93         struct xfs_scrub        *sc,
94         xfs_agblock_t           agbno)
95 {
96         struct xfs_buf          *agfl_bp;
97         int                     error;
98
99         /* Make sure there's space on the freelist. */
100         error = xrep_fix_freelist(sc, true);
101         if (error)
102                 return error;
103
104         /*
105          * Since we're "freeing" a lost block onto the AGFL, we have to
106          * create an rmap for the block prior to merging it or else other
107          * parts will break.
108          */
109         error = xfs_rmap_alloc(sc->tp, sc->sa.agf_bp, sc->sa.pag, agbno, 1,
110                         &XFS_RMAP_OINFO_AG);
111         if (error)
112                 return error;
113
114         /* Put the block on the AGFL. */
115         error = xfs_alloc_read_agfl(sc->sa.pag, sc->tp, &agfl_bp);
116         if (error)
117                 return error;
118
119         error = xfs_alloc_put_freelist(sc->sa.pag, sc->tp, sc->sa.agf_bp,
120                         agfl_bp, agbno, 0);
121         if (error)
122                 return error;
123         xfs_extent_busy_insert(sc->tp, sc->sa.pag, agbno, 1,
124                         XFS_EXTENT_BUSY_SKIP_DISCARD);
125
126         return 0;
127 }
128
129 /* Try to invalidate the incore buffer for a block that we're about to free. */
130 STATIC void
131 xrep_block_reap_binval(
132         struct xfs_scrub        *sc,
133         xfs_fsblock_t           fsbno)
134 {
135         struct xfs_buf          *bp = NULL;
136         int                     error;
137
138         /*
139          * If there's an incore buffer for exactly this block, invalidate it.
140          * Avoid invalidating AG headers and post-EOFS blocks because we never
141          * own those.
142          */
143         if (!xfs_verify_fsbno(sc->mp, fsbno))
144                 return;
145
146         /*
147          * We assume that the lack of any other known owners means that the
148          * buffer can be locked without risk of deadlocking.
149          */
150         error = xfs_buf_incore(sc->mp->m_ddev_targp,
151                         XFS_FSB_TO_DADDR(sc->mp, fsbno),
152                         XFS_FSB_TO_BB(sc->mp, 1), 0, &bp);
153         if (error)
154                 return;
155
156         xfs_trans_bjoin(sc->tp, bp);
157         xfs_trans_binval(sc->tp, bp);
158 }
159
160 /* Dispose of a single block. */
161 STATIC int
162 xrep_reap_block(
163         uint64_t                        fsbno,
164         void                            *priv)
165 {
166         struct xrep_reap_state          *rs = priv;
167         struct xfs_scrub                *sc = rs->sc;
168         struct xfs_btree_cur            *cur;
169         xfs_agnumber_t                  agno;
170         xfs_agblock_t                   agbno;
171         bool                            has_other_rmap;
172         bool                            need_roll = true;
173         int                             error;
174
175         agno = XFS_FSB_TO_AGNO(sc->mp, fsbno);
176         agbno = XFS_FSB_TO_AGBNO(sc->mp, fsbno);
177
178         /* We don't support reaping file extents yet. */
179         if (sc->ip != NULL || sc->sa.pag->pag_agno != agno) {
180                 ASSERT(0);
181                 return -EFSCORRUPTED;
182         }
183
184         cur = xfs_rmapbt_init_cursor(sc->mp, sc->tp, sc->sa.agf_bp, sc->sa.pag);
185
186         /* Can we find any other rmappings? */
187         error = xfs_rmap_has_other_keys(cur, agbno, 1, rs->oinfo,
188                         &has_other_rmap);
189         xfs_btree_del_cursor(cur, error);
190         if (error)
191                 return error;
192
193         /*
194          * If there are other rmappings, this block is cross linked and must
195          * not be freed.  Remove the reverse mapping and move on.  Otherwise,
196          * we were the only owner of the block, so free the extent, which will
197          * also remove the rmap.
198          *
199          * XXX: XFS doesn't support detecting the case where a single block
200          * metadata structure is crosslinked with a multi-block structure
201          * because the buffer cache doesn't detect aliasing problems, so we
202          * can't fix 100% of crosslinking problems (yet).  The verifiers will
203          * blow on writeout, the filesystem will shut down, and the admin gets
204          * to run xfs_repair.
205          */
206         if (has_other_rmap) {
207                 trace_xrep_dispose_unmap_extent(sc->sa.pag, agbno, 1);
208
209                 error = xfs_rmap_free(sc->tp, sc->sa.agf_bp, sc->sa.pag, agbno,
210                                 1, rs->oinfo);
211                 if (error)
212                         return error;
213
214                 goto roll_out;
215         }
216
217         trace_xrep_dispose_free_extent(sc->sa.pag, agbno, 1);
218
219         xrep_block_reap_binval(sc, fsbno);
220
221         if (rs->resv == XFS_AG_RESV_AGFL) {
222                 error = xrep_put_freelist(sc, agbno);
223         } else {
224                 /*
225                  * Use deferred frees to get rid of the old btree blocks to try
226                  * to minimize the window in which we could crash and lose the
227                  * old blocks.  However, we still need to roll the transaction
228                  * every 100 or so EFIs so that we don't exceed the log
229                  * reservation.
230                  */
231                 error = __xfs_free_extent_later(sc->tp, fsbno, 1, rs->oinfo,
232                                 rs->resv, true);
233                 if (error)
234                         return error;
235                 rs->deferred++;
236                 need_roll = rs->deferred > 100;
237         }
238         if (error || !need_roll)
239                 return error;
240
241 roll_out:
242         rs->deferred = 0;
243         return xrep_roll_ag_trans(sc);
244 }
245
246 /* Dispose of every block of every extent in the bitmap. */
247 int
248 xrep_reap_extents(
249         struct xfs_scrub                *sc,
250         struct xbitmap                  *bitmap,
251         const struct xfs_owner_info     *oinfo,
252         enum xfs_ag_resv_type           type)
253 {
254         struct xrep_reap_state          rs = {
255                 .sc                     = sc,
256                 .oinfo                  = oinfo,
257                 .resv                   = type,
258         };
259         int                             error;
260
261         ASSERT(xfs_has_rmapbt(sc->mp));
262
263         error = xbitmap_walk_bits(bitmap, xrep_reap_block, &rs);
264         if (error || rs.deferred == 0)
265                 return error;
266
267         return xrep_roll_ag_trans(sc);
268 }