btrfs: pass bytenr directly to __process_pages_contig()

As a preparation for incoming subpage support, we need bytenr passed to
__process_pages_contig() directly, not the current page index.

So change the parameter and all callers to pass bytenr in.

With the modification, here we need to replace the old @index_ret with
@processed_end for __process_pages_contig(), but this brings a small
problem.

Normally we follow the inclusive return value, meaning @processed_end
should be the last byte we processed.

If parameter @start is 0, and we failed to lock any page, then we would
return @processed_end as -1, causing more problems for
__unlock_for_delalloc().

So here for @processed_end, we use two different return value patterns.
If we have locked any page, @processed_end will be the last byte of
locked page.
Or it will be @start otherwise.

This change will impact lock_delalloc_pages(), so it needs to check
@processed_end to only unlock the range if we have locked any.

Tested-by: Ritesh Harjani <riteshh@linux.ibm.com> # [ppc64]
Tested-by: Anand Jain <anand.jain@oracle.com> # [aarch64]
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2021-05-31 16:50:37 +08:00 committed by David Sterba
parent 968f2566ad
commit 98af9ab12b

View File

@ -1810,8 +1810,8 @@ out:
static int __process_pages_contig(struct address_space *mapping,
struct page *locked_page,
pgoff_t start_index, pgoff_t end_index,
unsigned long page_ops, pgoff_t *index_ret);
u64 start, u64 end, unsigned long page_ops,
u64 *processed_end);
static noinline void __unlock_for_delalloc(struct inode *inode,
struct page *locked_page,
@ -1824,7 +1824,7 @@ static noinline void __unlock_for_delalloc(struct inode *inode,
if (index == locked_page->index && end_index == index)
return;
__process_pages_contig(inode->i_mapping, locked_page, index, end_index,
__process_pages_contig(inode->i_mapping, locked_page, start, end,
PAGE_UNLOCK, NULL);
}
@ -1834,19 +1834,19 @@ static noinline int lock_delalloc_pages(struct inode *inode,
u64 delalloc_end)
{
unsigned long index = delalloc_start >> PAGE_SHIFT;
unsigned long index_ret = index;
unsigned long end_index = delalloc_end >> PAGE_SHIFT;
u64 processed_end = delalloc_start;
int ret;
ASSERT(locked_page);
if (index == locked_page->index && index == end_index)
return 0;
ret = __process_pages_contig(inode->i_mapping, locked_page, index,
end_index, PAGE_LOCK, &index_ret);
if (ret == -EAGAIN)
ret = __process_pages_contig(inode->i_mapping, locked_page, delalloc_start,
delalloc_end, PAGE_LOCK, &processed_end);
if (ret == -EAGAIN && processed_end > delalloc_start)
__unlock_for_delalloc(inode, locked_page, delalloc_start,
(u64)index_ret << PAGE_SHIFT);
processed_end);
return ret;
}
@ -1941,12 +1941,14 @@ out_failed:
static int __process_pages_contig(struct address_space *mapping,
struct page *locked_page,
pgoff_t start_index, pgoff_t end_index,
unsigned long page_ops, pgoff_t *index_ret)
u64 start, u64 end, unsigned long page_ops,
u64 *processed_end)
{
pgoff_t start_index = start >> PAGE_SHIFT;
pgoff_t end_index = end >> PAGE_SHIFT;
pgoff_t index = start_index;
unsigned long nr_pages = end_index - start_index + 1;
unsigned long pages_processed = 0;
pgoff_t index = start_index;
struct page *pages[16];
unsigned ret;
int err = 0;
@ -1954,17 +1956,19 @@ static int __process_pages_contig(struct address_space *mapping,
if (page_ops & PAGE_LOCK) {
ASSERT(page_ops == PAGE_LOCK);
ASSERT(index_ret && *index_ret == start_index);
ASSERT(processed_end && *processed_end == start);
}
if ((page_ops & PAGE_SET_ERROR) && nr_pages > 0)
mapping_set_error(mapping, -EIO);
while (nr_pages > 0) {
ret = find_get_pages_contig(mapping, index,
int found_pages;
found_pages = find_get_pages_contig(mapping, index,
min_t(unsigned long,
nr_pages, ARRAY_SIZE(pages)), pages);
if (ret == 0) {
if (found_pages == 0) {
/*
* Only if we're going to lock these pages,
* can we find nothing at @index.
@ -2007,13 +2011,27 @@ static int __process_pages_contig(struct address_space *mapping,
put_page(pages[i]);
pages_processed++;
}
nr_pages -= ret;
index += ret;
nr_pages -= found_pages;
index += found_pages;
cond_resched();
}
out:
if (err && index_ret)
*index_ret = start_index + pages_processed - 1;
if (err && processed_end) {
/*
* Update @processed_end. I know this is awful since it has
* two different return value patterns (inclusive vs exclusive).
*
* But the exclusive pattern is necessary if @start is 0, or we
* underflow and check against processed_end won't work as
* expected.
*/
if (pages_processed)
*processed_end = min(end,
((u64)(start_index + pages_processed) << PAGE_SHIFT) - 1);
else
*processed_end = start;
}
return err;
}
@ -2024,8 +2042,7 @@ void extent_clear_unlock_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
clear_extent_bit(&inode->io_tree, start, end, clear_bits, 1, 0, NULL);
__process_pages_contig(inode->vfs_inode.i_mapping, locked_page,
start >> PAGE_SHIFT, end >> PAGE_SHIFT,
page_ops, NULL);
start, end, page_ops, NULL);
}
/*