Commit a1513309 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] Stop using address_space.locked_pages

Instead, use a radix-tree walk of the pages which are tagged as being under
writeback.

The new function wait_on_page_writeback_range() was generalised out of
filemap_fdatawait().  We can later use this to provide concurrent fsync of
just a section of a file.
parent 3c1ed9b2
...@@ -179,7 +179,6 @@ void inode_init_once(struct inode *inode) ...@@ -179,7 +179,6 @@ void inode_init_once(struct inode *inode)
memset(inode, 0, sizeof(*inode)); memset(inode, 0, sizeof(*inode));
INIT_HLIST_NODE(&inode->i_hash); INIT_HLIST_NODE(&inode->i_hash);
INIT_LIST_HEAD(&inode->i_data.clean_pages); INIT_LIST_HEAD(&inode->i_data.clean_pages);
INIT_LIST_HEAD(&inode->i_data.locked_pages);
INIT_LIST_HEAD(&inode->i_dentry); INIT_LIST_HEAD(&inode->i_dentry);
INIT_LIST_HEAD(&inode->i_devices); INIT_LIST_HEAD(&inode->i_devices);
sema_init(&inode->i_sem, 1); sema_init(&inode->i_sem, 1);
......
...@@ -324,7 +324,6 @@ struct address_space { ...@@ -324,7 +324,6 @@ struct address_space {
struct radix_tree_root page_tree; /* radix tree of all pages */ struct radix_tree_root page_tree; /* radix tree of all pages */
spinlock_t tree_lock; /* and spinlock protecting it */ spinlock_t tree_lock; /* and spinlock protecting it */
struct list_head clean_pages; /* list of clean pages */ struct list_head clean_pages; /* list of clean pages */
struct list_head locked_pages; /* list of locked pages */
unsigned long nrpages; /* number of total pages */ unsigned long nrpages; /* number of total pages */
struct address_space_operations *a_ops; /* methods */ struct address_space_operations *a_ops; /* methods */
struct list_head i_mmap; /* list of private mappings */ struct list_head i_mmap; /* list of private mappings */
......
...@@ -182,7 +182,7 @@ struct page { ...@@ -182,7 +182,7 @@ struct page {
atomic_t count; /* Usage count, see below. */ atomic_t count; /* Usage count, see below. */
struct list_head list; /* ->mapping has some page lists. */ struct list_head list; /* ->mapping has some page lists. */
struct address_space *mapping; /* The inode (or ...) we belong to. */ struct address_space *mapping; /* The inode (or ...) we belong to. */
unsigned long index; /* Our offset within mapping. */ pgoff_t index; /* Our offset within mapping. */
struct list_head lru; /* Pageout list, eg. active_list; struct list_head lru; /* Pageout list, eg. active_list;
protected by zone->lru_lock !! */ protected by zone->lru_lock !! */
union { union {
......
...@@ -154,7 +154,6 @@ int filemap_fdatawrite(struct address_space *mapping) ...@@ -154,7 +154,6 @@ int filemap_fdatawrite(struct address_space *mapping)
{ {
return __filemap_fdatawrite(mapping, WB_SYNC_ALL); return __filemap_fdatawrite(mapping, WB_SYNC_ALL);
} }
EXPORT_SYMBOL(filemap_fdatawrite); EXPORT_SYMBOL(filemap_fdatawrite);
/* /*
...@@ -165,51 +164,40 @@ int filemap_flush(struct address_space *mapping) ...@@ -165,51 +164,40 @@ int filemap_flush(struct address_space *mapping)
{ {
return __filemap_fdatawrite(mapping, WB_SYNC_NONE); return __filemap_fdatawrite(mapping, WB_SYNC_NONE);
} }
EXPORT_SYMBOL(filemap_flush); EXPORT_SYMBOL(filemap_flush);
/** /*
* filemap_fdatawait - walk the list of locked pages of the given address * Wait for writeback to complete against pages indexed by start->end
* space and wait for all of them. * inclusive
* @mapping: address space structure to wait for
*/ */
int filemap_fdatawait(struct address_space * mapping) static int wait_on_page_writeback_range(struct address_space *mapping,
pgoff_t start, pgoff_t end)
{ {
struct pagevec pvec;
int nr_pages;
int ret = 0; int ret = 0;
int progress; pgoff_t index;
restart:
progress = 0;
spin_lock_irq(&mapping->tree_lock);
while (!list_empty(&mapping->locked_pages)) {
struct page *page;
page = list_entry(mapping->locked_pages.next,struct page,list);
list_del_init(&page->list);
if (!PageWriteback(page)) { if (end < start)
if (++progress > 32) { return 0;
if (need_resched()) {
spin_unlock_irq(&mapping->tree_lock);
__cond_resched();
goto restart;
}
}
continue;
}
progress = 0; pagevec_init(&pvec, 0);
page_cache_get(page); index = start;
spin_unlock_irq(&mapping->tree_lock); while ((nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
PAGECACHE_TAG_WRITEBACK,
min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
unsigned i;
wait_on_page_writeback(page); for (i = 0; i < nr_pages; i++) {
if (PageError(page)) struct page *page = pvec.pages[i];
ret = -EIO;
page_cache_release(page); wait_on_page_writeback(page);
spin_lock_irq(&mapping->tree_lock); if (PageError(page))
ret = -EIO;
}
pagevec_release(&pvec);
cond_resched();
} }
spin_unlock_irq(&mapping->tree_lock);
/* Check for outstanding write errors */ /* Check for outstanding write errors */
if (test_and_clear_bit(AS_ENOSPC, &mapping->flags)) if (test_and_clear_bit(AS_ENOSPC, &mapping->flags))
...@@ -219,6 +207,18 @@ int filemap_fdatawait(struct address_space * mapping) ...@@ -219,6 +207,18 @@ int filemap_fdatawait(struct address_space * mapping)
return ret; return ret;
} }
/**
* filemap_fdatawait - walk the list of under-writeback pages of the given
* address space and wait for all of them.
*
* @mapping: address space structure to wait for
*/
int filemap_fdatawait(struct address_space *mapping)
{
return wait_on_page_writeback_range(mapping, 0, -1);
}
EXPORT_SYMBOL(filemap_fdatawait); EXPORT_SYMBOL(filemap_fdatawait);
int filemap_write_and_wait(struct address_space *mapping) int filemap_write_and_wait(struct address_space *mapping)
......
...@@ -27,7 +27,6 @@ struct address_space swapper_space = { ...@@ -27,7 +27,6 @@ struct address_space swapper_space = {
.page_tree = RADIX_TREE_INIT(GFP_ATOMIC), .page_tree = RADIX_TREE_INIT(GFP_ATOMIC),
.tree_lock = SPIN_LOCK_UNLOCKED, .tree_lock = SPIN_LOCK_UNLOCKED,
.clean_pages = LIST_HEAD_INIT(swapper_space.clean_pages), .clean_pages = LIST_HEAD_INIT(swapper_space.clean_pages),
.locked_pages = LIST_HEAD_INIT(swapper_space.locked_pages),
.a_ops = &swap_aops, .a_ops = &swap_aops,
.backing_dev_info = &swap_backing_dev_info, .backing_dev_info = &swap_backing_dev_info,
.i_mmap = LIST_HEAD_INIT(swapper_space.i_mmap), .i_mmap = LIST_HEAD_INIT(swapper_space.i_mmap),
......
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