Skip to content

Commit 526aab5

Browse files
author
Darrick J. Wong
committed
xfs: implement online scrubbing of rtsummary info
Finish the realtime summary scrubber by adding the functions we need to compute a fresh copy of the rtsummary info and comparing it to the copy on disk. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Dave Chinner <[email protected]>
1 parent b7d47a7 commit 526aab5

File tree

7 files changed

+298
-28
lines changed

7 files changed

+298
-28
lines changed

fs/xfs/scrub/common.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,16 @@ int xchk_setup_xattr(struct xfs_scrub *sc);
8888
int xchk_setup_symlink(struct xfs_scrub *sc);
8989
int xchk_setup_parent(struct xfs_scrub *sc);
9090
#ifdef CONFIG_XFS_RT
91-
int xchk_setup_rt(struct xfs_scrub *sc);
91+
int xchk_setup_rtbitmap(struct xfs_scrub *sc);
92+
int xchk_setup_rtsummary(struct xfs_scrub *sc);
9293
#else
9394
static inline int
94-
xchk_setup_rt(struct xfs_scrub *sc)
95+
xchk_setup_rtbitmap(struct xfs_scrub *sc)
96+
{
97+
return -ENOENT;
98+
}
99+
static inline int
100+
xchk_setup_rtsummary(struct xfs_scrub *sc)
95101
{
96102
return -ENOENT;
97103
}
@@ -163,6 +169,14 @@ static inline bool xchk_skip_xref(struct xfs_scrub_metadata *sm)
163169

164170
int xchk_metadata_inode_forks(struct xfs_scrub *sc);
165171

