VFSOPS(9)

πŸ“¦ version 11.0, in nixpkgs unstable

✨ NAME ✨

okay so this is VFSOPS(9), straight from the Kernel Developer's Manual, and it's literally the kernel file system interface πŸ’…. The whole squad is here: vfsops, VFS_MOUNT, VFS_START, VFS_UNMOUNT, VFS_ROOT, VFS_QUOTACTL, VFS_STATVFS, VFS_SYNC, VFS_VGET, VFS_LOADVNODE, VFS_NEWVNODE, VFS_FHTOVP, VFS_VPTOFH, VFS_SNAPSHOT, and VFS_SUSPENDCTL. That's the lineup, bestie β€” no cap 🫢.


πŸ¦‹ SYNOPSIS πŸ¦‹

here's the exact signature situation, copied character-for-character because we do not play with kernel code πŸ’€:

#include <sys/param.h>
#include <sys/mount.h>
#include <sys/vnode.h>

int
VFS_MOUNT(struct mount *mp, const char *path, void *data, size_t *dlen);

int
VFS_START(struct mount *mp, int flags);

int
VFS_UNMOUNT(struct mount *mp, int mntflags);

int
VFS_ROOT(struct mount *mp, int lktype, struct vnode **vpp);

int
VFS_QUOTACTL(struct mount *mp, struct quotactl_args *args);

int
VFS_STATVFS(struct mount *mp, struct statvfs *sbp);

int
VFS_SYNC(struct mount *mp, int waitfor, kauth_cred_t cred);

int
VFS_VGET(struct mount *mp, ino_t ino, int lktype, struct vnode **vpp);

int
VFS_LOADVNODE(struct mount *mp, struct vnode *vp, const void *key,
    size_t key_len, const void **new_key);

int
VFS_NEWVNODE(struct mount *mp, struct vnode *dvp, struct vnode *vp,
    struct vattr *vap, kauth_cred_t cred, void *extra, size_t *key_len,
    const void **new_key);

int
VFS_FHTOVP(struct mount *mp, struct fid *fhp, int lktype,
    struct vnode **vpp);

int
VFS_VPTOFH(struct vnode *vp, struct fid *fhp, size_t *fh_size);

int
VFS_SNAPSHOT(struct mount *mp, struct vnode *vp, struct timespec *ts);

int
VFS_SUSPENDCTL(struct mount *mp, int cmd);

πŸ’… DESCRIPTION πŸ’…

so basically, it's giving the same energy as the vnode(9) interface ✨. Every operation that gets done on a file system goes through one single interface, and that lets the system carry out operations on a file system without knowing its construction or type. iconic, honestly.

all supported file systems in the kernel have an entry in the vfs_list_initial table. this table is generated by config(1) and is a NULL-terminated list of vfsops structures. the vfsops structure describes the operations that can be done to a specific file system type. the following lineup lists the elements of the vfsops vector, the corresponding invocation macro, and a description of the element β€” same info as the boring table, just with better vibes πŸŽ€:

  • int (*vfs_mount)() β†’ macro VFS_MOUNT β€” mount a file system.
  • int (*vfs_start)() β†’ macro VFS_START β€” make operational.
  • int (*vfs_unmount)() β†’ macro VFS_UNMOUNT β€” unmount a file system.
  • int (*vfs_root)() β†’ macro VFS_ROOT β€” get the file system root vnode.
  • int (*vfs_quotactl)() β†’ macro VFS_QUOTACTL β€” query/modify space quotas.
  • int (*vfs_statvfs)() β†’ macro VFS_STATVFS β€” get file system statistics.
  • int (*vfs_sync)() β†’ macro VFS_SYNC β€” flush file system buffers.
  • int (*vfs_vget)() β†’ macro VFS_VGET β€” get vnode from file id.
  • int (*vfs_loadvnode)() β†’ macro VFS_LOADVNODE β€” initialize vnode with file.
  • int (*vfs_newvnode)() β†’ macro VFS_NEWVNODE β€” initialize vnode with new file.
  • int (*vfs_fhtovp)() β†’ macro VFS_FHTOVP β€” NFS file handle to vnode lookup.
  • int (*vfs_vptofh)() β†’ macro VFS_VPTOFH β€” vnode to NFS file handle lookup.
  • void (*vfs_init)() β†’ macro - β€” initialize file system.
  • void (*vfs_reinit)() β†’ macro - β€” reinitialize file system.
  • void (*vfs_done)() β†’ macro - β€” cleanup unmounted file system.
  • int (*vfs_mountroot)() β†’ macro - β€” mount the root file system.
  • int (*vfs_snapshot)() β†’ macro VFS_SNAPSHOT β€” take a snapshot.
  • int (*vfs_suspendctl)() β†’ macro VFS_SUSPENDCTL β€” suspend or resume.

