The patch fixes the following race (leading to deadlock): 1. Thread A. Enter fuse_prepare_write() checks for FUSE_S_FAIL_IMMEDIATELY, but it was not set yet, so it doesn't return -EIO.
2. Thread B. Enter fuse_invalidate_files(). It sets FUSE_S_FAIL_IMMEDIATELY, calls filemap_write_and_wait() and fuse_kill_requests(), then release fc->lock. 3. Thread A. fuse_commit_write() marks page as "Dirty", then fuse_write_end() unlocks the page. 4. Thread B. fuse_invalidate_files() calls invalidate_inode_pages2(). The page is dirty, so it ends up in fuse_launder_page() calling fuse_writepage_locked(). The latter successfully proceeds queuing fuse-write-back request, but then fuse_launder_page() calls fuse_wait_on_page_writeback() that blocks forever because Thread A is still blocked in fuse_invalidate_files(). Signed-off-by: Maxim Patlasov <[email protected]> --- fs/fuse/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 4fcf4f4..e21b8b7 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -1827,7 +1827,8 @@ __acquires(fc->lock) struct fuse_write_in *inarg = &req->misc.write.in; __u64 data_size = req->num_pages * PAGE_CACHE_SIZE; - if (!fc->connected) + if (!fc->connected || + test_bit(FUSE_S_FAIL_IMMEDIATELY, &req->ff->ff_state)) goto out_free; if (inarg->offset + data_size <= size) { _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
