diff options
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 9d21afd692b9..8c88e186a773 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -909,13 +909,33 @@ static void wake_up_page_bit(struct page *page, int bit_nr) | |||
909 | wait_queue_head_t *q = page_waitqueue(page); | 909 | wait_queue_head_t *q = page_waitqueue(page); |
910 | struct wait_page_key key; | 910 | struct wait_page_key key; |
911 | unsigned long flags; | 911 | unsigned long flags; |
912 | wait_queue_entry_t bookmark; | ||
912 | 913 | ||
913 | key.page = page; | 914 | key.page = page; |
914 | key.bit_nr = bit_nr; | 915 | key.bit_nr = bit_nr; |
915 | key.page_match = 0; | 916 | key.page_match = 0; |
916 | 917 | ||
918 | bookmark.flags = 0; | ||
919 | bookmark.private = NULL; | ||
920 | bookmark.func = NULL; | ||
921 | INIT_LIST_HEAD(&bookmark.entry); | ||
922 | |||
917 | spin_lock_irqsave(&q->lock, flags); | 923 | spin_lock_irqsave(&q->lock, flags); |
918 | __wake_up_locked_key(q, TASK_NORMAL, &key); | 924 | __wake_up_locked_key_bookmark(q, TASK_NORMAL, &key, &bookmark); |
925 | |||
926 | while (bookmark.flags & WQ_FLAG_BOOKMARK) { | ||
927 | /* | ||
928 | * Take a breather from holding the lock, | ||
929 | * allow pages that finish wake up asynchronously | ||
930 | * to acquire the lock and remove themselves | ||
931 | * from wait queue | ||
932 | */ | ||
933 | spin_unlock_irqrestore(&q->lock, flags); | ||
934 | cpu_relax(); | ||
935 | spin_lock_irqsave(&q->lock, flags); | ||
936 | __wake_up_locked_key_bookmark(q, TASK_NORMAL, &key, &bookmark); | ||
937 | } | ||
938 | |||
919 | /* | 939 | /* |
920 | * It is possible for other pages to have collided on the waitqueue | 940 | * It is possible for other pages to have collided on the waitqueue |
921 | * hash, so in that case check for a page match. That prevents a long- | 941 | * hash, so in that case check for a page match. That prevents a long- |