diff options
| author | Christian Brauner <brauner@kernel.org> | 2026-01-12 10:55:54 +0100 |
|---|---|---|
| committer | Christian Brauner <brauner@kernel.org> | 2026-01-12 10:55:54 +0100 |
| commit | 7e463614c97b643f60caa66caf13ce5f94ea91c1 (patch) | |
| tree | 9604640012fd39594bbf5978291f0cb00e472c47 | |
| parent | 7d42f2b1cc3a60a71784967384ddcf29fe3f35ed (diff) | |
| parent | 51e49111c00bee76ca403adf7cd617b71a9a0da4 (diff) | |
Merge patch series "vfs: require filesystems to explicitly opt-in to lease support"
Jeff Layton <jlayton@kernel.org> says:
Yesterday, I sent patches to fix how directory delegation support is
handled on filesystems where the should be disabled [1]. That set is
appropriate for v6.19. For v7.0, I want to make lease support be more
opt-in, rather than opt-out:
For historical reasons, when ->setlease() file_operation is set to NULL,
the default is to use the kernel-internal lease implementation. This
means that if you want to disable them, you need to explicitly set the
->setlease() file_operation to simple_nosetlease() or the equivalent.
This has caused a number of problems over the years as some filesystems
have inadvertantly allowed leases to be acquired simply by having left
it set to NULL. It would be better if filesystems had to opt-in to lease
support, particularly with the advent of directory delegations.
This series has sets the ->setlease() operation in a pile of existing
local filesystems to generic_setlease() and then changes
kernel_setlease() to return -EINVAL when the setlease() operation is not
set.
With this change, new filesystems will need to explicitly set the
->setlease() operations in order to provide lease and delegation
support.
I mainly focused on filesystems that are NFS exportable, since NFS and
SMB are the main users of file leases, and they tend to end up exporting
the same filesystem types. Let me know if I've missed any.
[1]: https://lore.kernel.org/linux-fsdevel/20260107-setlease-6-19-v1-0-85f034abcc57@kernel.org/
* patches from https://patch.msgid.link/20260108-setlease-6-20-v1-0-ea4dec9b67fa@kernel.org: (24 commits)
fs: remove simple_nosetlease()
filelock: default to returning -EINVAL when ->setlease operation is NULL
xfs: add setlease file operation
ufs: add setlease file operation
udf: add setlease file operation
tmpfs: add setlease file operation
squashfs: add setlease file operation
overlayfs: add setlease file operation
orangefs: add setlease file operation
ocfs2: add setlease file operation
ntfs3: add setlease file operation
nilfs2: add setlease file operation
jfs: add setlease file operation
jffs2: add setlease file operation
gfs2: add a setlease file operation
fat: add setlease file operation
f2fs: add setlease file operation
exfat: add setlease file operation
ext4: add setlease file operation
ext2: add setlease file operation
...
Link: https://patch.msgid.link/20260108-setlease-6-20-v1-0-ea4dec9b67fa@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
61 files changed, 116 insertions, 42 deletions
diff --git a/Documentation/filesystems/porting.rst b/Documentation/filesystems/porting.rst index 3397937ed838..c0f7103628ab 100644 --- a/Documentation/filesystems/porting.rst +++ b/Documentation/filesystems/porting.rst @@ -1334,3 +1334,12 @@ end_creating() and the parent will be unlocked precisely when necessary. kill_litter_super() is gone; convert to DCACHE_PERSISTENT use (as all in-tree filesystems have done). + +--- + +**mandatory** + +The ->setlease() file_operation must now be explicitly set in order to provide +support for leases. When set to NULL, the kernel will now return -EINVAL to +attempts to set a lease. Filesystems that wish to use the kernel-internal lease +implementation should set it to generic_setlease(). diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst index 670ba66b60e4..21dc8921dd9e 100644 --- a/Documentation/filesystems/vfs.rst +++ b/Documentation/filesystems/vfs.rst @@ -1180,9 +1180,12 @@ otherwise noted. method is used by the splice(2) system call ``setlease`` - called by the VFS to set or release a file lock lease. setlease - implementations should call generic_setlease to record or remove - the lease in the inode after setting it. + called by the VFS to set or release a file lock lease. Local + filesystems that wish to use the kernel-internal lease implementation + should set this to generic_setlease(). Other setlease implementations + should call generic_setlease() to record or remove the lease in the inode + after setting it. When set to NULL, attempts to set or remove a lease will + return -EINVAL. ``fallocate`` called by the VFS to preallocate blocks or punch a hole. diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index af7f72abbb76..e0d34e4e9076 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c @@ -242,7 +242,6 @@ const struct file_operations v9fs_dir_operations = { .iterate_shared = v9fs_dir_readdir, .open = v9fs_file_open, .release = v9fs_dir_release, - .setlease = simple_nosetlease, }; const struct file_operations v9fs_dir_operations_dotl = { @@ -252,5 +251,4 @@ const struct file_operations v9fs_dir_operations_dotl = { .open = v9fs_file_open, .release = v9fs_dir_release, .fsync = v9fs_file_fsync_dotl, - .setlease = simple_nosetlease, }; diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 6f3880208587..c5e73c37baea 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -517,7 +517,6 @@ const struct file_operations v9fs_file_operations = { .splice_read = v9fs_file_splice_read, .splice_write = iter_file_splice_write, .fsync = v9fs_file_fsync, - .setlease = simple_nosetlease, }; const struct file_operations v9fs_file_operations_dotl = { @@ -532,5 +531,4 @@ const struct file_operations v9fs_file_operations_dotl = { .splice_read = v9fs_file_splice_read, .splice_write = iter_file_splice_write, .fsync = v9fs_file_fsync_dotl, - .setlease = simple_nosetlease, }; diff --git a/fs/affs/dir.c b/fs/affs/dir.c index bd40d5f08810..fe18caaf4d65 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c @@ -15,6 +15,7 @@ */ #include <linux/iversion.h> +#include <linux/filelock.h> #include "affs.h" struct affs_dir_data { @@ -55,6 +56,7 @@ const struct file_operations affs_dir_operations = { .iterate_shared = affs_readdir, .fsync = affs_file_fsync, .release = affs_dir_release, + .setlease = generic_setlease, }; /* diff --git a/fs/affs/file.c b/fs/affs/file.c index 765c3443663e..6c9258359ddb 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -15,6 +15,7 @@ #include <linux/uio.h> #include <linux/blkdev.h> +#include <linux/filelock.h> #include <linux/mpage.h> #include "affs.h" @@ -1008,6 +1009,7 @@ const struct file_operations affs_file_operations = { .release = affs_file_release, .fsync = affs_file_fsync, .splice_read = filemap_splice_read, + .setlease = generic_setlease, }; const struct inode_operations affs_file_inode_operations = { diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 9fcfdd6b8189..d7c5d9270387 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -14,6 +14,7 @@ #include <linux/fs_context.h> #include <linux/fs_parser.h> #include <linux/errno.h> +#include <linux/filelock.h> #include <linux/stat.h> #include <linux/nls.h> #include <linux/buffer_head.h> @@ -79,6 +80,7 @@ static const struct file_operations befs_dir_operations = { .read = generic_read_dir, .iterate_shared = befs_readdir, .llseek = generic_file_llseek, + .setlease = generic_setlease, }; static const struct inode_operations befs_dir_inode_operations = { diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 1abc7ed2990e..aca2b541e72d 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -10,6 +10,7 @@ #include <linux/string.h> #include <linux/backing-dev.h> #include <linux/falloc.h> +#include <linux/filelock.h> #include <linux/writeback.h> #include <linux/compat.h> #include <linux/slab.h> @@ -3867,6 +3868,7 @@ const struct file_operations btrfs_file_operations = { .remap_file_range = btrfs_remap_file_range, .uring_cmd = btrfs_uring_cmd, .fop_flags = FOP_BUFFER_RASYNC | FOP_BUFFER_WASYNC, + .setlease = generic_setlease, }; int btrfs_fdatawrite_range(struct btrfs_inode *inode, loff_t start, loff_t end) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index d2b302ac6af9..d377794b4c9f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8,6 +8,7 @@ #include <linux/bio.h> #include <linux/blk-cgroup.h> #include <linux/file.h> +#include <linux/filelock.h> #include <linux/fs.h> #include <linux/fs_struct.h> #include <linux/pagemap.h> @@ -10596,6 +10597,7 @@ static const struct file_operations btrfs_dir_file_operations = { #endif .release = btrfs_release_file, .fsync = btrfs_sync_file, + .setlease = generic_setlease, }; /* diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 804588524cd5..86d7aa594ea9 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -2214,7 +2214,6 @@ const struct file_operations ceph_dir_fops = { .fsync = ceph_fsync, .lock = ceph_lock, .flock = ceph_flock, - .setlease = simple_nosetlease, }; const struct file_operations ceph_snapdir_fops = { @@ -2222,7 +2221,6 @@ const struct file_operations ceph_snapdir_fops = { .llseek = ceph_dir_llseek, .open = ceph_open, .release = ceph_release, - .setlease = simple_nosetlease, }; const struct inode_operations ceph_dir_iops = { diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 983390069f73..31b691b2aea2 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -3169,7 +3169,6 @@ const struct file_operations ceph_file_fops = { .mmap_prepare = ceph_mmap_prepare, .fsync = ceph_fsync, .lock = ceph_lock, - .setlease = simple_nosetlease, .flock = ceph_flock, .splice_read = ceph_splice_read, .splice_write = iter_file_splice_write, diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index e54ebe402df7..41b1a869cf13 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/fs.h> #include <linux/file.h> +#include <linux/filelock.h> #include <linux/pagemap.h> #include <linux/ramfs.h> #include <linux/init.h> @@ -938,6 +939,7 @@ static const struct file_operations cramfs_directory_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .iterate_shared = cramfs_readdir, + .setlease = generic_setlease, }; static const struct inode_operations cramfs_dir_inode_operations = { diff --git a/fs/efs/dir.c b/fs/efs/dir.c index f892ac7c2a35..35ad0092c115 100644 --- a/fs/efs/dir.c +++ b/fs/efs/dir.c @@ -6,6 +6,7 @@ */ #include <linux/buffer_head.h> +#include <linux/filelock.h> #include "efs.h" static int efs_readdir(struct file *, struct dir_context *); @@ -14,6 +15,7 @@ const struct file_operations efs_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .iterate_shared = efs_readdir, + .setlease = generic_setlease, }; const struct inode_operations efs_dir_inode_operations = { diff --git a/fs/erofs/data.c b/fs/erofs/data.c index bb13c4cb8455..e2941b471561 100644 --- a/fs/erofs/data.c +++ b/fs/erofs/data.c @@ -5,6 +5,7 @@ * Copyright (C) 2021, Alibaba Cloud */ #include "internal.h" +#include <linux/filelock.h> #include <linux/sched/mm.h> #include <trace/events/erofs.h> @@ -483,4 +484,5 @@ const struct file_operations erofs_file_fops = { .mmap_prepare = erofs_file_mmap_prepare, .get_unmapped_area = thp_get_unmapped_area, .splice_read = filemap_splice_read, + .setlease = generic_setlease, }; diff --git a/fs/erofs/dir.c b/fs/erofs/dir.c index 32b4f5aa60c9..e5132575b9d3 100644 --- a/fs/erofs/dir.c +++ b/fs/erofs/dir.c @@ -5,6 +5,7 @@ * Copyright (C) 2022, Alibaba Cloud */ #include "internal.h" +#include <linux/filelock.h> static int erofs_fill_dentries(struct inode *dir, struct dir_context *ctx, void *dentry_blk, struct erofs_dirent *de, @@ -127,4 +128,5 @@ const struct file_operations erofs_dir_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = erofs_compat_ioctl, #endif + .setlease = generic_setlease, }; diff --git a/fs/exfat/dir.c b/fs/exfat/dir.c index 3045a58e124a..2dbf335eafef 100644 --- a/fs/exfat/dir.c +++ b/fs/exfat/dir.c @@ -7,6 +7,7 @@ #include <linux/compat.h> #include <linux/bio.h> #include <linux/buffer_head.h> +#include <linux/filelock.h> #include "exfat_raw.h" #include "exfat_fs.h" @@ -298,6 +299,7 @@ const struct file_operations exfat_dir_operations = { .compat_ioctl = exfat_compat_ioctl, #endif .fsync = exfat_file_fsync, + .setlease = generic_setlease, }; int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu) diff --git a/fs/exfat/file.c b/fs/exfat/file.c index 536c8078f0c1..b60ee0e1bec9 100644 --- a/fs/exfat/file.c +++ b/fs/exfat/file.c @@ -12,6 +12,7 @@ #include <linux/security.h> #include <linux/msdos_fs.h> #include <linux/writeback.h> +#include <linux/filelock.h> #include "exfat_raw.h" #include "exfat_fs.h" @@ -772,6 +773,7 @@ const struct file_operations exfat_file_operations = { .fsync = exfat_file_fsync, .splice_read = exfat_splice_read, .splice_write = iter_file_splice_write, + .setlease = generic_setlease, }; const struct inode_operations exfat_file_inode_operations = { diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index b07b3b369710..395fc36c089b 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -24,6 +24,7 @@ #include "ext2.h" #include <linux/buffer_head.h> +#include <linux/filelock.h> #include <linux/pagemap.h> #include <linux/swap.h> #include <linux/iversion.h> @@ -734,4 +735,5 @@ const struct file_operations ext2_dir_operations = { .compat_ioctl = ext2_compat_ioctl, #endif .fsync = ext2_fsync, + .setlease = generic_setlease, }; diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 76bddce462fc..ebe356a38b18 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -22,6 +22,7 @@ #include <linux/time.h> #include <linux/pagemap.h> #include <linux/dax.h> +#include <linux/filelock.h> #include <linux/quotaops.h> #include <linux/iomap.h> #include <linux/uio.h> @@ -325,6 +326,7 @@ const struct file_operations ext2_file_operations = { .get_unmapped_area = thp_get_unmapped_area, .splice_read = filemap_splice_read, .splice_write = iter_file_splice_write, + .setlease = generic_setlease, }; const struct inode_operations ext2_file_inode_operations = { diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 256fe2c1d4c1..00c4b3c82b65 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -24,6 +24,7 @@ #include <linux/fs.h> #include <linux/buffer_head.h> +#include <linux/filelock.h> #include <linux/slab.h> #include <linux/iversion.h> #include <linux/unicode.h> @@ -690,4 +691,5 @@ const struct file_operations ext4_dir_operations = { #endif .fsync = ext4_sync_file, .release = ext4_release_dir, + .setlease = generic_setlease, }; diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 7a8b30932189..534cf864101f 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -25,6 +25,7 @@ #include <linux/mount.h> #include <linux/path.h> #include <linux/dax.h> +#include <linux/filelock.h> #include <linux/quotaops.h> #include <linux/pagevec.h> #include <linux/uio.h> @@ -980,6 +981,7 @@ const struct file_operations ext4_file_operations = { .fop_flags = FOP_MMAP_SYNC | FOP_BUFFER_RASYNC | FOP_DIO_PARALLEL_WRITE | FOP_DONTCACHE, + .setlease = generic_setlease, }; const struct inode_operations ext4_file_inode_operations = { diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 48f4f98afb01..be70dfb3b152 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -8,6 +8,7 @@ #include <linux/unaligned.h> #include <linux/fs.h> #include <linux/f2fs_fs.h> +#include <linux/filelock.h> #include <linux/sched/signal.h> #include <linux/unicode.h> #include "f2fs.h" @@ -1136,4 +1137,5 @@ const struct file_operations f2fs_dir_operations = { #ifdef CONFIG_COMPAT .compat_ioctl = f2fs_compat_ioctl, #endif + .setlease = generic_setlease, }; diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index d7047ca6b98d..cd4b1d3c90ab 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -11,6 +11,7 @@ #include <linux/writeback.h> #include <linux/blkdev.h> #include <linux/falloc.h> +#include <linux/filelock.h> #include <linux/types.h> #include <linux/compat.h> #include <linux/uaccess.h> @@ -5457,4 +5458,5 @@ const struct file_operations f2fs_file_operations = { .splice_write = iter_file_splice_write, .fadvise = f2fs_file_fadvise, .fop_flags = FOP_BUFFER_RASYNC, + .setlease = generic_setlease, }; diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 92b091783966..807bc8b1bc14 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <linux/compat.h> +#include <linux/filelock.h> #include <linux/uaccess.h> #include <linux/iversion.h> #include "fat.h" @@ -876,6 +877,7 @@ const struct file_operations fat_dir_operations = { .compat_ioctl = fat_compat_dir_ioctl, #endif .fsync = fat_file_fsync, + .setlease = generic_setlease, }; static int fat_get_short_entry(struct inode *dir, loff_t *pos, diff --git a/fs/fat/file.c b/fs/fat/file.c index 4fc49a614fb8..d50a6d8bfaae 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -13,6 +13,7 @@ #include <linux/mount.h> #include <linux/blkdev.h> #include <linux/backing-dev.h> +#include <linux/filelock.h> #include <linux/fsnotify.h> #include <linux/security.h> #include <linux/falloc.h> @@ -212,6 +213,7 @@ const struct file_operations fat_file_operations = { .splice_read = filemap_splice_read, .splice_write = iter_file_splice_write, .fallocate = fat_fallocate, + .setlease = generic_setlease, }; static int fat_cont_expand(struct inode *inode, loff_t size) diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c index 1b0bca8b4cc6..138e08de976e 100644 --- a/fs/freevxfs/vxfs_lookup.c +++ b/fs/freevxfs/vxfs_lookup.c @@ -8,6 +8,7 @@ * Veritas filesystem driver - lookup and other directory related code. */ #include <linux/fs.h> +#include <linux/filelock.h> #include <linux/time.h> #include <linux/mm.h> #include <linux/highmem.h> @@ -36,6 +37,7 @@ const struct file_operations vxfs_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .iterate_shared = vxfs_readdir, + .setlease = generic_setlease, }; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 64b29db52cf4..7c183ec496bf 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -2430,7 +2430,6 @@ static const struct file_operations fuse_dir_operations = { .fsync = fuse_dir_fsync, .unlocked_ioctl = fuse_dir_ioctl, .compat_ioctl = fuse_dir_compat_ioctl, - .setlease = simple_nosetlease, }; static const struct inode_operations fuse_common_inode_operations = { diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index 86376f0dbf3a..3e061e8115ec 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -1593,7 +1593,6 @@ const struct file_operations gfs2_file_fops = { .flock = gfs2_flock, .splice_read = copy_splice_read, .splice_write = gfs2_file_splice_write, - .setlease = simple_nosetlease, .fallocate = gfs2_fallocate, .fop_flags = FOP_ASYNC_LOCK, }; @@ -1608,7 +1607,6 @@ const struct file_operations gfs2_dir_fops = { .lock = gfs2_lock, .flock = gfs2_flock, .llseek = default_llseek, - .setlease = simple_nosetlease, .fop_ |