some additional non-function members of the vfsops structure are the file system name vfs_name and a reference count vfs_refcount 🧚. it is not mandatory for a file system type to support a particular operation, but it must assign each member function pointer to a suitable function to do the minimum required of it. in most cases, such functions either do nothing or return an error value to the effect that it is not supported. vfs_reinit, vfs_mountroot, vfs_fhtovp, and vfs_vptofh may be NULL.

at system boot, each file system with an entry in vfs_list_initial is established and initialized. each initialized file system is recorded by the kernel in the list vfs_list, and the file system specific initialization function vfs_init in its vfsops vector is invoked. when the file system is no longer needed, vfs_done is invoked to run file system specific cleanups and the file system is removed from the kernel list πŸ¦‹.

at system boot, the root file system is mounted by invoking the file system type specific vfs_mountroot function in the vfsops vector. all file systems that can be mounted as a root file system must define this function. it is responsible for initializing the list of mount structures for all future mounted file systems πŸ‘‘.

kernel state which affects a specific file system type can be queried and modified using the sysctl(8) interface ⭐.

πŸ’– FUNCTIONS πŸ’–

Okay bestie, this is the main character section β€” every single vfs operation, what it does, and what it's giving. Grab a snack πŸ“


πŸŽ€ VFS_MOUNT(mp, path, data, dlen)

Mounts a file system on the mount point described by path, where the file system itself is specified by the mount structure mp. The argument data holds file-system-type-specific data, and dlen points to a location that says how long that data is.

VFS_MOUNT() initializes the mount structure for the mounted file system. That structure is literally the receipt 🧾 β€” it records mount-specific info for the file system and records the list of vnodes associated with the file system. This function gets invoked both to mount brand new file systems and to change the attributes of one that's already out there. If the flag MNT_UPDATE is set in mp->mnt_flag, the file system should update its state β€” think converting a read-only file system to read-write, that's the classic glow-up ✨. You can fetch the current attributes for a mounted file system by specifying MNT_GETARGS. And if neither MNT_UPDATE nor MNT_GETARGS are specified, a new file system will be attempted to be mounted.


πŸ¦‹ VFS_START(mp, flags)

Makes the file system specified by the mount structure mp operational. The argument flags is a set of flags controlling how VFS_START() operates. This one is invoked after VFS_MOUNT() and before the very first access to the file system β€” like the pre-show soundcheck, no cap 🎀


πŸ’… VFS_UNMOUNT(mp, mntflags)

