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