aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2018-09-28 10:43:22 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2018-09-28 10:43:22 -0400
commit908a572b80f6e9577b45e81b3dfe2e22111286b8 (patch)
tree9752e255244d3e6314f471fdc15f4491c1dc8939
parent4c316f2f3ff315cb48efb7435621e5bfb81df96d (diff)
fuse: fix blocked_waitq wakeup
Using waitqueue_active() is racy. Make sure we issue a wake_up() unconditionally after storing into fc->blocked. After that it's okay to optimize with waitqueue_active() since the first wake up provides the necessary barrier for all waiters, not the just the woken one. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Fixes: 3c18ef8117f0 ("fuse: optimize wake_up") Cc: <stable@vger.kernel.org> # v3.10
-rw-r--r--fs/fuse/dev.c15
1 files changed, 11 insertions, 4 deletions
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 34976b42f3e1..51eb602a435b 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -391,12 +391,19 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req)
391 if (test_bit(FR_BACKGROUND, &req->flags)) { 391 if (test_bit(FR_BACKGROUND, &req->flags)) {
392 spin_lock(&fc->lock); 392 spin_lock(&fc->lock);
393 clear_bit(FR_BACKGROUND, &req->flags); 393 clear_bit(FR_BACKGROUND, &req->flags);
394 if (fc->num_background == fc->max_background) 394 if (fc->num_background == fc->max_background) {
395 fc->blocked = 0; 395 fc->blocked = 0;
396
397 /* Wake up next waiter, if any */
398 if (!fc->blocked && waitqueue_active(&fc->blocked_waitq))
399 wake_up(&fc->blocked_waitq); 396 wake_up(&fc->blocked_waitq);
397 } else if (!fc->blocked) {
398 /*
399 * Wake up next waiter, if any. It's okay to use
400 * waitqueue_active(), as we've already synced up
401 * fc->blocked with waiters with the wake_up() call
402 * above.
403 */
404 if (waitqueue_active(&fc->blocked_waitq))
405 wake_up(&fc->blocked_waitq);
406 }
400 407
401 if (fc->num_background == fc->congestion_threshold && fc->sb) { 408 if (fc->num_background == fc->congestion_threshold && fc->sb) {
402 clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC); 409 clear_bdi_congested(fc->sb->s_bdi, BLK_RW_SYNC);