xfs
[Top] [All Lists]

[PATCH 15/25] xfs: scrub inodes

To: david@xxxxxxxxxxxxx, darrick.wong@xxxxxxxxxx
Subject: [PATCH 15/25] xfs: scrub inodes
From: "Darrick J. Wong" <darrick.wong@xxxxxxxxxx>
Date: Thu, 25 Aug 2016 16:41:50 -0700
Cc: linux-xfs@xxxxxxxxxxxxxxx, xfs@xxxxxxxxxxx
Delivered-to: xfs@xxxxxxxxxxx
In-reply-to: <147216841262.3108.10746252464845687338.stgit@xxxxxxxxxxxxxxxx>
References: <147216841262.3108.10746252464845687338.stgit@xxxxxxxxxxxxxxxx>
User-agent: StGit/0.17.1-dirty
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. */

<Prev in Thread] Current Thread [Next in Thread>