Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Copyright (C) 2020-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_rtalloc.h"
16 : #include "xfs_inode.h"
17 : #include "xfs_bit.h"
18 : #include "xfs_bmap.h"
19 : #include "xfs_bmap_btree.h"
20 : #include "xfs_swapext.h"
21 : #include "xfs_rtbitmap.h"
22 : #include "scrub/scrub.h"
23 : #include "scrub/common.h"
24 : #include "scrub/trace.h"
25 : #include "scrub/repair.h"
26 : #include "scrub/tempfile.h"
27 : #include "scrub/tempswap.h"
28 : #include "scrub/reap.h"
29 : #include "scrub/xfile.h"
30 : #include "scrub/rtsummary.h"
31 :
32 : struct xrep_rtsummary {
33 : /* suminfo position of xfile as we write buffers to disk. */
34 : xfs_rtsumoff_t prep_wordoff;
35 : };
36 :
37 : /* Set us up to repair the rtsummary file. */
38 : int
39 33630 : xrep_setup_rtsummary(
40 : struct xfs_scrub *sc,
41 : unsigned int *resblks,
42 : size_t *bufsize)
43 : {
44 33630 : struct xfs_mount *mp = sc->mp;
45 33630 : unsigned long long blocks;
46 33630 : int error;
47 :
48 33630 : *bufsize = max(*bufsize, sizeof(struct xrep_tempswap));
49 :
50 33630 : error = xrep_tempfile_create(sc, S_IFREG);
51 33634 : if (error)
52 : return error;
53 :
54 : /*
55 : * If we're doing a repair, we reserve enough blocks to write out a
56 : * completely new summary file, plus twice as many blocks as we would
57 : * need if we can only allocate one block per data fork mapping. This
58 : * should cover the preallocation of the temporary file and swapping
59 : * the extent mappings.
60 : *
61 : * We cannot use xfs_swapext_estimate because we have not yet
62 : * constructed the replacement rtsummary and therefore do not know how
63 : * many extents it will use. By the time we do, we will have a dirty
64 : * transaction (which we cannot drop because we cannot drop the
65 : * rtsummary ILOCK) and cannot ask for more reservation.
66 : */
67 33622 : blocks = XFS_B_TO_FSB(mp, mp->m_rsumsize);
68 33622 : blocks += xfs_bmbt_calc_size(mp, blocks) * 2;
69 33621 : if (blocks > UINT_MAX)
70 : return -EOPNOTSUPP;
71 :
72 33621 : *resblks += blocks;
73 :
74 : /*
75 : * Grab support for atomic extent swapping before we allocate any
76 : * transactions or grab ILOCKs.
77 : */
78 33621 : return xrep_tempswap_grab_log_assist(sc);
79 : }
80 :
81 : static int
82 218649 : xrep_rtsummary_prep_buf(
83 : struct xfs_scrub *sc,
84 : struct xfs_buf *bp,
85 : void *data)
86 : {
87 218649 : struct xrep_rtsummary *rs = data;
88 218649 : struct xfs_mount *mp = sc->mp;
89 218649 : int error;
90 :
91 437298 : error = xfsum_copyout(sc, rs->prep_wordoff,
92 : xfs_rsumblock_infoptr(bp, 0), mp->m_blockwsize);
93 218649 : if (error)
94 : return error;
95 :
96 218649 : if (xfs_has_rtgroups(sc->mp)) {
97 218649 : struct xfs_rtbuf_blkinfo *hdr = bp->b_addr;
98 :
99 218649 : hdr->rt_magic = cpu_to_be32(XFS_RTSUMMARY_MAGIC);
100 218649 : hdr->rt_owner = cpu_to_be64(sc->ip->i_ino);
101 218649 : hdr->rt_blkno = cpu_to_be64(xfs_buf_daddr(bp));
102 218649 : hdr->rt_lsn = 0;
103 218649 : uuid_copy(&hdr->rt_uuid, &sc->mp->m_sb.sb_meta_uuid);
104 218649 : bp->b_ops = &xfs_rtsummary_buf_ops;
105 : } else {
106 0 : bp->b_ops = &xfs_rtbuf_ops;
107 : }
108 :
109 218649 : rs->prep_wordoff += mp->m_blockwsize;
110 218649 : xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_RTSUMMARY_BUF);
111 218649 : return 0;
112 : }
113 :
114 : /* Repair the realtime summary. */
115 : int
116 33537 : xrep_rtsummary(
117 : struct xfs_scrub *sc)
118 : {
119 33537 : struct xrep_rtsummary rs = { .prep_wordoff = 0, };
120 33537 : struct xrep_tempswap *ti = NULL;
121 33537 : xfs_filblks_t rsumblocks;
122 33537 : int error;
123 :
124 : /* We require the rmapbt to rebuild anything. */
125 33537 : if (!xfs_has_rmapbt(sc->mp))
126 : return -EOPNOTSUPP;
127 :
128 : /* Make sure any problems with the fork are fixed. */
129 33537 : error = xrep_metadata_inode_forks(sc);
130 33537 : if (error)
131 : return error;
132 :
133 : /*
134 : * Try to take ILOCK_EXCL of the temporary file. We had better be the
135 : * only ones holding onto this inode, but we can't block while holding
136 : * the rtsummary file's ILOCK_EXCL.
137 : */
138 33525 : while (!xrep_tempfile_ilock_nowait(sc)) {
139 0 : if (xchk_should_terminate(sc, &error))
140 0 : return error;
141 0 : delay(1);
142 : }
143 :
144 : /* Make sure we have space allocated for the entire summary file. */
145 33525 : rsumblocks = XFS_B_TO_FSB(sc->mp, sc->mp->m_rsumsize);
146 33525 : xfs_trans_ijoin(sc->tp, sc->ip, 0);
147 33525 : xfs_trans_ijoin(sc->tp, sc->tempip, 0);
148 33525 : error = xrep_tempfile_prealloc(sc, 0, rsumblocks);
149 33525 : if (error)
150 : return error;
151 :
152 : /* Last chance to abort before we start committing fixes. */
153 33525 : if (xchk_should_terminate(sc, &error))
154 0 : return error;
155 :
156 : /* Copy the rtsummary file that we generated. */
157 33525 : error = xrep_tempfile_copyin(sc, 0, rsumblocks,
158 : xrep_rtsummary_prep_buf, &rs);
159 33525 : if (error)
160 : return error;
161 33525 : error = xrep_tempfile_set_isize(sc, sc->mp->m_rsumsize);
162 33525 : if (error)
163 : return error;
164 :
165 : /*
166 : * Now swap the extents. Nothing in repair uses the temporary buffer,
167 : * so we can reuse it for the tempfile swapext information.
168 : */
169 33525 : ti = sc->buf;
170 33525 : error = xrep_tempswap_trans_reserve(sc, XFS_DATA_FORK, 0, rsumblocks,
171 : ti);
172 33525 : if (error)
173 : return error;
174 :
175 33525 : error = xrep_tempswap_contents(sc, ti);
176 33525 : if (error)
177 : return error;
178 33525 : ti = NULL;
179 :
180 : /* Free the old rtsummary blocks if they're not in use. */
181 33525 : return xrep_reap_ifork(sc, sc->tempip, XFS_DATA_FORK);
182 : }
|