Commit 595afaf9 authored by Miklos Szeredi's avatar Miklos Szeredi

fuse: flush background queue on connection close

David Bartly reported that fuse can hang in fuse_get_req_nofail() when
the connection to the filesystem server is no longer active.

If bg_queue is not empty then flush_bg_queue() called from
request_end() can put more requests on to the pending queue.  If this
happens while ending requests on the processing queue then those
background requests will be queued to the pending list and never
ended.

Another problem is that fuse_dev_release() didn't wake up processes
sleeping on blocked_waitq.

Solve this by:

 a) flushing the background queue before calling end_requests() on the
    pending and processing queues

 b) setting blocked = 0 and waking up processes waiting on
    blocked_waitq()

Thanks to David for an excellent bug report.
Reported-by: default avatarDavid Bartley <andareed@gmail.com>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
CC: stable@kernel.org
parent 2bfc96a1
...@@ -1769,6 +1769,14 @@ __acquires(&fc->lock) ...@@ -1769,6 +1769,14 @@ __acquires(&fc->lock)
} }
} }
static void end_queued_requests(struct fuse_conn *fc)
{
fc->max_background = UINT_MAX;
flush_bg_queue(fc);
end_requests(fc, &fc->pending);
end_requests(fc, &fc->processing);
}
/* /*
* Abort all requests. * Abort all requests.
* *
...@@ -1795,8 +1803,7 @@ void fuse_abort_conn(struct fuse_conn *fc) ...@@ -1795,8 +1803,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
fc->connected = 0; fc->connected = 0;
fc->blocked = 0; fc->blocked = 0;
end_io_requests(fc); end_io_requests(fc);
end_requests(fc, &fc->pending); end_queued_requests(fc);
end_requests(fc, &fc->processing);
wake_up_all(&fc->waitq); wake_up_all(&fc->waitq);
wake_up_all(&fc->blocked_waitq); wake_up_all(&fc->blocked_waitq);
kill_fasync(&fc->fasync, SIGIO, POLL_IN); kill_fasync(&fc->fasync, SIGIO, POLL_IN);
...@@ -1811,8 +1818,9 @@ int fuse_dev_release(struct inode *inode, struct file *file) ...@@ -1811,8 +1818,9 @@ int fuse_dev_release(struct inode *inode, struct file *file)
if (fc) { if (fc) {
spin_lock(&fc->lock); spin_lock(&fc->lock);
fc->connected = 0; fc->connected = 0;
end_requests(fc, &fc->pending); fc->blocked = 0;
end_requests(fc, &fc->processing); end_queued_requests(fc);
wake_up_all(&fc->blocked_waitq);
spin_unlock(&fc->lock); spin_unlock(&fc->lock);
fuse_conn_put(fc); fuse_conn_put(fc);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment