Scrub the fields within an inode. Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --- 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(-) diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index 60dfe03..30903d1 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/libxfs/xfs_fs.h @@ -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 */ diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 66e8817..4fd5fe1 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c @@ -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) diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h index 6ea8b39..dd2427b 100644 --- a/fs/xfs/xfs_itable.h +++ b/fs/xfs/xfs_itable.h @@ -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__ */ diff --git a/fs/xfs/xfs_scrub.c b/fs/xfs/xfs_scrub.c index 4894221..383a00e 100644 --- a/fs/xfs/xfs_scrub.c +++ b/fs/xfs/xfs_scrub.c @@ -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. */ _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs