Skip to content

Commit 11a19c7

Browse files
pdxChentorvalds
authored andcommitted
sched/wait: Introduce wakeup boomark in wake_up_page_bit
Now that we have added breaks in the wait queue scan and allow bookmark on scan position, we put this logic in the wake_up_page_bit function. We can have very long page wait list in large system where multiple pages share the same wait list. We break the wake up walk here to allow other cpus a chance to access the list, and not to disable the interrupts when traversing the list for too long. This reduces the interrupt and rescheduling latency, and excessive page wait queue lock hold time. [ v2: Remove bookmark_wake_function ] Signed-off-by: Tim Chen <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 2554db9 commit 11a19c7

File tree

3 files changed

+30
-1
lines changed

3 files changed

+30
-1
lines changed

include/linux/wait.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ __remove_wait_queue(struct wait_queue_head *wq_head, struct wait_queue_entry *wq
185185

186186
void __wake_up(struct wait_queue_head *wq_head, unsigned int mode, int nr, void *key);
187187
void __wake_up_locked_key(struct wait_queue_head *wq_head, unsigned int mode, void *key);
188+
void __wake_up_locked_key_bookmark(struct wait_queue_head *wq_head,
189+
unsigned int mode, void *key, wait_queue_entry_t *bookmark);
188190
void __wake_up_sync_key(struct wait_queue_head *wq_head, unsigned int mode, int nr, void *key);
189191
void __wake_up_locked(struct wait_queue_head *wq_head, unsigned int mode, int nr);
190192
void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode, int nr);

kernel/sched/wait.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,13 @@ void __wake_up_locked_key(struct wait_queue_head *wq_head, unsigned int mode, vo
165165
}
166166
EXPORT_SYMBOL_GPL(__wake_up_locked_key);
167167

168+
void __wake_up_locked_key_bookmark(struct wait_queue_head *wq_head,
169+
unsigned int mode, void *key, wait_queue_entry_t *bookmark)
170+
{
171+
__wake_up_common(wq_head, mode, 1, 0, key, bookmark);
172+
}
173+
EXPORT_SYMBOL_GPL(__wake_up_locked_key_bookmark);
174+
168175
/**
169176
* __wake_up_sync_key - wake up threads blocked on a waitqueue.
170177
* @wq_head: the waitqueue

mm/filemap.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -909,13 +909,33 @@ static void wake_up_page_bit(struct page *page, int bit_nr)
909909
wait_queue_head_t *q = page_waitqueue(page);
910910
struct wait_page_key key;
911911
unsigned long flags;
912+
wait_queue_entry_t bookmark;
912913

913914
key.page = page;
914915
key.bit_nr = bit_nr;
915916
key.page_match = 0;
916917

918+
bookmark.flags = 0;
919+
bookmark.private = NULL;
920+
bookmark.func = NULL;
921+
INIT_LIST_HEAD(&bookmark.entry);
922+
917923
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+
919939
/*
920940
* It is possible for other pages to have collided on the waitqueue
921941
* hash, so in that case check for a page match. That prevents a long-

0 commit comments

Comments
 (0)