From: Liu Bo Date: Fri, 10 Feb 2017 15:41:05 +0000 (+0100) Subject: btrfs: teach __process_pages_contig about PAGE_LOCK operation X-Git-Tag: v4.11-rc1~69^2~59 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=da2c7009f6cafe0a550cf57a1aa79e0f1b3093d6;p=karo-tx-linux.git btrfs: teach __process_pages_contig about PAGE_LOCK operation Signed-off-by: Liu Bo Reviewed-by: David Sterba [ changes to the helper separated from the following patch ] Signed-off-by: David Sterba --- 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); } /* diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 17f9ce479ed7..4551a5b4b8f5 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h @@ -45,13 +45,14 @@ #define EXTENT_BUFFER_IN_TREE 10 #define EXTENT_BUFFER_WRITE_ERR 11 /* write IO error */ -/* these are flags for extent_clear_unlock_delalloc */ +/* these are flags for __process_pages_contig */ #define PAGE_UNLOCK (1 << 0) #define PAGE_CLEAR_DIRTY (1 << 1) #define PAGE_SET_WRITEBACK (1 << 2) #define PAGE_END_WRITEBACK (1 << 3) #define PAGE_SET_PRIVATE2 (1 << 4) #define PAGE_SET_ERROR (1 << 5) +#define PAGE_LOCK (1 << 6) /* * page->private values. Every page that is controlled by the extent