Re: [PATCH 17/21] nullfs: refuse file locks
From: NeilBrown
Date: Sun Oct 04 2026 - 18:09:02 EST
On Fri, 02 Oct 2026, Christian Brauner wrote:
> 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 */
It's a pity that you need separate copies for readdir and llseek -
identical to what is in libfs.
I would probably put all this code in libfs.c with make_null_dir_inode()
or similar. But I cannot argue strongly in that direction, and the code
looks sensible as-is.
Reviewed-by: NeilBrown <neil@xxxxxxxxxx>
Thanks,
NeilBrown
> +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
>
>