[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250617221456.888231-3-paullawrence@google.com>
Date: Tue, 17 Jun 2025 15:14:54 -0700
From: Paul Lawrence <paullawrence@...gle.com>
To: Miklos Szeredi <miklos@...redi.hu>
Cc: linux-kernel@...r.kernel.org, linux-fsdevel@...r.kernel.org,
Paul Lawrence <paullawrence@...gle.com>
Subject: [PATCH v1 2/2] fuse: open/close backing file
Add support for opening and closing the backing file on a passthrough
directory.
* Add backing file to fuse file
* Add fuse_inode_has_backing - this is how we will detect whether to use
traditional fuse operations or the added backing file operations
* Add backing operations to open, flush and close
Signed-off-by: Paul Lawrence <paullawrence@...gle.com>
---
fs/fuse/backing.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++
fs/fuse/dir.c | 16 -----------
fs/fuse/file.c | 34 ++++++++++++++++--------
fs/fuse/fuse_i.h | 39 +++++++++++++++++++++++++++
4 files changed, 130 insertions(+), 27 deletions(-)
diff --git a/fs/fuse/backing.c b/fs/fuse/backing.c
index 1dcc617bf660..04265bd06695 100644
--- a/fs/fuse/backing.c
+++ b/fs/fuse/backing.c
@@ -6,6 +6,64 @@
#include "fuse_i.h"
+#include <linux/backing-file.h>
+
+int fuse_open_backing(struct inode *inode, struct file *file, bool isdir)
+{
+ struct fuse_mount *fm = get_fuse_mount(inode);
+ struct fuse_file *ff;
+ int retval;
+ int mask;
+ union fuse_dentry *fd = get_fuse_dentry(file->f_path.dentry);
+ struct file *backing_file;
+ uint32_t flags = file->f_flags & ~(O_CREAT | O_EXCL | O_NOCTTY);
+
+ ff = fuse_file_alloc(fm, true);
+ if (!ff)
+ return -ENOMEM;
+
+ switch (flags & O_ACCMODE) {
+ case O_RDONLY:
+ mask = MAY_READ;
+ break;
+
+ case O_WRONLY:
+ mask = MAY_WRITE;
+ break;
+
+ case O_RDWR:
+ mask = MAY_READ | MAY_WRITE;
+ break;
+
+ default:
+ retval = -EINVAL;
+ goto outerr;
+ }
+
+ retval = inode_permission(&nop_mnt_idmap,
+ get_fuse_inode(inode)->backing_inode, mask);
+ if (retval)
+ goto outerr;
+
+ backing_file = backing_file_open(&file->f_path, file->f_flags,
+ &fd->backing_path, current_cred());
+
+ if (IS_ERR(backing_file)) {
+ retval = PTR_ERR(backing_file);
+ goto outerr;
+ }
+
+ ff->backing_file = backing_file;
+ ff->nodeid = get_fuse_inode(inode)->nodeid;
+ file->private_data = ff;
+ return 0;
+
+outerr:
+ if (retval)
+ fuse_file_free(ff);
+ return retval;
+}
+
int fuse_handle_backing(struct fuse_entry_backing *feb,
struct inode **backing_inode, struct path *backing_path)
{
@@ -27,3 +85,13 @@ int fuse_handle_backing(struct fuse_entry_backing *feb,
return 0;
}
+
+int fuse_flush_backing(struct file *file, fl_owner_t id)
+{
+ struct fuse_file *fuse_file = file->private_data;
+ struct file *backing_file = fuse_file->backing_file;
+
+ if (backing_file->f_op->flush)
+ return backing_file->f_op->flush(backing_file, id);
+ return 0;
+}
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 909463fae94d..658898f324b5 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -44,18 +44,7 @@ static inline u64 fuse_dentry_time(const struct dentry *entry)
{
return (u64)entry->d_fsdata;
}
-
#else
-union fuse_dentry {
- struct {
- u64 time;
-#ifdef CONFIG_FUSE_PASSTHROUGH_DIR
- struct path backing_path;
-#endif
- };
- struct rcu_head rcu;
-};
-
static inline void __fuse_dentry_settime(struct dentry *dentry, u64 time)
{
((union fuse_dentry *) dentry->d_fsdata)->time = time;
@@ -65,11 +54,6 @@ static inline u64 fuse_dentry_time(const struct dentry *entry)
{
return ((union fuse_dentry *) entry->d_fsdata)->time;
}
-
-static inline union fuse_dentry *get_fuse_dentry(const struct dentry *entry)
-{
- return entry->d_fsdata;
-}
#endif
static void fuse_dentry_settime(struct dentry *dentry, u64 time)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 754378dd9f71..0cd0a94073c7 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -21,6 +21,7 @@
#include <linux/filelock.h>
#include <linux/splice.h>
#include <linux/task_io_accounting_ops.h>
+#include <linux/file.h>
static int fuse_send_open(struct fuse_mount *fm, u64 nodeid,
unsigned int open_flags, int opcode,
@@ -105,19 +106,24 @@ static void fuse_file_put(struct fuse_file *ff, bool sync)
struct fuse_release_args *ra = &ff->args->release_args;
struct fuse_args *args = (ra ? &ra->args : NULL);
- if (ra && ra->inode)
- fuse_file_io_release(ff, ra->inode);
-
- if (!args) {
- /* Do nothing when server does not implement 'open' */
- } else if (sync) {
- fuse_simple_request(ff->fm, args);
+ if (ff->backing_file) {
fuse_release_end(ff->fm, args, 0);
+ fput(ff->backing_file);
} else {
- args->end = fuse_release_end;
- if (fuse_simple_background(ff->fm, args,
- GFP_KERNEL | __GFP_NOFAIL))
- fuse_release_end(ff->fm, args, -ENOTCONN);
+ if (ra && ra->inode)
+ fuse_file_io_release(ff, ra->inode);
+
+ if (!args) {
+ /* Do nothing when server does not implement 'open' */
+ } else if (sync) {
+ fuse_simple_request(ff->fm, args);
+ fuse_release_end(ff->fm, args, 0);
+ } else {
+ args->end = fuse_release_end;
+ if (fuse_simple_background(ff->fm, args,
+ GFP_KERNEL | __GFP_NOFAIL))
+ fuse_release_end(ff->fm, args, -ENOTCONN);
+ }
}
kfree(ff);
}
@@ -248,6 +254,9 @@ static int fuse_open(struct inode *inode, struct file *file)
if (err)
return err;
+ if (fuse_inode_has_backing(inode))
+ return fuse_open_backing(inode, file, false);
+
if (is_wb_truncate || dax_truncate)
inode_lock(inode);
@@ -522,6 +531,9 @@ static int fuse_flush(struct file *file, fl_owner_t id)
FUSE_ARGS(args);
int err;
+ if (fuse_inode_has_backing(file->f_inode))
+ return fuse_flush_backing(file, id);
+
if (fuse_is_bad(inode))
return -EIO;
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 1dc04bc6ac49..a27c05810bab 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -96,6 +96,25 @@ struct fuse_submount_lookup {
struct fuse_forget_link *forget;
};
+
+/** FUSE specific dentry data */
+#if BITS_PER_LONG < 64 || defined(CONFIG_FUSE_PASSTHROUGH_DIR)
+union fuse_dentry {
+ struct {
+ u64 time;
+#ifdef CONFIG_FUSE_PASSTHROUGH_DIR
+ struct path backing_path;
+#endif
+ };
+ struct rcu_head rcu;
+};
+
+static inline union fuse_dentry *get_fuse_dentry(const struct dentry *entry)
+{
+ return entry->d_fsdata;
+}
+#endif
+
/** Container for data related to mapping to backing file */
struct fuse_backing {
struct file *file;
@@ -287,6 +306,14 @@ struct fuse_file {
} readdir;
+#ifdef CONFIG_FUSE_PASSTHROUGH_DIR
+ /**
+ * TODO: Reconcile with passthrough file
+ * backing file when in bpf mode
+ */
+ struct file *backing_file;
+#endif
+
/** RB node to be linked on fuse_conn->polled_files */
struct rb_node polled_node;
@@ -1597,4 +1624,16 @@ extern void fuse_sysctl_unregister(void);
/* backing.c */
int fuse_handle_backing(struct fuse_entry_backing *feb,
struct inode **backing_inode, struct path *backing_path);
+
+
+static inline bool fuse_inode_has_backing(struct inode *inode)
+{
+ struct fuse_inode *fuse_inode = get_fuse_inode(inode);
+
+ return fuse_inode && fuse_inode->backing_inode;
+}
+
+int fuse_open_backing(struct inode *inode, struct file *file, bool isdir);
+int fuse_flush_backing(struct file *file, fl_owner_t id);
+
#endif /* _FS_FUSE_I_H */
--
2.49.0.1112.g889b7c5bd8-goog
Powered by blists - more mailing lists