Unmounts a file system specified by the mount structure mp. VFS_UNMOUNT() performs any file-system-type-specific operations required before the file system is unmounted β€” flushing buffers and all that ✨. If MNT_FORCE is specified in the flags mntflags, then open files are forcibly closed 😳 (yes, forcibly, they don't get a vote). This function also deallocates space associated with data structures that were allocated for the file system back when it was mounted. Cleanup era 🧹


🌸 VFS_ROOT(mp, lktype, vpp)

Gets the root vnode of the file system specified by the mount structure mp. The vnode comes back in the address given by vpp, with lock type lktype. lktype can be LK_NONE, or LK_SHARED, or LK_EXCLUSIVE β€” those are the three, periodt. This function is used by the pathname translation algorithms when a vnode that has been covered by a mounted file system is encountered. While resolving the pathname, the pathname translation algorithm has to go through the directory tree in the file system associated with that mount point, and therefore it requires the root vnode of the file system. It's giving "you can't get anywhere without the front door" πŸšͺ


⭐ VFS_QUOTACTL(mp, args)

Queries and/or modifies user space quotas for the file system specified by the mount structure mp. The argument structure provides the operation ID and the arguments to perform. This is the same interface as documented in __quotactl(2), except that the file system argument has already been resolved. All the copyin(9) and copyout(9) processing is handled by code above the file system β€” so not your problem, bestie 🫢


🌈 VFS_STATVFS(mp, sbp)

Gets file system statistics for the file system specified by the mount structure mp. A statvfs structure filled with the statistics is returned in sbp. VFS_STATVFS() is the file-system-type-specific implementation of the statvfs(2) and fstatvfs(2) system calls. Stats queen πŸ“Š


🧚 VFS_SYNC(mp, waitfor, cred)

Flushes file system I/O buffers for the file system specified by the mount structure mp. The waitfor argument indicates whether a partial flush or a complete flush should be performed. The argument cred specifies the calling credentials. And here's the slay: VFS_SYNC() does not provide any return value since the operation can never fail. Never. It simply cannot flop πŸ’€βœ¨


πŸ‘‘ VFS_VGET(mp, ino, lktype, vpp)

Gets a vnode for a file-system-type-specific file id ino, for the file system specified by the mount structure mp, with lock type lktype. lktype can be LK_NONE, or LK_SHARED, or LK_EXCLUSIVE. The vnode is returned in the address specified by vpp. This function is optional for file systems which have a unique id number for every file in the file system. It's used internally by the UFS file system and also by the NFSv3 server to implement the READDIRPLUS NFS call. If the file system does not support this function, it should return EOPNOTSUPP.


πŸ“ VFS_LOADVNODE(mp, vp, key, key_len, new_key)

Initialises the vnode vp with the file identified by the arguments key and key_len, for the file system specified by the mount structure mp.

The new key is returned in the address specified by new_key.

Caller of this function assures no other thread will try to load this file. Exclusive access, main character energy only πŸ’…


🎀 VFS_NEWVNODE(mp, dvp, vp, vap, cred, extra, key_len, new_key)

Initialises the vnode vp with a new file, for the file system specified by the mount structure mp. Fresh file, who dis 🌱

The argument dvp points to the directory to create the file in.

The argument vap points to the attributes for the file to create.

The argument cred holds the credentials for the file to create.

The argument extra allows the caller to pass more information about the file to create.

And the key for the file is returned in the addresses specified by key_len and new_key.


πŸ”₯ VFS_FHTOVP(mp, fhp, lktype, vpp)

Gets the vnode for the file handle fhp in the file system specified by the mount structure mp, with lock type lktype. lktype can be LK_NONE, or LK_SHARED, or LK_EXCLUSIVE. The locked vnode is returned in vpp.

When exporting, the call to VFS_FHTOVP() should follow a call to netexport_check(), which checks if the file is accessible to the client. Security check first, always πŸ”

If file handles are not supported by the file system, this function must return EOPNOTSUPP.

πŸ¦‹ VFS_VPTOFH(vp, fhp, fh_size)

Gets a file handle for the vnode specified by vp. The file handle is returned in fhp. The contents of the file handle are defined by the file system and are not examined by any other subsystems. It should contain enough information to uniquely identify a file within the file system, as well as to notice when a file has been removed and the file system resources have been recycled for a new file. It's like a little name tag that also knows when someone's gone πŸ‘€

The parameter fh_size points to the container size for the file handle. This parameter should be updated to the size of the finished file handle. Note that it is legal to call this function with fhp set to NULL in case fh_size is zero. In case fh_size indicates a storage space too small, the storage space required for the file handle corresponding to vp should be filled in and E2BIG should be returned.

If file handles are not supported by the file system, this function must return EOPNOTSUPP.

🌸 VFS_SNAPSHOT(mp, vp, ts)

Takes a snapshot of the file system specified by the mount structure mp and makes it accessible through the locked vnode vp. If ts is not NULL, it will receive the time this snapshot was taken. If the file system does not support this function, it should return EOPNOTSUPP. Say cheese πŸ“Έ


πŸ’œ VFS_SUSPENDCTL(mp, cmd)

Suspends or resumes all operations on this file system. cmd is either SUSPEND_SUSPEND to suspend or SUSPEND_RESUME to resume operations. If the file system does not support this function, it should return EOPNOTSUPP. Freeze frame, then unfreeze πŸ§Šβž‘οΈπŸ’§


⭐ CODE REFERENCES ⭐

The vfs operations are implemented within the files sys/kern/vfs_subr.c and sys/kern/vfs_init.c. Go read the source, bestie, it's literally right there 🫢


🌈 SEE ALSO 🌈

intro(9), namei(9), vfs(9), vfssubr(9), vnode(9), vnodeops(9)

The friend group πŸ«‚


πŸŽ€ HISTORY πŸŽ€

The vfs operations vector, its functions and the corresponding macros appeared in 4.3BSD. Vintage, and yet still iconic ✨


That's the whole page, bestie πŸ’– This one's from Debian, dated August 7, 2020, and it's the VFSOPS(9) page β€” you're officially a vfs girlie now, go forth and slay those file system operations πŸ‘‘πŸ’…

πŸ“¦ where this page comes from