aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorNicholas Piggin <npiggin@gmail.com>2016-12-24 22:00:30 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-25 14:54:48 -0500
commit62906027091f1d02de44041524f0769f60bb9cf3 (patch)
tree6444171af03e463bb0123a392d7b91a0ae6a1f40 /include
parent6326fec1122cde256bd2a8c63f2606e08e44ce1d (diff)
mm: add PageWaiters indicating tasks are waiting for a page bit
Add a new page flag, PageWaiters, to indicate the page waitqueue has tasks waiting. This can be tested rather than testing waitqueue_active which requires another cacheline load. This bit is always set when the page has tasks on page_waitqueue(page), and is set and cleared under the waitqueue lock. It may be set when there are no tasks on the waitqueue, which will cause a harmless extra wakeup check that will clears the bit. The generic bit-waitqueue infrastructure is no longer used for pages. Instead, waitqueues are used directly with a custom key type. The generic code was not flexible enough to have PageWaiters manipulation under the waitqueue lock (which simplifies concurrency). This improves the performance of page lock intensive microbenchmarks by 2-3%. Putting two bits in the same word opens the opportunity to remove the memory barrier between clearing the lock bit and testing the waiters bit, after some work on the arch primitives (e.g., ensuring memory operand widths match and cover both bits). Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: Bob Peterson <rpeterso@redhat.com> Cc: Steven Whitehouse <swhiteho@redhat.com> Cc: Andrew Lutomirski <luto@kernel.org> Cc: Andreas Gruenbacher <agruenba@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Mel Gorman <mgorman@techsingularity.net> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include')
-rw-r--r--include/linux/mm.h2
-rw-r--r--include/linux/page-flags.h9
-rw-r--r--include/linux/pagemap.h23
-rw-r--r--include/linux/writeback.h1
-rw-r--r--include/trace/events/mmflags.h1
5 files changed, 23 insertions, 13 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 4424784ac374..fe6b4036664a 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1758,6 +1758,8 @@ static inline spinlock_t *pmd_lock(struct mm_struct *mm, pmd_t *pmd)
1758 return ptl; 1758 return ptl;
1759} 1759}
1760 1760
1761extern void __init pagecache_init(void);
1762
1761extern void free_area_init(unsigned long * zones_size); 1763extern void free_area_init(unsigned long * zones_size);
1762extern void free_area_init_node(int nid, unsigned long * zones_size, 1764extern void free_area_init_node(int nid, unsigned long * zones_size,
1763 unsigned long zone_start_pfn, unsigned long *zholes_size); 1765 unsigned long zone_start_pfn, unsigned long *zholes_size);
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index a57c909a15e4..c56b39890a41 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -73,6 +73,7 @@
73 */ 73 */
74enum pageflags { 74enum pageflags {
75 PG_locked, /* Page is locked. Don't touch. */ 75 PG_locked, /* Page is locked. Don't touch. */
76 PG_waiters, /* Page has waiters, check its waitqueue */
76 PG_error, 77 PG_error,
77 PG_referenced, 78 PG_referenced,
78 PG_uptodate, 79 PG_uptodate,
@@ -169,6 +170,9 @@ static __always_inline int PageCompound(struct page *page)
169 * for compound page all operations related to the page flag applied to 170 * for compound page all operations related to the page flag applied to
170 * head page. 171 * head page.
171 * 172 *
173 * PF_ONLY_HEAD:
174 * for compound page, callers only ever operate on the head page.
175 *
172 * PF_NO_TAIL: 176 * PF_NO_TAIL:
173 * modifications of the page flag must be done on small or head pages, 177 * modifications of the page flag must be done on small or head pages,
174 * checks can be done on tail pages too. 178 * checks can be done on tail pages too.
@@ -178,6 +182,9 @@ static __always_inline int PageCompound(struct page *page)
178 */ 182 */
179#define PF_ANY(page, enforce) page 183#define PF_ANY(page, enforce) page
180#define PF_HEAD(page, enforce) compound_head(page) 184#define PF_HEAD(page, enforce) compound_head(page)
185#define PF_ONLY_HEAD(page, enforce) ({ \
186 VM_BUG_ON_PGFLAGS(PageTail(page), page); \
187 page;})
181#define PF_NO_TAIL(page, enforce) ({ \ 188#define PF_NO_TAIL(page, enforce) ({ \
182 VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \ 189 VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \
183 compound_head(page);}) 190 compound_head(page);})
@@ -255,6 +262,7 @@ static inline int TestClearPage##uname(struct page *page) { return 0; }
255 TESTSETFLAG_FALSE(uname) TESTCLEARFLAG_FALSE(uname) 262 TESTSETFLAG_FALSE(uname) TESTCLEARFLAG_FALSE(uname)
256 263
257__PAGEFLAG(Locked, locked, PF_NO_TAIL) 264__PAGEFLAG(Locked, locked, PF_NO_TAIL)
265PAGEFLAG(Waiters, waiters, PF_ONLY_HEAD) __CLEARPAGEFLAG(Waiters, waiters, PF_ONLY_HEAD)
258PAGEFLAG(Error, error, PF_NO_COMPOUND) TESTCLEARFLAG(Error, error, PF_NO_COMPOUND) 266PAGEFLAG(Error, error, PF_NO_COMPOUND) TESTCLEARFLAG(Error, error, PF_NO_COMPOUND)
259PAGEFLAG(Referenced, referenced, PF_HEAD) 267PAGEFLAG(Referenced, referenced, PF_HEAD)
260 TESTCLEARFLAG(Referenced, referenced, PF_HEAD) 268 TESTCLEARFLAG(Referenced, referenced, PF_HEAD)
@@ -743,6 +751,7 @@ static inline int page_has_private(struct page *page)
743 751
744#undef PF_ANY 752#undef PF_ANY
745#undef PF_HEAD 753#undef PF_HEAD
754#undef PF_ONLY_HEAD
746#undef PF_NO_TAIL 755#undef PF_NO_TAIL
747#undef PF_NO_COMPOUND 756#undef PF_NO_COMPOUND
748#endif /* !__GENERATING_BOUNDS_H */ 757#endif /* !__GENERATING_BOUNDS_H */
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index f29f80f81dbf..324c8dbad1e1 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -486,22 +486,14 @@ static inline int lock_page_or_retry(struct page *page, struct mm_struct *mm,
486 * and for filesystems which need to wait on PG_private. 486 * and for filesystems which need to wait on PG_private.
487 */ 487 */
488extern void wait_on_page_bit(struct page *page, int bit_nr); 488extern void wait_on_page_bit(struct page *page, int bit_nr);
489
490extern int wait_on_page_bit_killable(struct page *page, int bit_nr); 489extern int wait_on_page_bit_killable(struct page *page, int bit_nr);
491extern int wait_on_page_bit_killable_timeout(struct page *page, 490extern void wake_up_page_bit(struct page *page, int bit_nr);
492 int bit_nr, unsigned long timeout);
493
494static inline int wait_on_page_locked_killable(struct page *page)
495{
496 if (!PageLocked(page))
497 return 0;
498 return wait_on_page_bit_killable(compound_head(page), PG_locked);
499}
500 491
501extern wait_queue_head_t *page_waitqueue(struct page *page);
502static inline void wake_up_page(struct page *page, int bit) 492static inline void wake_up_page(struct page *page, int bit)
503{ 493{
504 __wake_up_bit(page_waitqueue(page), &page->flags, bit); 494 if (!PageWaiters(page))
495 return;
496 wake_up_page_bit(page, bit);
505} 497}
506 498
507/* 499/*
@@ -517,6 +509,13 @@ static inline void wait_on_page_locked(struct page *page)
517 wait_on_page_bit(compound_head(page), PG_locked); 509 wait_on_page_bit(compound_head(page), PG_locked);
518} 510}
519 511
512static inline int wait_on_page_locked_killable(struct page *page)
513{
514 if (!PageLocked(page))
515 return 0;
516 return wait_on_page_bit_killable(compound_head(page), PG_locked);
517}
518
520/* 519/*
521 * Wait for a page to complete writeback 520 * Wait for a page to complete writeback
522 */ 521 */
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index c78f9f0920b5..5527d910ba3d 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -375,7 +375,6 @@ void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty);
375unsigned long wb_calc_thresh(struct bdi_writeback *wb, unsigned long thresh); 375unsigned long wb_calc_thresh(struct bdi_writeback *wb, unsigned long thresh);
376 376
377void wb_update_bandwidth(struct bdi_writeback *wb, unsigned long start_time); 377void wb_update_bandwidth(struct bdi_writeback *wb, unsigned long start_time);
378void page_writeback_init(void);
379void balance_dirty_pages_ratelimited(struct address_space *mapping); 378void balance_dirty_pages_ratelimited(struct address_space *mapping);
380bool wb_over_bg_thresh(struct bdi_writeback *wb); 379bool wb_over_bg_thresh(struct bdi_writeback *wb);
381 380
diff --git a/include/trace/events/mmflags.h b/include/trace/events/mmflags.h
index 30c2adbdebe8..9e687ca9a307 100644
--- a/include/trace/events/mmflags.h
+++ b/include/trace/events/mmflags.h
@@ -81,6 +81,7 @@
81 81
82#define __def_pageflag_names \ 82#define __def_pageflag_names \
83 {1UL << PG_locked, "locked" }, \ 83 {1UL << PG_locked, "locked" }, \
84 {1UL << PG_waiters, "waiters" }, \
84 {1UL << PG_error, "error" }, \ 85 {1UL << PG_error, "error" }, \
85 {1UL << PG_referenced, "referenced" }, \ 86 {1UL << PG_referenced, "referenced" }, \
86 {1UL << PG_uptodate, "uptodate" }, \ 87 {1UL << PG_uptodate, "uptodate" }, \