172+
/*
173+
* Helper macros to allocate and format xfile description strings.
174+
* Callers must kfree the pointer returned.
175+
*/
176+
#define xchk_xfile_descr(sc, fmt, ...) \
177+
kasprintf(XCHK_GFP_FLAGS, "XFS (%s): " fmt, \
178+
(sc)->mp->m_super->s_id, ##__VA_ARGS__)
179+
166180
/*
167181
* Setting up a hook to wait for intents to drain is costly -- we have to take
168182
* the CPU hotplug lock and force an i-cache flush on all CPUs once to set it

fs/xfs/scrub/rtbitmap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919

2020
/* Set us up with the realtime metadata locked. */
2121
int
22-
xchk_setup_rt(
22+
xchk_setup_rtbitmap(
2323
struct xfs_scrub *sc)
2424
{
2525
int error;
2626

27-
error = xchk_setup_fs(sc);
27+
error = xchk_trans_alloc(sc, 0);
2828
if (error)
2929
return error;
3030

fs/xfs/scrub/rtsummary.c

Lines changed: 232 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,41 +14,251 @@
1414
#include "xfs_log_format.h"
1515
#include "xfs_trans.h"
1616
#include "xfs_rtalloc.h"
17+
#include "xfs_bit.h"
18+
#include "xfs_bmap.h"
1719
#include "scrub/scrub.h"
1820
#include "scrub/common.h"
21+
#include "scrub/trace.h"
22+
#include "scrub/xfile.h"
1923

20-
/* Scrub the realtime summary. */
24+
/*
25+
* Realtime Summary
26+
* ================
27+
*
28+
* We check the realtime summary by scanning the realtime bitmap file to create
29+
* a new summary file incore, and then we compare the computed version against
30+
* the ondisk version. We use the 'xfile' functionality to store this
31+
* (potentially large) amount of data in pageable memory.
32+
*/
33+
34+
/* Set us up to check the rtsummary file. */
2135
int
22-
xchk_rtsummary(
36+
xchk_setup_rtsummary(
2337
struct xfs_scrub *sc)
2438
{
25-
struct xfs_inode *rsumip = sc->mp->m_rsumip;
26-
struct xfs_inode *old_ip = sc->ip;
27-
uint old_ilock_flags = sc->ilock_flags;
28-
int error = 0;
39+
struct xfs_mount *mp = sc->mp;
40+
char *descr;
41+
int error;
42+
43+
/*
44+
* Create an xfile to construct a new rtsummary file. The xfile allows
45+
* us to avoid pinning kernel memory for this purpose.
46+
*/
47+
descr = xchk_xfile_descr(sc, "realtime summary file");
48+
error = xfile_create(descr, mp->m_rsumsize, &sc->xfile);
49+
kfree(descr);
50+
if (error)
51+
return error;
52+
53+
error = xchk_trans_alloc(sc, 0);
54+
if (error)
55+
return error;
56+
57+
/* Allocate a memory buffer for the summary comparison. */
58+
sc->buf = kvmalloc(mp->m_sb.sb_blocksize, XCHK_GFP_FLAGS);
59+
if (!sc->buf)
60+
return -ENOMEM;
61+
62+
error = xchk_install_live_inode(sc, mp->m_rsumip);
63+
if (error)
64+
return error;
2965

3066
/*
31-
* We ILOCK'd the rt bitmap ip in the setup routine, now lock the
32-
* rt summary ip in compliance with the rt inode locking rules.
33-
*
34-
* Since we switch sc->ip to rsumip we have to save the old ilock
35-
* flags so that we don't mix up the inode state that @sc tracks.
67+
* Locking order requires us to take the rtbitmap first. We must be
68+
* careful to unlock it ourselves when we are done with the rtbitmap
69+
* file since the scrub infrastructure won't do that for us. Only
70+
* then we can lock the rtsummary inode.
3671
*/
37-
sc->ip = rsumip;
38-
sc->ilock_flags = 0;
72+
xfs_ilock(mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
3973
xchk_ilock(sc, XFS_ILOCK_EXCL | XFS_ILOCK_RTSUM);
74+
return 0;
75+
}
76+
77+
/* Helper functions to record suminfo words in an xfile. */
78+
79+
typedef unsigned int xchk_rtsumoff_t;
80+
81+
static inline int
82+
xfsum_load(
83+
struct xfs_scrub *sc,
84+
xchk_rtsumoff_t sumoff,
85+
xfs_suminfo_t *info)
86+
{
87+
return xfile_obj_load(sc->xfile, info, sizeof(xfs_suminfo_t),
88+
sumoff << XFS_WORDLOG);
89+
}
90+
91+
static inline int
92+
xfsum_store(
93+
struct xfs_scrub *sc,
94+
xchk_rtsumoff_t sumoff,
95+
const xfs_suminfo_t info)
96+
{
97+
return xfile_obj_store(sc->xfile, &info, sizeof(xfs_suminfo_t),
98+
sumoff << XFS_WORDLOG);
99+
}
100+
101+
static inline int
102+
xfsum_copyout(
103+
struct xfs_scrub *sc,
104+
xchk_rtsumoff_t sumoff,
105+
xfs_suminfo_t *info,
106+
unsigned int nr_words)
107+
{
108+
return xfile_obj_load(sc->xfile, info, nr_words << XFS_WORDLOG,
109+
sumoff << XFS_WORDLOG);
110+
}
111+
112+
/* Update the summary file to reflect the free extent that we've accumulated. */
113+
STATIC int
114+
xchk_rtsum_record_free(
115+
struct xfs_mount *mp,
116+
struct xfs_trans *tp,
117+
const struct xfs_rtalloc_rec *rec,
118+
void *priv)
119+
{
120+
struct xfs_scrub *sc = priv;
121+
xfs_fileoff_t rbmoff;
122+
xfs_rtblock_t rtbno;
123+
xfs_filblks_t rtlen;
124+
xchk_rtsumoff_t offs;
125+
unsigned int lenlog;
126+
xfs_suminfo_t v = 0;
127+
int error = 0;
128+
129+
if (xchk_should_terminate(sc, &error))
130+
return error;
131+
132+
/* Compute the relevant location in the rtsum file. */
133+
rbmoff = XFS_BITTOBLOCK(mp, rec->ar_startext);
134+
lenlog = XFS_RTBLOCKLOG(rec->ar_extcount);
135+
offs = XFS_SUMOFFS(mp, lenlog, rbmoff);
136+
137+
rtbno = rec->ar_startext * mp->m_sb.sb_rextsize;
138+
rtlen = rec->ar_extcount * mp->m_sb.sb_rextsize;
139+
140+
if (!xfs_verify_rtext(mp, rtbno, rtlen)) {
141+
xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);
142+
return -EFSCORRUPTED;
143+
}
144+
145+
/* Bump the summary count. */
146+
error = xfsum_load(sc, offs, &v);
147+
if (error)
148+
return error;
149+
150+
v++;
151+
trace_xchk_rtsum_record_free(mp, rec->ar_startext, rec->ar_extcount,
152+
lenlog, offs, v);
153+
154+
return xfsum_store(sc, offs, v);
155+
}
156+
157+
/* Compute the realtime summary from the realtime bitmap. */
158+
STATIC int
159+
xchk_rtsum_compute(
160+
struct xfs_scrub *sc)
161+
{
162+
struct xfs_mount *mp = sc->mp;
163+
unsigned long long rtbmp_bytes;
164+
165+
/* If the bitmap size doesn't match the computed size, bail. */
166+
rtbmp_bytes = howmany_64(mp->m_sb.sb_rextents, NBBY);
167+
if (roundup_64(rtbmp_bytes, mp->m_sb.sb_blocksize) !=
168+
mp->m_rbmip->i_disk_size)
169+
return -EFSCORRUPTED;
170+
171+
return xfs_rtalloc_query_all(sc->mp, sc->tp, xchk_rtsum_record_free,
172+
sc);
173+
}
174+
175+
/* Compare the rtsummary file against the one we computed. */
176+
STATIC int
177+
xchk_rtsum_compare(
178+
struct xfs_scrub *sc)
179+
{
180+
struct xfs_mount *mp = sc->mp;
181+
struct xfs_buf *bp;
182+
struct xfs_bmbt_irec map;
183+
xfs_fileoff_t off;
184+
xchk_rtsumoff_t sumoff = 0;
185+
int nmap;
186+
187+
for (off = 0; off < XFS_B_TO_FSB(mp, mp->m_rsumsize); off++) {
188+
int error = 0;
189+
190+
if (xchk_should_terminate(sc, &error))
191+
return error;
192+
if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
193+
return 0;
194+
195+
/* Make sure we have a written extent. */
196+
nmap = 1;
197+
error = xfs_bmapi_read(mp->m_rsumip, off, 1, &map, &nmap,
198+
XFS_DATA_FORK);
199+
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))
200+
return error;
201+
202+
if (nmap != 1 || !xfs_bmap_is_written_extent(&map)) {
203+
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off);
204+
return 0;
205+
}
206+
207+
/* Read a block's worth of ondisk rtsummary file. */
208+
error = xfs_rtbuf_get(mp, sc->tp, off, 1, &bp);
209+
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, off, &error))
210+
return error;
211+
212+
/* Read a block's worth of computed rtsummary file. */
213+
error = xfsum_copyout(sc, sumoff, sc->buf, mp->m_blockwsize);
214+
if (error) {
215+
xfs_trans_brelse(sc->tp, bp);
216+
return error;
217+
}
218+
219+
if (memcmp(bp->b_addr, sc->buf,
220+
mp->m_blockwsize << XFS_WORDLOG) != 0)
221+
xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, off);
222+
223+
xfs_trans_brelse(sc->tp, bp);
224+
sumoff += mp->m_blockwsize;
225+
}
226+
227+
return 0;
228+
}
229+
230+
/* Scrub the realtime summary. */
231+
int
232+
xchk_rtsummary(
233+
struct xfs_scrub *sc)
234+
{
235+
struct xfs_mount *mp = sc->mp;
236+
int error = 0;
40237

41238
/* Invoke the fork scrubber. */
42239
error = xchk_metadata_inode_forks(sc);
43240
if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
44-
goto out;
45-
46-
/* XXX: implement this some day */
47-
xchk_set_incomplete(sc);
48-
out:
49-
/* Switch back to the rtbitmap inode and lock flags. */
50-
xchk_iunlock(sc, XFS_ILOCK_EXCL | XFS_ILOCK_RTSUM);
51-
sc->ilock_flags = old_ilock_flags;
52-
sc->ip = old_ip;
241+
goto out_rbm;
242+
243+
/* Construct the new summary file from the rtbitmap. */
244+
error = xchk_rtsum_compute(sc);
245+
if (error == -EFSCORRUPTED) {
246+
/*
247+
* EFSCORRUPTED means the rtbitmap is corrupt, which is an xref
248+
* error since we're checking the summary file.
249+
*/
250+
xchk_ino_xref_set_corrupt(sc, mp->m_rbmip->i_ino);
251+
error = 0;
252+
goto out_rbm;
253+
}
254+
if (error)
255+
goto out_rbm;
256+
257+
/* Does the computed summary file match the actual rtsummary file? */
258+
error = xchk_rtsum_compare(sc);
259+
260+
out_rbm:
261+
/* Unlock the rtbitmap since we're done with it. */
262+
xfs_iunlock(mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
53263
return error;
54264
}

fs/xfs/scrub/scrub.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "scrub/repair.h"
2424
#include "scrub/health.h"
2525
#include "scrub/stats.h"
26+
#include "scrub/xfile.h"
2627

2728
/*
2829
* Online Scrub and Repair
@@ -183,6 +184,10 @@ xchk_teardown(
183184
}
184185
if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)
185186
mnt_drop_write_file(sc->file);
187+
if (sc->xfile) {
188+
xfile_destroy(sc->xfile);
189+
sc->xfile = NULL;
190+
}
186191
if (sc->buf) {
187192
if (sc->buf_cleanup)
188193
sc->buf_cleanup(sc->buf);
@@ -317,14 +322,14 @@ static const struct xchk_meta_ops meta_scrub_ops[] = {
317322
},
318323
[XFS_SCRUB_TYPE_RTBITMAP] = { /* realtime bitmap */
319324
.type = ST_FS,
320-
.setup = xchk_setup_rt,
325+
.setup = xchk_setup_rtbitmap,
321326
.scrub = xchk_rtbitmap,
322327
.has = xfs_has_realtime,
323328
.repair = xrep_notsupported,
324329
},
325330
[XFS_SCRUB_TYPE_RTSUM] = { /* realtime summary */
326331
.type = ST_FS,
327-
.setup = xchk_setup_rt,
332+
.setup = xchk_setup_rtsummary,
328333
.scrub = xchk_rtsummary,
329334
.has = xfs_has_realtime,
330335
.repair = xrep_notsupported,

fs/xfs/scrub/scrub.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ struct xfs_scrub {
8888
*/
8989
void (*buf_cleanup)(void *buf);
9090

91+
/* xfile used by the scrubbers; freed at teardown. */
92+
struct xfile *xfile;
93+
94+
/* Lock flags for @ip. */
9195
uint ilock_flags;
9296

9397
/* See the XCHK/XREP state flags below. */

0 commit comments

Comments
 (0)