diff options
author | Miklos Szeredi <mszeredi@redhat.com> | 2018-09-28 10:43:22 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@redhat.com> | 2018-09-28 10:43:22 -0400 |
commit | 908a572b80f6e9577b45e81b3dfe2e22111286b8 (patch) | |
tree | 9752e255244d3e6314f471fdc15f4491c1dc8939 | |
parent | 4c316f2f3ff315cb48efb7435621e5bfb81df96d (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.c | 15 |
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); |