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 <tim.c.chen@linux.intel.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Tim Chen and committed by
Linus Torvalds
11a19c7b 2554db91

+30 -1
+2
include/linux/wait.h
··· 185 185 186 186 void __wake_up(struct wait_queue_head *wq_head, unsigned int mode, int nr, void *key); 187 187 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); 188 190 void __wake_up_sync_key(struct wait_queue_head *wq_head, unsigned int mode, int nr, void *key); 189 191 void __wake_up_locked(struct wait_queue_head *wq_head, unsigned int mode, int nr); 190 192 void __wake_up_sync(struct wait_queue_head *wq_head, unsigned int mode, int nr);
+7
kernel/sched/wait.c
··· 165 165 } 166 166 EXPORT_SYMBOL_GPL(__wake_up_locked_key); 167 167 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 + 168 175 /** 169 176 * __wake_up_sync_key - wake up threads blocked on a waitqueue. 170 177 * @wq_head: the waitqueue
+21 -1
mm/filemap.c
··· 909 909 wait_queue_head_t *q = page_waitqueue(page); 910 910 struct wait_page_key key; 911 911 unsigned long flags; 912 + wait_queue_entry_t bookmark; 912 913 913 914 key.page = page; 914 915 key.bit_nr = bit_nr; 915 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 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 940 * It is possible for other pages to have collided on the waitqueue 921 941 * hash, so in that case check for a page match. That prevents a long-