Commit da2c7009 authored by Liu Bo's avatar Liu Bo Committed by David Sterba

btrfs: teach __process_pages_contig about PAGE_LOCK operation

Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Reviewed-by: default avatarDavid Sterba <dsterba@suse.com>
[ changes to the helper separated from the following patch ]
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 873695b3
...@@ -1554,6 +1554,11 @@ static noinline u64 find_delalloc_range(struct extent_io_tree *tree, ...@@ -1554,6 +1554,11 @@ static noinline u64 find_delalloc_range(struct extent_io_tree *tree,
return found; 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, static noinline void __unlock_for_delalloc(struct inode *inode,
struct page *locked_page, struct page *locked_page,
u64 start, u64 end) u64 start, u64 end)
...@@ -1731,17 +1736,24 @@ STATIC u64 find_lock_delalloc_range(struct inode *inode, ...@@ -1731,17 +1736,24 @@ STATIC u64 find_lock_delalloc_range(struct inode *inode,
return found; return found;
} }
static void __process_pages_contig(struct address_space *mapping, static int __process_pages_contig(struct address_space *mapping,
struct page *locked_page, struct page *locked_page,
pgoff_t start_index, pgoff_t end_index, pgoff_t start_index, pgoff_t end_index,
unsigned long page_ops) unsigned long page_ops, pgoff_t *index_ret)
{ {
unsigned long nr_pages = end_index - start_index + 1; unsigned long nr_pages = end_index - start_index + 1;
unsigned long pages_locked = 0;
pgoff_t index = start_index; pgoff_t index = start_index;
struct page *pages[16]; struct page *pages[16];
unsigned ret; unsigned ret;
int err = 0;
int i; 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) if ((page_ops & PAGE_SET_ERROR) && nr_pages > 0)
mapping_set_error(mapping, -EIO); mapping_set_error(mapping, -EIO);
...@@ -1749,13 +1761,22 @@ static void __process_pages_contig(struct address_space *mapping, ...@@ -1749,13 +1761,22 @@ static void __process_pages_contig(struct address_space *mapping,
ret = find_get_pages_contig(mapping, index, ret = find_get_pages_contig(mapping, index,
min_t(unsigned long, min_t(unsigned long,
nr_pages, ARRAY_SIZE(pages)), pages); 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) if (page_ops & PAGE_SET_PRIVATE2)
SetPagePrivate2(pages[i]); SetPagePrivate2(pages[i]);
if (pages[i] == locked_page) { if (pages[i] == locked_page) {
put_page(pages[i]); put_page(pages[i]);
pages_locked++;
continue; continue;
} }
if (page_ops & PAGE_CLEAR_DIRTY) if (page_ops & PAGE_CLEAR_DIRTY)
...@@ -1768,12 +1789,27 @@ static void __process_pages_contig(struct address_space *mapping, ...@@ -1768,12 +1789,27 @@ static void __process_pages_contig(struct address_space *mapping,
end_page_writeback(pages[i]); end_page_writeback(pages[i]);
if (page_ops & PAGE_UNLOCK) if (page_ops & PAGE_UNLOCK)
unlock_page(pages[i]); 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]); put_page(pages[i]);
err = -EAGAIN;
goto out;
}
}
put_page(pages[i]);
pages_locked++;
} }
nr_pages -= ret; nr_pages -= ret;
index += ret; index += ret;
cond_resched(); 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, 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, ...@@ -1786,7 +1822,7 @@ void extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
__process_pages_contig(inode->i_mapping, locked_page, __process_pages_contig(inode->i_mapping, locked_page,
start >> PAGE_SHIFT, end >> PAGE_SHIFT, start >> PAGE_SHIFT, end >> PAGE_SHIFT,
page_ops); page_ops, NULL);
} }
/* /*
......
...@@ -45,13 +45,14 @@ ...@@ -45,13 +45,14 @@
#define EXTENT_BUFFER_IN_TREE 10 #define EXTENT_BUFFER_IN_TREE 10
#define EXTENT_BUFFER_WRITE_ERR 11 /* write IO error */ #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_UNLOCK (1 << 0)
#define PAGE_CLEAR_DIRTY (1 << 1) #define PAGE_CLEAR_DIRTY (1 << 1)
#define PAGE_SET_WRITEBACK (1 << 2) #define PAGE_SET_WRITEBACK (1 << 2)
#define PAGE_END_WRITEBACK (1 << 3) #define PAGE_END_WRITEBACK (1 << 3)
#define PAGE_SET_PRIVATE2 (1 << 4) #define PAGE_SET_PRIVATE2 (1 << 4)
#define PAGE_SET_ERROR (1 << 5) #define PAGE_SET_ERROR (1 << 5)
#define PAGE_LOCK (1 << 6)
/* /*
* page->private values. Every page that is controlled by the extent * page->private values. Every page that is controlled by the extent
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment