xref: /linux/fs/xfs/scrub/cow_repair.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
1dbbdbd00SDarrick J. Wong // SPDX-License-Identifier: GPL-2.0-or-later
2dbbdbd00SDarrick J. Wong /*
3dbbdbd00SDarrick J. Wong  * Copyright (C) 2022-2023 Oracle.  All Rights Reserved.
4dbbdbd00SDarrick J. Wong  * Author: Darrick J. Wong <djwong@kernel.org>
5dbbdbd00SDarrick J. Wong  */
6dbbdbd00SDarrick J. Wong #include "xfs.h"
7dbbdbd00SDarrick J. Wong #include "xfs_fs.h"
8dbbdbd00SDarrick J. Wong #include "xfs_shared.h"
9dbbdbd00SDarrick J. Wong #include "xfs_format.h"
10dbbdbd00SDarrick J. Wong #include "xfs_trans_resv.h"
11dbbdbd00SDarrick J. Wong #include "xfs_mount.h"
12dbbdbd00SDarrick J. Wong #include "xfs_defer.h"
13dbbdbd00SDarrick J. Wong #include "xfs_btree.h"
14dbbdbd00SDarrick J. Wong #include "xfs_log_format.h"
15dbbdbd00SDarrick J. Wong #include "xfs_trans.h"
16dbbdbd00SDarrick J. Wong #include "xfs_inode.h"
17dbbdbd00SDarrick J. Wong #include "xfs_inode_fork.h"
18dbbdbd00SDarrick J. Wong #include "xfs_alloc.h"
19dbbdbd00SDarrick J. Wong #include "xfs_bmap.h"
20dbbdbd00SDarrick J. Wong #include "xfs_rmap.h"
21dbbdbd00SDarrick J. Wong #include "xfs_refcount.h"
22dbbdbd00SDarrick J. Wong #include "xfs_quota.h"
23dbbdbd00SDarrick J. Wong #include "xfs_ialloc.h"
24dbbdbd00SDarrick J. Wong #include "xfs_ag.h"
25dbbdbd00SDarrick J. Wong #include "xfs_error.h"
26dbbdbd00SDarrick J. Wong #include "xfs_errortag.h"
27dbbdbd00SDarrick J. Wong #include "xfs_icache.h"
28dbbdbd00SDarrick J. Wong #include "xfs_refcount_btree.h"
29dbbdbd00SDarrick J. Wong #include "scrub/xfs_scrub.h"
30dbbdbd00SDarrick J. Wong #include "scrub/scrub.h"
31dbbdbd00SDarrick J. Wong #include "scrub/common.h"
32dbbdbd00SDarrick J. Wong #include "scrub/trace.h"
33dbbdbd00SDarrick J. Wong #include "scrub/repair.h"
34dbbdbd00SDarrick J. Wong #include "scrub/bitmap.h"
35dbbdbd00SDarrick J. Wong #include "scrub/off_bitmap.h"
36dbbdbd00SDarrick J. Wong #include "scrub/fsb_bitmap.h"
37dbbdbd00SDarrick J. Wong #include "scrub/reap.h"
38dbbdbd00SDarrick J. Wong 
39dbbdbd00SDarrick J. Wong /*
40dbbdbd00SDarrick J. Wong  * CoW Fork Mapping Repair
41dbbdbd00SDarrick J. Wong  * =======================
42dbbdbd00SDarrick J. Wong  *
43dbbdbd00SDarrick J. Wong  * Although CoW staging extents are owned by incore CoW inode forks, on disk
44dbbdbd00SDarrick J. Wong  * they are owned by the refcount btree.  The ondisk metadata does not record
45dbbdbd00SDarrick J. Wong  * any ownership information, which limits what we can do to repair the
46dbbdbd00SDarrick J. Wong  * mappings in the CoW fork.  At most, we can replace ifork mappings that lack
47dbbdbd00SDarrick J. Wong  * an entry in the refcount btree or are described by a reverse mapping record
48dbbdbd00SDarrick J. Wong  * whose owner is not OWN_COW.
49dbbdbd00SDarrick J. Wong  *
50dbbdbd00SDarrick J. Wong  * Replacing extents is also tricky -- we can't touch written CoW fork extents
51dbbdbd00SDarrick J. Wong  * since they are undergoing writeback, and delalloc extents do not require
52dbbdbd00SDarrick J. Wong  * repair since they only exist incore.  Hence the most we can do is find the
53dbbdbd00SDarrick J. Wong  * bad parts of unwritten mappings, allocate a replacement set of blocks, and
54dbbdbd00SDarrick J. Wong  * replace the incore mapping.  We use the regular reaping process to unmap
55dbbdbd00SDarrick J. Wong  * or free the discarded blocks, as appropriate.
56dbbdbd00SDarrick J. Wong  */
57dbbdbd00SDarrick J. Wong struct xrep_cow {
58dbbdbd00SDarrick J. Wong 	struct xfs_scrub	*sc;
59dbbdbd00SDarrick J. Wong 
60dbbdbd00SDarrick J. Wong 	/* Bitmap of file offset ranges that need replacing. */
61dbbdbd00SDarrick J. Wong 	struct xoff_bitmap	bad_fileoffs;
62dbbdbd00SDarrick J. Wong 
63dbbdbd00SDarrick J. Wong 	/* Bitmap of fsblocks that were removed from the CoW fork. */
64dbbdbd00SDarrick J. Wong 	struct xfsb_bitmap	old_cowfork_fsblocks;
65dbbdbd00SDarrick J. Wong 
66dbbdbd00SDarrick J. Wong 	/* CoW fork mappings used to scan for bad CoW staging extents. */
67dbbdbd00SDarrick J. Wong 	struct xfs_bmbt_irec	irec;
68dbbdbd00SDarrick J. Wong 
69dbbdbd00SDarrick J. Wong 	/* refcount btree block number of irec.br_startblock */
70dbbdbd00SDarrick J. Wong 	unsigned int		irec_startbno;
71dbbdbd00SDarrick J. Wong 
72dbbdbd00SDarrick J. Wong 	/* refcount btree block number of the next refcount record we expect */
73dbbdbd00SDarrick J. Wong 	unsigned int		next_bno;
74dbbdbd00SDarrick J. Wong };
75dbbdbd00SDarrick J. Wong 
76dbbdbd00SDarrick J. Wong /* CoW staging extent. */
77dbbdbd00SDarrick J. Wong struct xrep_cow_extent {
78dbbdbd00SDarrick J. Wong 	xfs_fsblock_t		fsbno;
79dbbdbd00SDarrick J. Wong 	xfs_extlen_t		len;
80dbbdbd00SDarrick J. Wong };
81dbbdbd00SDarrick J. Wong 
82dbbdbd00SDarrick J. Wong /*
83dbbdbd00SDarrick J. Wong  * Mark the part of the file range that corresponds to the given physical
84dbbdbd00SDarrick J. Wong  * space.  Caller must ensure that the physical range is within xc->irec.
85dbbdbd00SDarrick J. Wong  */
86dbbdbd00SDarrick J. Wong STATIC int
xrep_cow_mark_file_range(struct xrep_cow * xc,xfs_fsblock_t startblock,xfs_filblks_t blockcount)87dbbdbd00SDarrick J. Wong xrep_cow_mark_file_range(
88dbbdbd00SDarrick J. Wong 	struct xrep_cow		*xc,
89dbbdbd00SDarrick J. Wong 	xfs_fsblock_t		startblock,
90dbbdbd00SDarrick J. Wong 	xfs_filblks_t		blockcount)
91dbbdbd00SDarrick J. Wong {
92dbbdbd00SDarrick J. Wong 	xfs_fileoff_t		startoff;
93dbbdbd00SDarrick J. Wong 
94dbbdbd00SDarrick J. Wong 	startoff = xc->irec.br_startoff +
95dbbdbd00SDarrick J. Wong 				(startblock - xc->irec.br_startblock);
96dbbdbd00SDarrick J. Wong 
97dbbdbd00SDarrick J. Wong 	trace_xrep_cow_mark_file_range(xc->sc->ip, startblock, startoff,
98dbbdbd00SDarrick J. Wong 			blockcount);
99dbbdbd00SDarrick J. Wong 
100dbbdbd00SDarrick J. Wong 	return xoff_bitmap_set(&xc->bad_fileoffs, startoff, blockcount);
101dbbdbd00SDarrick J. Wong }
102dbbdbd00SDarrick J. Wong 
103dbbdbd00SDarrick J. Wong /*
104dbbdbd00SDarrick J. Wong  * Trim @src to fit within the CoW fork mapping being examined, and put the
105dbbdbd00SDarrick J. Wong  * result in @dst.
106dbbdbd00SDarrick J. Wong  */
107dbbdbd00SDarrick J. Wong static inline void
xrep_cow_trim_refcount(struct xrep_cow * xc,struct xfs_refcount_irec * dst,const struct xfs_refcount_irec * src)108dbbdbd00SDarrick J. Wong xrep_cow_trim_refcount(
109dbbdbd00SDarrick J. Wong 	struct xrep_cow			*xc,
110dbbdbd00SDarrick J. Wong 	struct xfs_refcount_irec	*dst,
111dbbdbd00SDarrick J. Wong 	const struct xfs_refcount_irec	*src)
112dbbdbd00SDarrick J. Wong {
113dbbdbd00SDarrick J. Wong 	unsigned int			adj;
114dbbdbd00SDarrick J. Wong 
115dbbdbd00SDarrick J. Wong 	memcpy(dst, src, sizeof(*dst));
116dbbdbd00SDarrick J. Wong 
117dbbdbd00SDarrick J. Wong 	if (dst->rc_startblock < xc->irec_startbno) {
118dbbdbd00SDarrick J. Wong 		adj = xc->irec_startbno - dst->rc_startblock;
119dbbdbd00SDarrick J. Wong 		dst->rc_blockcount -= adj;
120dbbdbd00SDarrick J. Wong 		dst->rc_startblock += adj;
121dbbdbd00SDarrick J. Wong 	}
122dbbdbd00SDarrick J. Wong 
123dbbdbd00SDarrick J. Wong 	if (dst->rc_startblock + dst->rc_blockcount >
124dbbdbd00SDarrick J. Wong 	    xc->irec_startbno + xc->irec.br_blockcount) {
125dbbdbd00SDarrick J. Wong 		adj = (dst->rc_startblock + dst->rc_blockcount) -
126dbbdbd00SDarrick J. Wong 		      (xc->irec_startbno + xc->irec.br_blockcount);
127dbbdbd00SDarrick J. Wong 		dst->rc_blockcount -= adj;
128dbbdbd00SDarrick J. Wong 	}
129dbbdbd00SDarrick J. Wong }
130dbbdbd00SDarrick J. Wong 
131dbbdbd00SDarrick J. Wong /* Mark any shared CoW staging extents. */
132dbbdbd00SDarrick J. Wong STATIC int
xrep_cow_mark_shared_staging(struct xfs_btree_cur * cur,const struct xfs_refcount_irec * rec,void * priv)133dbbdbd00SDarrick J. Wong xrep_cow_mark_shared_staging(
134dbbdbd00SDarrick J. Wong 	struct xfs_btree_cur		*cur,
135dbbdbd00SDarrick J. Wong 	const struct xfs_refcount_irec	*rec,
136dbbdbd00SDarrick J. Wong 	void				*priv)
137dbbdbd00SDarrick J. Wong {
138dbbdbd00SDarrick J. Wong 	struct xrep_cow			*xc = priv;
139dbbdbd00SDarrick J. Wong 	struct xfs_refcount_irec	rrec;
140dbbdbd00SDarrick J. Wong 	xfs_fsblock_t			fsbno;
141dbbdbd00SDarrick J. Wong 
142dbbdbd00SDarrick J. Wong 	if (!xfs_refcount_check_domain(rec) ||
143dbbdbd00SDarrick J. Wong 	    rec->rc_domain != XFS_REFC_DOMAIN_SHARED)
144dbbdbd00SDarrick J. Wong 		return -EFSCORRUPTED;
145dbbdbd00SDarrick J. Wong 
146dbbdbd00SDarrick J. Wong 	xrep_cow_trim_refcount(xc, &rrec, rec);
147dbbdbd00SDarrick J. Wong 
148dbbdbd00SDarrick J. Wong 	fsbno = XFS_AGB_TO_FSB(xc->sc->mp, cur->bc_ag.pag->pag_agno,
149dbbdbd00SDarrick J. Wong 			rrec.rc_startblock);
150dbbdbd00SDarrick J. Wong 	return xrep_cow_mark_file_range(xc, fsbno, rrec.rc_blockcount);
151dbbdbd00SDarrick J. Wong }
152dbbdbd00SDarrick J. Wong 
153dbbdbd00SDarrick J. Wong /*
154dbbdbd00SDarrick J. Wong  * Mark any portion of the CoW fork file offset range where there is not a CoW
155dbbdbd00SDarrick J. Wong  * staging extent record in the refcountbt, and keep a record of where we did
156dbbdbd00SDarrick J. Wong  * find correct refcountbt records.  Staging records are always cleaned out at
157dbbdbd00SDarrick J. Wong  * mount time, so any two inodes trying to map the same staging area would have
158dbbdbd00SDarrick J. Wong  * already taken the fs down due to refcount btree verifier errors.  Hence this
159dbbdbd00SDarrick J. Wong  * inode should be the sole creator of the staging extent records ondisk.
160dbbdbd00SDarrick J. Wong  */
161dbbdbd00SDarrick J. Wong STATIC int
xrep_cow_mark_missing_staging(struct xfs_btree_cur * cur,const struct xfs_refcount_irec * rec,void * priv)162dbbdbd00SDarrick J. Wong xrep_cow_mark_missing_staging(
163dbbdbd00SDarrick J. Wong 	struct xfs_btree_cur		*cur,
164dbbdbd00SDarrick J. Wong 	const struct xfs_refcount_irec	*rec,
165dbbdbd00SDarrick J. Wong 	void				*priv)
166dbbdbd00SDarrick J. Wong {
167dbbdbd00SDarrick J. Wong 	struct xrep_cow			*xc = priv;
168dbbdbd00SDarrick J. Wong 	struct xfs_refcount_irec	rrec;
169dbbdbd00SDarrick J. Wong 	int				error;
170dbbdbd00SDarrick J. Wong 
171dbbdbd00SDarrick J. Wong 	if (!xfs_refcount_check_domain(rec) ||
172dbbdbd00SDarrick J. Wong 	    rec->rc_domain != XFS_REFC_DOMAIN_COW)
173dbbdbd00SDarrick J. Wong 		return -EFSCORRUPTED;
174dbbdbd00SDarrick J. Wong 
175dbbdbd00SDarrick J. Wong 	xrep_cow_trim_refcount(xc, &rrec, rec);
176dbbdbd00SDarrick J. Wong 
177dbbdbd00SDarrick J. Wong 	if (xc->next_bno >= rrec.rc_startblock)
178dbbdbd00SDarrick J. Wong 		goto next;
179dbbdbd00SDarrick J. Wong 
180dbbdbd00SDarrick J. Wong 	error = xrep_cow_mark_file_range(xc,
181dbbdbd00SDarrick J. Wong 			XFS_AGB_TO_FSB(xc->sc->mp, cur->bc_ag.pag->pag_agno,
182dbbdbd00SDarrick J. Wong 				       xc->next_bno),
183dbbdbd00SDarrick J. Wong 			rrec.rc_startblock - xc->next_bno);
184dbbdbd00SDarrick J. Wong 	if (error)
185dbbdbd00SDarrick J. Wong 		return error;
186dbbdbd00SDarrick J. Wong 
187dbbdbd00SDarrick J. Wong next:
188dbbdbd00SDarrick J. Wong 	xc->next_bno = rrec.rc_startblock + rrec.rc_blockcount;
189dbbdbd00SDarrick J. Wong 	return 0;
190dbbdbd00SDarrick J. Wong }
191dbbdbd00SDarrick J. Wong 
192dbbdbd00SDarrick J. Wong /*
193dbbdbd00SDarrick J. Wong  * Mark any area that does not correspond to a CoW staging rmap.  These are
194dbbdbd00SDarrick J. Wong  * cross-linked areas that must be avoided.
195dbbdbd00SDarrick J. Wong  */
196dbbdbd00SDarrick J. Wong STATIC int
xrep_cow_mark_missing_staging_rmap(struct xfs_btree_cur * cur,const struct xfs_rmap_irec * rec,void * priv)197dbbdbd00SDarrick J. Wong xrep_cow_mark_missing_staging_rmap(
198dbbdbd00SDarrick J. Wong 	struct xfs_btree_cur		*cur,
199dbbdbd00SDarrick J. Wong 	const struct xfs_rmap_irec	*rec,
200dbbdbd00SDarrick J. Wong 	void				*priv)
201dbbdbd00SDarrick J. Wong {
202dbbdbd00SDarrick J. Wong 	struct xrep_cow			*xc = priv;
203dbbdbd00SDarrick J. Wong 	xfs_fsblock_t			fsbno;
204dbbdbd00SDarrick J. Wong 	xfs_agblock_t			rec_bno;
205dbbdbd00SDarrick J. Wong 	xfs_extlen_t			rec_len;
206dbbdbd00SDarrick J. Wong 	unsigned int			adj;
207dbbdbd00SDarrick J. Wong 
208dbbdbd00SDarrick J. Wong 	if (rec->rm_owner == XFS_RMAP_OWN_COW)
209dbbdbd00SDarrick J. Wong 		return 0;
210dbbdbd00SDarrick J. Wong 
211dbbdbd00SDarrick J. Wong 	rec_bno = rec->rm_startblock;
212dbbdbd00SDarrick J. Wong 	rec_len = rec->rm_blockcount;
213dbbdbd00SDarrick J. Wong 	if (rec_bno < xc->irec_startbno) {
214dbbdbd00SDarrick J. Wong 		adj = xc->irec_startbno - rec_bno;
215dbbdbd00SDarrick J. Wong 		rec_len -= adj;
216dbbdbd00SDarrick J. Wong 		rec_bno += adj;
217dbbdbd00SDarrick J. Wong 	}
218dbbdbd00SDarrick J. Wong 
219dbbdbd00SDarrick J. Wong 	if (rec_bno + rec_len > xc->irec_startbno + xc->irec.br_blockcount) {
220dbbdbd00SDarrick J. Wong 		adj = (rec_bno + rec_len) -
221dbbdbd00SDarrick J. Wong 		      (xc->irec_startbno + xc->irec.br_blockcount);
222dbbdbd00SDarrick J. Wong 		rec_len -= adj;
223dbbdbd00SDarrick J. Wong 	}
224dbbdbd00SDarrick J. Wong 
225dbbdbd00SDarrick J. Wong 	fsbno = XFS_AGB_TO_FSB(xc->sc->mp, cur->bc_ag.pag->pag_agno, rec_bno);
226dbbdbd00SDarrick J. Wong 	return xrep_cow_mark_file_range(xc, fsbno, rec_len);
227dbbdbd00SDarrick J. Wong }
228dbbdbd00SDarrick J. Wong 
229dbbdbd00SDarrick J. Wong /*
230dbbdbd00SDarrick J. Wong  * Find any part of the CoW fork mapping that isn't a single-owner CoW staging
231dbbdbd00SDarrick J. Wong  * extent and mark the corresponding part of the file range in the bitmap.
232dbbdbd00SDarrick J. Wong  */
233dbbdbd00SDarrick J. Wong STATIC int
xrep_cow_find_bad(struct xrep_cow * xc)234dbbdbd00SDarrick J. Wong xrep_cow_find_bad(
235dbbdbd00SDarrick J. Wong 	struct xrep_cow			*xc)
236dbbdbd00SDarrick J. Wong {
237dbbdbd00SDarrick J. Wong 	struct xfs_refcount_irec	rc_low = { 0 };
238dbbdbd00SDarrick J. Wong 	struct xfs_refcount_irec	rc_high = { 0 };
239dbbdbd00SDarrick J. Wong 	struct xfs_rmap_irec		rm_low = { 0 };
240dbbdbd00SDarrick J. Wong 	struct xfs_rmap_irec		rm_high = { 0 };
241dbbdbd00SDarrick J. Wong 	struct xfs_perag		*pag;
242dbbdbd00SDarrick J. Wong 	struct xfs_scrub		*sc = xc->sc;
243dbbdbd00SDarrick J. Wong 	xfs_agnumber_t			agno;
244dbbdbd00SDarrick J. Wong 	int				error;
245dbbdbd00SDarrick J. Wong 
246dbbdbd00SDarrick J. Wong 	agno = XFS_FSB_TO_AGNO(sc->mp, xc->irec.br_startblock);
247dbbdbd00SDarrick J. Wong 	xc->irec_startbno = XFS_FSB_TO_AGBNO(sc->mp, xc->irec.br_startblock);
248dbbdbd00SDarrick J. Wong 
249dbbdbd00SDarrick J. Wong 	pag = xfs_perag_get(sc->mp, agno);
250dbbdbd00SDarrick J. Wong 	if (!pag)
251dbbdbd00SDarrick J. Wong 		return -EFSCORRUPTED;
252dbbdbd00SDarrick J. Wong 
253dbbdbd00SDarrick J. Wong 	error = xrep_ag_init(sc, pag, &sc->sa);
254dbbdbd00SDarrick J. Wong 	if (error)
255dbbdbd00SDarrick J. Wong 		goto out_pag;
256dbbdbd00SDarrick J. Wong 
257dbbdbd00SDarrick J. Wong 	/* Mark any CoW fork extents that are shared. */
258dbbdbd00SDarrick J. Wong 	rc_low.rc_startblock = xc->irec_startbno;
259dbbdbd00SDarrick J. Wong 	rc_high.rc_startblock = xc->irec_startbno + xc->irec.br_blockcount - 1;
260dbbdbd00SDarrick J. Wong 	rc_low.rc_domain = rc_high.rc_domain = XFS_REFC_DOMAIN_SHARED;
261dbbdbd00SDarrick J. Wong 	error = xfs_refcount_query_range(sc->sa.refc_cur, &rc_low, &rc_high,
262dbbdbd00SDarrick J. Wong 			xrep_cow_mark_shared_staging, xc);
263dbbdbd00SDarrick J. Wong 	if (error)
264dbbdbd00SDarrick J. Wong 		goto out_sa;
265dbbdbd00SDarrick J. Wong 
266dbbdbd00SDarrick J. Wong 	/* Make sure there are CoW staging extents for the whole mapping. */
267dbbdbd00SDarrick J. Wong 	rc_low.rc_startblock = xc->irec_startbno;
268dbbdbd00SDarrick J. Wong 	rc_high.rc_startblock = xc->irec_startbno + xc->irec.br_blockcount - 1;
269dbbdbd00SDarrick J. Wong 	rc_low.rc_domain = rc_high.rc_domain = XFS_REFC_DOMAIN_COW;
270dbbdbd00SDarrick J. Wong 	xc->next_bno = xc->irec_startbno;
271dbbdbd00SDarrick J. Wong 	error = xfs_refcount_query_range(sc->sa.refc_cur, &rc_low, &rc_high,
272dbbdbd00SDarrick J. Wong 			xrep_cow_mark_missing_staging, xc);
273dbbdbd00SDarrick J. Wong 	if (error)
274dbbdbd00SDarrick J. Wong 		goto out_sa;
275dbbdbd00SDarrick J. Wong 
276dbbdbd00SDarrick J. Wong 	if (xc->next_bno < xc->irec_startbno + xc->irec.br_blockcount) {
277dbbdbd00SDarrick J. Wong 		error = xrep_cow_mark_file_range(xc,
278dbbdbd00SDarrick J. Wong 				XFS_AGB_TO_FSB(sc->mp, pag->pag_agno,
279dbbdbd00SDarrick J. Wong 					       xc->next_bno),
280dbbdbd00SDarrick J. Wong 				xc->irec_startbno + xc->irec.br_blockcount -
281dbbdbd00SDarrick J. Wong 				xc->next_bno);
282dbbdbd00SDarrick J. Wong 		if (error)
283dbbdbd00SDarrick J. Wong 			goto out_sa;
284dbbdbd00SDarrick J. Wong 	}
285dbbdbd00SDarrick J. Wong 
286dbbdbd00SDarrick J. Wong 	/* Mark any area has an rmap that isn't a COW staging extent. */
287dbbdbd00SDarrick J. Wong 	rm_low.rm_startblock = xc->irec_startbno;
288dbbdbd00SDarrick J. Wong 	memset(&rm_high, 0xFF, sizeof(rm_high));
289dbbdbd00SDarrick J. Wong 	rm_high.rm_startblock = xc->irec_startbno + xc->irec.br_blockcount - 1;
290dbbdbd00SDarrick J. Wong 	error = xfs_rmap_query_range(sc->sa.rmap_cur, &rm_low, &rm_high,
291dbbdbd00SDarrick J. Wong 			xrep_cow_mark_missing_staging_rmap, xc);
292dbbdbd00SDarrick J. Wong 	if (error)
293dbbdbd00SDarrick J. Wong 		goto out_sa;
294dbbdbd00SDarrick J. Wong 
295dbbdbd00SDarrick J. Wong 	/*
296dbbdbd00SDarrick J. Wong 	 * If userspace is forcing us to rebuild the CoW fork or someone turned
297dbbdbd00SDarrick J. Wong 	 * on the debugging knob, replace everything in the CoW fork.
298dbbdbd00SDarrick J. Wong 	 */
299dbbdbd00SDarrick J. Wong 	if ((sc->sm->sm_flags & XFS_SCRUB_IFLAG_FORCE_REBUILD) ||
300dbbdbd00SDarrick J. Wong 	    XFS_TEST_ERROR(false, sc->mp, XFS_ERRTAG_FORCE_SCRUB_REPAIR)) {
301dbbdbd00SDarrick J. Wong 		error = xrep_cow_mark_file_range(xc, xc->irec.br_startblock,
302dbbdbd00SDarrick J. Wong 				xc->irec.br_blockcount);
303dbbdbd00SDarrick J. Wong 		if (error)
304dbbdbd00SDarrick J. Wong 			return error;
305dbbdbd00SDarrick J. Wong 	}
306dbbdbd00SDarrick J. Wong 
307dbbdbd00SDarrick J. Wong out_sa:
308dbbdbd00SDarrick J. Wong 	xchk_ag_free(sc, &sc->sa);
309dbbdbd00SDarrick J. Wong out_pag:
310dbbdbd00SDarrick J. Wong 	xfs_perag_put(pag);
311dbbdbd00SDarrick J. Wong 	return 0;
312dbbdbd00SDarrick J. Wong }
313dbbdbd00SDarrick J. Wong 
314dbbdbd00SDarrick J. Wong /*
315dbbdbd00SDarrick J. Wong  * Allocate a replacement CoW staging extent of up to the given number of
316dbbdbd00SDarrick J. Wong  * blocks, and fill out the mapping.
317dbbdbd00SDarrick J. Wong  */
318dbbdbd00SDarrick J. Wong STATIC int
xrep_cow_alloc(struct xfs_scrub * sc,xfs_extlen_t maxlen,struct xrep_cow_extent * repl)319dbbdbd00SDarrick J. Wong xrep_cow_alloc(
320dbbdbd00SDarrick J. Wong 	struct xfs_scrub	*sc,
321dbbdbd00SDarrick J. Wong 	xfs_extlen_t		maxlen,
322dbbdbd00SDarrick J. Wong 	struct xrep_cow_extent	*repl)
323dbbdbd00SDarrick J. Wong {
324dbbdbd00SDarrick J. Wong 	struct xfs_alloc_arg	args = {
325dbbdbd00SDarrick J. Wong 		.tp		= sc->tp,
326dbbdbd00SDarrick J. Wong 		.mp		= sc->mp,
327dbbdbd00SDarrick J. Wong 		.oinfo		= XFS_RMAP_OINFO_SKIP_UPDATE,
328dbbdbd00SDarrick J. Wong 		.minlen		= 1,
329dbbdbd00SDarrick J. Wong 		.maxlen		= maxlen,
330dbbdbd00SDarrick J. Wong 		.prod		= 1,
331dbbdbd00SDarrick J. Wong 		.resv		= XFS_AG_RESV_NONE,
332dbbdbd00SDarrick J. Wong 		.datatype	= XFS_ALLOC_USERDATA,
333dbbdbd00SDarrick J. Wong 	};
334dbbdbd00SDarrick J. Wong 	int			error;
335dbbdbd00SDarrick J. Wong 
336dbbdbd00SDarrick J. Wong 	error = xfs_trans_reserve_more(sc->tp, maxlen, 0);
337dbbdbd00SDarrick J. Wong 	if (error)
338dbbdbd00SDarrick J. Wong 		return error;
339dbbdbd00SDarrick J. Wong 
340dbbdbd00SDarrick J. Wong 	error = xfs_alloc_vextent_start_ag(&args,
341dbbdbd00SDarrick J. Wong 			XFS_INO_TO_FSB(sc->mp, sc->ip->i_ino));
342dbbdbd00SDarrick J. Wong 	if (error)
343dbbdbd00SDarrick J. Wong 		return error;
344dbbdbd00SDarrick J. Wong 	if (args.fsbno == NULLFSBLOCK)
345dbbdbd00SDarrick J. Wong 		return -ENOSPC;
346dbbdbd00SDarrick J. Wong 
347dbbdbd00SDarrick J. Wong 	xfs_refcount_alloc_cow_extent(sc->tp, args.fsbno, args.len);
348dbbdbd00SDarrick J. Wong 
349dbbdbd00SDarrick J. Wong 	repl->fsbno = args.fsbno;
350dbbdbd00SDarrick J. Wong 	repl->len = args.len;
351dbbdbd00SDarrick J. Wong 	return 0;
352dbbdbd00SDarrick J. Wong }
353dbbdbd00SDarrick J. Wong 
354dbbdbd00SDarrick J. Wong /*
355dbbdbd00SDarrick J. Wong  * Look up the current CoW fork mapping so that we only allocate enough to
356dbbdbd00SDarrick J. Wong  * replace a single mapping.  If we don't find a mapping that covers the start
357dbbdbd00SDarrick J. Wong  * of the file range, or we find a delalloc or written extent, something is
358dbbdbd00SDarrick J. Wong  * seriously wrong, since we didn't drop the ILOCK.
359dbbdbd00SDarrick J. Wong  */
360dbbdbd00SDarrick J. Wong static inline int
xrep_cow_find_mapping(struct xrep_cow * xc,struct xfs_iext_cursor * icur,xfs_fileoff_t startoff,struct xfs_bmbt_irec * got)361dbbdbd00SDarrick J. Wong xrep_cow_find_mapping(
362dbbdbd00SDarrick J. Wong 	struct xrep_cow		*xc,
363dbbdbd00SDarrick J. Wong 	struct xfs_iext_cursor	*icur,
364dbbdbd00SDarrick J. Wong 	xfs_fileoff_t		startoff,
365dbbdbd00SDarrick J. Wong 	struct xfs_bmbt_irec	*got)
366dbbdbd00SDarrick J. Wong {
367dbbdbd00SDarrick J. Wong 	struct xfs_inode	*ip = xc->sc->ip;
368dbbdbd00SDarrick J. Wong 	struct xfs_ifork	*ifp = xfs_ifork_ptr(ip, XFS_COW_FORK);
369dbbdbd00SDarrick J. Wong 
370dbbdbd00SDarrick J. Wong 	if (!xfs_iext_lookup_extent(ip, ifp, startoff, icur, got))
371dbbdbd00SDarrick J. Wong 		goto bad;
372dbbdbd00SDarrick J. Wong 
373dbbdbd00SDarrick J. Wong 	if (got->br_startoff > startoff)
374dbbdbd00SDarrick J. Wong 		goto bad;
375dbbdbd00SDarrick J. Wong 
376dbbdbd00SDarrick J. Wong 	if (got->br_blockcount == 0)
377dbbdbd00SDarrick J. Wong 		goto bad;
378dbbdbd00SDarrick J. Wong 
379dbbdbd00SDarrick J. Wong 	if (isnullstartblock(got->br_startblock))
380dbbdbd00SDarrick J. Wong 		goto bad;
381dbbdbd00SDarrick J. Wong 
382dbbdbd00SDarrick J. Wong 	if (xfs_bmap_is_written_extent(got))
383dbbdbd00SDarrick J. Wong 		goto bad;
384dbbdbd00SDarrick J. Wong 
385dbbdbd00SDarrick J. Wong 	return 0;
386dbbdbd00SDarrick J. Wong bad:
387dbbdbd00SDarrick J. Wong 	ASSERT(0);
388dbbdbd00SDarrick J. Wong 	return -EFSCORRUPTED;
389dbbdbd00SDarrick J. Wong }
390dbbdbd00SDarrick J. Wong 
391dbbdbd00SDarrick J. Wong #define REPLACE_LEFT_SIDE	(1U << 0)
392dbbdbd00SDarrick J. Wong #define REPLACE_RIGHT_SIDE	(1U << 1)
393dbbdbd00SDarrick J. Wong 
394dbbdbd00SDarrick J. Wong /*
395dbbdbd00SDarrick J. Wong  * Given a CoW fork mapping @got and a replacement mapping @repl, remap the
396dbbdbd00SDarrick J. Wong  * beginning of @got with the space described by @rep.
397dbbdbd00SDarrick J. Wong  */
398dbbdbd00SDarrick J. Wong static inline void
xrep_cow_replace_mapping(struct xfs_inode * ip,struct xfs_iext_cursor * icur,const struct xfs_bmbt_irec * got,const struct xrep_cow_extent * repl)399dbbdbd00SDarrick J. Wong xrep_cow_replace_mapping(
400dbbdbd00SDarrick J. Wong 	struct xfs_inode		*ip,
401dbbdbd00SDarrick J. Wong 	struct xfs_iext_cursor		*icur,
402dbbdbd00SDarrick J. Wong 	const struct xfs_bmbt_irec	*got,
403dbbdbd00SDarrick J. Wong 	const struct xrep_cow_extent	*repl)
404dbbdbd00SDarrick J. Wong {
405dbbdbd00SDarrick J. Wong 	struct xfs_bmbt_irec		new = *got; /* struct copy */
406dbbdbd00SDarrick J. Wong 
407dbbdbd00SDarrick J. Wong 	ASSERT(repl->len > 0);
408dbbdbd00SDarrick J. Wong 	ASSERT(!isnullstartblock(got->br_startblock));
409dbbdbd00SDarrick J. Wong 
410dbbdbd00SDarrick J. Wong 	trace_xrep_cow_replace_mapping(ip, got, repl->fsbno, repl->len);
411dbbdbd00SDarrick J. Wong 
412dbbdbd00SDarrick J. Wong 	if (got->br_blockcount == repl->len) {
413dbbdbd00SDarrick J. Wong 		/*
414dbbdbd00SDarrick J. Wong 		 * The new extent is a complete replacement for the existing
415dbbdbd00SDarrick J. Wong 		 * extent.  Update the COW fork record.
416dbbdbd00SDarrick J. Wong 		 */
417dbbdbd00SDarrick J. Wong 		new.br_startblock = repl->fsbno;
418dbbdbd00SDarrick J. Wong 		xfs_iext_update_extent(ip, BMAP_COWFORK, icur, &new);
419dbbdbd00SDarrick J. Wong 		return;
420dbbdbd00SDarrick J. Wong 	}
421dbbdbd00SDarrick J. Wong 
422dbbdbd00SDarrick J. Wong 	/*
423dbbdbd00SDarrick J. Wong 	 * The new extent can replace the beginning of the COW fork record.
424dbbdbd00SDarrick J. Wong 	 * Move the left side of @got upwards, then insert the new record.
425dbbdbd00SDarrick J. Wong 	 */
426dbbdbd00SDarrick J. Wong 	new.br_startoff += repl->len;
427dbbdbd00SDarrick J. Wong 	new.br_startblock += repl->len;
428dbbdbd00SDarrick J. Wong 	new.br_blockcount -= repl->len;
429dbbdbd00SDarrick J. Wong 	xfs_iext_update_extent(ip, BMAP_COWFORK, icur, &new);
430dbbdbd00SDarrick J. Wong 
431dbbdbd00SDarrick J. Wong 	new.br_startoff = got->br_startoff;
432dbbdbd00SDarrick J. Wong 	new.br_startblock = repl->fsbno;
433dbbdbd00SDarrick J. Wong 	new.br_blockcount = repl->len;
434dbbdbd00SDarrick J. Wong 	xfs_iext_insert(ip, icur, &new, BMAP_COWFORK);
435dbbdbd00SDarrick J. Wong }
436dbbdbd00SDarrick J. Wong 
437dbbdbd00SDarrick J. Wong /*
438dbbdbd00SDarrick J. Wong  * Replace the unwritten CoW staging extent backing the given file range with a
439dbbdbd00SDarrick J. Wong  * new space extent that isn't as problematic.
440dbbdbd00SDarrick J. Wong  */
441dbbdbd00SDarrick J. Wong STATIC int
xrep_cow_replace_range(struct xrep_cow * xc,xfs_fileoff_t startoff,xfs_extlen_t * blockcount)442dbbdbd00SDarrick J. Wong xrep_cow_replace_range(
443dbbdbd00SDarrick J. Wong 	struct xrep_cow		*xc,
444dbbdbd00SDarrick J. Wong 	xfs_fileoff_t		startoff,
445dbbdbd00SDarrick J. Wong 	xfs_extlen_t		*blockcount)
446dbbdbd00SDarrick J. Wong {
447dbbdbd00SDarrick J. Wong 	struct xfs_iext_cursor	icur;
448dbbdbd00SDarrick J. Wong 	struct xrep_cow_extent	repl;
449dbbdbd00SDarrick J. Wong 	struct xfs_bmbt_irec	got;
450dbbdbd00SDarrick J. Wong 	struct xfs_scrub	*sc = xc->sc;
451dbbdbd00SDarrick J. Wong 	xfs_fileoff_t		nextoff;
452dbbdbd00SDarrick J. Wong 	xfs_extlen_t		alloc_len;
453dbbdbd00SDarrick J. Wong 	int			error;
454dbbdbd00SDarrick J. Wong 
455dbbdbd00SDarrick J. Wong 	/*
456dbbdbd00SDarrick J. Wong 	 * Put the existing CoW fork mapping in @got.  If @got ends before
457dbbdbd00SDarrick J. Wong 	 * @rep, truncate @rep so we only replace one extent mapping at a time.
458dbbdbd00SDarrick J. Wong 	 */
459dbbdbd00SDarrick J. Wong 	error = xrep_cow_find_mapping(xc, &icur, startoff, &got);
460dbbdbd00SDarrick J. Wong 	if (error)
461dbbdbd00SDarrick J. Wong 		return error;
462dbbdbd00SDarrick J. Wong 	nextoff = min(startoff + *blockcount,
463dbbdbd00SDarrick J. Wong 		      got.br_startoff + got.br_blockcount);
464dbbdbd00SDarrick J. Wong 
465dbbdbd00SDarrick J. Wong 	/*
466dbbdbd00SDarrick J. Wong 	 * Allocate a replacement extent.  If we don't fill all the blocks,
467dbbdbd00SDarrick J. Wong 	 * shorten the quantity that will be deleted in this step.
468dbbdbd00SDarrick J. Wong 	 */
469dbbdbd00SDarrick J. Wong 	alloc_len = min_t(xfs_fileoff_t, XFS_MAX_BMBT_EXTLEN,
470dbbdbd00SDarrick J. Wong 			  nextoff - startoff);
471dbbdbd00SDarrick J. Wong 	error = xrep_cow_alloc(sc, alloc_len, &repl);
472dbbdbd00SDarrick J. Wong 	if (error)
473dbbdbd00SDarrick J. Wong 		return error;
474dbbdbd00SDarrick J. Wong 
475dbbdbd00SDarrick J. Wong 	/*
476dbbdbd00SDarrick J. Wong 	 * Replace the old mapping with the new one, and commit the metadata
477dbbdbd00SDarrick J. Wong 	 * changes made so far.
478dbbdbd00SDarrick J. Wong 	 */
479dbbdbd00SDarrick J. Wong 	xrep_cow_replace_mapping(sc->ip, &icur, &got, &repl);
480dbbdbd00SDarrick J. Wong 
481dbbdbd00SDarrick J. Wong 	xfs_inode_set_cowblocks_tag(sc->ip);
482dbbdbd00SDarrick J. Wong 	error = xfs_defer_finish(&sc->tp);
483dbbdbd00SDarrick J. Wong 	if (error)
484dbbdbd00SDarrick J. Wong 		return error;
485dbbdbd00SDarrick J. Wong 
486dbbdbd00SDarrick J. Wong 	/* Note the old CoW staging extents; we'll reap them all later. */
487dbbdbd00SDarrick J. Wong 	error = xfsb_bitmap_set(&xc->old_cowfork_fsblocks, got.br_startblock,
488dbbdbd00SDarrick J. Wong 			repl.len);
489dbbdbd00SDarrick J. Wong 	if (error)
490dbbdbd00SDarrick J. Wong 		return error;
491dbbdbd00SDarrick J. Wong 
492dbbdbd00SDarrick J. Wong 	*blockcount = repl.len;
493dbbdbd00SDarrick J. Wong 	return 0;
494dbbdbd00SDarrick J. Wong }
495dbbdbd00SDarrick J. Wong 
496dbbdbd00SDarrick J. Wong /*
497dbbdbd00SDarrick J. Wong  * Replace a bad part of an unwritten CoW staging extent with a fresh delalloc
498dbbdbd00SDarrick J. Wong  * reservation.
499dbbdbd00SDarrick J. Wong  */
500dbbdbd00SDarrick J. Wong STATIC int
xrep_cow_replace(uint64_t startoff,uint64_t blockcount,void * priv)501dbbdbd00SDarrick J. Wong xrep_cow_replace(
502dbbdbd00SDarrick J. Wong 	uint64_t		startoff,
503dbbdbd00SDarrick J. Wong 	uint64_t		blockcount,
504dbbdbd00SDarrick J. Wong 	void			*priv)
505dbbdbd00SDarrick J. Wong {
506dbbdbd00SDarrick J. Wong 	struct xrep_cow		*xc = priv;
507dbbdbd00SDarrick J. Wong 	int			error = 0;
508dbbdbd00SDarrick J. Wong 
509dbbdbd00SDarrick J. Wong 	while (blockcount > 0) {
510dbbdbd00SDarrick J. Wong 		xfs_extlen_t	len = min_t(xfs_filblks_t, blockcount,
511dbbdbd00SDarrick J. Wong 					    XFS_MAX_BMBT_EXTLEN);
512dbbdbd00SDarrick J. Wong 
513dbbdbd00SDarrick J. Wong 		error = xrep_cow_replace_range(xc, startoff, &len);
514dbbdbd00SDarrick J. Wong 		if (error)
515dbbdbd00SDarrick J. Wong 			break;
516dbbdbd00SDarrick J. Wong 
517dbbdbd00SDarrick J. Wong 		blockcount -= len;
518dbbdbd00SDarrick J. Wong 		startoff += len;
519dbbdbd00SDarrick J. Wong 	}
520dbbdbd00SDarrick J. Wong 
521dbbdbd00SDarrick J. Wong 	return error;
522dbbdbd00SDarrick J. Wong }
523dbbdbd00SDarrick J. Wong 
524dbbdbd00SDarrick J. Wong /*
525dbbdbd00SDarrick J. Wong  * Repair an inode's CoW fork.  The CoW fork is an in-core structure, so
526dbbdbd00SDarrick J. Wong  * there's no btree to rebuid.  Instead, we replace any mappings that are
527dbbdbd00SDarrick J. Wong  * cross-linked or lack ondisk CoW fork records in the refcount btree.
528dbbdbd00SDarrick J. Wong  */
529dbbdbd00SDarrick J. Wong int
xrep_bmap_cow(struct xfs_scrub * sc)530dbbdbd00SDarrick J. Wong xrep_bmap_cow(
531dbbdbd00SDarrick J. Wong 	struct xfs_scrub	*sc)
532dbbdbd00SDarrick J. Wong {
533dbbdbd00SDarrick J. Wong 	struct xrep_cow		*xc;
534dbbdbd00SDarrick J. Wong 	struct xfs_iext_cursor	icur;
535dbbdbd00SDarrick J. Wong 	struct xfs_ifork	*ifp = xfs_ifork_ptr(sc->ip, XFS_COW_FORK);
536dbbdbd00SDarrick J. Wong 	int			error;
537dbbdbd00SDarrick J. Wong 
538dbbdbd00SDarrick J. Wong 	if (!xfs_has_rmapbt(sc->mp) || !xfs_has_reflink(sc->mp))
539dbbdbd00SDarrick J. Wong 		return -EOPNOTSUPP;
540dbbdbd00SDarrick J. Wong 
541dbbdbd00SDarrick J. Wong 	if (!ifp)
542dbbdbd00SDarrick J. Wong 		return 0;
543dbbdbd00SDarrick J. Wong 
544dbbdbd00SDarrick J. Wong 	/* realtime files aren't supported yet */
545dbbdbd00SDarrick J. Wong 	if (XFS_IS_REALTIME_INODE(sc->ip))
546dbbdbd00SDarrick J. Wong 		return -EOPNOTSUPP;
547dbbdbd00SDarrick J. Wong 
548dbbdbd00SDarrick J. Wong 	/*
549dbbdbd00SDarrick J. Wong 	 * If we're somehow not in extents format, then reinitialize it to
550dbbdbd00SDarrick J. Wong 	 * an empty extent mapping fork and exit.
551dbbdbd00SDarrick J. Wong 	 */
552dbbdbd00SDarrick J. Wong 	if (ifp->if_format != XFS_DINODE_FMT_EXTENTS) {
553dbbdbd00SDarrick J. Wong 		ifp->if_format = XFS_DINODE_FMT_EXTENTS;
554dbbdbd00SDarrick J. Wong 		ifp->if_nextents = 0;
555dbbdbd00SDarrick J. Wong 		return 0;
556dbbdbd00SDarrick J. Wong 	}
557dbbdbd00SDarrick J. Wong 
558dbbdbd00SDarrick J. Wong 	xc = kzalloc(sizeof(struct xrep_cow), XCHK_GFP_FLAGS);
559dbbdbd00SDarrick J. Wong 	if (!xc)
560dbbdbd00SDarrick J. Wong 		return -ENOMEM;
561dbbdbd00SDarrick J. Wong 
562dbbdbd00SDarrick J. Wong 	xfs_trans_ijoin(sc->tp, sc->ip, 0);
563dbbdbd00SDarrick J. Wong 
564dbbdbd00SDarrick J. Wong 	xc->sc = sc;
565dbbdbd00SDarrick J. Wong 	xoff_bitmap_init(&xc->bad_fileoffs);
566dbbdbd00SDarrick J. Wong 	xfsb_bitmap_init(&xc->old_cowfork_fsblocks);
567dbbdbd00SDarrick J. Wong 
568dbbdbd00SDarrick J. Wong 	for_each_xfs_iext(ifp, &icur, &xc->irec) {
569dbbdbd00SDarrick J. Wong 		if (xchk_should_terminate(sc, &error))
570dbbdbd00SDarrick J. Wong 			goto out_bitmap;
571dbbdbd00SDarrick J. Wong 
572dbbdbd00SDarrick J. Wong 		/*
573dbbdbd00SDarrick J. Wong 		 * delalloc reservations only exist incore, so there is no
574dbbdbd00SDarrick J. Wong 		 * ondisk metadata that we can examine.  Hence we leave them
575dbbdbd00SDarrick J. Wong 		 * alone.
576dbbdbd00SDarrick J. Wong 		 */
577dbbdbd00SDarrick J. Wong 		if (isnullstartblock(xc->irec.br_startblock))
578dbbdbd00SDarrick J. Wong 			continue;
579dbbdbd00SDarrick J. Wong 
580dbbdbd00SDarrick J. Wong 		/*
581dbbdbd00SDarrick J. Wong 		 * COW fork extents are only in the written state if writeback
582dbbdbd00SDarrick J. Wong 		 * is actively writing to disk.  We cannot restart the write
583dbbdbd00SDarrick J. Wong 		 * at a different disk address since we've already issued the
584dbbdbd00SDarrick J. Wong 		 * IO, so we leave these alone and hope for the best.
585dbbdbd00SDarrick J. Wong 		 */
586dbbdbd00SDarrick J. Wong 		if (xfs_bmap_is_written_extent(&xc->irec))
587dbbdbd00SDarrick J. Wong 			continue;
588dbbdbd00SDarrick J. Wong 
589dbbdbd00SDarrick J. Wong 		error = xrep_cow_find_bad(xc);
590dbbdbd00SDarrick J. Wong 		if (error)
591dbbdbd00SDarrick J. Wong 			goto out_bitmap;
592dbbdbd00SDarrick J. Wong 	}
593dbbdbd00SDarrick J. Wong 
594dbbdbd00SDarrick J. Wong 	/* Replace any bad unwritten mappings with fresh reservations. */
595dbbdbd00SDarrick J. Wong 	error = xoff_bitmap_walk(&xc->bad_fileoffs, xrep_cow_replace, xc);
596dbbdbd00SDarrick J. Wong 	if (error)
597dbbdbd00SDarrick J. Wong 		goto out_bitmap;
598dbbdbd00SDarrick J. Wong 
599dbbdbd00SDarrick J. Wong 	/*
600dbbdbd00SDarrick J. Wong 	 * Reap as many of the old CoW blocks as we can.  They are owned ondisk
601dbbdbd00SDarrick J. Wong 	 * by the refcount btree, not the inode, so it is correct to treat them
602dbbdbd00SDarrick J. Wong 	 * like inode metadata.
603dbbdbd00SDarrick J. Wong 	 */
604dbbdbd00SDarrick J. Wong 	error = xrep_reap_fsblocks(sc, &xc->old_cowfork_fsblocks,
605dbbdbd00SDarrick J. Wong 			&XFS_RMAP_OINFO_COW);
606dbbdbd00SDarrick J. Wong 	if (error)
607dbbdbd00SDarrick J. Wong 		goto out_bitmap;
608dbbdbd00SDarrick J. Wong 
609dbbdbd00SDarrick J. Wong out_bitmap:
610dbbdbd00SDarrick J. Wong 	xfsb_bitmap_destroy(&xc->old_cowfork_fsblocks);
611dbbdbd00SDarrick J. Wong 	xoff_bitmap_destroy(&xc->bad_fileoffs);
612*d4c75a1bSDave Chinner 	kfree(xc);
613dbbdbd00SDarrick J. Wong 	return error;
614dbbdbd00SDarrick J. Wong }
615