#define XFS_SICK_INO_SYMLINK   (1 << 6)  /* symbolic link remote target */
 #define XFS_SICK_INO_PARENT    (1 << 7)  /* parent pointers */
 
+#define XFS_SICK_INO_BMBTD_ZAPPED      (1 << 8)  /* data fork erased */
+#define XFS_SICK_INO_BMBTA_ZAPPED      (1 << 9)  /* attr fork erased */
+#define XFS_SICK_INO_DIR_ZAPPED                (1 << 10) /* directory erased */
+#define XFS_SICK_INO_SYMLINK_ZAPPED    (1 << 11) /* symlink erased */
+
 /* Primary evidence of health problems in a given group. */
 #define XFS_SICK_FS_PRIMARY    (XFS_SICK_FS_COUNTERS | \
                                 XFS_SICK_FS_UQUOTA | \
                                 XFS_SICK_INO_SYMLINK | \
                                 XFS_SICK_INO_PARENT)
 
+#define XFS_SICK_INO_ZAPPED    (XFS_SICK_INO_BMBTD_ZAPPED | \
+                                XFS_SICK_INO_BMBTA_ZAPPED | \
+                                XFS_SICK_INO_DIR_ZAPPED | \
+                                XFS_SICK_INO_SYMLINK_ZAPPED)
+
 /* These functions must be provided by the xfs implementation. */
 
 void xfs_fs_mark_sick(struct xfs_mount *mp, unsigned int mask);
 
 #include "xfs_bmap_btree.h"
 #include "xfs_rmap.h"
 #include "xfs_rmap_btree.h"
+#include "xfs_health.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/btree.h"
+#include "scrub/health.h"
 #include "xfs_ag.h"
 
 /* Set us up with an inode's bmap. */
 xchk_bmap_data(
        struct xfs_scrub        *sc)
 {
-       return xchk_bmap(sc, XFS_DATA_FORK);
+       int                     error;
+
+       if (xchk_file_looks_zapped(sc, XFS_SICK_INO_BMBTD_ZAPPED)) {
+               xchk_ino_set_corrupt(sc, sc->ip->i_ino);
+               return 0;
+       }
+
+       error = xchk_bmap(sc, XFS_DATA_FORK);
+       if (error)
+               return error;
+
+       /* If the data fork is clean, it is clearly not zapped. */
+       xchk_mark_healthy_if_clean(sc, XFS_SICK_INO_BMBTD_ZAPPED);
+       return 0;
 }
 
 /* Scrub an inode's attr fork. */
 xchk_bmap_attr(
        struct xfs_scrub        *sc)
 {
-       return xchk_bmap(sc, XFS_ATTR_FORK);
+       int                     error;
+
+       /*
+        * If the attr fork has been zapped, it's possible that forkoff was
+        * reset to zero and hence sc->ip->i_afp is NULL.  We don't want the
+        * NULL ifp check in xchk_bmap to conclude that the attr fork is ok,
+        * so short circuit that logic by setting the corruption flag and
+        * returning immediately.
+        */
+       if (xchk_file_looks_zapped(sc, XFS_SICK_INO_BMBTA_ZAPPED)) {
+               xchk_ino_set_corrupt(sc, sc->ip->i_ino);
+               return 0;
+       }
+
+       error = xchk_bmap(sc, XFS_ATTR_FORK);
+       if (error)
+               return error;
+
+       /* If the attr fork is clean, it is clearly not zapped. */
+       xchk_mark_healthy_if_clean(sc, XFS_SICK_INO_BMBTA_ZAPPED);
+       return 0;
 }
 
 /* Scrub an inode's CoW fork. */
 
        unsigned int            scrub_type)
 {
        __u32                   smtype = sc->sm->sm_type;
+       unsigned int            sick_mask = sc->sick_mask;
        int                     error;
 
        sc->sm->sm_type = scrub_type;
                break;
        }
 
+       sc->sick_mask = sick_mask;
        sc->sm->sm_type = smtype;
        return error;
 }
 
 #include "xfs_icache.h"
 #include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
+#include "xfs_health.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/dabtree.h"
 #include "scrub/readdir.h"
+#include "scrub/health.h"
 
 /* Set us up to scrub directories. */
 int
        if (!S_ISDIR(VFS_I(sc->ip)->i_mode))
                return -ENOENT;
 
