What are the locking rules for VFS and VNOP operations?

I'm observing all sorts of race conditions occurring in various VNOPs my custom filesystem implements.

I'm inclined to attribute this to my implementation not following the locking rules expected by the system of a 3rd party filesystem as well as it should.

I've looked at how locking is done in Apple's own implementation of Samba and NFS clients.

The Samba client uses read/write locks to protect its node from data races. While the NFS client uses mutex locks for the same purpose.

I realised that I don't have a clear model in my head of how locking should be done properly.

Thus my question, what are the locking rules for VFS and VNOP operations?

Thanks.

Answered by DTS Engineer in 806897022

First off, a bit of a warning and a disclaimer. The vfs system has never been documented to any significant degree. It's supported API in the sense that it is technically possible to create a function VFS KEXT. However, VFS development is not something we've ever encouraged or actively supported. If you choose to use these APIs, you need to understand that state of what you're working with and the limits to the help you'll find.

So I assumed that macOS must have its own locking rules for VFS as well.

It would be helpful to understand what they are, so my filesystem can adhere to them properly.

The best statement of the "rules" I've found are in the EmptyFS ReadMe. It's to long to summarize, the quick introduction is:

VFS handles the locking and reference counting needed for the structures it manages (mount points, vnodes, and so on). Your VFS plug-in can decide how to lock the structures it manages; VFS does not impose locking requirements on your plug-in. You can use mutexes or read/write locks explicitly, so you can get the maximum concurrency, or let VFS do most of your locking for you, which makes your code easier.

See the ReadMe for the more complete description.

On macOS, this doesn't seem sufficient. Thus my query.

What's actually happening? Locking issues in the VFS layer tend to result in hangs or panics, but it sounds like you're dealing with data corruption or presentation issues. That's generally caused by problems with your own locking, not the VFS layer.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Have you seen the MFSLives sample code? While it is wildly out of date, the comments at the top of HashNode.h were my attempt at explaining how this stuff works.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I'm observing all sorts of race conditions occurring in various VNOPs my custom filesystem implements.

I'm inclined to attribute this to my implementation not following the locking rules expected by the system of a 3rd party filesystem as well as it should. ... Thus my question, what are the locking rules for VFS and VNOP operations?

The term "rules" here is very misleading. On it's own, the VFS system doesn't necessarily require any locks at all. When you look at something like this:

I've looked at how locking is done in Apple's own implementation of Samba and NFS clients.

The Samba client uses read/write locks to protect its node from data races. While the NFS client uses mutex locks for the same purpose.

While some of those looks are about the vfs implemenation itself (VNOP_LOOKUP is one example), most of the locking are about ensuring the the file system itself behave in a "sane" matter. As the simplest example, it's hard to see how a basic operation like file moving could be implemented unless some kind of lock ensures that the directories involved don't change while the operation is in progress.

I realised that I don't have a clear model in my head of how locking should be done properly.

This is just a guess, but are you using FUSE and mapping to some kind of "high level" data source (like an existing directory hierarchy)? Part of what creates this kind of confusion is both abstraction layers (FUSE and your data source) end up creating their own "locks" which end up hiding what would otherwise be obvious failures. For example, moving clearly requires significant locking, but it's easy to overlook that reality when your underlying data source is a pre-existing file system... because the file system your using ends up acting as "the lock".

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks for your input.

No, my filesystem is not based on FUSE.

It's a port of a distributed filesystem from a UNIX-like OS to macOS.

The original implementation mostly uses locking to protect the RPCs involved in each file operation.

On macOS, this doesn't seem sufficient. Thus my query.

The Linux kernel documentation for VFS describes the locking rules that must be followed by all filesystems.

FreeBSD filesystems extensively employ locking in their VFS implementations.

So I assumed that macOS must have its own locking rules for VFS as well.

It would be helpful to understand what they are, so my filesystem can adhere to them properly.

First off, a bit of a warning and a disclaimer. The vfs system has never been documented to any significant degree. It's supported API in the sense that it is technically possible to create a function VFS KEXT. However, VFS development is not something we've ever encouraged or actively supported. If you choose to use these APIs, you need to understand that state of what you're working with and the limits to the help you'll find.

So I assumed that macOS must have its own locking rules for VFS as well.

It would be helpful to understand what they are, so my filesystem can adhere to them properly.

The best statement of the "rules" I've found are in the EmptyFS ReadMe. It's to long to summarize, the quick introduction is:

VFS handles the locking and reference counting needed for the structures it manages (mount points, vnodes, and so on). Your VFS plug-in can decide how to lock the structures it manages; VFS does not impose locking requirements on your plug-in. You can use mutexes or read/write locks explicitly, so you can get the maximum concurrency, or let VFS do most of your locking for you, which makes your code easier.

See the ReadMe for the more complete description.

On macOS, this doesn't seem sufficient. Thus my query.

What's actually happening? Locking issues in the VFS layer tend to result in hangs or panics, but it sounds like you're dealing with data corruption or presentation issues. That's generally caused by problems with your own locking, not the VFS layer.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

What are the locking rules for VFS and VNOP operations?
 
 
Q