lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