From: Jan Kara <jack@suse.cz>
To: linux-mm@kvack.org
Cc: Hugh Dickins <hughd@google.com>,
David Howells <dhowells@redhat.com>,
linux-afs@lists.infradead.org,
Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>,
linux-nilfs@vger.kernel.org, Bob Peterson <rpeterso@redhat.com>,
cluster-devel@redhat.com, Jaegeuk Kim <jaegeuk@kernel.org>,
linux-f2fs-devel@lists.sourceforge.net, tytso@mit.edu,
linux-ext4@vger.kernel.org, Ilya Dryomov <idryomov@gmail.com>,
"Yan, Zheng" <zyan@redhat.com>,
ceph-devel@vger.kernel.org, linux-btrfs@vger.kernel.org,
David Sterba <dsterba@suse.com>,
"Darrick J . Wong" <darrick.wong@oracle.com>,
linux-xfs@vger.kernel.org,
Nadia Yvette Chambers <nyc@holomorphy.com>,
Jan Kara <jack@suse.cz>,
stable@vger.kernel.org, Zheng Liu <wenqing.lz@taobao.com>
Subject: [PATCH 02/35] ext4: Fix SEEK_HOLE
Date: Thu, 1 Jun 2017 11:32:12 +0200 [thread overview]
Message-ID: <20170601093245.29238-3-jack@suse.cz> (raw)
In-Reply-To: <20170601093245.29238-1-jack@suse.cz>
Currently, SEEK_HOLE implementation in ext4 may both return that there's
a hole at some offset although that offset already has data and skip
some holes during a search for the next hole. The first problem is
demostrated by:
xfs_io -c "falloc 0 256k" -c "pwrite 0 56k" -c "seek -h 0" file
wrote 57344/57344 bytes at offset 0
56 KiB, 14 ops; 0.0000 sec (2.054 GiB/sec and 538461.5385 ops/sec)
Whence Result
HOLE 0
Where we can see that SEEK_HOLE wrongly returned offset 0 as containing
a hole although we have written data there. The second problem can be
demonstrated by:
xfs_io -c "falloc 0 256k" -c "pwrite 0 56k" -c "pwrite 128k 8k"
-c "seek -h 0" file
wrote 57344/57344 bytes at offset 0
56 KiB, 14 ops; 0.0000 sec (1.978 GiB/sec and 518518.5185 ops/sec)
wrote 8192/8192 bytes at offset 131072
8 KiB, 2 ops; 0.0000 sec (2 GiB/sec and 500000.0000 ops/sec)
Whence Result
HOLE 139264
Where we can see that hole at offsets 56k..128k has been ignored by the
SEEK_HOLE call.
The underlying problem is in the ext4_find_unwritten_pgoff() which is
just buggy. In some cases it fails to update returned offset when it
finds a hole (when no pages are found or when the first found page has
higher index than expected), in some cases conditions for detecting hole
are just missing (we fail to detect a situation where indices of
returned pages are not contiguous).
Fix ext4_find_unwritten_pgoff() to properly detect non-contiguous page
indices and also handle all cases where we got less pages then expected
in one place and handle it properly there.
CC: stable@vger.kernel.org
Fixes: c8c0df241cc2719b1262e627f999638411934f60
CC: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: Jan Kara <jack@suse.cz>
---
fs/ext4/file.c | 50 ++++++++++++++------------------------------------
1 file changed, 14 insertions(+), 36 deletions(-)
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 831fd6beebf0..bbea2dccd584 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -484,47 +484,27 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
num = min_t(pgoff_t, end - index, PAGEVEC_SIZE);
nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index,
(pgoff_t)num);
- if (nr_pages == 0) {
- if (whence == SEEK_DATA)
- break;
-
- BUG_ON(whence != SEEK_HOLE);
- /*
- * If this is the first time to go into the loop and
- * offset is not beyond the end offset, it will be a
- * hole at this offset
- */
- if (lastoff == startoff || lastoff < endoff)
- found = 1;
- break;
- }
-
- /*
- * If this is the first time to go into the loop and
- * offset is smaller than the first page offset, it will be a
- * hole at this offset.
- */
- if (lastoff == startoff && whence == SEEK_HOLE &&
- lastoff < page_offset(pvec.pages[0])) {
- found = 1;
+ if (nr_pages == 0)
break;
- }
for (i = 0; i < nr_pages; i++) {
struct page *page = pvec.pages[i];
struct buffer_head *bh, *head;
/*
- * If the current offset is not beyond the end of given
- * range, it will be a hole.
+ * If current offset is smaller than the page offset,
+ * there is a hole at this offset.
*/
- if (lastoff < endoff && whence == SEEK_HOLE &&
- page->index > end) {
+ if (whence == SEEK_HOLE && lastoff < endoff &&
+ lastoff < page_offset(pvec.pages[i])) {
found = 1;
*offset = lastoff;
goto out;
}
+ if (page->index > end)
+ goto out;
+
lock_page(page);
if (unlikely(page->mapping != inode->i_mapping)) {
@@ -564,20 +544,18 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
unlock_page(page);
}
- /*
- * The no. of pages is less than our desired, that would be a
- * hole in there.
- */
- if (nr_pages < num && whence == SEEK_HOLE) {
- found = 1;
- *offset = lastoff;
+ /* The no. of pages is less than our desired, we are done. */
+ if (nr_pages < num)
break;
- }
index = pvec.pages[i - 1]->index + 1;
pagevec_release(&pvec);
} while (index <= end);
+ if (whence == SEEK_HOLE && lastoff < endoff) {
+ found = 1;
+ *offset = lastoff;
+ }
out:
pagevec_release(&pvec);
return found;
--
2.12.3
next prev parent reply other threads:[~2017-06-01 9:32 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-06-01 9:32 [PATCH 00/35 v1] pagevec API cleanups Jan Kara
2017-06-01 9:32 ` [PATCH 01/35] fscache: Remove unused ->now_uncached callback Jan Kara
2017-06-01 9:32 ` Jan Kara [this message]
[not found] ` <20170601093245.29238-1-jack-AlSwsSmVLrQ@public.gmane.org>
2017-06-01 9:32 ` [PATCH 03/35] ext4: Fix off-by-in in loop termination in ext4_find_unwritten_pgoff() Jan Kara
2017-06-01 9:32 ` [PATCH 04/35] dax: Fix inefficiency in dax_writeback_mapping_range() Jan Kara
2017-06-01 9:32 ` [PATCH 05/35] mm: Fix THP handling in invalidate_mapping_pages() Jan Kara
2017-06-01 9:32 ` [PATCH 06/35] mm: Make pagevec_lookup() update index Jan Kara
2017-06-01 9:32 ` [PATCH 07/35] mm: Implement find_get_pages_range() Jan Kara
2017-06-01 9:32 ` [PATCH 08/35] fs: Fix performance regression in clean_bdev_aliases() Jan Kara
2017-06-01 9:32 ` [PATCH 09/35] ext4: Use pagevec_lookup_range() in ext4_find_unwritten_pgoff() Jan Kara
2017-06-01 9:32 ` [PATCH 10/35] ext4: Use pagevec_lookup_range() in writeback code Jan Kara
2017-06-01 9:32 ` [PATCH 11/35] hugetlbfs: Use pagevec_lookup_range() in remove_inode_hugepages() Jan Kara
2017-06-01 9:32 ` [PATCH 12/35] xfs: Use pagevec_lookup_range() in xfs_find_get_desired_pgoff() Jan Kara
2017-06-01 9:32 ` [PATCH 13/35] mm: Remove nr_pages argument from pagevec_lookup{, _range}() Jan Kara
2017-06-01 9:32 ` [PATCH 14/35] mm: Implement find_get_pages_range_tag() Jan Kara
2017-06-01 9:32 ` [PATCH 15/35] btrfs: Use pagevec_lookup_range_tag() Jan Kara
2017-06-01 9:32 ` [PATCH 16/35] ceph: " Jan Kara
2017-06-01 9:32 ` [PATCH 17/35] ext4: " Jan Kara
2017-06-01 9:32 ` [PATCH 18/35] f2fs: " Jan Kara
2017-06-01 9:32 ` [PATCH 19/35] f2fs: Simplify page iteration loops Jan Kara
2017-06-01 13:00 ` kbuild test robot
2017-06-01 9:32 ` [PATCH 20/35] f2fs: Use find_get_pages_tag() for looking up single page Jan Kara
2017-06-01 9:32 ` [PATCH 21/35] gfs2: Use pagevec_lookup_range_tag() Jan Kara
2017-06-01 9:32 ` [PATCH 22/35] nilfs2: " Jan Kara
2017-06-01 9:32 ` [PATCH 23/35] mm: Use pagevec_lookup_range_tag() in __filemap_fdatawait_range() Jan Kara
2017-06-01 9:32 ` [PATCH 24/35] mm: Use pagevec_lookup_range_tag() in write_cache_pages() Jan Kara
2017-06-01 9:32 ` [PATCH 25/35] mm: Remove nr_pages argument from pagevec_lookup_{, range}_tag() Jan Kara
2017-06-01 9:32 ` [PATCH 26/35] afs: Use find_get_pages_range_tag() Jan Kara
2017-06-01 9:32 ` [PATCH 27/35] shmem: Use pagevec_lookup() in shmem_unlock_mapping() Jan Kara
2017-06-01 9:32 ` [PATCH 28/35] shmem: Use pagevec_lookup_entries() Jan Kara
2017-06-01 9:32 ` [PATCH 29/35] mm: Make pagevec_lookup_entries() update index Jan Kara
2017-06-01 9:32 ` [PATCH 30/35] mm: Implement find_get_entries_range() Jan Kara
2017-06-01 9:32 ` [PATCH 31/35] shmem: Convert to pagevec_lookup_entries_range() Jan Kara
2017-06-01 13:55 ` kbuild test robot
2017-06-01 9:32 ` [PATCH 32/35] mm: Convert truncate code " Jan Kara
2017-06-01 9:32 ` [PATCH 33/35] mm: Remove nr_entries argument from pagevec_lookup_entries{, _range}() Jan Kara
2017-06-01 9:32 ` [PATCH 34/35] mm: Make find_get_entries_tag() update index Jan Kara
2017-06-01 9:32 ` [PATCH 35/35] mm: Implement find_get_entries_range_tag() Jan Kara
2017-06-01 10:26 ` [PATCH 01/35] fscache: Remove unused ->now_uncached callback David Howells
2017-06-01 11:34 ` Jan Kara
2017-06-19 13:12 ` Jan Kara
2017-06-01 11:36 ` [Cluster-devel] [PATCH 00/35 v1] pagevec API cleanups Christoph Hellwig
2017-06-01 12:05 ` Jan Kara
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20170601093245.29238-3-jack@suse.cz \
--to=jack@suse.cz \
--cc=ceph-devel@vger.kernel.org \
--cc=cluster-devel@redhat.com \
--cc=darrick.wong@oracle.com \
--cc=dhowells@redhat.com \
--cc=dsterba@suse.com \
--cc=hughd@google.com \
--cc=idryomov@gmail.com \
--cc=jaegeuk@kernel.org \
--cc=konishi.ryusuke@lab.ntt.co.jp \
--cc=linux-afs@lists.infradead.org \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-f2fs-devel@lists.sourceforge.net \
--cc=linux-mm@kvack.org \
--cc=linux-nilfs@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
--cc=nyc@holomorphy.com \
--cc=rpeterso@redhat.com \
--cc=stable@vger.kernel.org \
--cc=tytso@mit.edu \
--cc=wenqing.lz@taobao.com \
--cc=zyan@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).