[PATCH v2] fuse: permit freezing while waiting for request answer
Sergey Senozhatsky <[email protected]>
| Newsgroups | dev.linux.lists.fuse-devel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Suspend freezes tasks in random order and doesn't take into consideration producer-consumer dependency that may exist between tasks. One example where this can cause issues is: fuse server getting frozen ahead of clients, which then get stuck waiting for req answers that never come (the server is already frozen). Make all wait-event calls in request_wait_answer() freezer-friendly. This, however, doesn't address all cases. E.g. in-place PM-freeze of a request_wait_answer() task holding a contended VFS lock still will block suspend. Note: this uses TASK_FREEZABLE, not TASK_FREEZABLE_UNSAFE, which may trigger debug_locks warning during suspend (if request_wait_answer() task holds some locks at the time of freeze.) Signed-off-by: Sergey Senozhatsky <[email protected]> --- fs/fuse/dev.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 34106f6e66a0..42098ddc2587 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -701,8 +701,9 @@ static void request_wait_answer(struct fuse_req *req) if (!fch->no_interrupt) { /* Any signal may interrupt this */ - err = wait_event_interruptible(req->waitq, - test_bit(FR_FINISHED, &req->flags)); + err = wait_event_state(req->waitq, + test_bit(FR_FINISHED, &req->flags), + (TASK_INTERRUPTIBLE | TASK_FREEZABLE)); if (!err) return; @@ -717,8 +718,9 @@ static void request_wait_answer(struct fuse_req *req) bool removed; /* Only fatal signals may interrupt this */ - err = wait_event_killable(req->waitq, - test_bit(FR_FINISHED, &req->flags)); + err = wait_event_state(req->waitq, + test_bit(FR_FINISHED, &req->flags), + (TASK_KILLABLE | TASK_FREEZABLE)); if (!err) return; @@ -740,7 +742,8 @@ static void request_wait_answer(struct fuse_req *req) * Either request is already in userspace, or it was forced. * Wait it out. */ - wait_event(req->waitq, test_bit(FR_FINISHED, &req->flags)); + wait_event_state(req->waitq, test_bit(FR_FINISHED, &req->flags), + (TASK_UNINTERRUPTIBLE | TASK_FREEZABLE)); } static void __fuse_request_send(struct fuse_req *req) -- 2.55.0.737.g08866a6d13-goog