ceph: add new "nopagecache" option
authorJeff Layton <jlayton@kernel.org>
Tue, 30 Nov 2021 19:12:13 +0000 (14:12 -0500)
committerIlya Dryomov <idryomov@gmail.com>
Thu, 13 Jan 2022 12:40:07 +0000 (13:40 +0100)
CephFS is a bit unlike most other filesystems in that it only
conditionally does buffered I/O based on the caps that it gets from the
MDS. In most cases, unless there is contended access for an inode the
MDS does give Fbc caps to the client, so the unbuffered codepaths are
only infrequently traveled and are difficult to test.

At one time, the "-o sync" mount option would give you this behavior,
but that was removed in commit 7ab9b3807097 ("ceph: Don't use
ceph-sync-mode for synchronous-fs.").

Add a new mount option to tell the client to ignore Fbc caps when doing
I/O, and to use the synchronous codepaths exclusively, even on
non-O_DIRECT file descriptors. We already have an ioctl that forces this
behavior on a per-file basis, so we can just always set the CEPH_F_SYNC
flag in the file description on such mounts.

Additionally, this patch also changes the client to not request Fbc when
doing direct I/O. We aren't using the cache with O_DIRECT so we don't
have any need for those caps.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Acked-by: Greg Farnum <gfarnum@redhat.com>
Reviewed-by: Venky Shankar <vshankar@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
fs/ceph/file.c
fs/ceph/super.c
fs/ceph/super.h

index c138e8126286cfe52996f982071003fbc95243a6..7de5db51c3d06b4e0ea079b3961ca1fc5c4da0b6 100644 (file)
@@ -204,6 +204,8 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,
                                        int fmode, bool isdir)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_mount_options *opt =
+               ceph_inode_to_client(&ci->vfs_inode)->mount_options;
        struct ceph_file_info *fi;
 
        dout("%s %p %p 0%o (%s)\n", __func__, inode, file,
@@ -225,6 +227,9 @@ static int ceph_init_file_info(struct inode *inode, struct file *file,
                if (!fi)
                        return -ENOMEM;
 
+               if (opt->flags & CEPH_MOUNT_OPT_NOPAGECACHE)
+                       fi->flags |= CEPH_F_SYNC;
+
                file->private_data = fi;
        }
 
@@ -1536,7 +1541,7 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to)
        struct ceph_inode_info *ci = ceph_inode(inode);
        bool direct_lock = iocb->ki_flags & IOCB_DIRECT;
        ssize_t ret;
-       int want, got = 0;
+       int want = 0, got = 0;
        int retry_op = 0, read = 0;
 
 again:
@@ -1551,13 +1556,14 @@ again:
        else
                ceph_start_io_read(inode);
 
+       if (!(fi->flags & CEPH_F_SYNC) && !direct_lock)
+               want |= CEPH_CAP_FILE_CACHE;
        if (fi->fmode & CEPH_FILE_MODE_LAZY)
-               want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO;
-       else
-               want = CEPH_CAP_FILE_CACHE;
+               want |= CEPH_CAP_FILE_LAZYIO;
+
        ret = ceph_get_caps(filp, CEPH_CAP_FILE_RD, want, -1, &got);
        if (ret < 0) {
-               if (iocb->ki_flags & IOCB_DIRECT)
+               if (direct_lock)
                        ceph_end_io_direct(inode);
                else
                        ceph_end_io_read(inode);
@@ -1691,7 +1697,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
        struct ceph_osd_client *osdc = &fsc->client->osdc;
        struct ceph_cap_flush *prealloc_cf;
        ssize_t count, written = 0;
-       int err, want, got;
+       int err, want = 0, got;
        bool direct_lock = false;
        u32 map_flags;
        u64 pool_flags;
@@ -1766,10 +1772,10 @@ retry_snap:
 
        dout("aio_write %p %llx.%llx %llu~%zd getting caps. i_size %llu\n",
             inode, ceph_vinop(inode), pos, count, i_size_read(inode));
+       if (!(fi->flags & CEPH_F_SYNC) && !direct_lock)
+               want |= CEPH_CAP_FILE_BUFFER;
        if (fi->fmode & CEPH_FILE_MODE_LAZY)
-               want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO;
-       else
-               want = CEPH_CAP_FILE_BUFFER;
+               want |= CEPH_CAP_FILE_LAZYIO;
        got = 0;
        err = ceph_get_caps(file, CEPH_CAP_FILE_WR, want, pos + count, &got);
        if (err < 0)
index 2166fc2c16256f9bd069eefcaa265247ac6de88c..eb255d24e321d1a1070af0dc308f96cf66f3a99a 100644 (file)
@@ -160,6 +160,7 @@ enum {
        Opt_quotadf,
        Opt_copyfrom,
        Opt_wsync,
+       Opt_pagecache,
 };
 
 enum ceph_recover_session_mode {
@@ -201,6 +202,7 @@ static const struct fs_parameter_spec ceph_mount_parameters[] = {
        fsparam_string  ("mon_addr",                    Opt_mon_addr),
        fsparam_u32     ("wsize",                       Opt_wsize),
        fsparam_flag_no ("wsync",                       Opt_wsync),
+       fsparam_flag_no ("pagecache",                   Opt_pagecache),
        {}
 };
 
@@ -564,6 +566,12 @@ static int ceph_parse_mount_param(struct fs_context *fc,
                else
                        fsopt->flags |= CEPH_MOUNT_OPT_ASYNC_DIROPS;
                break;
+       case Opt_pagecache:
+               if (result.negated)
+                       fsopt->flags |= CEPH_MOUNT_OPT_NOPAGECACHE;
+               else
+                       fsopt->flags &= ~CEPH_MOUNT_OPT_NOPAGECACHE;
+               break;
        default:
                BUG();
        }
@@ -699,6 +707,9 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
        if (!(fsopt->flags & CEPH_MOUNT_OPT_ASYNC_DIROPS))
                seq_puts(m, ",wsync");
 
+       if (fsopt->flags & CEPH_MOUNT_OPT_NOPAGECACHE)
+               seq_puts(m, ",nopagecache");
+
        if (fsopt->wsize != CEPH_MAX_WRITE_SIZE)
                seq_printf(m, ",wsize=%u", fsopt->wsize);
        if (fsopt->rsize != CEPH_MAX_READ_SIZE)
index 5ec465a1350a6e4550b9a02c7f34357a757d6809..0d489a973d5e163a84f21a4d5a5afa48ba4f515c 100644 (file)
@@ -46,6 +46,7 @@
 #define CEPH_MOUNT_OPT_NOQUOTADF       (1<<13) /* no root dir quota in statfs */
 #define CEPH_MOUNT_OPT_NOCOPYFROM      (1<<14) /* don't use RADOS 'copy-from' op */
 #define CEPH_MOUNT_OPT_ASYNC_DIROPS    (1<<15) /* allow async directory ops */
+#define CEPH_MOUNT_OPT_NOPAGECACHE     (1<<16) /* bypass pagecache altogether */
 
 #define CEPH_MOUNT_OPT_DEFAULT                 \
        (CEPH_MOUNT_OPT_DCACHE |                \