From patchwork Fri May 25 03:46:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ming Lei X-Patchwork-Id: 10426221 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 5B281602D8 for ; Fri, 25 May 2018 03:55:45 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4C890294E4 for ; Fri, 25 May 2018 03:55:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 40239295A6; Fri, 25 May 2018 03:55: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=unavailable 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 CABEC294E4 for ; Fri, 25 May 2018 03:55:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935709AbeEYDuQ (ORCPT ); Thu, 24 May 2018 23:50:16 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:38050 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S932618AbeEYDuP (ORCPT ); Thu, 24 May 2018 23:50:15 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id B696E402290A; Fri, 25 May 2018 03:50:14 +0000 (UTC) Received: from localhost (ovpn-12-30.pek2.redhat.com [10.72.12.30]) by smtp.corp.redhat.com (Postfix) with ESMTP id 97CF72166BB2; Fri, 25 May 2018 03:50:06 +0000 (UTC) From: Ming Lei To: Jens Axboe , Christoph Hellwig , Alexander Viro , Kent Overstreet Cc: David Sterba , Huang Ying , linux-kernel@vger.kernel.org, linux-block@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, Theodore Ts'o , "Darrick J . Wong" , Coly Li , Filipe Manana , Ming Lei Subject: [RESEND PATCH V5 18/33] block: deal with dirtying pages for multipage bvec Date: Fri, 25 May 2018 11:46:06 +0800 Message-Id: <20180525034621.31147-19-ming.lei@redhat.com> In-Reply-To: <20180525034621.31147-1-ming.lei@redhat.com> References: <20180525034621.31147-1-ming.lei@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Fri, 25 May 2018 03:50:14 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Fri, 25 May 2018 03:50:14 +0000 (UTC) for IP:'10.11.54.6' DOMAIN:'int-mx06.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'ming.lei@redhat.com' RCPT:'' 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 In bio_check_pages_dirty(), bvec->bv_page is used as flag for marking if the page has been dirtied & released, and if no, it will be dirtied in deferred workqueue. With multipage bvec, we can't do that any more, so change the logic into checking all pages in one mp bvec, and only release all these pages if all are dirtied, otherwise dirty them all in deferred wrokqueue. This patch introduces segment_for_each_page_all() to deal with the case a bit easier. Signed-off-by: Ming Lei --- block/bio.c | 45 +++++++++++++++++++++++++++++++++++++-------- include/linux/bvec.h | 7 +++++++ 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/block/bio.c b/block/bio.c index 63d4fe85f42e..a200c42e55dc 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1630,8 +1630,9 @@ void bio_set_pages_dirty(struct bio *bio) { struct bio_vec *bvec; int i; + struct bvec_iter_all bia; - bio_for_each_page_all(bvec, bio, i) { + bio_for_each_page_all2(bvec, bio, i, bia) { struct page *page = bvec->bv_page; if (page && !PageCompound(page)) @@ -1640,16 +1641,26 @@ void bio_set_pages_dirty(struct bio *bio) } EXPORT_SYMBOL_GPL(bio_set_pages_dirty); +static inline void release_mp_bvec_pages(struct bio_vec *bvec) +{ + struct bio_vec bv; + struct bvec_iter iter; + + segment_for_each_page_all(bv, bvec, iter) + put_page(bv.bv_page); +} + static void bio_release_pages(struct bio *bio) { struct bio_vec *bvec; int i; - bio_for_each_page_all(bvec, bio, i) { + /* iterate each mp bvec */ + bio_for_each_segment_all(bvec, bio, i) { struct page *page = bvec->bv_page; if (page) - put_page(page); + release_mp_bvec_pages(bvec); } } @@ -1693,20 +1704,38 @@ static void bio_dirty_fn(struct work_struct *work) } } +static inline void check_mp_bvec_pages(struct bio_vec *bvec, + int *nr_dirty, int *nr_pages) +{ + struct bio_vec bv; + struct bvec_iter iter; + + segment_for_each_page_all(bv, bvec, iter) { + struct page *page = bv.bv_page; + + if (PageDirty(page) || PageCompound(page)) + (*nr_dirty)++; + (*nr_pages)++; + } +} + void bio_check_pages_dirty(struct bio *bio) { struct bio_vec *bvec; int nr_clean_pages = 0; int i; - bio_for_each_page_all(bvec, bio, i) { - struct page *page = bvec->bv_page; + bio_for_each_segment_all(bvec, bio, i) { + int nr_dirty = 0, nr_pages = 0; + + check_mp_bvec_pages(bvec, &nr_dirty, &nr_pages); - if (PageDirty(page) || PageCompound(page)) { - put_page(page); + /* release all pages in the mp bvec if all are dirtied */ + if (nr_dirty == nr_pages) { + release_mp_bvec_pages(bvec); bvec->bv_page = NULL; } else { - nr_clean_pages++; + nr_clean_pages += nr_pages; } } diff --git a/include/linux/bvec.h b/include/linux/bvec.h index 2deee87b823e..893e8fef0dd0 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -225,6 +225,13 @@ static inline bool bvec_iter_seg_advance(const struct bio_vec *bv, .bi_bvec_done = 0, \ } +#define segment_for_each_page_all(pg_bvl, seg_bvec, iter) \ + for (iter = BVEC_ITER_ALL_INIT, \ + (iter).bi_size = (seg_bvec)->bv_len - (iter).bi_bvec_done;\ + (iter).bi_size && \ + ((pg_bvl = bvec_iter_bvec((seg_bvec), (iter))), 1); \ + bvec_iter_advance((seg_bvec), &(iter), (pg_bvl).bv_len)) + /* get the last page from the multipage bvec and store it in @pg */ static inline void segment_last_page(const struct bio_vec *seg, struct bio_vec *pg)