# Reading file name from vnode



## vtx (Sep 17, 2020)

Hello,

I'm using FreeBSD 8.2 on some ARM board. I'm trying to write some extension for Lauterbach HW debugger. To complete it I need to know how to fetch file name from vnode structure. I have pointer to this structure. I've analysed this structure but unfortunately I didn't find any usable fields which I could use for fetchin file name.

During the research I found vn_fullpath() procedure, but I cannot use it because I have no access to any FreeBSD API (neither kernel nor user space). The reason is that I'm writing this extension to HW debugger so I only operate on debugging symbols of the kernel and do some read or writes to the system memory. This code have some limitations and because of that I want to do it as simple sa possible. The second reason is that I want to write code to run as quick as possible because it will be used for performance metering.

As far as I know vn_fullpath() uses filesystem cache, but I don't want to go through this cache to keep the code as simple as possible.

My question is - how to get file name from vnode structure when I have pointer to that structure?


----------



## olli@ (Sep 17, 2020)

Short answer: Please read the vn_fullpath(9) manual page.

Long answer: A vnode does _not_ have a file name, because there is no one-to-one relationship between file names and vnodes. A vnode represents a file inside the kernel, but this is _not_ attached to a particular directory entry. In fact, a vnode exists independently of the actual storage of the file on physical media.

For example, if the underlying file system is UFS (or another file system that supports POSIX semantics), a single file can have multiple names, i.e. multiple directory entries (a.k.a. hardlinks). But a vnode does not contain any information about which of those names was used to open the file. The same happens when a file system is attached to multiple paths, using nullfs(5) or similar. So, asking for “the file’s name” is inherently ambiguous.

Furthermore, a directory entry can be renamed after the file was opened. The vnode stays valid, of course, but the name that was used to open it does not exist anymore. The same applies if a directory along the path in which the file resides was renamed.

Similarly, a directory entry can be removed after the file was opened. If this was the last name of the file (i.e. the link count drops to zero), then the file is not accessible via the file system anymore, i.e. it does not have a name at all. But the file does still exist, as does the vnode, until the last reference to it is closed.

There are even more complicated situations when multiple file systems are overlaid over each other, for example using mount_unionfs(8) or the `-o union` option of mount(8) (these two are quite different from each other and should not be confused). In this case, the same file name can refer to two different files on different file systems. Things will get even more complicated if so-called whiteout files are created in the upper layer of the union file system. And yet another thing that might spoil the fun is the kernel’s ABI emulation that translates path names – for example, when a Linux binary opens /etc/shells, the kernel will actually create a vnode for /compat/linux/etc/shells.

The vn_fullpath(9) kernel function tries to reconstruct a file name by searching through the name cache. This may work, but it’s not guaranteed. It may return a different name than the one that was used to open the file. It may fail completely if the directory entry was removed after opening the file. And it may fail if the entry has been purged from the name cache (which is normal behavior because the size of the name cache is limited). Also, there are file systems that don’t use the name cache (for example procfs or devfs, maybe also tmpfs but I’m not sure).

Also note that the vn_fullpath(9) function is not very efficient. It’s probably not a good idea to call it often in a tight loop. You can see this clearly by running `lsof` (from the sysutils/lsof package):

```
$ /usr/bin/time lsof >/dev/null
        1.71 real         0.83 user         0.87 sys
$ /usr/bin/time lsof -C >/dev/null
        0.02 real         0.00 user         0.01 sys
```
By default, lsof(8) uses the name cache to (try to) find file names for files that processes have opened. This can be inhibited with the `-C` option. As you can see, searching the name cache makes lsof(8) about a hundred times slower.


----------