+       if (xchk_file_looks_zapped(sc, XFS_SICK_INO_DIR_ZAPPED)) {
+               xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
+               return 0;
+       }
+
        /* Plausible size? */
        if (sc->ip->i_disk_size < xfs_dir2_sf_hdr_size(0)) {
                xchk_ino_set_corrupt(sc, sc->ip->i_ino);
 
        /* Look up every name in this directory by hash. */
        error = xchk_dir_walk(sc, sc->ip, xchk_dir_actor, NULL);
-       if (error == -ECANCELED)
-               error = 0;
-       return error;
+       if (error && error != -ECANCELED)
+               return error;
+
+       /* If the dir is clean, it is clearly not zapped. */
+       xchk_mark_healthy_if_clean(sc, XFS_SICK_INO_DIR_ZAPPED);
+       return 0;
 }
 
        return type_to_health_flag[scrub_type].sick_mask;
 }
 
+/*
+ * If the scrub state is clean, add @mask to the scrub sick mask to clear
+ * additional sick flags from the metadata object's sick state.
+ */
+void
+xchk_mark_healthy_if_clean(
+       struct xfs_scrub        *sc,
+       unsigned int            mask)
+{
+       if (!(sc->sm->sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
+                                 XFS_SCRUB_OFLAG_XCORRUPT)))
+               sc->sick_mask |= mask;
+}
+
+/*
+ * If we're scrubbing a piece of file metadata for the first time, does it look
+ * like it has been zapped?  Skip the check if we just repaired the metadata
+ * and are revalidating it.
+ */
+bool
+xchk_file_looks_zapped(
+       struct xfs_scrub        *sc,
+       unsigned int            mask)
+{
+       ASSERT((mask & ~XFS_SICK_INO_ZAPPED) == 0);
+
+       if (sc->flags & XREP_ALREADY_FIXED)
+               return false;
+
+       return xfs_inode_has_sickness(sc->ip, mask);
+}
+
 /*
  * Update filesystem health assessments based on what we found and did.
  *
 
 void xchk_update_health(struct xfs_scrub *sc);
 bool xchk_ag_btree_healthy_enough(struct xfs_scrub *sc, struct xfs_perag *pag,
                xfs_btnum_t btnum);
+void xchk_mark_healthy_if_clean(struct xfs_scrub *sc, unsigned int mask);
+bool xchk_file_looks_zapped(struct xfs_scrub *sc, unsigned int mask);
 
 #endif /* __XFS_SCRUB_HEALTH_H__ */
 
 #include "xfs_log_format.h"
 #include "xfs_inode.h"
 #include "xfs_symlink.h"
+#include "xfs_health.h"
 #include "scrub/scrub.h"
 #include "scrub/common.h"
+#include "scrub/health.h"
 
 /* Set us up to scrub a symbolic link. */
 int
 
        if (!S_ISLNK(VFS_I(ip)->i_mode))
                return -ENOENT;
+
+       if (xchk_file_looks_zapped(sc, XFS_SICK_INO_SYMLINK_ZAPPED)) {
+               xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
+               return 0;
+       }
+
        ifp = xfs_ifork_ptr(ip, XFS_DATA_FORK);
        len = ip->i_disk_size;
 
        /* Plausible size? */
        if (len > XFS_SYMLINK_MAXLEN || len <= 0) {
                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
-               goto out;
+               return 0;
        }
 
        /* Inline symlink? */
                if (len > xfs_inode_data_fork_size(ip) ||
                    len > strnlen(ifp->if_u1.if_data, xfs_inode_data_fork_size(ip)))
                        xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
-               goto out;
+               return 0;
        }
 
        /* Remote symlink; must read the contents. */
        error = xfs_readlink_bmap_ilocked(sc->ip, sc->buf);
        if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
-               goto out;
+               return error;
        if (strnlen(sc->buf, XFS_SYMLINK_MAXLEN) < len)
                xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
-out:
-       return error;
+
+       /* If a remote symlink is clean, it is clearly not zapped. */
+       xchk_mark_healthy_if_clean(sc, XFS_SICK_INO_SYMLINK_ZAPPED);
+       return 0;
 }
 
 #include "xfs_bmap.h"
 #include "xfs_trans.h"
 #include "xfs_error.h"
