summaryrefslogtreecommitdiff
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2026-03-11 21:02:41 +0100
committerMiklos Szeredi <mszeredi@redhat.com>2026-04-02 20:43:24 +0200
commita8dd5f1b73bc533e1192d38c82fc144595d3ce9a (patch)
tree00b9f4425e3ff4deaf57204e81e7b896f11a9045 /fs/fuse/dev.c
parente45f591f704aecec31dc738694a5e43acdfd020b (diff)
downloadlinux-next-a8dd5f1b73bc533e1192d38c82fc144595d3ce9a.tar.gz
linux-next-a8dd5f1b73bc533e1192d38c82fc144595d3ce9a.zip
fuse: create fuse_dev on /dev/fuse open instead of mount
Allocate struct fuse_dev when opening the device. This means that unlike before, ->private_data is always set to a valid pointer. The use of USE_DEV_SYNC_INIT magic pointer for the private_data is now replaced with a simple bool sync_init member. If sync INIT is not set, I/O on the device returns error before mount. Keep this behavior by checking for the ->fc member. If fud->fc is set, the mount has succeeded. Testing this used READ_ONCE(file->private_data) and smp_mb() to try and provide the necessary semantics. Switch this to smp_store_release() and smp_load_acquire(). Setting fud->fc is protected by fuse_mutex, this is unchanged. Will need this later so the /dev/fuse open file reference is not held during FSCONFIG_CMD_CREATE. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c47
1 files changed, 18 insertions, 29 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 952dd56f0a02..0c03bbb21c12 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1548,32 +1548,24 @@ out_end:
static int fuse_dev_open(struct inode *inode, struct file *file)
{
- /*
- * The fuse device's file's private_data is used to hold
- * the fuse_conn(ection) when it is mounted, and is used to
- * keep track of whether the file has been mounted already.
- */
- file->private_data = NULL;
+ struct fuse_dev *fud = fuse_dev_alloc();
+
+ if (!fud)
+ return -ENOMEM;
+
+ file->private_data = fud;
return 0;
}
struct fuse_dev *fuse_get_dev(struct file *file)
{
- struct fuse_dev *fud = __fuse_get_dev(file);
+ struct fuse_dev *fud = fuse_file_to_fud(file);
int err;
- if (likely(fud))
- return fud;
-
- err = wait_event_interruptible(fuse_dev_waitq,
- READ_ONCE(file->private_data) != FUSE_DEV_SYNC_INIT);
+ err = wait_event_interruptible(fuse_dev_waitq, fuse_dev_fc_get(fud) != NULL);
if (err)
return ERR_PTR(err);
- fud = __fuse_get_dev(file);
- if (!fud)
- return ERR_PTR(-EPERM);
-
return fud;
}
@@ -2547,10 +2539,10 @@ void fuse_wait_aborted(struct fuse_conn *fc)
int fuse_dev_release(struct inode *inode, struct file *file)
{
- struct fuse_dev *fud = __fuse_get_dev(file);
+ struct fuse_dev *fud = fuse_file_to_fud(file);
+ struct fuse_conn *fc = fuse_dev_fc_get(fud);
- if (fud) {
- struct fuse_conn *fc = fud->fc;
+ if (fc) {
struct fuse_pqueue *fpq = &fud->pq;
LIST_HEAD(to_end);
unsigned int i;
@@ -2568,8 +2560,8 @@ int fuse_dev_release(struct inode *inode, struct file *file)
WARN_ON(fc->iq.fasync != NULL);
fuse_abort_conn(fc);
}
- fuse_dev_free(fud);
}
+ fuse_dev_free(fud);
return 0;
}
EXPORT_SYMBOL_GPL(fuse_dev_release);
@@ -2587,16 +2579,12 @@ static int fuse_dev_fasync(int fd, struct file *file, int on)
static int fuse_device_clone(struct fuse_conn *fc, struct file *new)
{
- struct fuse_dev *fud;
+ struct fuse_dev *new_fud = fuse_file_to_fud(new);
- if (__fuse_get_dev(new))
+ if (fuse_dev_fc_get(new_fud))
return -EINVAL;
- fud = fuse_dev_alloc_install(fc);
- if (!fud)
- return -ENOMEM;
-
- new->private_data = fud;
+ fuse_dev_install(new_fud, fc);
atomic_inc(&fc->dev_count);
return 0;
@@ -2667,10 +2655,11 @@ static long fuse_dev_ioctl_backing_close(struct file *file, __u32 __user *argp)
static long fuse_dev_ioctl_sync_init(struct file *file)
{
int err = -EINVAL;
+ struct fuse_dev *fud = fuse_file_to_fud(file);
mutex_lock(&fuse_mutex);
- if (!__fuse_get_dev(file)) {
- WRITE_ONCE(file->private_data, FUSE_DEV_SYNC_INIT);
+ if (!fuse_dev_fc_get(fud)) {
+ fud->sync_init = true;
err = 0;
}
mutex_unlock(&fuse_mutex);