xfs: report inode corruption errors to the health system
authorDarrick J. Wong <djwong@kernel.org>
Thu, 22 Feb 2024 20:32:43 +0000 (12:32 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Thu, 22 Feb 2024 20:32:43 +0000 (12:32 -0800)
Whenever we encounter corrupt inode records, we should report that to
the health monitoring system for later reporting.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_ialloc.c
fs/xfs/libxfs/xfs_inode_buf.c
fs/xfs/libxfs/xfs_inode_fork.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_inode.c

index 91584e9..56f82b8 100644 (file)
@@ -2999,6 +2999,7 @@ xfs_ialloc_check_shrink(
                goto out;
 
        if (!has) {
+               xfs_ag_mark_sick(pag, XFS_SICK_AG_INOBT);
                error = -EFSCORRUPTED;
                goto out;
        }
index 137a65b..1280d6a 100644 (file)
@@ -18,6 +18,7 @@
 #include "xfs_trans.h"
 #include "xfs_ialloc.h"
 #include "xfs_dir2.h"
+#include "xfs_health.h"
 
 #include <linux/iversion.h>
 
@@ -132,9 +133,14 @@ xfs_imap_to_bp(
        struct xfs_imap         *imap,
        struct xfs_buf          **bpp)
 {
-       return xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
-                                  imap->im_len, XBF_UNMAPPED, bpp,
-                                  &xfs_inode_buf_ops);
+       int                     error;
+
+       error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
+                       imap->im_len, XBF_UNMAPPED, bpp, &xfs_inode_buf_ops);
+       if (xfs_metadata_is_sick(error))
+               xfs_agno_mark_sick(mp, xfs_daddr_to_agno(mp, imap->im_blkno),
+                               XFS_SICK_AG_INOBT);
+       return error;
 }
 
 static inline struct timespec64 xfs_inode_decode_bigtime(uint64_t ts)
index 60758f7..83194ed 100644 (file)
@@ -25,6 +25,7 @@
 #include "xfs_attr_leaf.h"
 #include "xfs_types.h"
 #include "xfs_errortag.h"
+#include "xfs_health.h"
 
 struct kmem_cache *xfs_ifork_cache;
 
@@ -88,6 +89,7 @@ xfs_iformat_local(
                xfs_inode_verifier_error(ip, -EFSCORRUPTED,
                                "xfs_iformat_local", dip, sizeof(*dip),
                                __this_address);
+               xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
                return -EFSCORRUPTED;
        }
 
@@ -125,6 +127,7 @@ xfs_iformat_extents(
                xfs_inode_verifier_error(ip, -EFSCORRUPTED,
                                "xfs_iformat_extents(1)", dip, sizeof(*dip),
                                __this_address);
+               xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
                return -EFSCORRUPTED;
        }
 
@@ -144,6 +147,7 @@ xfs_iformat_extents(
                                xfs_inode_verifier_error(ip, -EFSCORRUPTED,
                                                "xfs_iformat_extents(2)",
                                                dp, sizeof(*dp), fa);
+                               xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
                                return xfs_bmap_complain_bad_rec(ip, whichfork,
                                                fa, &new);
                        }
@@ -202,6 +206,7 @@ xfs_iformat_btree(
                xfs_inode_verifier_error(ip, -EFSCORRUPTED,
                                "xfs_iformat_btree", dfp, size,
                                __this_address);
+               xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
                return -EFSCORRUPTED;
        }
 
@@ -267,12 +272,14 @@ xfs_iformat_data_fork(
                default:
                        xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__,
                                        dip, sizeof(*dip), __this_address);
+                       xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
                        return -EFSCORRUPTED;
                }
                break;
        default:
                xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
                                sizeof(*dip), __this_address);
+               xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
                return -EFSCORRUPTED;
        }
 }
@@ -344,6 +351,7 @@ xfs_iformat_attr_fork(
        default:
                xfs_inode_verifier_error(ip, error, __func__, dip,
                                sizeof(*dip), __this_address);
+               xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
                error = -EFSCORRUPTED;
                break;
        }
index 0604682..e64265b 100644 (file)
@@ -24,6 +24,7 @@
 #include "xfs_ialloc.h"
 #include "xfs_ag.h"
 #include "xfs_log_priv.h"
+#include "xfs_health.h"
 
 #include <linux/iversion.h>
 
@@ -415,6 +416,9 @@ xfs_iget_check_free_state(
                        xfs_warn(ip->i_mount,
 "Corruption detected! Free inode 0x%llx not marked free! (mode 0x%x)",
                                ip->i_ino, VFS_I(ip)->i_mode);
+                       xfs_agno_mark_sick(ip->i_mount,
+                                       XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino),
+                                       XFS_SICK_AG_INOBT);
                        return -EFSCORRUPTED;
                }
 
@@ -422,6 +426,9 @@ xfs_iget_check_free_state(
                        xfs_warn(ip->i_mount,
 "Corruption detected! Free inode 0x%llx has blocks allocated!",
                                ip->i_ino);
+                       xfs_agno_mark_sick(ip->i_mount,
+                                       XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino),
+                                       XFS_SICK_AG_INOBT);
                        return -EFSCORRUPTED;
                }
                return 0;
@@ -640,6 +647,8 @@ xfs_iget_cache_miss(
                                xfs_buf_offset(bp, ip->i_imap.im_boffset));
                if (!error)
                        xfs_buf_set_ref(bp, XFS_INO_REF);
+               else
+                       xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
                xfs_trans_brelse(tp, bp);
 
                if (error)
index ab2d891..5d0ac5c 100644 (file)
@@ -3422,6 +3422,8 @@ flush_out:
 
        /* generate the checksum. */
        xfs_dinode_calc_crc(mp, dip);
+       if (error)
+               xfs_inode_mark_sick(ip, XFS_SICK_INO_CORE);
        return error;
 }