lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1337250784.4281.19.camel@twins>
Date:	Thu, 17 May 2012 12:33:04 +0200
From:	Peter Zijlstra <peterz@...radead.org>
To:	Mel Gorman <mgorman@...e.de>
Cc:	Andrew Morton <akpm@...ux-foundation.org>,
	Miao Xie <miaox@...fujitsu.com>,
	David Rientjes <rientjes@...gle.com>,
	Christoph Lameter <cl@...ux.com>, linux-mm@...ck.org,
	linux-kernel@...r.kernel.org
Subject: Re: [PATCH] mm: Optimize put_mems_allowed() usage

Anybody care to pick this one up? Andrew?

On Tue, 2012-03-27 at 15:14 +0200, Peter Zijlstra wrote:
> Subject: mm: Optimize put_mems_allowed() usage
> From: Peter Zijlstra <a.p.zijlstra@...llo.nl>
> Date: Mon Mar 26 14:13:05 CEST 2012
> 
> 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.
> 
> Acked-by: Mel Gorman <mgorman@...e.de>
> Signed-off-by: Peter Zijlstra <a.p.zijlstra@...llo.nl>
> ---
>  include/linux/cpuset.h |   27 ++++++++++++++-------------
>  kernel/cpuset.c        |    2 +-
>  mm/filemap.c           |    4 ++--
>  mm/hugetlb.c           |    4 ++--
>  mm/mempolicy.c         |   14 +++++++-------
>  mm/page_alloc.c        |    8 ++++----
>  mm/slab.c              |    4 ++--
>  mm/slub.c              |   16 +++-------------
>  8 files changed, 35 insertions(+), 44 deletions(-)
> 
> --- a/include/linux/cpuset.h
> +++ b/include/linux/cpuset.h
> @@ -89,25 +89,26 @@ extern void rebuild_sched_domains(void);
>  extern void cpuset_print_task_mems_allowed(struct task_struct *p);
>  
>  /*
> - * get_mems_allowed is required when making decisions involving mems_allowed
> - * such as during page allocation. mems_allowed can be updated in parallel
> - * and depending on the new value an operation can fail potentially causing
> - * process failure. A retry loop with get_mems_allowed and put_mems_allowed
> - * prevents these artificial failures.
> + * read_mems_allowed_begin is required when making decisions involving
> + * mems_allowed such as during page allocation. mems_allowed can be updated in
> + * parallel and depending on the new value an operation can fail potentially
> + * causing process failure. A retry loop with read_mems_allowed_begin and
> + * read_mems_allowed_retry prevents these artificial failures.
>   */
> -static inline unsigned int get_mems_allowed(void)
> +static inline unsigned int read_mems_allowed_begin(void)
>  {
>  	return read_seqcount_begin(&current->mems_allowed_seq);
>  }
>  
>  /*
> - * If this returns false, the operation that took place after get_mems_allowed
> - * may have failed. It is up to the caller to retry the operation if
> + * If this returns true, the operation that took place after
> + * read_mems_allowed_begin may have failed artificially due to a concurrent
> + * update of mems_allowed. It is up to the caller to retry the operation if
>   * appropriate.
>   */
> -static inline bool put_mems_allowed(unsigned int seq)
> +static inline bool read_mems_allowed_retry(unsigned int seq)
>  {
> -	return !read_seqcount_retry(&current->mems_allowed_seq, seq);
> +	return read_seqcount_retry(&current->mems_allowed_seq, seq);
>  }
>  
>  static inline void set_mems_allowed(nodemask_t nodemask)
> @@ -225,14 +226,14 @@ static inline void set_mems_allowed(node
>  {
>  }
>  
> -static inline unsigned int get_mems_allowed(void)
> +static inline unsigned int read_mems_allowed_begin(void)
>  {
>  	return 0;
>  }
>  
> -static inline bool put_mems_allowed(unsigned int seq)
> +static inline bool read_mems_allowed_retry(unsigned int seq)
>  {
> -	return true;
> +	return false;
>  }
>  
>  #endif /* !CONFIG_CPUSETS */
> --- a/kernel/cpuset.c
> +++ b/kernel/cpuset.c
> @@ -976,7 +976,7 @@ static void cpuset_change_task_nodemask(
>  	task_lock(tsk);
>  	/*
>  	 * Determine if a loop is necessary if another thread is doing
> -	 * get_mems_allowed().  If at least one node remains unchanged and
> +	 * read_mems_allowed_begin().  If at least one node remains unchanged and
>  	 * tsk does not have a mempolicy, then an empty nodemask will not be
>  	 * possible when mems_allowed is larger than a word.
>  	 */
> --- a/mm/filemap.c
> +++ b/mm/filemap.c
> @@ -501,10 +501,10 @@ struct page *__page_cache_alloc(gfp_t gf
>  	if (cpuset_do_page_mem_spread()) {
>  		unsigned int cpuset_mems_cookie;
>  		do {
> -			cpuset_mems_cookie = get_mems_allowed();
> +			cpuset_mems_cookie = read_mems_allowed_begin();
>  			n = cpuset_mem_spread_node();
>  			page = alloc_pages_exact_node(n, gfp, 0);
> -		} while (!put_mems_allowed(cpuset_mems_cookie) && !page);
> +		} while (!page && read_mems_allowed_retry(cpuset_mems_cookie));
>  
>  		return page;
>  	}
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -541,7 +541,7 @@ static struct page *dequeue_huge_page_vm
>  	unsigned int cpuset_mems_cookie;
>  
>  retry_cpuset:
> -	cpuset_mems_cookie = get_mems_allowed();
> +	cpuset_mems_cookie = read_mems_allowed_begin();
>  	zonelist = huge_zonelist(vma, address,
>  					htlb_alloc_mask, &mpol, &nodemask);
>  	/*
> @@ -570,7 +570,7 @@ static struct page *dequeue_huge_page_vm
>  	}
>  
>  	mpol_cond_put(mpol);
> -	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
> +	if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
>  		goto retry_cpuset;
>  	return page;
>  
> --- a/mm/mempolicy.c
> +++ b/mm/mempolicy.c
> @@ -1692,7 +1692,7 @@ int node_random(const nodemask_t *maskp)
>   * If the effective policy is 'BIND, returns a pointer to the mempolicy's
>   * @nodemask for filtering the zonelist.
>   *
> - * Must be protected by get_mems_allowed()
> + * Must be protected by read_mems_allowed_begin()
>   */
>  struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr,
>  				gfp_t gfp_flags, struct mempolicy **mpol,
> @@ -1857,7 +1857,7 @@ alloc_pages_vma(gfp_t gfp, int order, st
>  
>  retry_cpuset:
>  	pol = get_vma_policy(current, vma, addr);
> -	cpuset_mems_cookie = get_mems_allowed();
> +	cpuset_mems_cookie = read_mems_allowed_begin();
>  
>  	if (unlikely(pol->mode == MPOL_INTERLEAVE)) {
>  		unsigned nid;
> @@ -1865,7 +1865,7 @@ alloc_pages_vma(gfp_t gfp, int order, st
>  		nid = interleave_nid(pol, vma, addr, PAGE_SHIFT + order);
>  		mpol_cond_put(pol);
>  		page = alloc_page_interleave(gfp, order, nid);
> -		if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
> +		if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
>  			goto retry_cpuset;
>  
>  		return page;
> @@ -1878,7 +1878,7 @@ alloc_pages_vma(gfp_t gfp, int order, st
>  		struct page *page =  __alloc_pages_nodemask(gfp, order,
>  						zl, policy_nodemask(gfp, pol));
>  		__mpol_put(pol);
> -		if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
> +		if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
>  			goto retry_cpuset;
>  		return page;
>  	}
> @@ -1887,7 +1887,7 @@ alloc_pages_vma(gfp_t gfp, int order, st
>  	 */
>  	page = __alloc_pages_nodemask(gfp, order, zl,
>  				      policy_nodemask(gfp, pol));
> -	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
> +	if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
>  		goto retry_cpuset;
>  	return page;
>  }
> @@ -1921,7 +1921,7 @@ struct page *alloc_pages_current(gfp_t g
>  		pol = &default_policy;
>  
>  retry_cpuset:
> -	cpuset_mems_cookie = get_mems_allowed();
> +	cpuset_mems_cookie = read_mems_allowed_begin();
>  
>  	/*
>  	 * No reference counting needed for current->mempolicy
> @@ -1934,7 +1934,7 @@ struct page *alloc_pages_current(gfp_t g
>  				policy_zonelist(gfp, pol, numa_node_id()),
>  				policy_nodemask(gfp, pol));
>  
> -	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
> +	if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
>  		goto retry_cpuset;
>  
>  	return page;
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -2402,7 +2402,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, u
>  		return NULL;
>  
>  retry_cpuset:
> -	cpuset_mems_cookie = get_mems_allowed();
> +	cpuset_mems_cookie = read_mems_allowed_begin();
>  
>  	/* The preferred zone is used for statistics later */
>  	first_zones_zonelist(zonelist, high_zoneidx,
> @@ -2429,7 +2429,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, u
>  	 * the mask is being updated. If a page allocation is about to fail,
>  	 * check if the cpuset changed during allocation and if so, retry.
>  	 */
> -	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
> +	if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
>  		goto retry_cpuset;
>  
>  	return page;
> @@ -2651,9 +2651,9 @@ bool skip_free_areas_node(unsigned int f
>  		goto out;
>  
>  	do {
> -		cpuset_mems_cookie = get_mems_allowed();
> +		cpuset_mems_cookie = read_mems_allowed_begin();
>  		ret = !node_isset(nid, cpuset_current_mems_allowed);
> -	} while (!put_mems_allowed(cpuset_mems_cookie));
> +	} while (read_mems_allowed_retry(cpuset_mems_cookie));
>  out:
>  	return ret;
>  }
> --- a/mm/slab.c
> +++ b/mm/slab.c
> @@ -3318,7 +3318,7 @@ static void *fallback_alloc(struct kmem_
>  	local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK);
>  
>  retry_cpuset:
> -	cpuset_mems_cookie = get_mems_allowed();
> +	cpuset_mems_cookie = read_mems_allowed_begin();
>  	zonelist = node_zonelist(slab_node(current->mempolicy), flags);
>  
>  retry:
> @@ -3374,7 +3374,7 @@ static void *fallback_alloc(struct kmem_
>  		}
>  	}
>  
> -	if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !obj))
> +	if (unlikely(!obj && read_mems_allowed_retry(cpuset_mems_cookie)))
>  		goto retry_cpuset;
>  	return obj;
>  }
> --- a/mm/slub.c
> +++ b/mm/slub.c
> @@ -1606,7 +1606,7 @@ static struct page *get_any_partial(stru
>  		return NULL;
>  
>  	do {
> -		cpuset_mems_cookie = get_mems_allowed();
> +		cpuset_mems_cookie = read_mems_allowed_begin();
>  		zonelist = node_zonelist(slab_node(current->mempolicy), flags);
>  		for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
>  			struct kmem_cache_node *n;
> @@ -1616,21 +1616,11 @@ static struct page *get_any_partial(stru
>  			if (n && cpuset_zone_allowed_hardwall(zone, flags) &&
>  					n->nr_partial > s->min_partial) {
>  				object = get_partial_node(s, n, c);
> -				if (object) {
> -					/*
> -					 * Return the object even if
> -					 * put_mems_allowed indicated that
> -					 * the cpuset mems_allowed was
> -					 * updated in parallel. It's a
> -					 * harmless race between the alloc
> -					 * and the cpuset update.
> -					 */
> -					put_mems_allowed(cpuset_mems_cookie);
> +				if (object)
>  					return object;
> -				}
>  			}
>  		}
> -	} while (!put_mems_allowed(cpuset_mems_cookie));
> +	} while (read_mems_allowed_retry(cpuset_mems_cookie));
>  #endif
>  	return NULL;
>  }
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