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>
This commit is contained in:
Родитель
873695b301
Коммит
da2c7009f6
|
@ -1554,6 +1554,11 @@ out:
|
||||||
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 @@ out_failed:
|
||||||
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,
|
||||||
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,
|
||||||
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]);
|
||||||
|
err = -EAGAIN;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
put_page(pages[i]);
|
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,
|
||||||
|
|
||||||
__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 @@
|
||||||
#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
|
||||||
|
|
Загрузка…
Ссылка в новой задаче