]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
libxfs: v3 inodes are only valid on crc-enabled filesystems
authorRoger Willcocks <roger@filmlight.ltd.uk>
Tue, 18 Aug 2015 07:53:18 +0000 (17:53 +1000)
committerDave Chinner <david@fromorbit.com>
Tue, 18 Aug 2015 07:53:18 +0000 (17:53 +1000)
xfs_repair was not detecting that version 3 inodes are invalid for
for non-CRC filesystems. The result is specific inode corruptions go
undetected and hence aren't repaired if only the version number is
out of range.

The core of the problem is that the XFS_DINODE_GOOD_VERSION() macro
doesn't know that valid inode versions are dependent on a superblock
version number. Fix this in libxfs, and propagate the new function
out into the rest of xfsprogs to fix the issue.

[dchinner: forward port from 3.2.4 to 4.2.0-rc1, move
xfs_dinode_good_version() to libxfs/xfs_inode-buf.c with all the
other dinode validation functions. ]

Reported-by: Leslie Rhorer <lrhorer@mygrande.net>
Signed-off-by: Roger Willcocks <roger@filmlight.ltd.uk>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
db/check.c
libxfs/xfs_format.h
libxfs/xfs_inode_buf.c
libxfs/xfs_inode_buf.h
repair/dinode.c
repair/prefetch.c

index afeea32dcfad9886c202949d51d0edd6c1f5900f..d28199ddaa2a57638ad7a6c8fa799b8107940ecf 100644 (file)
@@ -2630,7 +2630,7 @@ process_inode(
                error++;
                return;
        }
-       if (!XFS_DINODE_GOOD_VERSION(idic.di_version)) {
+       if (!xfs_dinode_good_version(mp, idic.di_version)) {
                if (isfree || v)
                        dbprintf(_("bad version number %#x for inode %lld\n"),
                                idic.di_version, ino);
index 282926da33c8fa1770f2bb536032c0cb9d4415f5..bb7cc043db9f89723e78969c57853c9b63ef281d 100644 (file)
@@ -828,7 +828,6 @@ typedef struct xfs_timestamp {
  * padding field for v3 inodes.
  */
 #define        XFS_DINODE_MAGIC                0x494e  /* 'IN' */
-#define XFS_DINODE_GOOD_VERSION(v)     ((v) >= 1 && (v) <= 3)
 typedef struct xfs_dinode {
        __be16          di_magic;       /* inode magic # = XFS_DINODE_MAGIC */
        __be16          di_mode;        /* mode and type of file */
index be9d1662af5bdb2ccc113c9b1dc4efb735fe4bc9..747a87968c201cf3a5b901b41544da82c64ef464 100644 (file)
@@ -54,6 +54,17 @@ xfs_inobp_check(
 }
 #endif
 
+bool
+xfs_dinode_good_version(
+       struct xfs_mount *mp,
+       __u8            version)
+{
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               return version == 3;
+
+       return version == 1 || version == 2;
+}
+
 /*
  * If we are doing readahead on an inode buffer, we might be in log recovery
  * reading an inode allocation buffer that hasn't yet been replayed, and hence
@@ -85,7 +96,7 @@ xfs_inode_buf_verify(
 
                dip = xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog));
                di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) &&
-                           XFS_DINODE_GOOD_VERSION(dip->di_version);
+                       xfs_dinode_good_version(mp, dip->di_version);
                if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
                                                XFS_ERRTAG_ITOBP_INOTOBP,
                                                XFS_RANDOM_ITOBP_INOTOBP))) {
index 56bc65e442f7943f4b6a9b2c9b9332f6b643b28e..03f2a906c58c84949821f88f8c785976fa6f0795 100644 (file)
@@ -43,6 +43,8 @@ void  xfs_dinode_from_disk(struct xfs_icdinode *to, struct xfs_dinode *from);
 bool   xfs_dinode_verify(struct xfs_mount *mp, xfs_ino_t ino,
                          struct xfs_dinode *dip);
 
+bool   xfs_dinode_good_version(struct xfs_mount *mp, __u8 version);
+
 #if defined(DEBUG)
 void   xfs_inobp_check(struct xfs_mount *, struct xfs_buf *);
 #else
index 7e07ca7014965f1095675c442222d1e4c43ec0c1..f78f907883473d1bc5200b8473811293322445e1 100644 (file)
@@ -129,7 +129,7 @@ clear_dinode_core(struct xfs_mount *mp, xfs_dinode_t *dinoc, xfs_ino_t ino_num)
                dinoc->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
        }
 
-       if (!XFS_DINODE_GOOD_VERSION(dinoc->di_version)) {
+       if (!xfs_dinode_good_version(mp, dinoc->di_version)) {
                __dirty_no_modify_ret(dirty);
                if (xfs_sb_version_hascrc(&mp->m_sb))
                        dinoc->di_version = 3;
@@ -2254,8 +2254,7 @@ process_dinode_int(xfs_mount_t *mp,
                }
        }
 
-       if (!XFS_DINODE_GOOD_VERSION(dino->di_version) ||
-           (xfs_sb_version_hascrc(&mp->m_sb) && dino->di_version < 3) )  {
+       if (!xfs_dinode_good_version(mp, dino->di_version)) {
                retval = 1;
                if (!uncertain)
                        do_warn(_("bad version number 0x%x on inode %" PRIu64 "%c"),
index 8b261ae6be810e8d348175e3ed44559fb86a3102..1de3ec0a578dd67737fa9546bafc13df974d7a7a 100644 (file)
@@ -419,7 +419,7 @@ pf_read_inode_dirs(
                if (be16_to_cpu(dino->di_magic) != XFS_DINODE_MAGIC)
                        continue;
 
-               if (!XFS_DINODE_GOOD_VERSION(dino->di_version))
+               if (!xfs_dinode_good_version(mp, dino->di_version))
                        continue;
 
                if (be64_to_cpu(dino->di_size) <= XFS_DFORK_DSIZE(dino, mp))