From: Miklos Szeredi Date: Tue, 17 Mar 2026 15:32:37 +0000 (+0100) Subject: fuse: split off fch->lock from fc->lock X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bf9932623d20e8b7b695077f531d1fa43ddaaaf3;p=thirdparty%2Fkernel%2Fstable.git fuse: split off fch->lock from fc->lock And document which members they protect. end_polls() is called with both, outer fch->lock is probably unnecessary, but doesn't hurt for now. Signed-off-by: Miklos Szeredi --- diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 27357ee01fe5..52f46efd85ba 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -354,6 +354,7 @@ struct fuse_chan *fuse_chan_new(void) if (!fch) return NULL; + spin_lock_init(&fch->lock); INIT_LIST_HEAD(&fch->devices); spin_lock_init(&fch->bg_lock); INIT_LIST_HEAD(&fch->bg_queue); @@ -418,7 +419,7 @@ void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc) { struct fuse_conn *old_fc; - spin_lock(&fc->lock); + spin_lock(&fc->chan->lock); /* * Pairs with: * - xchg() in fuse_dev_release() @@ -436,7 +437,7 @@ void fuse_dev_install(struct fuse_dev *fud, struct fuse_conn *fc) list_add_tail(&fud->entry, &fc->chan->devices); fuse_conn_get(fc); } - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); } EXPORT_SYMBOL_GPL(fuse_dev_install); @@ -463,9 +464,9 @@ void fuse_dev_put(struct fuse_dev *fud) 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); + spin_lock(&fc->chan->lock); list_del(&fud->entry); - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); fuse_conn_put(fc); } @@ -2060,9 +2061,9 @@ static void fuse_resend(struct fuse_conn *fc) LIST_HEAD(to_queue); unsigned int i; - spin_lock(&fc->lock); + spin_lock(&fc->chan->lock); if (!fc->chan->connected) { - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); return; } @@ -2074,7 +2075,7 @@ static void fuse_resend(struct fuse_conn *fc) list_splice_tail_init(&fpq->processing[i], &to_queue); spin_unlock(&fpq->lock); } - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); list_for_each_entry_safe(req, next, &to_queue, list) { set_bit(FR_PENDING, &req->flags); @@ -2498,6 +2499,7 @@ static void end_polls(struct fuse_conn *fc) { struct rb_node *p; + spin_lock(&fc->lock); p = rb_first(&fc->polled_files); while (p) { @@ -2507,6 +2509,7 @@ static void end_polls(struct fuse_conn *fc) p = rb_next(p); } + spin_unlock(&fc->lock); } /* @@ -2531,7 +2534,7 @@ void fuse_abort_conn(struct fuse_conn *fc) { struct fuse_iqueue *fiq = &fc->chan->iq; - spin_lock(&fc->lock); + spin_lock(&fc->chan->lock); if (fc->chan->connected) { struct fuse_dev *fud; struct fuse_req *req, *next; @@ -2586,17 +2589,17 @@ void fuse_abort_conn(struct fuse_conn *fc) kill_fasync(&fiq->fasync, SIGIO, POLL_IN); end_polls(fc); wake_up_all(&fc->chan->blocked_waitq); - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); fuse_dev_end_requests(&to_end); /* - * fc->lock must not be taken to avoid conflicts with io-uring + * fc->chan->lock must not be taken to avoid conflicts with io-uring * locks */ fuse_uring_abort(fc); } else { - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); } } EXPORT_SYMBOL_GPL(fuse_abort_conn); @@ -2630,11 +2633,11 @@ int fuse_dev_release(struct inode *inode, struct file *file) fuse_dev_end_requests(&to_end); - spin_lock(&fc->lock); + spin_lock(&fc->chan->lock); list_del(&fud->entry); /* Are we the last open device? */ last = list_empty(&fc->chan->devices); - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); if (last) { WARN_ON(fc->chan->iq.fasync != NULL); diff --git a/fs/fuse/dev_uring.c b/fs/fuse/dev_uring.c index eef7f7eac795..53bd5ae4b686 100644 --- a/fs/fuse/dev_uring.c +++ b/fs/fuse/dev_uring.c @@ -243,14 +243,14 @@ static struct fuse_ring *fuse_uring_create(struct fuse_conn *fc) max_payload_size = max(FUSE_MIN_READ_BUFFER, fc->max_write); max_payload_size = max(max_payload_size, fc->max_pages * PAGE_SIZE); - spin_lock(&fc->lock); + spin_lock(&fc->chan->lock); if (!fc->chan->connected) { - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); goto out_err; } if (fc->chan->ring) { /* race, another thread created the ring in the meantime */ - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); res = fc->chan->ring; goto out_err; } @@ -262,7 +262,7 @@ static struct fuse_ring *fuse_uring_create(struct fuse_conn *fc) ring->max_payload_sz = max_payload_size; smp_store_release(&fc->chan->ring, ring); - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); return ring; out_err: @@ -302,9 +302,9 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring, queue->fpq.processing = pq; fuse_pqueue_init(&queue->fpq); - spin_lock(&fc->lock); + spin_lock(&fc->chan->lock); if (ring->queues[qid]) { - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); kfree(queue->fpq.processing); kfree(queue); return ring->queues[qid]; @@ -314,7 +314,7 @@ static struct fuse_ring_queue *fuse_uring_create_queue(struct fuse_ring *ring, * write_once and lock as the caller mostly doesn't take the lock at all */ WRITE_ONCE(ring->queues[qid], queue); - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); return queue; } @@ -1008,16 +1008,16 @@ static int fuse_uring_do_register(struct fuse_ring_ent *ent, struct fuse_conn *fc = ring->fc; struct fuse_iqueue *fiq = &fc->chan->iq; - spin_lock(&fc->lock); + spin_lock(&fc->chan->lock); /* abort teardown path is running or has run */ if (!fc->chan->connected) { - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); if (atomic_dec_and_test(&ring->queue_refs)) wake_up_all(&ring->stop_waitq); kfree(ent); return -ECONNABORTED; } - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); fuse_uring_prepare_cancel(cmd, issue_flags, ent); diff --git a/fs/fuse/fuse_dev_i.h b/fs/fuse/fuse_dev_i.h index 5c31272a4902..22d9c9e795d9 100644 --- a/fs/fuse/fuse_dev_i.h +++ b/fs/fuse/fuse_dev_i.h @@ -88,6 +88,14 @@ struct fuse_iqueue { }; struct fuse_chan { + /** Lock protecting: + - devices + - connected + - ring + - ring->queues[qid] + */ + spinlock_t lock; + /** Input queue */ struct fuse_iqueue iq; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 59bdabaf994b..6343218563b1 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -421,7 +421,7 @@ enum fuse_req_flag { * * .waitq.lock protects the following fields: * - FR_ABORTED - * - FR_LOCKED (may also be modified under fc->lock, tested under both) + * - FR_LOCKED (may also be modified under fpq->lock, tested under both) */ struct fuse_req { /** This can be on either pending processing or io lists in @@ -520,7 +520,11 @@ struct fuse_sync_bucket { * fuse_mount is destroyed. */ struct fuse_conn { - /** Lock protecting accessess to members of this structure */ + /** Lock protecting: + - polled_files + - backing_files_map + - curr_bucket + */ spinlock_t lock; /** Refcount */ diff --git a/fs/fuse/req_timeout.c b/fs/fuse/req_timeout.c index ef2e39e4dcf4..401d3545b0a8 100644 --- a/fs/fuse/req_timeout.c +++ b/fs/fuse/req_timeout.c @@ -89,9 +89,9 @@ static void fuse_check_timeout(struct work_struct *work) if (expired) goto abort_conn; - spin_lock(&fc->lock); + spin_lock(&fc->chan->lock); if (!fc->chan->connected) { - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); return; } list_for_each_entry(fud, &fc->chan->devices, entry) { @@ -100,13 +100,13 @@ static void fuse_check_timeout(struct work_struct *work) if (fuse_request_expired(fc, &fpq->io) || fuse_fpq_processing_expired(fc, fpq->processing)) { spin_unlock(&fpq->lock); - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); goto abort_conn; } spin_unlock(&fpq->lock); } - spin_unlock(&fc->lock); + spin_unlock(&fc->chan->lock); if (fuse_uring_request_expired(fc)) goto abort_conn;