@@ -545,7 +545,8 @@ struct xfs_scrub_metadata {
#define XFS_SCRUB_TYPE_FINOBT 7 /* free inode btree */
#define XFS_SCRUB_TYPE_RMAPBT 8 /* reverse mapping btree */
#define XFS_SCRUB_TYPE_REFCNTBT 9 /* reference count btree */
-#define XFS_SCRUB_TYPE_MAX 9
+#define XFS_SCRUB_TYPE_INODE 10 /* inode record */
+#define XFS_SCRUB_TYPE_MAX 10
#define XFS_SCRUB_FLAGS_ALL 0x0 /* no flags yet */
@@ -31,7 +31,7 @@
#include "xfs_trace.h"
#include "xfs_icache.h"
-STATIC int
+int
xfs_internal_inum(
xfs_mount_t *mp,
xfs_ino_t ino)
@@ -96,4 +96,9 @@ xfs_inumbers(
void __user *buffer, /* buffer with inode info */
inumbers_fmt_pf formatter);
+int
+xfs_internal_inum(
+ xfs_mount_t *mp,
+ xfs_ino_t ino);
+
#endif /* __XFS_ITABLE_H__ */
@@ -43,6 +43,8 @@
#include "xfs_rmap.h"
#include "xfs_rmap_btree.h"
#include "xfs_rtalloc.h"
+#include "xfs_icache.h"
+#include "xfs_itable.h"
/* Report a scrub corruption in dmesg. */
STATIC void
@@ -1313,6 +1315,72 @@ xfs_scrub_refcountbt(
return error;
}
+/* Scrub an inode. */
+STATIC int
+xfs_scrub_inode(
+ struct xfs_inode *ip,
+ struct xfs_scrub_metadata *sm)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ struct xfs_inode *ips;
+ int error;
+
+ if (sm->flags)
+ return -EINVAL;
+
+ if (sm->control && sm->control != ip->i_ino) {
+ if (xfs_internal_inum(mp, sm->control)) {
+ error = -ENOENT;
+ goto out;
+ }
+ error = xfs_iget(ip->i_mount, NULL, sm->control,
+ XFS_IGET_UNTRUSTED | XFS_IGET_DONTCACHE,
+ XFS_ILOCK_EXCL, &ips);
+ if (error)
+ goto out;
+ } else {
+ ips = ip;
+ xfs_ilock(ips, XFS_ILOCK_EXCL);
+ }
+
+ /* The verifiers should refuse any inode with bad fields. */
+ XFS_INO_SCRUB_GOTO(ips, NULL, "inode", ips != NULL, out_unlock);
+
+ XFS_INO_SCRUB_CHECK(ips, NULL, "inode",
+ ips->i_d.di_projid_hi == 0 ||
+ xfs_sb_version_hasprojid32bit(&mp->m_sb));
+
+ if (ips->i_d.di_flags & XFS_DIFLAG_EXTSIZE) {
+ XFS_INO_SCRUB_CHECK(ips, NULL, "inode",
+ ips->i_d.di_extsize > 0);
+ XFS_INO_SCRUB_CHECK(ips, NULL, "inode",
+ ips->i_d.di_extsize <= MAXEXTLEN);
+ XFS_INO_SCRUB_CHECK(ips, NULL, "inode",
+ XFS_IS_REALTIME_INODE(ip) ||
+ ips->i_d.di_extsize <= mp->m_sb.sb_agblocks / 2);
+ }
+ XFS_INO_SCRUB_CHECK(ips, NULL, "inode",
+ !(ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE) ||
+ !(ip->i_d.di_flags & XFS_DIFLAG_APPEND));
+
+ if (ips->i_d.di_version == 3 &&
+ ips->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) {
+ XFS_INO_SCRUB_CHECK(ips, NULL, "inode",
+ ips->i_d.di_cowextsize > 0);
+ XFS_INO_SCRUB_CHECK(ips, NULL, "inode",
+ ips->i_d.di_cowextsize <= MAXEXTLEN);
+ XFS_INO_SCRUB_CHECK(ips, NULL, "inode",
+ ips->i_d.di_cowextsize <= mp->m_sb.sb_agblocks / 2);
+ }
+
+out_unlock:
+ xfs_iunlock(ips, XFS_ILOCK_EXCL);
+ if (ips != ip)
+ IRELE(ips);
+out:
+ return error;
+}
+
/* Scrubbing dispatch. */
struct xfs_scrub_meta_fns {
@@ -1331,6 +1399,7 @@ static const struct xfs_scrub_meta_fns meta_scrub_fns[] = {
{xfs_scrub_finobt, xfs_sb_version_hasfinobt},
{xfs_scrub_rmapbt, xfs_sb_version_hasrmapbt},
{xfs_scrub_refcountbt, xfs_sb_version_hasreflink},
+ {xfs_scrub_inode, NULL},
};
/* Dispatch metadata scrubbing. */
Scrub the fields within an inode. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> --- fs/xfs/libxfs/xfs_fs.h | 3 +- fs/xfs/xfs_itable.c | 2 + fs/xfs/xfs_itable.h | 5 +++ fs/xfs/xfs_scrub.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-)