This started as a more general question in r/linux_programming, but seeing no responses there I want to ask a more basic question.
Once I have an NFS file handle (for the sake of discussion say I've worked out even under volatile file handles in NFSv4 it is a valid file handle), is there a sequence of library calls to derive its fully-qualified path? The kernel documentation on just local filesystem path lookup, and an old paper on a proposed NFS path lookup scheme change, convinces me this is not code I want to roll my own.
Going through documentation and source code, so far I suspect the code has to be sitting in between either or both the VFS and NFS filesystem device driver code bases. But I must not be understanding the interrelationships between VFS, NFS and the kernel because I've been unable to find out how to bridge the gap between the NFS file handle and the path we are used to seeing in the shell. There is discussion about the open(2) call in userspace translating to a vnode in VFS, and from there to an NFS file handle, but I'm trying to go in the reverse direction (because FS-Cache stores the NFS file handle as near as I can tell from reading the NFS source, not a path value that could be passed to open(2)).
Related to this is how to get the file attributes like ownership, permissions, dates, etc., if I have an NFS file handle, and the file is cached within FS-Cache. I think I can get the inode and then get the attributes that way, but I'm trying to avoid having to hit NFS and stay in FS-Cache, and especially avoid performing a find(1) for the inode.
tl; dr: nfs_fhget()
-> d_obtain_alias() -> d_absolute_path()
.
You will need the struct vfsmount
that describes the mounted filesystem.
Disclaimer: The assumption here is that you got the file handle from fs-cache, i.e. it's the raw NFS file handle, not a struct fid
that you got from something like name_to_handle_at(2).
If you got this handle from the handle fairy, i.e. with no previous context, then the client can't map it to a path. In fact, the server will probably also be unable to map it into a path without a find(1)
.
Just like an inode, it can have multiple paths within the filesystem, and multiple mount points of that filesystem within the mount tree.
But assuming that you got this handle by means of file name lookup, the dcache will contain dentries which point to an inode, which will have an i_private
pointing to that file handle. The inode will also have its list of cached dentries in i_dentry
.
Likewise, the mount tree may have the same NFS mount bind-mounted multiple times.
Because you have a raw NFS file handle, we start at the NFS layer, mapping a file handle to an inode using nfs_fhget()
.
If the inode isn't already in the cache, nfs_fhget()
will just return a blank NFS inode. This can be detected by putting some interesting value in the contents of the fattr
argument.
There are a couple of requirements on fattr
, see nfs_find_actor().
But once you've succeeded, you're done with the NFS layer and you have a VFS inode.
The returned inode also has all the other information like inode permissions, ownership, dates, etc..
Once you have an inode, you want a dentry that points to it.
That's done by d_obtain_alias().
Like with nfs_fhget()
, d_obtain_alias()
won't fail if there's no dentry in the cache. Instead, it will create an "anonymous dentry", i.e. a dentry without an actual name. In this case, its name, relative to the mount point, is just /
.
Assuming that you have the struct vfsmount
and now that you have the dentry, you can build a you have a struct path
.
With a struct path
, you can now call d_absolute_path()
, which finally returns an absolute path.