@@ -7,6 +7,7 @@ cachefiles-y := \
bind.o \
daemon.o \
interface.o \
+ io.o \
key.o \
main.o \
namei.o \
@@ -478,5 +478,6 @@ const struct fscache_cache_ops cachefiles_cache_ops = {
.withdraw_cookie = cachefiles_withdraw_cookie,
.invalidate_cookie = cachefiles_invalidate_cookie,
.resize_cookie = cachefiles_resize_cookie,
+ .begin_operation = cachefiles_begin_operation,
.prepare_to_write = cachefiles_prepare_to_write,
};
@@ -206,6 +206,12 @@ extern void cachefiles_put_object(struct cachefiles_object *object,
enum cachefiles_obj_ref_trace why);
extern void cachefiles_sync_cache(struct cachefiles_cache *cache);
+/*
+ * io.c
+ */
+extern bool cachefiles_begin_operation(struct netfs_cache_resources *cres,
+ enum fscache_want_stage want_stage);
+
/*
* key.c
*/
new file mode 100644
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* kiocb-using read/write
+ *
+ * Copyright (C) 2021 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/falloc.h>
+#include <linux/sched/mm.h>
+#include <trace/events/fscache.h>
+#include "internal.h"
+
+/*
+ * Clean up an operation.
+ */
+static void cachefiles_end_operation(struct netfs_cache_resources *cres)
+{
+ struct file *file = cachefiles_cres_file(cres);
+
+ if (file)
+ fput(file);
+ fscache_end_cookie_access(fscache_cres_cookie(cres), fscache_access_io_end);
+}
+
+static const struct netfs_cache_ops cachefiles_netfs_cache_ops = {
+ .end_operation = cachefiles_end_operation,
+};
+
+/*
+ * Open the cache file when beginning a cache operation.
+ */
+bool cachefiles_begin_operation(struct netfs_cache_resources *cres,
+ enum fscache_want_stage want_stage)
+{
+ struct cachefiles_object *object = cachefiles_cres_object(cres);
+
+ if (!cachefiles_cres_file(cres)) {
+ cres->ops = &cachefiles_netfs_cache_ops;
+ if (object->file) {
+ spin_lock(&object->lock);
+ if (!cres->cache_priv2 && object->file)
+ cres->cache_priv2 = get_file(object->file);
+ spin_unlock(&object->lock);
+ }
+ }
+
+ if (!cachefiles_cres_file(cres) && want_stage != FSCACHE_WANT_PARAMS) {
+ pr_err("failed to get cres->file\n");
+ return false;
+ }
+
+ return true;
+}
@@ -77,6 +77,7 @@ enum fscache_access_trace {
fscache_access_cache_unpin,
fscache_access_invalidate_cookie,
fscache_access_invalidate_cookie_end,
+ fscache_access_io_end,
fscache_access_io_not_live,
fscache_access_io_read,
fscache_access_io_resize,
@@ -149,6 +150,7 @@ enum fscache_access_trace {
EM(fscache_access_cache_unpin, "UNPIN cache ") \
EM(fscache_access_invalidate_cookie, "BEGIN inval ") \
EM(fscache_access_invalidate_cookie_end,"END inval ") \
+ EM(fscache_access_io_end, "END io ") \
EM(fscache_access_io_not_live, "END io_notl") \
EM(fscache_access_io_read, "BEGIN io_read") \
EM(fscache_access_io_resize, "BEGIN io_resz") \
Implement the routines for beginning and ending an I/O operation. When beginning an I/O operation, we are guaranteed that the cookie has reached a certain stage (we're called by fscache after it has done a suitable wait). If a file is available, we paste a ref over into the cache resources for the I/O routines to use. This means that the object can be invalidated whilst the I/O is ongoing without needing to synchronise as the file pointer in the object is replaced, but the file pointer in the cache resources is unaffected. Ending the operation just requires ditching any refs we have and dropping the access guarantee that fscache got for us on the cookie. Signed-off-by: David Howells <dhowells@redhat.com> cc: linux-cachefs@redhat.com --- fs/cachefiles/Makefile | 1 + fs/cachefiles/interface.c | 1 + fs/cachefiles/internal.h | 6 ++++ fs/cachefiles/io.c | 57 ++++++++++++++++++++++++++++++++++++++++ include/trace/events/fscache.h | 2 + 5 files changed, 67 insertions(+) create mode 100644 fs/cachefiles/io.c