aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2010-09-07 07:42:41 -0400
committerMiklos Szeredi <mszeredi@suse.cz>2010-09-07 07:42:41 -0400
commit595afaf9e6ee1b48e13ec4b8bcc8c7dee888161a (patch)
tree18ec100cfce992b61aaca2e0a8d0897e67c72300 /fs
parent2bfc96a127bc1cc94d26bfaa40159966064f9c8c (diff)
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: David Bartley <andareed@gmail.com> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> CC: stable@kernel.org
Diffstat (limited to 'fs')
-rw-r--r--fs/fuse/dev.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 69ad053ffd78..b4fc47ff4bc2 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1769,6 +1769,14 @@ __acquires(&fc->lock)
1769 } 1769 }
1770} 1770}
1771 1771
1772static void end_queued_requests(struct fuse_conn *fc)
1773{
1774 fc->max_background = UINT_MAX;
1775 flush_bg_queue(fc);
1776 end_requests(fc, &fc->pending);
1777 end_requests(fc, &fc->processing);
1778}
1779
1772/* 1780/*
1773 * Abort all requests. 1781 * Abort all requests.
1774 * 1782 *
@@ -1795,8 +1803,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
1795 fc->connected = 0; 1803 fc->connected = 0;
1796 fc->blocked = 0; 1804 fc->blocked = 0;
1797 end_io_requests(fc); 1805 end_io_requests(fc);
1798 end_requests(fc, &fc->pending); 1806 end_queued_requests(fc);
1799 end_requests(fc, &fc->processing);
1800 wake_up_all(&fc->waitq); 1807 wake_up_all(&fc->waitq);
1801 wake_up_all(&fc->blocked_waitq); 1808 wake_up_all(&fc->blocked_waitq);
1802 kill_fasync(&fc->fasync, SIGIO, POLL_IN); 1809 kill_fasync(&fc->fasync, SIGIO, POLL_IN);
@@ -1811,8 +1818,9 @@ int fuse_dev_release(struct inode *inode, struct file *file)
1811 if (fc) { 1818 if (fc) {
1812 spin_lock(&fc->lock); 1819 spin_lock(&fc->lock);
1813 fc->connected = 0; 1820 fc->connected = 0;
1814 end_requests(fc, &fc->pending); 1821 fc->blocked = 0;
1815 end_requests(fc, &fc->processing); 1822 end_queued_requests(fc);
1823 wake_up_all(&fc->blocked_waitq);
1816 spin_unlock(&fc->lock); 1824 spin_unlock(&fc->lock);
1817 fuse_conn_put(fc); 1825 fuse_conn_put(fc);
1818 } 1826 }