From patchwork Wed Sep 14 08:37:14 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Miklos Szeredi X-Patchwork-Id: 9330899 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 6AD376077F for ; Wed, 14 Sep 2016 08:39:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5BA0029B6D for ; Wed, 14 Sep 2016 08:39:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5006629B70; Wed, 14 Sep 2016 08:39:23 +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=-6.4 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM 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 CFEC229B6D for ; Wed, 14 Sep 2016 08:39:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1761643AbcINIi7 (ORCPT ); Wed, 14 Sep 2016 04:38:59 -0400 Received: from mail-wm0-f46.google.com ([74.125.82.46]:37008 "EHLO mail-wm0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1761178AbcINIhd (ORCPT ); Wed, 14 Sep 2016 04:37:33 -0400 Received: by mail-wm0-f46.google.com with SMTP id c131so16231949wmh.0 for ; Wed, 14 Sep 2016 01:37:32 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ngq12OT9klcGfIbqrPCd9rAbyImXGtzTzYz7FchXGmo=; b=KOAWp8YXYG4BrTNHI6IfK9+j3FUJ0jROrJL/3T+ox5nwidaRXXfml9/cUjaMryRFHR +wOVKeN6fjq4rF0bmc+TrsL6fXhPkx/JbTncFmhTiM06w5GVTm/7K0ACMGY1kb+3F1Qv lcHjjzyUWSrjcsuLNZMz0AVEC/A4fGnlpibiU4dEAxq3el1xBR1ZXnxpObXfwt3WXYV2 YmBPWAeZMG9Kr6tC+sSnje2vFmtN18aJLjeNYczcmenAGBWnUKwpj3o9wqHZ+wChHvlc sFES3BulM+ZhkfYsrTqR+fNhfIqXJ2Wg18zLFNuQSc4r8SDQsW0i0vJBf3PU+wRKtZJR ijVg== X-Gm-Message-State: AE9vXwPy7CWDh1e5GpWGCxPsPSLAhFPkds7+rjrS1+GY+3MvXXbVdinVMOLHFxeryUe0SNg0 X-Received: by 10.194.140.77 with SMTP id re13mr1380101wjb.79.1473842251957; Wed, 14 Sep 2016 01:37:31 -0700 (PDT) Received: from veci.piliscsaba.szeredi.hu (pool-dsl-2c-0018.externet.hu. [217.173.44.24]) by smtp.gmail.com with ESMTPSA id g184sm9533889wme.15.2016.09.14.01.37.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 14 Sep 2016 01:37:31 -0700 (PDT) From: Miklos Szeredi To: linux-fsdevel@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Al Viro Subject: [PATCH 09/11] splice: use get_page_for_read() Date: Wed, 14 Sep 2016 10:37:14 +0200 Message-Id: <1473842236-28655-10-git-send-email-mszeredi@redhat.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1473842236-28655-1-git-send-email-mszeredi@redhat.com> References: <1473842236-28655-1-git-send-email-mszeredi@redhat.com> 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 What __generic_file_splice_read() does is get a series of uptodate pages and put them into the pipe buffer. The get_page_for_read() helper can now be used to get the pages, simplifying the code and making sure the splice(2) stays in sync with read(2). For example get_page_for_read() can handle partially uptodate pages and now splice can take advantage of these as well. Signed-off-by: Miklos Szeredi --- fs/splice.c | 169 +++++------------------------------------------------------- 1 file changed, 12 insertions(+), 157 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index dc4648ba6e8d..e7757b363b6c 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -265,14 +265,12 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) { - struct address_space *mapping = in->f_mapping; unsigned int loff, nr_pages, req_pages; struct page *pages[PIPE_DEF_BUFFERS]; struct partial_page partial[PIPE_DEF_BUFFERS]; struct page *page; - pgoff_t index, end_index; - loff_t isize; - int error, page_nr; + pgoff_t index; + int error; struct splice_pipe_desc spd = { .pages = pages, .partial = partial, @@ -290,168 +288,25 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, req_pages = (len + loff + PAGE_SIZE - 1) >> PAGE_SHIFT; nr_pages = min(req_pages, spd.nr_pages_max); - /* - * Lookup the (hopefully) full range of pages we need. - */ - spd.nr_pages = find_get_pages_contig(mapping, index, nr_pages, spd.pages); - index += spd.nr_pages; - - /* - * If find_get_pages_contig() returned fewer pages than we needed, - * readahead/allocate the rest and fill in the holes. - */ - if (spd.nr_pages < nr_pages) - page_cache_sync_readahead(mapping, &in->f_ra, in, - index, req_pages - spd.nr_pages); - error = 0; - while (spd.nr_pages < nr_pages) { - /* - * Page could be there, find_get_pages_contig() breaks on - * the first hole. - */ - page = find_get_page(mapping, index); - if (!page) { - /* - * page didn't exist, allocate one. - */ - page = page_cache_alloc_cold(mapping); - if (!page) - break; + while (spd.nr_pages < nr_pages && len) { + long ret; - error = add_to_page_cache_lru(page, mapping, index, - mapping_gfp_constraint(mapping, GFP_KERNEL)); - if (unlikely(error)) { - put_page(page); - if (error == -EEXIST) - continue; - break; - } - /* - * add_to_page_cache() locks the page, unlock it - * to avoid convoluting the logic below even more. - */ - unlock_page(page); - } - - spd.pages[spd.nr_pages++] = page; - index++; - } - - /* - * Now loop over the map and see if we need to start IO on any - * pages, fill in the partial map, etc. - */ - index = *ppos >> PAGE_SHIFT; - nr_pages = spd.nr_pages; - spd.nr_pages = 0; - for (page_nr = 0; page_nr < nr_pages; page_nr++) { - unsigned int this_len; - - if (!len) + ret = get_page_for_read(in, loff, len, index, &page); + if (ret <= 0) { + error = ret; break; - - /* - * this_len is the max we'll use from this page - */ - this_len = min_t(unsigned long, len, PAGE_SIZE - loff); - page = spd.pages[page_nr]; - - if (PageReadahead(page)) - page_cache_async_readahead(mapping, &in->f_ra, in, - page, index, req_pages - page_nr); - - /* - * If the page isn't uptodate, we may need to start io on it - */ - if (!PageUptodate(page)) { - lock_page(page); - - /* - * Page was truncated, or invalidated by the - * filesystem. Redo the find/create, but this time the - * page is kept locked, so there's no chance of another - * race with truncate/invalidate. - */ - if (!page->mapping) { - unlock_page(page); -retry_lookup: - page = find_or_create_page(mapping, index, - mapping_gfp_mask(mapping)); - - if (!page) { - error = -ENOMEM; - break; - } - put_page(spd.pages[page_nr]); - spd.pages[page_nr] = page; - } - /* - * page was already under io and is now done, great - */ - if (PageUptodate(page)) { - unlock_page(page); - goto fill_it; - } - - /* - * need to read in the page - */ - error = mapping->a_ops->readpage(in, page); - if (unlikely(error)) { - /* - * Re-lookup the page - */ - if (error == AOP_TRUNCATED_PAGE) - goto retry_lookup; - - break; - } - } -fill_it: - /* - * i_size must be checked after PageUptodate. - */ - isize = i_size_read(mapping->host); - end_index = (isize - 1) >> PAGE_SHIFT; - if (unlikely(!isize || index > end_index)) - break; - - /* - * if this is the last page, see if we need to shrink - * the length and stop - */ - if (end_index == index) { - unsigned int plen; - - /* - * max good bytes in this page - */ - plen = ((isize - 1) & ~PAGE_MASK) + 1; - if (plen <= loff) - break; - - /* - * force quit after adding this page - */ - this_len = min(this_len, plen - loff); - len = this_len; } - spd.partial[page_nr].offset = loff; - spd.partial[page_nr].len = this_len; - len -= this_len; - loff = 0; + spd.pages[spd.nr_pages] = page; + spd.partial[spd.nr_pages].offset = loff; + spd.partial[spd.nr_pages].len = ret; spd.nr_pages++; index++; + len -= ret; + loff = 0; } - /* - * Release any pages at the end, if we quit early. 'page_nr' is how far - * we got, 'nr_pages' is how many pages are in the map. - */ - while (page_nr < nr_pages) - put_page(spd.pages[page_nr++]); in->f_ra.prev_pos = (loff_t)index << PAGE_SHIFT; if (spd.nr_pages)