{
        xfs_extnum_t            di_nextents;
        xfs_extnum_t            max_extents;
+       mode_t                  mode = be16_to_cpu(dip->di_mode);
+       uint32_t                fork_size = XFS_DFORK_SIZE(dip, mp, whichfork);
+       uint32_t                fork_format = XFS_DFORK_FORMAT(dip, whichfork);
 
        di_nextents = xfs_dfork_nextents(dip, whichfork);
 
-       switch (XFS_DFORK_FORMAT(dip, whichfork)) {
+       /*
+        * For fork types that can contain local data, check that the fork
+        * format matches the size of local data contained within the fork.
+        *
+        * For all types, check that when the size says the should be in extent
+        * or btree format, the inode isn't claiming it is in local format.
+        */
+       if (whichfork == XFS_DATA_FORK) {
+               if (S_ISDIR(mode) || S_ISLNK(mode)) {
+                       if (be64_to_cpu(dip->di_size) <= fork_size &&
+                           fork_format != XFS_DINODE_FMT_LOCAL)
+                               return __this_address;
+               }
+
+               if (be64_to_cpu(dip->di_size) > fork_size &&
+                   fork_format == XFS_DINODE_FMT_LOCAL)
+                       return __this_address;
+       }
+
+       switch (fork_format) {
        case XFS_DINODE_FMT_LOCAL:
                /*
-                * no local regular files yet
+                * No local regular files yet.
                 */
-               if (whichfork == XFS_DATA_FORK) {
-                       if (S_ISREG(be16_to_cpu(dip->di_mode)))
-                               return __this_address;
-                       if (be64_to_cpu(dip->di_size) >
-                                       XFS_DFORK_SIZE(dip, mp, whichfork))
-                               return __this_address;
-               }
+               if (S_ISREG(mode) && whichfork == XFS_DATA_FORK)
+                       return __this_address;
                if (di_nextents)
                        return __this_address;
                break;