diff options
| author | Mel Gorman <mgorman@suse.de> | 2014-04-03 17:47:24 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-04-03 19:20:58 -0400 |
| commit | d26914d11751b23ca2e8747725f2cae10c2f2c1b (patch) | |
| tree | 020b606fb9223e29292f54922a11111239e3a3f4 | |
| parent | 91ca9186484809c57303b33778d841cc28f696ed (diff) | |
mm: optimize put_mems_allowed() usage
Since put_mems_allowed() is strictly optional, its a seqcount retry, we
don't need to evaluate the function if the allocation was in fact
successful, saving a smp_rmb some loads and comparisons on some relative
fast-paths.
Since the naming, get/put_mems_allowed() does suggest a mandatory
pairing, rename the interface, as suggested by Mel, to resemble the
seqcount interface.
This gives us: read_mems_allowed_begin() and read_mems_allowed_retry(),
where it is important to note that the return value of the latter call
is inverted from its previous incarnation.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Mel Gorman <mgorman@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | include/linux/cpuset.h | 27 | ||||
| -rw-r--r-- | kernel/cpuset.c | 2 | ||||
| -rw-r--r-- | mm/filemap.c | 4 | ||||
| -rw-r--r-- | mm/hugetlb.c | 4 | ||||
| -rw-r--r-- | mm/mempolicy.c | 12 | ||||
| -rw-r--r-- | mm/page_alloc.c | 8 | ||||
| -rw-r--r-- | mm/slab.c | 4 | ||||
| -rw-r--r-- | mm/slub.c | 16 |
8 files changed, 38 insertions, 39 deletions
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h index 3fe661fe96d1..b19d3dc2e651 100644 --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h | |||
| @@ -87,25 +87,26 @@ extern void rebuild_sched_domains(void); | |||
| 87 | extern void cpuset_print_task_mems_allowed(struct task_struct *p); | 87 | extern void cpuset_print_task_mems_allowed(struct task_struct *p); |
| 88 | 88 | ||
| 89 | /* | 89 | /* |
| 90 | * get_mems_allowed is required when making decisions involving mems_allowed | 90 | * read_mems_allowed_begin is required when making decisions involving |
| 91 | * such as during page allocation. mems_allowed can be updated in parallel | 91 | * mems_allowed such as during page allocation. mems_allowed can be updated in |
| 92 | * and depending on the new value an operation can fail potentially causing | 92 | * parallel and depending on the new value an operation can fail potentially |
| 93 | * process failure. A retry loop with get_mems_allowed and put_mems_allowed | 93 | * causing process failure. A retry loop with read_mems_allowed_begin and |
| 94 | * prevents these artificial failures. | 94 | * read_mems_allowed_retry prevents these artificial failures. |
| 95 | */ | 95 | */ |
| 96 | static inline unsigned int get_mems_allowed(void) | 96 | static inline unsigned int read_mems_allowed_begin(void) |
| 97 | { | 97 | { |
| 98 | return read_seqcount_begin(¤t->mems_allowed_seq); | 98 | return read_seqcount_begin(¤t->mems_allowed_seq); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | /* | 101 | /* |
| 102 | * If this returns false, the operation that took place after get_mems_allowed | 102 | * If this returns true, the operation that took place after |
| 103 | * may have failed. It is up to the caller to retry the operation if | 103 | * read_mems_allowed_begin may have failed artificially due to a concurrent |
| 104 | * update of mems_allowed. It is up to the caller to retry the operation if | ||
| 104 | * appropriate. | 105 | * appropriate. |
| 105 | */ | 106 | */ |
| 106 | static inline bool put_mems_allowed(unsigned int seq) | 107 | static inline bool read_mems_allowed_retry(unsigned int seq) |
| 107 | { | 108 | { |
| 108 | return !read_seqcount_retry(¤t->mems_allowed_seq, seq); | 109 | return read_seqcount_retry(¤t->mems_allowed_seq, seq); |
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | static inline void set_mems_allowed(nodemask_t nodemask) | 112 | static inline void set_mems_allowed(nodemask_t nodemask) |
| @@ -225,14 +226,14 @@ static inline void set_mems_allowed(nodemask_t nodemask) | |||
| 225 | { | 226 | { |
| 226 | } | 227 | } |
| 227 | 228 | ||
| 228 | static inline unsigned int get_mems_allowed(void) | 229 | static inline unsigned int read_mems_allowed_begin(void) |
| 229 | { | 230 | { |
| 230 | return 0; | 231 | return 0; |
| 231 | } | 232 | } |
| 232 | 233 | ||
| 233 | static inline bool put_mems_allowed(unsigned int seq) | 234 | static inline bool read_mems_allowed_retry(unsigned int seq) |
| 234 | { | 235 | { |
| 235 | return true; | 236 | return false; |
| 236 | } | 237 | } |
| 237 | 238 | ||
| 238 | #endif /* !CONFIG_CPUSETS */ | 239 | #endif /* !CONFIG_CPUSETS */ |
diff --git a/kernel/cpuset.c b/kernel/cpuset.c index e6b1b66afe52..f6fc7475f1a1 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c | |||
| @@ -1022,7 +1022,7 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk, | |||
| 1022 | task_lock(tsk); | 1022 | task_lock(tsk); |
| 1023 | /* | 1023 | /* |
| 1024 | * Determine if a loop is necessary if another thread is doing | 1024 | * Determine if a loop is necessary if another thread is doing |
| 1025 | * get_mems_allowed(). If at least one node remains unchanged and | 1025 | * read_mems_allowed_begin(). If at least one node remains unchanged and |
| 1026 | * tsk does not have a mempolicy, then an empty nodemask will not be | 1026 | * tsk does not have a mempolicy, then an empty nodemask will not be |
| 1027 | * possible when mems_allowed is larger than a word. | 1027 | * possible when mems_allowed is larger than a word. |
| 1028 | */ | 1028 | */ |
diff --git a/mm/filemap.c b/mm/filemap.c index 7a13f6ac5421..068cd2a63d32 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
| @@ -520,10 +520,10 @@ struct page *__page_cache_alloc(gfp_t gfp) | |||
| 520 | if (cpuset_do_page_mem_spread()) { | 520 | if (cpuset_do_page_mem_spread()) { |
| 521 | unsigned int cpuset_mems_cookie; | 521 | unsigned int cpuset_mems_cookie; |
| 522 | do { | 522 | do { |
| 523 | cpuset_mems_cookie = get_mems_allowed(); | 523 | cpuset_mems_cookie = read_mems_allowed_begin(); |
| 524 | n = cpuset_mem_spread_node(); | 524 | n = cpuset_mem_spread_node(); |
| 525 | page = alloc_pages_exact_node(n, gfp, 0); | 525 | page = alloc_pages_exact_node(n, gfp, 0); |
| 526 | } while (!put_mems_allowed(cpuset_mems_cookie) && !page); | 526 | } while (!page && read_mems_allowed_retry(cpuset_mems_cookie)); |
| 527 | 527 | ||
| 528 | return page; | 528 | return page; |
| 529 | } | 529 | } |
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index c01cb9fedb18..139b7462203b 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
| @@ -540,7 +540,7 @@ static struct page *dequeue_huge_page_vma(struct hstate *h, | |||
| 540 | goto err; | 540 | goto err; |
| 541 | 541 | ||
| 542 | retry_cpuset: | 542 | retry_cpuset: |
| 543 | cpuset_mems_cookie = get_mems_allowed(); | 543 | cpuset_mems_cookie = read_mems_allowed_begin(); |
| 544 | zonelist = huge_zonelist(vma, address, | 544 | zonelist = huge_zonelist(vma, address, |
| 545 | htlb_alloc_mask(h), &mpol, &nodemask); | 545 | htlb_alloc_mask(h), &mpol, &nodemask); |
| 546 | 546 | ||
| @@ -562,7 +562,7 @@ retry_cpuset: | |||
| 562 | } | 562 | } |
| 563 | 563 | ||
| 564 | mpol_cond_put(mpol); | 564 | mpol_cond_put(mpol); |
| 565 | if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page)) | 565 | if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie))) |
| 566 | goto retry_cpuset; | 566 | goto retry_cpuset; |
| 567 | return page; | 567 | return page; |
| 568 | 568 | ||
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 4755c8576942..e3ab02822799 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
| @@ -1899,7 +1899,7 @@ int node_random(const nodemask_t *maskp) | |||
| 1899 | * If the effective policy is 'BIND, returns a pointer to the mempolicy's | 1899 | * If the effective policy is 'BIND, returns a pointer to the mempolicy's |
| 1900 | * @nodemask for filtering the zonelist. | 1900 | * @nodemask for filtering the zonelist. |
| 1901 | * | 1901 | * |
| 1902 | * Must be protected by get_mems_allowed() | 1902 | * Must be protected by read_mems_allowed_begin() |
| 1903 | */ | 1903 | */ |
| 1904 | struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr, | 1904 | struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr, |
| 1905 | gfp_t gfp_flags, struct mempolicy **mpol, | 1905 | gfp_t gfp_flags, struct mempolicy **mpol, |
| @@ -2063,7 +2063,7 @@ alloc_pages_vma(gfp_t gfp, int order, struct vm_area_struct *vma, | |||
| 2063 | 2063 | ||
| 2064 | retry_cpuset: | 2064 | retry_cpuset: |
| 2065 | pol = get_vma_policy(current, vma, addr); | 2065 | pol = get_vma_policy(current, vma, addr); |
| 2066 | cpuset_mems_cookie = get_mems_allowed(); | 2066 | cpuset_mems_cookie = read_mems_allowed_begin(); |
| 2067 | 2067 | ||
| 2068 | if (unlikely(pol->mode == MPOL_INTERLEAVE)) { | 2068 | if (unlikely(pol->mode == MPOL_INTERLEAVE)) { |
| 2069 | unsigned nid; | 2069 | unsigned nid; |
| @@ -2071,7 +2071,7 @@ retry_cpuset: | |||
| 2071 | nid = interleave_nid(pol, vma, addr, PAGE_SHIFT + order); | 2071 | nid = interleave_nid(pol, vma, addr, PAGE_SHIFT + order); |
| 2072 | mpol_cond_put(pol); | 2072 | mpol_cond_put(pol); |
| 2073 | page = alloc_page_interleave(gfp, order, nid); | 2073 | page = alloc_page_interleave(gfp, order, nid); |
| 2074 | if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page)) | 2074 | if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie))) |
| 2075 | goto retry_cpuset; | 2075 | goto retry_cpuset; |
| 2076 | 2076 | ||
| 2077 | return page; | 2077 | return page; |
| @@ -2081,7 +2081,7 @@ retry_cpuset: | |||
| 2081 | policy_nodemask(gfp, pol)); | 2081 | policy_nodemask(gfp, pol)); |
| 2082 | if (unlikely(mpol_needs_cond_ref(pol))) | 2082 | if (unlikely(mpol_needs_cond_ref(pol))) |
| 2083 | __mpol_put(pol); | 2083 | __mpol_put(pol); |
| 2084 | if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page)) | 2084 | if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie))) |
| 2085 | goto retry_cpuset; | 2085 | goto retry_cpuset; |
| 2086 | return page; | 2086 | return page; |
| 2087 | } | 2087 | } |
| @@ -2115,7 +2115,7 @@ struct page *alloc_pages_current(gfp_t gfp, unsigned order) | |||
| 2115 | pol = &default_policy; | 2115 | pol = &default_policy; |
| 2116 | 2116 | ||
| 2117 | retry_cpuset: | 2117 | retry_cpuset: |
| 2118 | cpuset_mems_cookie = get_mems_allowed(); | 2118 | cpuset_mems_cookie = read_mems_allowed_begin(); |
| 2119 | 2119 | ||
| 2120 | /* | 2120 | /* |
| 2121 | * No reference counting needed for current->mempolicy | 2121 | * No reference counting needed for current->mempolicy |
| @@ -2128,7 +2128,7 @@ retry_cpuset: | |||
| 2128 | policy_zonelist(gfp, pol, numa_node_id()), | 2128 | policy_zonelist(gfp, pol, numa_node_id()), |
| 2129 | policy_nodemask(gfp, pol)); | 2129 | policy_nodemask(gfp, pol)); |
| 2130 | 2130 | ||
| 2131 | if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page)) | 2131 | if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie))) |
| 2132 | goto retry_cpuset; | 2132 | goto retry_cpuset; |
| 2133 | 2133 | ||
| 2134 | return page; | 2134 | return page; |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 3bac76ae4b30..979378deccbf 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
| @@ -2739,7 +2739,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, | |||
| 2739 | return NULL; | 2739 | return NULL; |
| 2740 | 2740 | ||
| 2741 | retry_cpuset: | 2741 | retry_cpuset: |
| 2742 | cpuset_mems_cookie = get_mems_allowed(); | 2742 | cpuset_mems_cookie = read_mems_allowed_begin(); |
| 2743 | 2743 | ||
| 2744 | /* The preferred zone is used for statistics later */ | 2744 | /* The preferred zone is used for statistics later */ |
| 2745 | first_zones_zonelist(zonelist, high_zoneidx, | 2745 | first_zones_zonelist(zonelist, high_zoneidx, |
| @@ -2777,7 +2777,7 @@ out: | |||
| 2777 | * the mask is being updated. If a page allocation is about to fail, | 2777 | * the mask is being updated. If a page allocation is about to fail, |
| 2778 | * check if the cpuset changed during allocation and if so, retry. | 2778 | * check if the cpuset changed during allocation and if so, retry. |
| 2779 | */ | 2779 | */ |
| 2780 | if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page)) | 2780 | if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie))) |
| 2781 | goto retry_cpuset; | 2781 | goto retry_cpuset; |
| 2782 | 2782 | ||
| 2783 | memcg_kmem_commit_charge(page, memcg, order); | 2783 | memcg_kmem_commit_charge(page, memcg, order); |
| @@ -3045,9 +3045,9 @@ bool skip_free_areas_node(unsigned int flags, int nid) | |||
| 3045 | goto out; | 3045 | goto out; |
| 3046 | 3046 | ||
| 3047 | do { | 3047 | do { |
| 3048 | cpuset_mems_cookie = get_mems_allowed(); | 3048 | cpuset_mems_cookie = read_mems_allowed_begin(); |
| 3049 | ret = !node_isset(nid, cpuset_current_mems_allowed); | 3049 | ret = !node_isset(nid, cpuset_current_mems_allowed); |
| 3050 | } while (!put_mems_allowed(cpuset_mems_cookie)); | 3050 | } while (read_mems_allowed_retry(cpuset_mems_cookie)); |
| 3051 | out: | 3051 | out: |
| 3052 | return ret; | 3052 | return ret; |
| 3053 | } | 3053 | } |
| @@ -3073,7 +3073,7 @@ static void *fallback_alloc(struct kmem_cache *cache, gfp_t flags) | |||
| 3073 | local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK); | 3073 | local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK); |
| 3074 | 3074 | ||
| 3075 | retry_cpuset: | 3075 | retry_cpuset: |
| 3076 | cpuset_mems_cookie = get_mems_allowed(); | 3076 | cpuset_mems_cookie = read_mems_allowed_begin(); |
| 3077 | zonelist = node_zonelist(slab_node(), flags); | 3077 | zonelist = node_zonelist(slab_node(), flags); |
| 3078 | 3078 | ||
| 3079 | retry: | 3079 | retry: |
| @@ -3131,7 +3131,7 @@ retry: | |||
| 3131 | } | 3131 | } |
| 3132 | } | 3132 | } |
| 3133 | 3133 | ||
| 3134 | if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !obj)) | 3134 | if (unlikely(!obj && read_mems_allowed_retry(cpuset_mems_cookie))) |
| 3135 | goto retry_cpuset; | 3135 | goto retry_cpuset; |
| 3136 | return obj; | 3136 | return obj; |
| 3137 | } | 3137 | } |
| @@ -1684,7 +1684,7 @@ static void *get_any_partial(struct kmem_cache *s, gfp_t flags, | |||
| 1684 | return NULL; | 1684 | return NULL; |
| 1685 | 1685 | ||
| 1686 | do { | 1686 | do { |
| 1687 | cpuset_mems_cookie = get_mems_allowed(); | 1687 | cpuset_mems_cookie = read_mems_allowed_begin(); |
| 1688 | zonelist = node_zonelist(slab_node(), flags); | 1688 | zonelist = node_zonelist(slab_node(), flags); |
| 1689 | for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) { | 1689 | for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) { |
| 1690 | struct kmem_cache_node *n; | 1690 | struct kmem_cache_node *n; |
| @@ -1696,19 +1696,17 @@ static void *get_any_partial(struct kmem_cache *s, gfp_t flags, | |||
| 1696 | object = get_partial_node(s, n, c, flags); | 1696 | object = get_partial_node(s, n, c, flags); |
| 1697 | if (object) { | 1697 | if (object) { |
| 1698 | /* | 1698 | /* |
| 1699 | * Return the object even if | 1699 | * Don't check read_mems_allowed_retry() |
| 1700 | * put_mems_allowed indicated that | 1700 | * here - if mems_allowed was updated in |
| 1701 | * the cpuset mems_allowed was | 1701 | * parallel, that was a harmless race |
| 1702 | * updated in parallel. It's a | 1702 | * between allocation and the cpuset |
| 1703 | * harmless race between the alloc | 1703 | * update |
| 1704 | * and the cpuset update. | ||
| 1705 | */ | 1704 | */ |
| 1706 | put_mems_allowed(cpuset_mems_cookie); | ||
| 1707 | return object; | 1705 | return object; |
| 1708 | } | 1706 | } |
| 1709 | } | 1707 | } |
| 1710 | } | 1708 | } |
| 1711 | } while (!put_mems_allowed(cpuset_mems_cookie)); | 1709 | } while (read_mems_allowed_retry(cpuset_mems_cookie)); |
| 1712 | #endif | 1710 | #endif |
| 1713 | return NULL; | 1711 | return NULL; |
| 1714 | } | 1712 | } |
