diff options
author | Liu Bo <bo.li.liu@oracle.com> | 2017-02-10 16:41:05 +0100 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2017-02-17 12:03:35 +0100 |
commit | da2c7009f6cafe0a550cf57a1aa79e0f1b3093d6 (patch) | |
tree | bbb0244a94f04c55c100627370371e8a6415cf31 /fs/btrfs/extent_io.c | |
parent | 873695b301df51dc9dac2573669ac8777d37bec3 (diff) | |
download | blackbird-op-linux-da2c7009f6cafe0a550cf57a1aa79e0f1b3093d6.tar.gz blackbird-op-linux-da2c7009f6cafe0a550cf57a1aa79e0f1b3093d6.zip |
btrfs: teach __process_pages_contig about PAGE_LOCK operation
Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
Reviewed-by: David Sterba <dsterba@suse.com>
[ changes to the helper separated from the following patch ]
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/extent_io.c')
-rw-r--r-- | fs/btrfs/extent_io.c | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 664f52c1c58a..5bb7ced20695 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1554,6 +1554,11 @@ out: return found; } +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); + static noinline void __unlock_for_delalloc(struct inode *inode, struct page *locked_page, u64 start, u64 end) @@ -1731,17 +1736,24 @@ out_failed: return found; } -static void __process_pages_contig(struct address_space *mapping, - struct page *locked_page, - pgoff_t start_index, pgoff_t end_index, - unsigned long page_ops) +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) { unsigned long nr_pages = end_index - start_index + 1; + unsigned long pages_locked = 0; pgoff_t index = start_index; struct page *pages[16]; unsigned ret; + int err = 0; int i; + if (page_ops & PAGE_LOCK) { + ASSERT(page_ops == PAGE_LOCK); + ASSERT(index_ret && *index_ret == start_index); + } + if ((page_ops & PAGE_SET_ERROR) && nr_pages > 0) mapping_set_error(mapping, -EIO); @@ -1749,13 +1761,22 @@ static void __process_pages_contig(struct address_space *mapping, ret = find_get_pages_contig(mapping, index, min_t(unsigned long, nr_pages, ARRAY_SIZE(pages)), pages); - for (i = 0; i < ret; i++) { + if (ret == 0) { + /* + * Only if we're going to lock these pages, + * can we find nothing at @index. + */ + ASSERT(page_ops & PAGE_LOCK); + return ret; + } + for (i = 0; i < ret; i++) { if (page_ops & PAGE_SET_PRIVATE2) SetPagePrivate2(pages[i]); if (pages[i] == locked_page) { put_page(pages[i]); + pages_locked++; continue; } if (page_ops & PAGE_CLEAR_DIRTY) @@ -1768,12 +1789,27 @@ static void __process_pages_contig(struct address_space *mapping, end_page_writeback(pages[i]); if (page_ops & PAGE_UNLOCK) unlock_page(pages[i]); + if (page_ops & PAGE_LOCK) { + lock_page(pages[i]); + if (!PageDirty(pages[i]) || + pages[i]->mapping != mapping) { + unlock_page(pages[i]); + put_page(pages[i]); + err = -EAGAIN; + goto out; + } + } put_page(pages[i]); + pages_locked++; } nr_pages -= ret; index += ret; cond_resched(); } +out: + if (err && index_ret) + *index_ret = start_index + pages_locked - 1; + return err; } void extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end, @@ -1786,7 +1822,7 @@ void extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end, __process_pages_contig(inode->i_mapping, locked_page, start >> PAGE_SHIFT, end >> PAGE_SHIFT, - page_ops); + page_ops, NULL); } /* |