linux-kernelnfsebpf

How to obtain the mount point of a given path struct in eBPF probe for the nfs_getattr function?


I am in the process of writing an eBPF probe for the nfs_getattr function in which one of the parameters passed is a path struct that represents the path whose attributes are being queried.

Given the path struct, I need to determine the mount point from the client's perspective.

I've tried getting the value via the vfsmount structure (path->mnt->mnt_root), and by traversing the main dentry up the tree (path->dentry->d_parent->...->d_parent). Both approaches result in the nfs share being returned, not the mount point.

For instance, if I have the following mount command:

mount 127.0.0.1:/nfs-share /mnt/nfs-mount

The returned value from those aforementioned references is nfs-share, but I'm interested in retrieving nfs-mount.

What are the available approaches or solutions to achieve this? Any pointers or guidance would be greatly appreciated.

If it is a namespaced value, then I want to retrieve some id that I could resolve to the mount point in user-space.

I'm targeting kernel version 6.3.0 if it's relevant.


Solution

  • Thanks to this answer I've found a kernel function named follow_up that does what I need. Though I cannot use this function directly because it's not an eBPF function, it gave me the direction for the solution.

    Using the container_of macro it's possible to get the mount struct, and inside it there is an mnt_mountpoint dentry that points to the mount point.

    struct mount* get_mount(const struct path *path)
    {
        if (!path)
            return NULL;
    
        struct vfsmount *vfsmount = BPF_CORE_READ(path, mnt);
    
        if (!vfsmount)
            return NULL;
    
        struct mount *mnt = container_of(vfsmount, struct mount, mnt);
        return mnt;
    }
    
    void get_mount_root(const struct path *path, char *buf, size_t size)
    {
        struct mount *mnt = get_mount(path);
    
        if (!mnt)
            return;
    
        struct dentry *mnt_mountpoint = BPF_CORE_READ(mnt, mnt_mountpoint);
    
        if (!mnt_mountpoint)
            return;
    
        struct qstr dname = BPF_CORE_READ(mnt_mountpoint, d_name);
        bpf_probe_read_kernel(buf, size, dname.name);
    }