Commit c7510ab2 authored by Jens Axboe's avatar Jens Axboe

mm: abstract out wake_page_match() from wake_page_function()

No functional changes in this patch, just in preparation for allowing
more callers.
Acked-by: default avatarJohannes Weiner <hannes@cmpxchg.org>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 2e85abf0
...@@ -496,6 +496,43 @@ static inline pgoff_t linear_page_index(struct vm_area_struct *vma, ...@@ -496,6 +496,43 @@ static inline pgoff_t linear_page_index(struct vm_area_struct *vma,
return pgoff; return pgoff;
} }
/* This has the same layout as wait_bit_key - see fs/cachefiles/rdwr.c */
struct wait_page_key {
struct page *page;
int bit_nr;
int page_match;
};
struct wait_page_queue {
struct page *page;
int bit_nr;
wait_queue_entry_t wait;
};
static inline int wake_page_match(struct wait_page_queue *wait_page,
struct wait_page_key *key)
{
if (wait_page->page != key->page)
return 0;
key->page_match = 1;
if (wait_page->bit_nr != key->bit_nr)
return 0;
/*
* Stop walking if it's locked.
* Is this safe if put_and_wait_on_page_locked() is in use?
* Yes: the waker must hold a reference to this page, and if PG_locked
* has now already been set by another task, that task must also hold
* a reference to the *same usage* of this page; so there is no need
* to walk on to wake even the put_and_wait_on_page_locked() callers.
*/
if (test_bit(key->bit_nr, &key->page->flags))
return -1;
return 1;
}
extern void __lock_page(struct page *page); extern void __lock_page(struct page *page);
extern int __lock_page_killable(struct page *page); extern int __lock_page_killable(struct page *page);
extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm, extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm,
......
...@@ -987,43 +987,16 @@ void __init pagecache_init(void) ...@@ -987,43 +987,16 @@ void __init pagecache_init(void)
page_writeback_init(); page_writeback_init();
} }
/* This has the same layout as wait_bit_key - see fs/cachefiles/rdwr.c */
struct wait_page_key {
struct page *page;
int bit_nr;
int page_match;
};
struct wait_page_queue {
struct page *page;
int bit_nr;
wait_queue_entry_t wait;
};
static int wake_page_function(wait_queue_entry_t *wait, unsigned mode, int sync, void *arg) static int wake_page_function(wait_queue_entry_t *wait, unsigned mode, int sync, void *arg)
{ {
struct wait_page_key *key = arg; struct wait_page_key *key = arg;
struct wait_page_queue *wait_page struct wait_page_queue *wait_page
= container_of(wait, struct wait_page_queue, wait); = container_of(wait, struct wait_page_queue, wait);
int ret;
if (wait_page->page != key->page) ret = wake_page_match(wait_page, key);
return 0; if (ret != 1)
key->page_match = 1; return ret;
if (wait_page->bit_nr != key->bit_nr)
return 0;
/*
* Stop walking if it's locked.
* Is this safe if put_and_wait_on_page_locked() is in use?
* Yes: the waker must hold a reference to this page, and if PG_locked
* has now already been set by another task, that task must also hold
* a reference to the *same usage* of this page; so there is no need
* to walk on to wake even the put_and_wait_on_page_locked() callers.
*/
if (test_bit(key->bit_nr, &key->page->flags))
return -1;
return autoremove_wake_function(wait, mode, sync, key); return autoremove_wake_function(wait, mode, sync, key);
} }
......
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