fs: claw back a few FMODE_* bits
authorChristian Brauner <brauner@kernel.org>
Thu, 28 Mar 2024 12:27:24 +0000 (13:27 +0100)
committerChristian Brauner <brauner@kernel.org>
Sun, 7 Apr 2024 11:49:02 +0000 (13:49 +0200)
There's a bunch of flags that are purely based on what the file
operations support while also never being conditionally set or unset.
IOW, they're not subject to change for individual files. Imho, such
flags don't need to live in f_mode they might as well live in the fops
structs itself. And the fops struct already has that lonely
mmap_supported_flags member. We might as well turn that into a generic
fop_flags member and move a few flags from FMODE_* space into FOP_*
space. That gets us four FMODE_* bits back and the ability for new
static flags that are about file ops to not have to live in FMODE_*
space but in their own FOP_* space. It's not the most beautiful thing
ever but it gets the job done. Yes, there'll be an additional pointer
chase but hopefully that won't matter for these flags.

I suspect there's a few more we can move into there and that we can also
redirect a bunch of new flag suggestions that follow this pattern into
the fop_flags field instead of f_mode.

Link: https://lore.kernel.org/r/20240328-gewendet-spargel-aa60a030ef74@brauner
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Christian Brauner <brauner@kernel.org>
12 files changed:
block/bdev.c
block/fops.c
drivers/dax/device.c
fs/btrfs/file.c
fs/ext4/file.c
fs/f2fs/file.c
fs/read_write.c
fs/xfs/xfs_file.c
include/linux/fs.h
io_uring/io_uring.c
io_uring/rw.c
mm/mmap.c

index 7a5f611c3d2e3e83eb00be12b9131f49d8348f5e..1322dfe32c5db393d0ce9241d6f29a3469db0424 100644 (file)
@@ -904,7 +904,7 @@ int bdev_open(struct block_device *bdev, blk_mode_t mode, void *holder,
                disk_unblock_events(disk);
 
        bdev_file->f_flags |= O_LARGEFILE;
-       bdev_file->f_mode |= FMODE_BUF_RASYNC | FMODE_CAN_ODIRECT;
+       bdev_file->f_mode |= FMODE_CAN_ODIRECT;
        if (bdev_nowait(bdev))
                bdev_file->f_mode |= FMODE_NOWAIT;
        bdev_file->f_mapping = bdev->bd_inode->i_mapping;
index 679d9b752fe828eb64b67d17e7492469c71e35d3..af6c244314afadb0674c1c354bf749de0f1ef74f 100644 (file)
@@ -863,6 +863,7 @@ const struct file_operations def_blk_fops = {
        .splice_read    = filemap_splice_read,
        .splice_write   = iter_file_splice_write,
        .fallocate      = blkdev_fallocate,
+       .fop_flags      = FOP_BUFFER_RASYNC,
 };
 
 static __init int blkdev_init(void)
index 93ebedc5ec8ca36357635e774d5ca094d0e70e54..c24ef4d3cf3104f73d390ecaa4f490695a68b418 100644 (file)
@@ -377,7 +377,7 @@ static const struct file_operations dax_fops = {
        .release = dax_release,
        .get_unmapped_area = dax_get_unmapped_area,
        .mmap = dax_mmap,
-       .mmap_supported_flags = MAP_SYNC,
+       .fop_flags = FOP_MMAP_SYNC,
 };
 
 static void dev_dax_cdev_del(void *cdev)
index f9d76072398da550e1ad4cd9c77bfcb3007c7c66..1640c46f215310a00f3925e7c05d3ffdcaafb424 100644 (file)
@@ -3719,8 +3719,7 @@ static int btrfs_file_open(struct inode *inode, struct file *filp)
 {
        int ret;
 
-       filp->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC | FMODE_BUF_WASYNC |
-                       FMODE_CAN_ODIRECT;
+       filp->f_mode |= FMODE_NOWAIT | FMODE_CAN_ODIRECT;
 
        ret = fsverity_file_open(inode, filp);
        if (ret)
@@ -3850,6 +3849,7 @@ const struct file_operations btrfs_file_operations = {
        .compat_ioctl   = btrfs_compat_ioctl,
 #endif
        .remap_file_range = btrfs_remap_file_range,
+       .fop_flags      = FOP_BUFFER_RASYNC | FOP_BUFFER_WASYNC,
 };
 
 int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end)
index 54d6ff22585cf1835e8aced5548dbac7c1b89757..28c51b0cc4db91a912d332deb4a53861a9b47227 100644 (file)
@@ -885,8 +885,7 @@ static int ext4_file_open(struct inode *inode, struct file *filp)
                        return ret;
        }
 
-       filp->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC |
-                       FMODE_DIO_PARALLEL_WRITE;
+       filp->f_mode |= FMODE_NOWAIT;
        return dquot_file_open(inode, filp);
 }
 