+#include "xfs_health.h"
 
 /*
  * Directory file type support functions
 
        if (xfs_is_shutdown(dp->i_mount))
                return -EIO;
+       if (xfs_ifork_zapped(dp, XFS_DATA_FORK))
+               return -EIO;
 
        ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
        ASSERT(xfs_isilocked(dp, XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL));
 
        struct xfs_inode        *ip,
        unsigned int            mask)
 {
-       ASSERT(!(mask & ~XFS_SICK_INO_PRIMARY));
+       ASSERT(!(mask & ~(XFS_SICK_INO_PRIMARY | XFS_SICK_INO_ZAPPED)));
        trace_xfs_inode_mark_sick(ip, mask);
 
        spin_lock(&ip->i_flags_lock);
        struct xfs_inode        *ip,
        unsigned int            mask)
 {
-       ASSERT(!(mask & ~XFS_SICK_INO_PRIMARY));
+       ASSERT(!(mask & ~(XFS_SICK_INO_PRIMARY | XFS_SICK_INO_ZAPPED)));
        trace_xfs_inode_mark_healthy(ip, mask);
 
        spin_lock(&ip->i_flags_lock);
        { XFS_SICK_INO_XATTR,   XFS_BS_SICK_XATTR },
        { XFS_SICK_INO_SYMLINK, XFS_BS_SICK_SYMLINK },
        { XFS_SICK_INO_PARENT,  XFS_BS_SICK_PARENT },
+       { XFS_SICK_INO_BMBTD_ZAPPED,    XFS_BS_SICK_BMBTD },
+       { XFS_SICK_INO_BMBTA_ZAPPED,    XFS_BS_SICK_BMBTA },
+       { XFS_SICK_INO_DIR_ZAPPED,      XFS_BS_SICK_DIR },
+       { XFS_SICK_INO_SYMLINK_ZAPPED,  XFS_BS_SICK_SYMLINK },
        { 0, 0 },
 };
 
 
 #include "xfs_reflink.h"
 #include "xfs_ag.h"
 #include "xfs_log_priv.h"
+#include "xfs_health.h"
 
 struct kmem_cache *xfs_inode_cache;
 
 
        if (xfs_is_shutdown(dp->i_mount))
                return -EIO;
+       if (xfs_ifork_zapped(dp, XFS_DATA_FORK))
+               return -EIO;
 
        error = xfs_dir_lookup(NULL, dp, name, &inum, ci_name);
        if (error)
 
        if (xfs_is_shutdown(mp))
                return -EIO;
+       if (xfs_ifork_zapped(dp, XFS_DATA_FORK))
+               return -EIO;
 
        prid = xfs_get_initial_prid(dp);
 
 
        if (xfs_is_shutdown(mp))
                return -EIO;
+       if (xfs_ifork_zapped(tdp, XFS_DATA_FORK))
+               return -EIO;
 
        error = xfs_qm_dqattach(sip);
        if (error)
 
        if (xfs_is_shutdown(mp))
                return -EIO;
+       if (xfs_ifork_zapped(dp, XFS_DATA_FORK))
+               return -EIO;
 
        error = xfs_qm_dqattach(dp);
        if (error)
 
        return error;
 }
+
+/* Has this inode fork been zapped by repair? */
+bool
+xfs_ifork_zapped(
+       const struct xfs_inode  *ip,
+       int                     whichfork)
+{
+       unsigned int            datamask = 0;
+
+       switch (whichfork) {
+       case XFS_DATA_FORK:
+               switch (ip->i_vnode.i_mode & S_IFMT) {
+               case S_IFDIR:
+                       datamask = XFS_SICK_INO_DIR_ZAPPED;
+                       break;
+               case S_IFLNK:
+                       datamask = XFS_SICK_INO_SYMLINK_ZAPPED;
+                       break;
+               }
+               return ip->i_sick & (XFS_SICK_INO_BMBTD_ZAPPED | datamask);
+       case XFS_ATTR_FORK:
+               return ip->i_sick & XFS_SICK_INO_BMBTA_ZAPPED;
+       default:
+               return false;
+       }
+}
 
 int xfs_inode_reload_unlinked_bucket(struct xfs_trans *tp, struct xfs_inode *ip);
 int xfs_inode_reload_unlinked(struct xfs_inode *ip);
 
+bool xfs_ifork_zapped(const struct xfs_inode *ip, int whichfork);
+
 #endif /* __XFS_INODE_H__ */
 
 #include "xfs_trans.h"
 #include "xfs_ialloc.h"
 #include "xfs_error.h"
+#include "xfs_health.h"
 
 /* ----- Kernel only functions below ----- */
 int
 
        if (xfs_is_shutdown(mp))
                return -EIO;
+       if (xfs_ifork_zapped(ip, XFS_DATA_FORK))
+               return -EIO;
 
        xfs_ilock(ip, XFS_ILOCK_SHARED);
 
 
        };
        int                     error;
 
+       if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK))
+               return -EIO;
+
        error = xfs_attr_get(&args);
        if (error)
                return error;
        struct inode    *inode = d_inode(dentry);
        int             error;
 
+       if (xfs_ifork_zapped(XFS_I(inode), XFS_ATTR_FORK))
+               return -EIO;
+
        /*
         * First read the regular on-disk attributes.
         */