summaryrefslogtreecommitdiffstats
path: root/mm/page_alloc.c
diff options
context:
space:
mode:
authorMel Gorman <mgorman@techsingularity.net>2016-05-19 20:14:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-05-19 22:12:14 -0400
commit0b423ca22f95a867f789aab1fe57ee4e378df43b (patch)
treecf0231b630d9be51604133f20d56a4e617914a33 /mm/page_alloc.c
parente5b31ac2ca2cd0cf6bf2fcbb708ed01466c89aaa (diff)
mm, page_alloc: inline pageblock lookup in page free fast paths
The function call overhead of get_pfnblock_flags_mask() is measurable in the page free paths. This patch uses an inlined version that is faster. Signed-off-by: Mel Gorman <mgorman@techsingularity.net> Acked-by: Vlastimil Babka <vbabka@suse.cz> Cc: Jesper Dangaard Brouer <brouer@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r--mm/page_alloc.c188
1 files changed, 100 insertions, 88 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 822ce86fc883..bdf7a13311b5 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -352,6 +352,106 @@ static inline bool update_defer_init(pg_data_t *pgdat,
352} 352}
353#endif 353#endif
354 354
355/* Return a pointer to the bitmap storing bits affecting a block of pages */
356static inline unsigned long *get_pageblock_bitmap(struct page *page,
357 unsigned long pfn)
358{
359#ifdef CONFIG_SPARSEMEM
360 return __pfn_to_section(pfn)->pageblock_flags;
361#else
362 return page_zone(page)->pageblock_flags;
363#endif /* CONFIG_SPARSEMEM */
364}
365
366static inline int pfn_to_bitidx(struct page *page, unsigned long pfn)
367{
368#ifdef CONFIG_SPARSEMEM
369 pfn &= (PAGES_PER_SECTION-1);
370 return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
371#else
372 pfn = pfn - round_down(page_zone(page)->zone_start_pfn, pageblock_nr_pages);
373 return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
374#endif /* CONFIG_SPARSEMEM */
375}
376
377/**
378 * get_pfnblock_flags_mask - Return the requested group of flags for the pageblock_nr_pages block of pages
379 * @page: The page within the block of interest
380 * @pfn: The target page frame number
381 * @end_bitidx: The last bit of interest to retrieve
382 * @mask: mask of bits that the caller is interested in
383 *
384 * Return: pageblock_bits flags
385 */
386static __always_inline unsigned long __get_pfnblock_flags_mask(struct page *page,
387 unsigned long pfn,
388 unsigned long end_bitidx,
389 unsigned long mask)
390{
391 unsigned long *bitmap;
392 unsigned long bitidx, word_bitidx;
393 unsigned long word;
394
395 bitmap = get_pageblock_bitmap(page, pfn);
396 bitidx = pfn_to_bitidx(page, pfn);
397 word_bitidx = bitidx / BITS_PER_LONG;
398 bitidx &= (BITS_PER_LONG-1);
399
400 word = bitmap[word_bitidx];
401 bitidx += end_bitidx;
402 return (word >> (BITS_PER_LONG - bitidx - 1)) & mask;
403}
404
405unsigned long get_pfnblock_flags_mask(struct page *page, unsigned long pfn,
406 unsigned long end_bitidx,
407 unsigned long mask)
408{
409 return __get_pfnblock_flags_mask(page, pfn, end_bitidx, mask);
410}
411
412static __always_inline int get_pfnblock_migratetype(struct page *page, unsigned long pfn)
413{
414 return __get_pfnblock_flags_mask(page, pfn, PB_migrate_end, MIGRATETYPE_MASK);
415}
416
417/**
418 * set_pfnblock_flags_mask - Set the requested group of flags for a pageblock_nr_pages block of pages
419 * @page: The page within the block of interest
420 * @flags: The flags to set
421 * @pfn: The target page frame number
422 * @end_bitidx: The last bit of interest
423 * @mask: mask of bits that the caller is interested in
424 */
425void set_pfnblock_flags_mask(struct page *page, unsigned long flags,
426 unsigned long pfn,
427 unsigned long end_bitidx,
428 unsigned long mask)
429{
430 unsigned long *bitmap;
431 unsigned long bitidx, word_bitidx;
432 unsigned long old_word, word;
433
434 BUILD_BUG_ON(NR_PAGEBLOCK_BITS != 4);
435
436 bitmap = get_pageblock_bitmap(page, pfn);
437 bitidx = pfn_to_bitidx(page, pfn);
438 word_bitidx = bitidx / BITS_PER_LONG;
439 bitidx &= (BITS_PER_LONG-1);
440
441 VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn), page);
442
443 bitidx += end_bitidx;
444 mask <<= (BITS_PER_LONG - bitidx - 1);
445 flags <<= (BITS_PER_LONG - bitidx - 1);
446
447 word = READ_ONCE(bitmap[word_bitidx]);
448 for (;;) {
449 old_word = cmpxchg(&bitmap[word_bitidx], word, (word & ~mask) | flags);
450 if (word == old_word)
451 break;
452 word = old_word;
453 }
454}
355 455
356void set_pageblock_migratetype(struct page *page, int migratetype) 456void set_pageblock_migratetype(struct page *page, int migratetype)
357{ 457{
@@ -6831,94 +6931,6 @@ void *__init alloc_large_system_hash(const char *tablename,
6831 return table; 6931 return table;
6832} 6932}
6833 6933
6834/* Return a pointer to the bitmap storing bits affecting a block of pages */
6835static inline unsigned long *get_pageblock_bitmap(struct page *page,
6836 unsigned long pfn)
6837{
6838#ifdef CONFIG_SPARSEMEM
6839 return __pfn_to_section(pfn)->pageblock_flags;
6840#else
6841 return page_zone(page)->pageblock_flags;
6842#endif /* CONFIG_SPARSEMEM */
6843}
6844
6845static inline int pfn_to_bitidx(struct page *page, unsigned long pfn)
6846{
6847#ifdef CONFIG_SPARSEMEM
6848 pfn &= (PAGES_PER_SECTION-1);
6849 return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
6850#else
6851 pfn = pfn - round_down(page_zone(page)->zone_start_pfn, pageblock_nr_pages);
6852 return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS;
6853#endif /* CONFIG_SPARSEMEM */
6854}
6855
6856/**
6857 * get_pfnblock_flags_mask - Return the requested group of flags for the pageblock_nr_pages block of pages
6858 * @page: The page within the block of interest
6859 * @pfn: The target page frame number
6860 * @end_bitidx: The last bit of interest to retrieve
6861 * @mask: mask of bits that the caller is interested in
6862 *
6863 * Return: pageblock_bits flags
6864 */
6865unsigned long get_pfnblock_flags_mask(struct page *page, unsigned long pfn,
6866 unsigned long end_bitidx,
6867 unsigned long mask)
6868{
6869 unsigned long *bitmap;
6870 unsigned long bitidx, word_bitidx;
6871 unsigned long word;
6872
6873 bitmap = get_pageblock_bitmap(page, pfn);
6874 bitidx = pfn_to_bitidx(page, pfn);
6875 word_bitidx = bitidx / BITS_PER_LONG;
6876 bitidx &= (BITS_PER_LONG-1);
6877
6878 word = bitmap[word_bitidx];
6879 bitidx += end_bitidx;
6880 return (word >> (BITS_PER_LONG - bitidx - 1)) & mask;
6881}
6882
6883/**
6884 * set_pfnblock_flags_mask - Set the requested group of flags for a pageblock_nr_pages block of pages
6885 * @page: The page within the block of interest
6886 * @flags: The flags to set
6887 * @pfn: The target page frame number
6888 * @end_bitidx: The last bit of interest
6889 * @mask: mask of bits that the caller is interested in
6890 */
6891void set_pfnblock_flags_mask(struct page *page, unsigned long flags,
6892 unsigned long pfn,
6893 unsigned long end_bitidx,
6894 unsigned long mask)
6895{
6896 unsigned long *bitmap;
6897 unsigned long bitidx, word_bitidx;
6898 unsigned long old_word, word;
6899
6900 BUILD_BUG_ON(NR_PAGEBLOCK_BITS != 4);
6901
6902 bitmap = get_pageblock_bitmap(page, pfn);
6903 bitidx = pfn_to_bitidx(page, pfn);
6904 word_bitidx = bitidx / BITS_PER_LONG;
6905 bitidx &= (BITS_PER_LONG-1);
6906
6907 VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn), page);
6908
6909 bitidx += end_bitidx;
6910 mask <<= (BITS_PER_LONG - bitidx - 1);
6911 flags <<= (BITS_PER_LONG - bitidx - 1);
6912
6913 word = READ_ONCE(bitmap[word_bitidx]);
6914 for (;;) {
6915 old_word = cmpxchg(&bitmap[word_bitidx], word, (word & ~mask) | flags);
6916 if (word == old_word)
6917 break;
6918 word = old_word;
6919 }
6920}
6921
6922/* 6934/*
6923 * This function checks whether pageblock includes unmovable pages or not. 6935 * This function checks whether pageblock includes unmovable pages or not.
6924 * If @count is not zero, it is okay to include less @count unmovable pages 6936 * If @count is not zero, it is okay to include less @count unmovable pages