summaryrefslogtreecommitdiff
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2026-03-11 22:05:17 +0100
committerMiklos Szeredi <mszeredi@redhat.com>2026-04-02 20:43:24 +0200
commite9bf38500ed9aec7cfdf9219c75d353645b41168 (patch)
treed531d968cfd670f784d61f90ad4905d6ffb84c51 /fs/fuse/dev.c
parenta8dd5f1b73bc533e1192d38c82fc144595d3ce9a (diff)
downloadlinux-next-e9bf38500ed9aec7cfdf9219c75d353645b41168.tar.gz
linux-next-e9bf38500ed9aec7cfdf9219c75d353645b41168.zip
fuse: add refcount to fuse_dev
This will make it possible to grab the fuse_dev and subsequently release the file that it came from. In the above case, fud->fc will be set to FUSE_DEV_FC_DISCONNECTED to indicate that this is no longer a functional device. When trying to assign an fc to such a disconnected fuse_dev, the fc is set to the disconnected state. Use atomic operations xchg() and cmpxchg() to prevent races. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 0c03bbb21c12..3d96e7a16103 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -2540,7 +2540,8 @@ void fuse_wait_aborted(struct fuse_conn *fc)
int fuse_dev_release(struct inode *inode, struct file *file)
{
struct fuse_dev *fud = fuse_file_to_fud(file);
- struct fuse_conn *fc = fuse_dev_fc_get(fud);
+ /* Pairs with cmpxchg() in fuse_dev_install() */
+ struct fuse_conn *fc = xchg(&fud->fc, FUSE_DEV_FC_DISCONNECTED);
if (fc) {
struct fuse_pqueue *fpq = &fud->pq;
@@ -2560,8 +2561,12 @@ int fuse_dev_release(struct inode *inode, struct file *file)
WARN_ON(fc->iq.fasync != NULL);
fuse_abort_conn(fc);
}
+ spin_lock(&fc->lock);
+ list_del(&fud->entry);
+ spin_unlock(&fc->lock);
+ fuse_conn_put(fc);
}
- fuse_dev_free(fud);
+ fuse_dev_put(fud);
return 0;
}
EXPORT_SYMBOL_GPL(fuse_dev_release);