st_dev of mount point directory is different to device ID of device-file

I have NTFS which is mounted on '/Volumes/usb_vol'

#mount
Filesystem       Mounted on
/dev/disk5s1     /Volumes/usb_vol

The following simple code reports different values of device Id for device-file and mount point directory

struct stat buf;

for (int i = 1; i < argc; i++)
{
    std::cout << argv[i] << std::endl;

    if (stat(argv[i], &buf) < 0)
    {
        continue;
    }

    if (S_ISBLK(buf.st_mode))
    {
        std::cout << "st_rdev (" << major(buf.st_rdev) << "/" << minor(buf.st_rdev) << ") hex: " << std::hex << buf.st_rdev << std::endl;
    }
    else
    {
        std::cout << "st_dev (" << major(buf.st_dev) << "/" << minor(buf.st_dev) << ") hex: " << std::hex << buf.st_dev << std::endl;
    }
}

Output:

/dev/disk5s1
st_rdev (1/22) hex: 1000016

/Volumes/usb_vol
st_dev (48/119) hex: 30000077

I believe this is expected but I have not found any explanation of this behaviour. Are there any explanation of difference these values?

I can assume the stat() will report (48/119) for all objects which are located on this file system. Is it correct?

Thank you for the help!

I have NTFS which is mounted on '/Volumes/usb_vol'

What mounted this volume? Was it our read-only driver or was it a 3rd party read/write driver?

I believe this is expected

Expected is a such a tricky word... I am both:

  • Surprised, in that this is definitely not what I would have expected stat to return.

  • Not Surprised, in that I know that the value returned by stat (and similar functions) are VERY loosely defined, to the point that stat can (in theory) basically return "anything".

but I have not found any explanation of this behaviour. Are there any explanation of difference these values?

I haven't looked into it in detail, but is suspect it's caused by one of two things:

  1. If it's our driver, then it's probably a side effect of the user land VFS driver. We've been moving more of our file system over to that system and that transitions changes "details" of how the file system "presents" itself to the higher level system. This is the first time I've heard of this, but there are other places where this is visible.

  2. If it's 3rd party driver then this it can basically return anything it wants.

Can you share it's entry from the volume list when you run "mount" in Terminal? That might provide more detail about what's actually going on. Also, what does "statfs()" return when run on the same path?

I can assume the stat() will report (48/119) for all objects which are located on this file system. Is it correct?

Well, yes. That is, the values of st_dev and st_rdev will be identical for any objects located on the same filesystem. However, this is basically a truism as part of what defines object as "being on the same volume"... is those values matching.

With all that context, the big question here is "What are you actually trying to do?". In my experience, stat() is rarely the "right" API choice. For higher level apps focused on "files", it's better/safer/faster to get the same information through them. For lower level apps that are "volume" focused, I think you're often better off moving "down" an API layer, typically into DiskArbritration, sometimes IOKit. The advantage of the lower level APIs is harder to summarize, but it's things like:

  • The give you access to a much broader information set.

  • They're closer to (or "are") "the truth", which it easier to understand "what's actually going on".

As a concrete example, things like software RAID or APFS volume container mean that you can't reliably determine the relationship between different volumes based on device paths. In concrete terms, it's entirely possible that a volume at "/dev/rdisk3s2" an another at "/dev/rdisk4s3" are in fact located on exactly the same physical device. Detecting that relationship is straightforward in IOKit and basically impossible above that later.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

st_dev of mount point directory is different to device ID of device-file
 
 
Q