// SPDX-License-Identifier: GPL-2.0-only #include "dev.h" #include "sysctl.h" #include "fuse_dev_i.h" #include "dev_uring_i.h" /* Frequency (in seconds) of request timeout checks, if opted into */ #define FUSE_TIMEOUT_TIMER_FREQ 15 /* Frequency (in jiffies) of request timeout checks, if opted into */ static const unsigned long fuse_timeout_timer_freq = secs_to_jiffies(FUSE_TIMEOUT_TIMER_FREQ); /* * Default timeout (in seconds) for the server to reply to a request * before the connection is aborted, if no timeout was specified on mount. * * Exported via sysctl */ unsigned int fuse_default_req_timeout; /* * Max timeout (in seconds) for the server to reply to a request before * the connection is aborted. * * Exported via sysctl */ unsigned int fuse_max_req_timeout; bool fuse_request_expired(struct fuse_chan *fch, 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 + fch->timeout.req_timeout); } static bool fuse_fpq_processing_expired(struct fuse_chan *fch, struct list_head *processing) { int i; for (i = 0; i < FUSE_PQ_HASH_SIZE; i++) if (fuse_request_expired(fch, &processing[i])) return true; return false; } /* * 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. */ static void fuse_check_timeout(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct fuse_chan *fch = container_of(dwork, struct fuse_chan, timeout.work); struct fuse_iqueue *fiq = &fch->iq; struct fuse_dev *fud; struct fuse_pqueue *fpq; bool expired = false; if (!atomic_read(&fch->num_waiting)) goto out; spin_lock(&fiq->lock); expired = fuse_request_expired(fch, &fiq->pending); spin_unlock(&fiq->lock); if (expired) goto chan_abort; spin_lock(&fch->bg_lock); expired = fuse_request_expired(fch, &fch->bg_queue); spin_unlock(&fch->bg_lock); if (expired) goto chan_abort; spin_lock(&fch->lock); if (!fch->connected) { spin_unlock(&fch->lock); return; } list_for_each_entry(fud, &fch->devices, entry) { fpq = &fud->pq; spin_lock(&fpq->lock); if (fuse_request_expired(fch, &fpq->io) || fuse_fpq_processing_expired(fch, fpq->processing)) { spin_unlock(&fpq->lock); spin_unlock(&fch->lock); goto chan_abort; } spin_unlock(&fpq->lock); } spin_unlock(&fch->lock); if (fuse_uring_request_expired(fch)) goto chan_abort; out: queue_delayed_work(system_percpu_wq, &fch->timeout.work, fuse_timeout_timer_freq); return; chan_abort: fuse_chan_abort(fch, false); } static void set_request_timeout(struct fuse_chan *fch, unsigned int timeout) { fch->timeout.req_timeout = secs_to_jiffies(timeout); INIT_DELAYED_WORK(&fch->timeout.work, fuse_check_timeout); queue_delayed_work(system_percpu_wq, &fch->timeout.work, fuse_timeout_timer_freq); } void fuse_init_server_timeout(struct fuse_chan *fch, unsigned int timeout) { if (!timeout && !fuse_max_req_timeout && !fuse_default_req_timeout) return; if (!timeout) timeout = fuse_default_req_timeout; if (fuse_max_req_timeout) { if (timeout) timeout = min(fuse_max_req_timeout, timeout); else timeout = fuse_max_req_timeout; } timeout = max(FUSE_TIMEOUT_TIMER_FREQ, timeout); set_request_timeout(fch, timeout); }