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 <mszeredi@redhat.com>
This commit is contained in:
Miklos Szeredi 2026-03-17 16:32:37 +01:00
parent 36b6a1e5ed
commit bf9932623d
5 changed files with 44 additions and 29 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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 */

View File

@ -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;