From patchwork Tue Jan 15 10:19:41 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kirill Tkhai X-Patchwork-Id: 10764247 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 40EA613B5 for ; Tue, 15 Jan 2019 10:19:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2DEDE2B2ED for ; Tue, 15 Jan 2019 10:19:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 223F62B2FF; Tue, 15 Jan 2019 10:19:45 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 964842B2ED for ; Tue, 15 Jan 2019 10:19:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728421AbfAOKTo (ORCPT ); Tue, 15 Jan 2019 05:19:44 -0500 Received: from relay.sw.ru ([185.231.240.75]:36308 "EHLO relay.sw.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728202AbfAOKTn (ORCPT ); Tue, 15 Jan 2019 05:19:43 -0500 Received: from [172.16.25.169] (helo=localhost.localdomain) by relay.sw.ru with esmtp (Exim 4.91) (envelope-from ) id 1gjLos-00012u-6J; Tue, 15 Jan 2019 13:19:42 +0300 Subject: [PATCH 5/7] fuse: Introduce generic fuse_copy_aborted() From: Kirill Tkhai To: miklos@szeredi.hu, ktkhai@virtuozzo.com, linux-fsdevel@vger.kernel.org Date: Tue, 15 Jan 2019 13:19:41 +0300 Message-ID: <154754758189.4244.13193829723902632197.stgit@localhost.localdomain> In-Reply-To: <154754701031.4244.8089449938935364463.stgit@localhost.localdomain> References: <154754701031.4244.8089449938935364463.stgit@localhost.localdomain> User-Agent: StGit/0.18 MIME-Version: 1.0 Sender: linux-fsdevel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-fsdevel@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP There is no a reason to set individual FR_ABORTED state for every request, since fuse_abort_conn() aborts all unlocked requests at once. FR_ABORTED bit just makes fuse_copy_aborted() to end some of requests, which are in the middle of fuse_dev_do_read() and fuse_dev_do_write(), but this is not a big deal. These functions may abort the requests themselves. The patch kills lock_request and unlock_request(), and introduces generic fuse_copy_aborted() to use instead of them. This allows next patches to kill FR_ABORTED, FR_LOCKED and FR_PRIVATE, and simplify fuse dev read/write function. Signed-off-by: Kirill Tkhai --- fs/fuse/dev.c | 82 +++++++++++++-------------------------------------------- 1 file changed, 18 insertions(+), 64 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index afadf462ec18..4905abfb279e 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -731,43 +731,6 @@ void fuse_force_forget(struct file *file, u64 nodeid) fuse_put_request(fc, req); } -/* - * Lock the request. Up to the next unlock_request() there mustn't be - * anything that could cause a page-fault. If the request was already - * aborted bail out. - */ -static int lock_request(struct fuse_req *req) -{ - int err = 0; - if (req) { - spin_lock(&req->waitq.lock); - if (test_bit(FR_ABORTED, &req->flags)) - err = -ENOENT; - else - set_bit(FR_LOCKED, &req->flags); - spin_unlock(&req->waitq.lock); - } - return err; -} - -/* - * Unlock request. If it was aborted while locked, caller is responsible - * for unlocking and ending the request. - */ -static int unlock_request(struct fuse_req *req) -{ - int err = 0; - if (req) { - spin_lock(&req->waitq.lock); - if (test_bit(FR_ABORTED, &req->flags)) - err = -ENOENT; - else - clear_bit(FR_LOCKED, &req->flags); - spin_unlock(&req->waitq.lock); - } - return err; -} - struct fuse_copy_state { struct fuse_dev *fud; int write; @@ -812,6 +775,16 @@ static void fuse_copy_finish(struct fuse_copy_state *cs) cs->pg = NULL; } +static int fuse_copy_aborted(struct fuse_copy_state *cs) +{ + struct fuse_pqueue *pq = &cs->fud->pq; + + if (READ_ONCE(pq->connected)) + return 0; + else + return -ENOENT; +} + /* * Get another pagefull of userspace buffer, and map it to kernel * address space, and lock request @@ -821,7 +794,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs) struct page *page; int err; - err = unlock_request(cs->req); + err = fuse_copy_aborted(cs); if (err) return err; @@ -872,7 +845,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs) iov_iter_advance(cs->iter, err); } - return lock_request(cs->req); + return fuse_copy_aborted(cs); } /* Do as much copy to/from userspace buffer as we can */ @@ -923,7 +896,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep) struct page *newpage; struct pipe_buffer *buf = cs->pipebufs; - err = unlock_request(cs->req); + err = fuse_copy_aborted(cs); if (err) return err; @@ -980,12 +953,10 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep) lru_cache_add_file(newpage); err = 0; - spin_lock(&cs->req->waitq.lock); - if (test_bit(FR_ABORTED, &cs->req->flags)) + if (fuse_copy_aborted(cs)) err = -ENOENT; else *pagep = newpage; - spin_unlock(&cs->req->waitq.lock); if (err) { unlock_page(newpage); @@ -1005,7 +976,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep) cs->pg = buf->page; cs->offset = buf->offset; - err = lock_request(cs->req); + err = fuse_copy_aborted(cs); if (err) return err; @@ -1021,7 +992,7 @@ static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page, if (cs->nr_segs == cs->pipe->buffers) return -EIO; - err = unlock_request(cs->req); + err = fuse_copy_aborted(cs); if (err) return err; @@ -2172,13 +2143,6 @@ static void end_polls(struct fuse_conn *fc) * and all users of the filesystem. The exception is the combination of an * asynchronous request and the tricky deadlock (see * Documentation/filesystems/fuse.txt). - * - * Aborting requests under I/O goes as follows: 1: Separate out unlocked - * requests, they should be finished off immediately. Locked requests will be - * finished after unlock; see unlock_request(). 2: Finish off the unlocked - * requests. It is possible that some request will finish before we can. This - * is OK, the request will in that case be removed from the list before we touch - * it. */ void fuse_abort_conn(struct fuse_conn *fc) { @@ -2187,7 +2151,7 @@ void fuse_abort_conn(struct fuse_conn *fc) spin_lock(&fc->lock); if (fc->connected) { struct fuse_dev *fud; - struct fuse_req *req, *next; + struct fuse_req *req; LIST_HEAD(to_end); unsigned int i; @@ -2205,17 +2169,6 @@ void fuse_abort_conn(struct fuse_conn *fc) spin_lock(&fpq->lock); fpq->connected = 0; - list_for_each_entry_safe(req, next, &fpq->io, list) { - req->out.h.error = -ECONNABORTED; - spin_lock(&req->waitq.lock); - set_bit(FR_ABORTED, &req->flags); - if (!test_bit(FR_LOCKED, &req->flags)) { - set_bit(FR_PRIVATE, &req->flags); - __fuse_get_request(req); - list_move(&req->list, &to_end); - } - spin_unlock(&req->waitq.lock); - } for (i = 0; i < FUSE_PQ_HASH_SIZE; i++) list_splice_tail_init(&fpq->processing[i], &to_end); @@ -2238,6 +2191,7 @@ void fuse_abort_conn(struct fuse_conn *fc) spin_unlock(&fc->lock); end_requests(fc, &to_end); + fuse_wait_aborted(fc); spin_lock(&fc->lock); fc->aborting = false;