// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2022-2023 Oracle. All Rights Reserved. * Author: Darrick J. Wong <[email protected]> */ #include "xfs.h" #include "xfs_fs.h" #include "xfs_shared.h" #include "xfs_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" #include "xfs_defer.h" #include "xfs_btree.h" #include "xfs_log_format.h" #include "xfs_trans.h" #include "xfs_inode.h" #include "xfs_inode_fork.h" #include "xfs_alloc.h" #include "xfs_bmap.h" #include "xfs_rmap.h" #include "xfs_refcount.h" #include "xfs_quota.h" #include "xfs_ialloc.h" #include "xfs_ag.h" #include "xfs_error.h" #include "xfs_errortag.h" #include "xfs_icache.h" #include "xfs_refcount_btree.h" #include "scrub/xfs_scrub.h" #include "scrub/scrub.h" #include "scrub/common.h" #include "scrub/trace.h" #include "scrub/repair.h" #include "scrub/bitmap.h" #include "scrub/off_bitmap.h" #include "scrub/fsb_bitmap.h" #include "scrub/reap.h" /* * CoW Fork Mapping Repair * ======================= * * Although CoW staging extents are owned by incore CoW inode forks, on disk * they are owned by the refcount btree. The ondisk metadata does not record * any ownership information, which limits what we can do to repair the * mappings in the CoW fork. At most, we can replace ifork mappings that lack * an entry in the refcount btree or are described by a reverse mapping record * whose owner is not OWN_COW. * * Replacing extents is also tricky -- we can't touch written CoW fork extents * since they are undergoing writeback, and delalloc extents do not require * repair since they only exist incore. Hence the most we can do is find the * bad parts of unwritten mappings, allocate a replacement set of blocks, and * replace the incore mapping. We use the regular reaping process to unmap * or free the discarded blocks, as appropriate. */ struct xrep_cow { … }; /* CoW staging extent. */ struct xrep_cow_extent { … }; /* * Mark the part of the file range that corresponds to the given physical * space. Caller must ensure that the physical range is within xc->irec. */ STATIC int xrep_cow_mark_file_range( struct xrep_cow *xc, xfs_fsblock_t startblock, xfs_filblks_t blockcount) { … } /* * Trim @src to fit within the CoW fork mapping being examined, and put the * result in @dst. */ static inline void xrep_cow_trim_refcount( struct xrep_cow *xc, struct xfs_refcount_irec *dst, const struct xfs_refcount_irec *src) { … } /* Mark any shared CoW staging extents. */ STATIC int xrep_cow_mark_shared_staging( struct xfs_btree_cur *cur, const struct xfs_refcount_irec *rec, void *priv) { … } /* * Mark any portion of the CoW fork file offset range where there is not a CoW * staging extent record in the refcountbt, and keep a record of where we did * find correct refcountbt records. Staging records are always cleaned out at * mount time, so any two inodes trying to map the same staging area would have * already taken the fs down due to refcount btree verifier errors. Hence this * inode should be the sole creator of the staging extent records ondisk. */ STATIC int xrep_cow_mark_missing_staging( struct xfs_btree_cur *cur, const struct xfs_refcount_irec *rec, void *priv) { … } /* * Mark any area that does not correspond to a CoW staging rmap. These are * cross-linked areas that must be avoided. */ STATIC int xrep_cow_mark_missing_staging_rmap( struct xfs_btree_cur *cur, const struct xfs_rmap_irec *rec, void *priv) { … } /* * Find any part of the CoW fork mapping that isn't a single-owner CoW staging * extent and mark the corresponding part of the file range in the bitmap. */ STATIC int xrep_cow_find_bad( struct xrep_cow *xc) { … } /* * Allocate a replacement CoW staging extent of up to the given number of * blocks, and fill out the mapping. */ STATIC int xrep_cow_alloc( struct xfs_scrub *sc, xfs_extlen_t maxlen, struct xrep_cow_extent *repl) { … } /* * Look up the current CoW fork mapping so that we only allocate enough to * replace a single mapping. If we don't find a mapping that covers the start * of the file range, or we find a delalloc or written extent, something is * seriously wrong, since we didn't drop the ILOCK. */ 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) { … } #define REPLACE_LEFT_SIDE … #define REPLACE_RIGHT_SIDE … /* * Given a CoW fork mapping @got and a replacement mapping @repl, remap the * beginning of @got with the space described by @rep. */ 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) { … } /* * Replace the unwritten CoW staging extent backing the given file range with a * new space extent that isn't as problematic. */ STATIC int xrep_cow_replace_range( struct xrep_cow *xc, xfs_fileoff_t startoff, xfs_extlen_t *blockcount) { … } /* * Replace a bad part of an unwritten CoW staging extent with a fresh delalloc * reservation. */ STATIC int xrep_cow_replace( uint64_t startoff, uint64_t blockcount, void *priv) { … } /* * Repair an inode's CoW fork. The CoW fork is an in-core structure, so * there's no btree to rebuid. Instead, we replace any mappings that are * cross-linked or lack ondisk CoW fork records in the refcount btree. */ int xrep_bmap_cow( struct xfs_scrub *sc) { … }