[PATCH 17/21] nullfs: refuse file locks

From: Christian Brauner

Date: Fri Oct 02 2026 - 09:57:17 EST


Refuse flock() and POSIX locks on nullfs. Its one inode is the root of
every kernel thread and the following patches make it the directory
that stands in for an unmounted mount, so a lock taken through one such
directory would block the locks of every other holder and F_GETLK would
tell them the pid of the holder. Give the directory file operations of
its own: what libfs gives an empty directory plus ->lock and ->flock
that fail with ENOLCK, the way a filesystem without lock support does.

Signed-off-by: Christian Brauner (Amutable) <brauner@xxxxxxxxxx>
---
fs/nullfs.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)

diff --git a/fs/nullfs.c b/fs/nullfs.c
index 55a04f2d7761..d90c71f5eece 100644
--- a/fs/nullfs.c
+++ b/fs/nullfs.c
@@ -10,6 +10,34 @@ static const struct super_operations nullfs_super_operations = {
.statfs = simple_statfs,
};

+static loff_t nullfs_dir_llseek(struct file *file, loff_t offset, int whence)
+{
+ /* an empty directory has two entries . and .. at offsets 0 and 1 */
+ return generic_file_llseek_size(file, offset, whence, 2, 2);
+}
+
+static int nullfs_dir_readdir(struct file *file, struct dir_context *ctx)
+{
+ dir_emit_dots(file, ctx);
+ return 0;
+}
+
+/* the one inode of nullfs is shared by every holder, so no locks on it */
+static int nullfs_nolock(struct file *file, int cmd, struct file_lock *fl)
+{
+ return -ENOLCK;
+}
+
+/* what libfs gives an empty directory, plus the refusal of file locks */
+static const struct file_operations nullfs_dir_operations = {
+ .llseek = nullfs_dir_llseek,
+ .read = generic_read_dir,
+ .iterate_shared = nullfs_dir_readdir,
+ .fsync = noop_fsync,
+ .lock = nullfs_nolock,
+ .flock = nullfs_nolock,
+};
+
static int nullfs_fs_fill_super(struct super_block *s, struct fs_context *fc)
{
struct inode *inode;
@@ -30,6 +58,7 @@ static int nullfs_fs_fill_super(struct super_block *s, struct fs_context *fc)

/* nullfs is permanently empty... */
make_empty_dir_inode(inode);
+ inode->i_fop = &nullfs_dir_operations;
simple_inode_init_ts(inode);
inode->i_ino = 1;
/* ... and immutable, reading it leaves no trace either. */

--
2.53.0