diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index c105aaf..5763a7c 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1,14 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
/*
FUSE: Filesystem in Userspace
-
- This program can be distributed under the terms of the GNU GPL.
- See the file COPYING.
*/
+#include "dev.h"
+#include "args.h"
#include "dev_uring_i.h"
-#include "fuse_i.h"
-#include "fuse_dev_i.h"
#include <linux/init.h>
#include <linux/module.h>
@@ -30,124 +28,33 @@
MODULE_ALIAS_MISCDEV(FUSE_MINOR);
MODULE_ALIAS("devname:fuse");
-static struct kmem_cache *fuse_req_cachep;
-
-const unsigned long fuse_timeout_timer_freq =
- secs_to_jiffies(FUSE_TIMEOUT_TIMER_FREQ);
-
-bool fuse_request_expired(struct fuse_conn *fc, struct list_head *list)
-{
- struct fuse_req *req;
-
- req = list_first_entry_or_null(list, struct fuse_req, list);
- if (!req)
- return false;
- return time_is_before_jiffies(req->create_time + fc->timeout.req_timeout);
-}
-
-static bool fuse_fpq_processing_expired(struct fuse_conn *fc, struct list_head *processing)
-{
- int i;
-
- for (i = 0; i < FUSE_PQ_HASH_SIZE; i++)
- if (fuse_request_expired(fc, &processing[i]))
- return true;
-
- return false;
-}
+static DECLARE_WAIT_QUEUE_HEAD(fuse_dev_waitq);
-/*
- * Check if any requests aren't being completed by the time the request timeout
- * elapses. To do so, we:
- * - check the fiq pending list
- * - check the bg queue
- * - check the fpq io and processing lists
- *
- * To make this fast, we only check against the head request on each list since
- * these are generally queued in order of creation time (eg newer requests get
- * queued to the tail). We might miss a few edge cases (eg requests transitioning
- * between lists, re-sent requests at the head of the pending list having a
- * later creation time than other requests on that list, etc.) but that is fine
- * since if the request never gets fulfilled, it will eventually be caught.
- */
-void fuse_check_timeout(struct work_struct *work)
-{
- struct delayed_work *dwork = to_delayed_work(work);
- struct fuse_conn *fc = container_of(dwork, struct fuse_conn,
- timeout.work);
- struct fuse_iqueue *fiq = &fc->iq;
- struct fuse_dev *fud;
- struct fuse_pqueue *fpq;
- bool expired = false;
-
- if (!atomic_read(&fc->num_waiting))
- goto out;
-
- spin_lock(&fiq->lock);
- expired = fuse_request_expired(fc, &fiq->pending);
- spin_unlock(&fiq->lock);
- if (expired)
- goto abort_conn;
-
- spin_lock(&fc->bg_lock);
- expired = fuse_request_expired(fc, &fc->bg_queue);
- spin_unlock(&fc->bg_lock);
- if (expired)
- goto abort_conn;
-
- spin_lock(&fc->lock);
- if (!fc->connected) {
- spin_unlock(&fc->lock);
- return;
- }
- list_for_each_entry(fud, &fc->devices, entry) {
- fpq = &fud->pq;
- spin_lock(&fpq->lock);
- if (fuse_request_expired(fc, &fpq->io) ||
- fuse_fpq_processing_expired(fc, fpq->processing)) {
- spin_unlock(&fpq->lock);
- spin_unlock(&fc->lock);
- goto abort_conn;
- }
-
- spin_unlock(&fpq->lock);
- }
- spin_unlock(&fc->lock);
-
- if (fuse_uring_request_expired(fc))
- goto abort_conn;
-
-out:
- queue_delayed_work(system_percpu_wq, &fc->timeout.work,
- fuse_timeout_timer_freq);
- return;
-
-abort_conn:
- fuse_abort_conn(fc);
-}
+static struct kmem_cache *fuse_req_cachep;
-static void fuse_request_init(struct fuse_mount *fm, struct fuse_req *req)
+static void fuse_request_init(struct fuse_chan *fch, struct fuse_req *req)
{
INIT_LIST_HEAD(&req->list);
INIT_LIST_HEAD(&req->intr_entry);
init_waitqueue_head(&req->waitq);
refcount_set(&req->count, 1);
__set_bit(FR_PENDING, &req->flags);
- req->fm = fm;
+ req->chan = fch;
req->create_time = jiffies;
}
-static struct fuse_req *fuse_request_alloc(struct fuse_mount *fm, gfp_t flags)
+static struct fuse_req *fuse_request_alloc(struct fuse_chan *fch, gfp_t flags)
{
struct fuse_req *req = kmem_cache_zalloc(fuse_req_cachep, flags);
if (req)
- fuse_request_init(fm, req);
+ fuse_request_init(fch, req);
return req;
}
static void fuse_request_free(struct fuse_req *req)
{
+ WARN_ON(!list_empty(&req->intr_entry));
kmem_cache_free(fuse_req_cachep, req);
}
@@ -162,110 +69,86 @@ static void __fuse_put_request(struct fuse_req *req)
refcount_dec(&req->count);
}
-void fuse_set_initialized(struct fuse_conn *fc)
+void fuse_chan_set_initialized(struct fuse_chan *fch, struct fuse_chan_param *param)
{
+ if (param) {
+ fch->minor = param->minor;
+ fch->max_write = param->max_write;
+ fch->max_pages = param->max_pages;
+ }
+
/* Make sure stores before this are seen on another CPU */
smp_wmb();
- fc->initialized = 1;
+ fch->initialized = 1;
+ wake_up_all(&fch->blocked_waitq);
}
-static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background)
+static bool fuse_block_alloc(struct fuse_chan *fch, bool for_background)
{
- return !fc->initialized || (for_background && fc->blocked) ||
- (fc->io_uring && fc->connected && !fuse_uring_ready(fc));
+ return !fch->initialized || (for_background && fch->blocked) ||
+ (fch->io_uring && fch->connected && !fuse_uring_ready(fch));
}
-static void fuse_drop_waiting(struct fuse_conn *fc)
+static void fuse_drop_waiting(struct fuse_chan *fch)
{
/*
- * lockess check of fc->connected is okay, because atomic_dec_and_test()
- * provides a memory barrier matched with the one in fuse_wait_aborted()
+ * lockess check of fch->connected is okay, because atomic_dec_and_test()
+ * provides a memory barrier matched with the one in fuse_chan_wait_aborted()
* to ensure no wake-up is missed.
*/
- if (atomic_dec_and_test(&fc->num_waiting) &&
- !READ_ONCE(fc->connected)) {
+ if (atomic_dec_and_test(&fch->num_waiting) &&
+ !READ_ONCE(fch->connected)) {
/* wake up aborters */
- wake_up_all(&fc->blocked_waitq);
+ wake_up_all(&fch->blocked_waitq);
}
}
static void fuse_put_request(struct fuse_req *req);
-static struct fuse_req *fuse_get_req(struct mnt_idmap *idmap,
- struct fuse_mount *fm,
- bool for_background)
+static struct fuse_req *fuse_get_req(struct fuse_chan *fch, bool for_background)
{
- struct fuse_conn *fc = fm->fc;
struct fuse_req *req;
- bool no_idmap = !fm->sb || (fm->sb->s_iflags & SB_I_NOIDMAP);
- kuid_t fsuid;
- kgid_t fsgid;
int err;
- atomic_inc(&fc->num_waiting);
+ atomic_inc(&fch->num_waiting);
- if (fuse_block_alloc(fc, for_background)) {
+ if (fuse_block_alloc(fch, for_background)) {
err = -EINTR;
- if (wait_event_state_exclusive(fc->blocked_waitq,
- !fuse_block_alloc(fc, for_background),
+ if (wait_event_state_exclusive(fch->blocked_waitq,
+ !fuse_block_alloc(fch, for_background),
(TASK_KILLABLE | TASK_FREEZABLE)))
goto out;