Implement the new fscache I/O backend API in cachefiles.  The
cachefiles_object struct carries a non-accounted file to the cachefiles
object (so that it doesn't cause ENFILE).

Signed-off-by: David Howells <[email protected]>
---

 fs/cachefiles/Makefile    |    1 +
 fs/cachefiles/interface.c |   13 +++++++
 fs/cachefiles/internal.h  |   19 ++++++++++
 fs/cachefiles/io.c        |   85 +++++++++++++++++++++++++++++++++++++++++++++
 fs/cachefiles/namei.c     |    3 ++
 5 files changed, 120 insertions(+), 1 deletion(-)
 create mode 100644 fs/cachefiles/io.c

diff --git a/fs/cachefiles/Makefile b/fs/cachefiles/Makefile
index 3455d3646547..d894d317d6e7 100644
--- a/fs/cachefiles/Makefile
+++ b/fs/cachefiles/Makefile
@@ -7,6 +7,7 @@ cachefiles-y := \
        bind.o \
        daemon.o \
        interface.o \
+       io.o \
        key.o \
        main.o \
        namei.o \
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c
index 3f6d2be690bc..dc8c875223bb 100644
--- a/fs/cachefiles/interface.c
+++ b/fs/cachefiles/interface.c
@@ -453,6 +453,18 @@ static unsigned int cachefiles_get_object_usage(const 
struct fscache_object *_ob
        return atomic_read(&object->usage);
 }
 
+static const struct fscache_op_ops cachefiles_io_ops = {
+       .wait_for_operation     = __fscache_wait_for_operation,
+       .end_operation          = __fscache_end_operation,
+       .read                   = cachefiles_read,
+       .write                  = cachefiles_write,
+};
+
+static void cachefiles_begin_operation(struct fscache_op_resources *opr)
+{
+       opr->ops = &cachefiles_io_ops;
+}
+
 const struct fscache_cache_ops cachefiles_cache_ops = {
        .name                   = "cachefiles",
        .alloc_object           = cachefiles_alloc_object,
@@ -466,4 +478,5 @@ const struct fscache_cache_ops cachefiles_cache_ops = {
        .put_object             = cachefiles_put_object,
        .get_object_usage       = cachefiles_get_object_usage,
        .sync_cache             = cachefiles_sync_cache,
+       .begin_operation        = cachefiles_begin_operation,
 };
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h
index 16d15291a629..caa6dfbaf333 100644
--- a/fs/cachefiles/internal.h
+++ b/fs/cachefiles/internal.h
@@ -115,6 +115,22 @@ extern const struct fscache_cache_ops cachefiles_cache_ops;
 extern struct fscache_object *cachefiles_grab_object(struct fscache_object 
*_object,
                                                     enum fscache_obj_ref_trace 
why);
 
+/*
+ * io.c
+ */
+extern int cachefiles_read(struct fscache_op_resources *opr,
+                          loff_t start_pos,
+                          struct iov_iter *iter,
+                          bool seek_data,
+                          fscache_io_terminated_t term_func,
+                          void *term_func_priv);
+extern int cachefiles_write(struct fscache_op_resources *opr,
+                           loff_t start_pos,
+                           struct iov_iter *iter,
+                           fscache_io_terminated_t term_func,
+                           void *term_func_priv);
+extern bool cachefiles_open_object(struct cachefiles_object *obj);
+
 /*
  * key.c
  */
@@ -216,7 +232,8 @@ do {                                                        
                \
                                                                        \
        ___cache = container_of((object)->fscache.cache,                \
                                struct cachefiles_cache, cache);        \
-       cachefiles_io_error(___cache, FMT, ##__VA_ARGS__);              \
+       cachefiles_io_error(___cache, FMT " [o=%08x]", ##__VA_ARGS__,   \
+                           object->fscache.debug_id);                  \
 } while (0)
 
 
diff --git a/fs/cachefiles/io.c b/fs/cachefiles/io.c
new file mode 100644
index 000000000000..f1d5976aa28c
--- /dev/null
+++ b/fs/cachefiles/io.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Data I/O routines
+ *
+ * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells ([email protected])
+ */
+
+#include <linux/mount.h>
+#include <linux/slab.h>
+#include <linux/file.h>
+#include <linux/uio.h>
+#include <linux/xattr.h>
+#include "internal.h"
+#include <trace/events/fscache.h>
+
+/*
+ * Initiate a read from the cache.
+ */
+int cachefiles_read(struct fscache_op_resources *opr,
+                   loff_t start_pos,
+                   struct iov_iter *iter,
+                   bool seek_data,
+                   fscache_io_terminated_t term_func,
+                   void *term_func_priv)
+{
+       fscache_wait_for_operation(opr, FSCACHE_WANT_READ);
+       fscache_count_io_operation(opr->object->cookie);
+       if (term_func)
+               term_func(term_func_priv, -ENODATA);
+       return -ENODATA;
+}
+
+/*
+ * Initiate a write to the cache.
+ */
+int cachefiles_write(struct fscache_op_resources *opr,
+                    loff_t start_pos,
+                    struct iov_iter *iter,
+                    fscache_io_terminated_t term_func,
+                    void *term_func_priv)
+{
+       fscache_wait_for_operation(opr, FSCACHE_WANT_WRITE);
+       fscache_count_io_operation(opr->object->cookie);
+       if (term_func)
+               term_func(term_func_priv, -ENOBUFS);
+       return -ENOBUFS;
+}
+
+/*
+ * Open a cache object.
+ */
+bool cachefiles_open_object(struct cachefiles_object *object)
+{
+       struct cachefiles_cache *cache =
+               container_of(object->fscache.cache, struct cachefiles_cache, 
cache);
+       struct file *file;
+       struct path path;
+
+       path.mnt = cache->mnt;
+       path.dentry = object->backer;
+
+       file = open_with_fake_path(&path,
+                                  O_RDWR | O_LARGEFILE | O_DIRECT,
+                                  d_backing_inode(object->backer),
+                                  cache->cache_cred);
+       if (IS_ERR(file))
+               goto error;
+
+       if (!S_ISREG(file_inode(file)->i_mode))
+               goto error_file;
+
+       if (unlikely(!file->f_op->read_iter) ||
+           unlikely(!file->f_op->write_iter)) {
+               pr_notice("Cache does not support read_iter and write_iter\n");
+               goto error_file;
+       }
+
+       object->backing_file = file;
+       return true;
+
+error_file:
+       fput(file);
+error:
+       return false;
+}
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index 0a7e2031efa2..4b515054d92e 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -490,6 +490,9 @@ bool cachefiles_walk_to_object(struct cachefiles_object 
*parent,
                } else {
                        BUG(); // TODO: open file in data-class subdir
                }
+
+               if (!cachefiles_open_object(object))
+                       goto check_error;
        }
 
        if (object->new)


Reply via email to