@@ -7,6 +7,7 @@ cachefiles-y := \
bind.o \
daemon.o \
interface.o \
+ io.o \
key.o \
main.o \
namei.o \
@@ -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,
};
@@ -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)
new file mode 100644
@@ -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 (dhowells@redhat.com)
+ */
+
+#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;
+}
@@ -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)
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 <dhowells@redhat.com> --- 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