Subject: 64-bit inodes can cause invalid message "mkid: warning: `A and `B' are the same file, but yield different scans!"

From: John DelSignore <[email-masked]>
Date: Fri, 4 Oct 2024 13:44:35 -0400

Hi,

I've been using the idutils for 30+ years. We recently moved to a NetApp NFS filesystem that uses 64-bit inodes. With that new filesystem, mkid generates a message like: "mkid: warning: `A and `B' are the same file, but yield different scans!" for hundreds of source files. Here is one example:

mkid: warning: `/nfs/homes/jdelsign/src/totalview.develop/cs/graphics/glyphd/motif/txelipse.cc' and `/nfs/homes/jdelsign/src/totalview.develop/3rdparty/mrnet/MRNet/src/parser.y' are the same file, but yield different scans!

However, the files are definitely not the same:

% ls -i /nfs/homes/jdelsign/src/totalview.develop/cs/graphics/glyphd/motif/txelipse.cc /nfs/homes/jdelsign/src/totalview.develop/3rdparty/mrnet/MRNet/src/parser.y
9257776846609958295 /nfs/homes/jdelsign/src/totalview.develop/3rdparty/mrnet/MRNet/src/parser.y
9257776842314990999 /nfs/homes/jdelsign/src/totalview.develop/cs/graphics/glyphd/motif/txelipse.cc
%

If I convert the inode numbers to hex, we have:

9257776846609958295 -> 0x807a3afe0005c597
9257776842314990999 -> 0x807a3afd0005c597

Notice the difference is in the top 32-bits, and the bottom 32-bits are equal, so mkid thinks they are the same file.

I ran mkid under a debugger to try to determine the source of the error. The problem seems to be that the hash table INTEGER_COMPARE macro assumes that the result is the same size at the integers being compared, and for dev/ino comparison the result is truncated from 64-bits to 32-bits. Here's the code:

static int
dev_ino_hash_compare (void const *x, void const *y) {
   int result;
   INTEGER_COMPARE (((struct dev_ino const *) x)->di_ino,
            ((struct dev_ino const *) y)->di_ino, result);
   if (result)
     return result;
   INTEGER_COMPARE (((struct dev_ino const *) x)->di_dev,
            ((struct dev_ino const *) y)->di_dev, result);
   return result;
}

Both di_ino and di_dev are 64-bits, so performing a subtraction and storing the difference in a 32-bit result is not valid.

I tried the following change and it seems to eliminate the warning messages:

lid 52 10/04 9:30 ~/src/tools-external/idutils-4.6 % diff -u libidu/idu-hash.h.~1~ libidu/idu-hash.h
--- libidu/idu-hash.h.~1~    2012-01-01 04:16:06.000000000 -0500
+++ libidu/idu-hash.h    2024-10-04 09:27:29.558975000 -0400
@@ -128,7 +128,7 @@
  } while (0)

  #define INTEGER_COMPARE(_x_, _y_, _result_) do { \
-  (_result_) = _x_ - _y_; \
+  (_result_) = _x_ < _y_ ? -1 : _x_ > _y_ ? 1 : 0; \
  } while (0)
  #define return_INTEGER_COMPARE(_x_, _y_) do { \
    int result; \
lid 53 10/04 9:30 ~/src/tools-external/idutils-4.6 %

Cheers, John D.