On Thu, Dec 31, 2020 at 12:56:00AM +0800, Shiyang Ruan wrote: > This function is used to handle errors which may cause data lost in > filesystem. Such as memory failure in fsdax mode. > > In XFS, it requires "rmapbt" feature in order to query for files or > metadata which associated to the corrupted data. Then we could call fs > recover functions to try to repair the corrupted data.(did not > implemented in this patchset) > > After that, the memory failure also needs to notify the processes who > are using those files. > > Only support data device. Realtime device is not supported for now. > > Signed-off-by: Shiyang Ruan <ruansy.fnst@xxxxxxxxxxxxxx> > --- > fs/xfs/xfs_fsops.c | 5 +++ > fs/xfs/xfs_mount.h | 1 + > fs/xfs/xfs_super.c | 107 +++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 113 insertions(+) > > diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c > index ef1d5bb88b93..0a2038875d32 100644 > --- a/fs/xfs/xfs_fsops.c > +++ b/fs/xfs/xfs_fsops.c > @@ -501,6 +501,11 @@ xfs_do_force_shutdown( > "Corruption of in-memory data detected. Shutting down filesystem"); > if (XFS_ERRLEVEL_HIGH <= xfs_error_level) > xfs_stack_trace(); > + } else if (flags & SHUTDOWN_CORRUPT_META) { > + xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT, > +"Corruption of on-disk metadata detected. Shutting down filesystem"); > + if (XFS_ERRLEVEL_HIGH <= xfs_error_level) > + xfs_stack_trace(); > } else if (logerror) { > xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR, > "Log I/O Error Detected. Shutting down filesystem"); > diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h > index dfa429b77ee2..8f0df67ffcc1 100644 > --- a/fs/xfs/xfs_mount.h > +++ b/fs/xfs/xfs_mount.h > @@ -274,6 +274,7 @@ void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname, > #define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */ > #define SHUTDOWN_FORCE_UMOUNT 0x0004 /* shutdown from a forced unmount */ > #define SHUTDOWN_CORRUPT_INCORE 0x0008 /* corrupt in-memory data structures */ > +#define SHUTDOWN_CORRUPT_META 0x0010 /* corrupt metadata on device */ > > /* > * Flags for xfs_mountfs > diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c > index e3e229e52512..cbcad419bb9e 100644 > --- a/fs/xfs/xfs_super.c > +++ b/fs/xfs/xfs_super.c > @@ -35,6 +35,11 @@ > #include "xfs_refcount_item.h" > #include "xfs_bmap_item.h" > #include "xfs_reflink.h" > +#include "xfs_alloc.h" > +#include "xfs_rmap.h" > +#include "xfs_rmap_btree.h" > +#include "xfs_rtalloc.h" > +#include "xfs_bit.h" > > #include <linux/magic.h> > #include <linux/fs_context.h> > @@ -1103,6 +1108,107 @@ xfs_fs_free_cached_objects( > return xfs_reclaim_inodes_nr(XFS_M(sb), sc->nr_to_scan); > } > > +static int > +xfs_corrupt_helper( > + struct xfs_btree_cur *cur, > + struct xfs_rmap_irec *rec, > + void *data) > +{ > + struct xfs_inode *ip; > + struct address_space *mapping; > + int rc = 0; > + int *flags = data; > + > + if (XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) || > + (rec->rm_flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK))) { > + // TODO check and try to fix metadata > + rc = -EFSCORRUPTED; > + } else { > + /* > + * Get files that incore, filter out others that are not in use. > + */ > + rc = xfs_iget(cur->bc_mp, cur->bc_tp, rec->rm_owner, > + XFS_IGET_INCORE, 0, &ip); > + if (rc || !ip) > + return rc; > + if (!VFS_I(ip)->i_mapping) > + goto out; > + > + mapping = VFS_I(ip)->i_mapping; > + if (IS_DAX(VFS_I(ip))) > + rc = mf_dax_mapping_kill_procs(mapping, rec->rm_offset, > + *flags); > + else > + mapping_set_error(mapping, -EFSCORRUPTED); Hm. I don't know if EFSCORRUPTED is the right error code for corrupt file data, since we (so far) have only used it for corrupt metadata. > + > + // TODO try to fix data > +out: > + xfs_irele(ip); > + } > + > + return rc; > +} > + > +static int > +xfs_fs_corrupted_range( > + struct super_block *sb, > + struct block_device *bdev, > + loff_t offset, > + size_t len, > + void *data) > +{ > + struct xfs_mount *mp = XFS_M(sb); > + struct xfs_trans *tp = NULL; > + struct xfs_btree_cur *cur = NULL; > + struct xfs_rmap_irec rmap_low, rmap_high; > + struct xfs_buf *agf_bp = NULL; > + xfs_fsblock_t fsbno = XFS_B_TO_FSB(mp, offset); > + xfs_filblks_t bcnt = XFS_B_TO_FSB(mp, len); > + xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, fsbno); > + xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, fsbno); > + int error = 0; > + > + if (mp->m_rtdev_targp && mp->m_rtdev_targp->bt_bdev == bdev) { > + xfs_warn(mp, "corrupted_range support not available for realtime device!"); > + return 0; > + } > + if (mp->m_logdev_targp && mp->m_logdev_targp->bt_bdev == bdev && > + mp->m_logdev_targp != mp->m_ddev_targp) { > + xfs_err(mp, "ondisk log corrupt, shutting down fs!"); > + xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_META); > + return 0; > + } > + > + if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) { > + xfs_warn(mp, "corrupted_range needs rmapbt enabled!"); > + return 0; > + } > + > + error = xfs_trans_alloc_empty(mp, &tp); > + if (error) > + return error; > + > + error = xfs_alloc_read_agf(mp, tp, agno, 0, &agf_bp); > + if (error) > + return error; > + > + cur = xfs_rmapbt_init_cursor(mp, tp, agf_bp, agno); > + > + /* Construct a range for rmap query */ > + memset(&rmap_low, 0, sizeof(rmap_low)); > + memset(&rmap_high, 0xFF, sizeof(rmap_high)); > + rmap_low.rm_startblock = rmap_high.rm_startblock = agbno; > + rmap_low.rm_blockcount = rmap_high.rm_blockcount = bcnt; > + > + error = xfs_rmap_query_range(cur, &rmap_low, &rmap_high, xfs_corrupt_helper, data); > + if (error == -EFSCORRUPTED) > + xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_META); > + > + xfs_btree_del_cursor(cur, error); > + xfs_trans_brelse(tp, agf_bp); The transaction needs to be committed (or cancelled) here, or else it leaks. --D > + return error; > +} > + > static const struct super_operations xfs_super_operations = { > .alloc_inode = xfs_fs_alloc_inode, > .destroy_inode = xfs_fs_destroy_inode, > @@ -1116,6 +1222,7 @@ static const struct super_operations xfs_super_operations = { > .show_options = xfs_fs_show_options, > .nr_cached_objects = xfs_fs_nr_cached_objects, > .free_cached_objects = xfs_fs_free_cached_objects, > + .corrupted_range = xfs_fs_corrupted_range, > }; > > static int > -- > 2.29.2 > > >