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