summaryrefslogtreecommitdiff
path: root/fs/fuse/dev.c
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2026-03-17 12:44:31 +0100
committerMiklos Szeredi <mszeredi@redhat.com>2026-06-15 14:06:15 +0200
commitd8189630a1a1468a8702e252dd93e36d6ec8121e (patch)
tree102b6a196b0867d1371c712d0878ce9e614d68ea /fs/fuse/dev.c
parentb88fb2b92b24b3eee0ea87001c8d9fbf5ba54bb7 (diff)
downloadlinux-next-d8189630a1a1468a8702e252dd93e36d6ec8121e.tar.gz
linux-next-d8189630a1a1468a8702e252dd93e36d6ec8121e.zip
fuse: move fuse_dev and fuse_pqueue to dev.c
Move function definitions to dev.c, struct definitions to fuse_dev_i.h. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
Diffstat (limited to 'fs/fuse/dev.c')
-rw-r--r--fs/fuse/dev.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 0c0906a2372a..7339959fa8d3 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -365,6 +365,100 @@ struct fuse_chan *fuse_dev_chan_new(void)
}
EXPORT_SYMBOL_GPL(fuse_dev_chan_new);
+void fuse_pqueue_init(struct fuse_pqueue *fpq)
+{
+ unsigned int i;
+
+ spin_lock_init(&fpq->lock);
+ for (i = 0; i < FUSE_PQ_HASH_SIZE; i++)
+ INIT_LIST_HEAD(&fpq->processing[i]);
+ INIT_LIST_HEAD(&fpq->io);
+ fpq->connected = 1;
+}
+
+struct fuse_dev *fuse_dev_alloc(void)
+{
+ struct fuse_dev *fud;
+ struct list_head *pq;
+
+ fud = kzalloc_obj(struct fuse_dev);
+ if (!fud)
+ return NULL;
+
+ refcount_set(&fud->ref, 1);
+ pq = kzalloc_objs(struct list_head, FUSE_PQ_HASH_SIZE);
+ if (!pq) {
+ kfree(fud);
+ return NULL;
+ }
+
+ fud->pq.processing = pq;
+ fuse_pqueue_init(&fud->pq);
+
+ return fud;
+}
+EXPORT_SYMBOL_GPL(fuse_dev_alloc);
+
+void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc)
+{
+ struct fuse_conn *old_fc;
+
+ spin_lock(&fc->lock);
+ /*
+ * Pairs with:
+ * - xchg() in fuse_dev_release()
+ * - smp_load_acquire() in fuse_dev_fc_get()
+ */
+ old_fc = cmpxchg(&fud->fc, NULL, fc);
+ if (old_fc) {
+ /*
+ * failed to set fud->fc because
+ * - it was already set to a different fc
+ * - it was set to disconneted
+ */
+ fc->connected = 0;
+ } else {
+ list_add_tail(&fud->entry, &fc->devices);
+ fuse_conn_get(fc);
+ }
+ spin_unlock(&fc->lock);
+}
+EXPORT_SYMBOL_GPL(fuse_dev_install);
+
+struct fuse_dev *fuse_dev_alloc_install(struct fuse_conn *fc)
+{
+ struct fuse_dev *fud;
+
+ fud = fuse_dev_alloc();
+ if (!fud)
+ return NULL;
+
+ fuse_dev_install(fud, fc);
+ return fud;
+}
+EXPORT_SYMBOL_GPL(fuse_dev_alloc_install);
+
+void fuse_dev_put(struct fuse_dev *fud)
+{
+ struct fuse_conn *fc;
+
+ if (!refcount_dec_and_test(&fud->ref))
+ return;
+
+ fc = fuse_dev_fc_get(fud);
+ if (fc && fc != FUSE_DEV_FC_DISCONNECTED) {
+ /* This is the virtiofs case (fuse_dev_release() not called) */
+ spin_lock(&fc->lock);
+ list_del(&fud->entry);
+ spin_unlock(&fc->lock);
+
+ fuse_conn_put(fc);
+ }
+ kfree(fud->pq.processing);
+ kfree(fud);
+}
+EXPORT_SYMBOL_GPL(fuse_dev_put);
+
static void fuse_send_one(struct fuse_iqueue *fiq, struct fuse_req *req)
{
req->in.h.len = sizeof(struct fuse_in_header) +