@@ -938,7 +937,6 @@ const struct file_operations ext4_file_operations = {
        .compat_ioctl   = ext4_compat_ioctl,
 #endif
        .mmap           = ext4_file_mmap,
-       .mmap_supported_flags = MAP_SYNC,
        .open           = ext4_file_open,
        .release        = ext4_release_file,
        .fsync          = ext4_sync_file,
@@ -946,6 +944,8 @@ const struct file_operations ext4_file_operations = {
        .splice_read    = ext4_file_splice_read,
        .splice_write   = iter_file_splice_write,
        .fallocate      = ext4_fallocate,
+       .fop_flags      = FOP_MMAP_SYNC | FOP_BUFFER_RASYNC |
+                         FOP_DIO_PARALLEL_WRITE,
 };
 
 const struct inode_operations ext4_file_inode_operations = {
index 1761ad125f97a37ebb7bb9ce5c35ff9decf8a130..2b65e09822d40482c22d38548697f3327cfb9a1c 100644 (file)
@@ -569,7 +569,7 @@ static int f2fs_file_open(struct inode *inode, struct file *filp)
        if (err)
                return err;
 
-       filp->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC;
+       filp->f_mode |= FMODE_NOWAIT;
        filp->f_mode |= FMODE_CAN_ODIRECT;
 
        return dquot_file_open(inode, filp);
@@ -5045,4 +5045,5 @@ const struct file_operations f2fs_file_operations = {
        .splice_read    = f2fs_file_splice_read,
        .splice_write   = iter_file_splice_write,
        .fadvise        = f2fs_file_fadvise,
+       .fop_flags      = FOP_BUFFER_RASYNC,
 };
index d4c036e82b6c38cf706e463363d16d78e4dd3fdf..2115d1f40bd5c6147b0ba4ab910fc61459e07119 100644 (file)
@@ -1685,7 +1685,7 @@ int generic_write_checks_count(struct kiocb *iocb, loff_t *count)
 
        if ((iocb->ki_flags & IOCB_NOWAIT) &&
            !((iocb->ki_flags & IOCB_DIRECT) ||
-             (file->f_mode & FMODE_BUF_WASYNC)))
+             (file->f_op->fop_flags & FOP_BUFFER_WASYNC)))
                return -EINVAL;
 
        return generic_write_check_limits(iocb->ki_filp, iocb->ki_pos, count);
index 632653e00906fa32e2b5a8c70451522952a8660a..147439ad358138bea02d0e932b53a5c8b1bb283a 100644 (file)
@@ -1230,8 +1230,7 @@ xfs_file_open(
 {
        if (xfs_is_shutdown(XFS_M(inode->i_sb)))
                return -EIO;
-       file->f_mode |= FMODE_NOWAIT | FMODE_BUF_RASYNC | FMODE_BUF_WASYNC |
-                       FMODE_DIO_PARALLEL_WRITE | FMODE_CAN_ODIRECT;
+       file->f_mode |= FMODE_NOWAIT | FMODE_CAN_ODIRECT;
        return generic_file_open(inode, file);
 }
 
@@ -1490,7 +1489,6 @@ const struct file_operations xfs_file_operations = {
        .compat_ioctl   = xfs_file_compat_ioctl,
 #endif
        .mmap           = xfs_file_mmap,
-       .mmap_supported_flags = MAP_SYNC,
        .open           = xfs_file_open,
        .release        = xfs_file_release,
        .fsync          = xfs_file_fsync,
@@ -1498,6 +1496,8 @@ const struct file_operations xfs_file_operations = {
        .fallocate      = xfs_file_fallocate,
        .fadvise        = xfs_file_fadvise,
        .remap_file_range = xfs_file_remap_range,
+       .fop_flags      = FOP_MMAP_SYNC | FOP_BUFFER_RASYNC | FOP_BUFFER_WASYNC |
+                         FOP_DIO_PARALLEL_WRITE,
 };
 
 const struct file_operations xfs_dir_file_operations = {
@@ -1510,4 +1510,6 @@ const struct file_operations xfs_dir_file_operations = {
        .compat_ioctl   = xfs_file_compat_ioctl,
 #endif
        .fsync          = xfs_dir_fsync,
+       .fop_flags      = FOP_MMAP_SYNC | FOP_BUFFER_RASYNC | FOP_BUFFER_WASYNC |
+                         FOP_DIO_PARALLEL_WRITE,
 };
index 9142450855978b680d7619874ccffd7db8686fc3..53cddf0131ca4c553b4bf9db368786272dac2b17 100644 (file)
@@ -163,9 +163,6 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 
 #define        FMODE_NOREUSE           ((__force fmode_t)0x800000)
 
-/* File supports non-exclusive O_DIRECT writes from multiple threads */
-#define FMODE_DIO_PARALLEL_WRITE       ((__force fmode_t)0x1000000)
-
 /* File is embedded in backing_file object */
 #define FMODE_BACKING          ((__force fmode_t)0x2000000)
 
@@ -181,12 +178,6 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
 /* File does not contribute to nr_files count */
 #define FMODE_NOACCOUNT                ((__force fmode_t)0x20000000)
 
-/* File supports async buffered reads */
-#define FMODE_BUF_RASYNC       ((__force fmode_t)0x40000000)
-
-/* File supports async nowait buffered writes */
-#define FMODE_BUF_WASYNC       ((__force fmode_t)0x80000000)
-
 /*
  * Attribute flags.  These should be or-ed together to figure out what
  * has been changed!
@@ -2001,8 +1992,11 @@ struct iov_iter;
 struct io_uring_cmd;
 struct offset_ctx;
 
+typedef unsigned int __bitwise fop_flags_t;
+
 struct file_operations {
        struct module *owner;
+       fop_flags_t fop_flags;
        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
@@ -2015,7 +2009,6 @@ struct file_operations {
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
        int (*mmap) (struct file *, struct vm_area_struct *);
-       unsigned long mmap_supported_flags;
        int (*open) (struct inode *, struct file *);
        int (*flush) (struct file *, fl_owner_t id);
        int (*release) (struct inode *, struct file *);
@@ -2046,6 +2039,15 @@ struct file_operations {
                                unsigned int poll_flags);
 } __randomize_layout;
 
+/* Supports async buffered reads */
+#define FOP_BUFFER_RASYNC      ((__force fop_flags_t)(1 << 0))
+/* Supports async buffered writes */
+#define FOP_BUFFER_WASYNC      ((__force fop_flags_t)(1 << 1))
+/* Supports synchronous page faults for mappings */
+#define FOP_MMAP_SYNC          ((__force fop_flags_t)(1 << 2))
+/* Supports non-exclusive O_DIRECT writes from multiple threads */
+#define FOP_DIO_PARALLEL_WRITE ((__force fop_flags_t)(1 << 3))
+
 /* Wrap a directory iterator that needs exclusive inode access */
 int wrap_directory_iterator(struct file *, struct dir_context *,
                            int (*) (struct file *, struct dir_context *));
index 5d4b448fdc503822cb97ca5ca93d545ade642db5..d73c9ad2d2f89b548ca2719b6c70135bf6142b3b 100644 (file)
@@ -471,7 +471,7 @@ static void io_prep_async_work(struct io_kiocb *req)
 
                /* don't serialize this request if the fs doesn't need it */
                if (should_hash && (req->file->f_flags & O_DIRECT) &&
-                   (req->file->f_mode & FMODE_DIO_PARALLEL_WRITE))
+                   (req->file->f_op->fop_flags & FOP_DIO_PARALLEL_WRITE))
                        should_hash = false;
                if (should_hash || (ctx->flags & IORING_SETUP_IOPOLL))
                        io_wq_hash_work(&req->work, file_inode(req->file));
index 0585ebcc9773d3349b007e6ff436c0320e26356d..d9dfde1142a1cbcb061abcfc89814f33f3c41b92 100644 (file)
@@ -683,7 +683,8 @@ static bool io_rw_should_retry(struct io_kiocb *req)
         * just use poll if we can, and don't attempt if the fs doesn't
         * support callback based unlocks
         */
-       if (io_file_can_poll(req) || !(req->file->f_mode & FMODE_BUF_RASYNC))
+       if (io_file_can_poll(req) ||
+           !(req->file->f_op->fop_flags & FOP_BUFFER_RASYNC))
                return false;
 
        wait->wait.func = io_async_buf_func;
@@ -1022,10 +1023,10 @@ int io_write(struct io_kiocb *req, unsigned int issue_flags)
                if (unlikely(!io_file_supports_nowait(req)))
                        goto copy_iov;
 
-               /* File path supports NOWAIT for non-direct_IO only for block devices. */
+               /* Check if we can support NOWAIT. */
                if (!(kiocb->ki_flags & IOCB_DIRECT) &&
-                       !(kiocb->ki_filp->f_mode & FMODE_BUF_WASYNC) &&
-                       (req->flags & REQ_F_ISREG))
+                   !(req->file->f_op->fop_flags & FOP_BUFFER_WASYNC) &&
+                   (req->flags & REQ_F_ISREG))
                        goto copy_iov;
 
                kiocb->ki_flags |= IOCB_NOWAIT;
index 6dbda99a47da1c332682c95c03bf3ce6c74f562f..3490af70f2592e05eb5740f5b6e9427c5ca3942f 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1294,7 +1294,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
                if (!file_mmap_ok(file, inode, pgoff, len))
                        return -EOVERFLOW;
 
-               flags_mask = LEGACY_MAP_MASK | file->f_op->mmap_supported_flags;
+               flags_mask = LEGACY_MAP_MASK;
+               if (file->f_op->fop_flags & FOP_MMAP_SYNC)
+                       flags_mask |= MAP_SYNC;
 
                switch (flags & MAP_TYPE) {
                case MAP_SHARED: