Linux NUMA userland tools development
 help / color / mirror / Atom feed
From: Lee Schermerhorn <lee.schermerhorn@hp.com>
To: linux-numa@vger.kernel.org
Cc: akpm@linux-foundation.org, Mel Gorman <mel@csn.ul.ie>,
	cl@linux-foundation.org, Nick Piggin <npiggin@kernel.dk>,
	Hugh Dickins <hughd@google.com>,
	KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>,
	andi@firstfloor.org, David Rientjes <rientjes@google.com>,
	Avi Kivity <avi@redhat.com>,
	Andrea Arcangeli <aarcange@redhat.com>
Subject: [PATCH/RFC 8/14] Shared Policy: use alloc_page_pol for swap and shmempages
Date: Thu, 11 Nov 2010 14:12:58 -0500	[thread overview]
Message-ID: <20101111191258.12370.73790.sendpatchset@zaphod.localdomain> (raw)
In-Reply-To: <20101111191147.12370.66074.sendpatchset@zaphod.localdomain>

Shared Policy Infrastructure - use alloc_page_pol() for shmem
and swap cache allocations

Now that we have the alloc_page_pol() to allocate a page
given a policy, we can use it to "simplify" shmem and swap
cache page allocations.  This eliminates the need for
pseudo-vmas on stack for shmem page allocations and moves us
towards a "policy + offset" model for page cache allocations,
rather that a "vma + address" model.  The vma+address are not
[both] available everywhere we would like to do policy-based page
allocation, whereas the policy and pgoff usually are.  However,
this does mean, however, that we need to be aware of mempolicy
reference counting in swapin read-ahead.

read_swap_cache_async() and swapin_readahead() have been changed
to take a policy and page offset [for interleaving] instead of a
vma and address.  swapin_readahead() passes the policy and pgoff
to read_swap_cache_async() to do the read.  read_swap_cache_async()
now uses alloc_page_pol() with the policy and offset, instead of
alloc_page_vma().

  Note that the pgoff used by swapin_readahead() is essentially
  bogus for all but the first read.  This was already the case
  for the 'address' argument before this patch.  With this patch,
  swapin_readahead() holds pgoff constant to select the same
  node for each readahead page, in the case of interleave
  policy.  This preserves pre-existing behavior.

shmem_swapin() now uses get_file_policy() directly to look up
the shared policy on the shmem pseudo-file which it passes
to swapin_readahead().  swapin_readahead() can call
read_swap_cache_async() multiple times in a loop before the final
tail call.  read_swap_cache_async() itself may loop to retry [in
case of swapin races?].  To avoid multiple "frees" of the shared
policy, swapin_readahead() makes a "conditional unshared" copy
of the policy on stack via mpol_cond_assign().  This releases the
extra ref for a shared policy, and is effectively a no-op for
non-shared policy.  Because the copy is non-shared, alloc_page_pol()
will not attempt to decrement the reference count.

Note that get_vma_policy() becomes an in-kernel global for
use outside of mempolicy.c, like get_file_policy(), to
lookup vma based policy for other calls to swapin_readahead().
Again, use of get_vma_policy() balances reference counts with
mpol_cond_assign() in swapin_readahead().


Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com>

 include/linux/mempolicy.h |    8 ++++++
 include/linux/swap.h      |    6 ++--
 mm/memory.c               |    5 +++
 mm/mempolicy.c            |    2 -
 mm/shmem.c                |   58 +++++++++++++++-------------------------------
 mm/swap_state.c           |   31 +++++++++++++++++-------
 mm/swapfile.c             |   14 ++++++++---
 7 files changed, 68 insertions(+), 56 deletions(-)

Index: linux-2.6.36-mmotm-101103-1217/mm/swap_state.c
===================================================================
--- linux-2.6.36-mmotm-101103-1217.orig/mm/swap_state.c
+++ linux-2.6.36-mmotm-101103-1217/mm/swap_state.c
@@ -17,6 +17,7 @@
 #include <linux/buffer_head.h>
 #include <linux/backing-dev.h>
 #include <linux/pagevec.h>
+#include <linux/mempolicy.h>
 #include <linux/migrate.h>
 #include <linux/page_cgroup.h>
 
@@ -275,9 +276,11 @@ struct page * lookup_swap_cache(swp_entr
  * and reading the disk if it is not already cached.
  * A failure return means that either the page allocation failed or that
  * the swap entry is no longer in use.
+ *
+ * This function will drop any incoming conditional reference on @pol.
  */
 struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
-			struct vm_area_struct *vma, unsigned long addr)
+			struct mempolicy *pol, pgoff_t pgoff)
 {
 	struct page *found_page, *new_page = NULL;
 	int err;
@@ -296,7 +299,8 @@ struct page *read_swap_cache_async(swp_e
 		 * Get a new page to read into from swap.
 		 */
 		if (!new_page) {
-			new_page = alloc_page_vma(gfp_mask, vma, addr);
+			new_page = alloc_page_pol(GFP_HIGHUSER_MOVABLE,
+								pol, pgoff);
 			if (!new_page)
 				break;		/* Out of memory */
 		}
@@ -353,8 +357,8 @@ struct page *read_swap_cache_async(swp_e
  * swapin_readahead - swap in pages in hope we need them soon
  * @entry: swap entry of this memory
  * @gfp_mask: memory allocation flags
- * @vma: user vma this address belongs to
- * @addr: target address for mempolicy
+ * @pol: mempolicy that controls allocation.
+ * @pgoff: page offset for interleave policy
  *
  * Returns the struct page for entry and addr, after queueing swapin.
  *
@@ -369,29 +373,38 @@ struct page *read_swap_cache_async(swp_e
  * Caller must hold down_read on the vma->vm_mm if vma is not NULL.
  */
 struct page *swapin_readahead(swp_entry_t entry, gfp_t gfp_mask,
-			struct vm_area_struct *vma, unsigned long addr)
+				struct mempolicy *pol, pgoff_t pgoff)
 {
-	int nr_pages;
+	struct mempolicy mpol;
 	struct page *page;
 	unsigned long offset;
 	unsigned long end_offset;
+	int nr_pages;
+
+	/*
+	 * make a non-shared copy of pol and release incoming ref, if
+	 * necessary, for read ahead loop and read_swap_cache_async()
+	 * retry loop.
+	 */
+	pol = mpol_cond_copy(&mpol, pol);
 
 	/*
 	 * Get starting offset for readaround, and number of pages to read.
 	 * Adjust starting address by readbehind (for NUMA interleave case)?
 	 * No, it's very unlikely that swap layout would follow vma layout,
 	 * more likely that neighbouring swap pages came from the same node:
-	 * so use the same "addr" to choose the same node for each swap read.
+	 * so use the same "pgoff" to choose the same node for each swap read.
 	 */
 	nr_pages = valid_swaphandles(entry, &offset);
 	for (end_offset = offset + nr_pages; offset < end_offset; offset++) {
+
 		/* Ok, do the async read-ahead now */
 		page = read_swap_cache_async(swp_entry(swp_type(entry), offset),
-						gfp_mask, vma, addr);
+						gfp_mask, pol, pgoff);
 		if (!page)
 			break;
 		page_cache_release(page);
 	}
 	lru_add_drain();	/* Push any new pages onto the LRU now */
-	return read_swap_cache_async(entry, gfp_mask, vma, addr);
+	return read_swap_cache_async(entry, gfp_mask, pol, pgoff);
 }
Index: linux-2.6.36-mmotm-101103-1217/include/linux/swap.h
===================================================================
--- linux-2.6.36-mmotm-101103-1217.orig/include/linux/swap.h
+++ linux-2.6.36-mmotm-101103-1217/include/linux/swap.h
@@ -317,9 +317,9 @@ extern void free_page_and_swap_cache(str
 extern void free_pages_and_swap_cache(struct page **, int);
 extern struct page *lookup_swap_cache(swp_entry_t);
 extern struct page *read_swap_cache_async(swp_entry_t, gfp_t,
-			struct vm_area_struct *vma, unsigned long addr);
+					struct mempolicy *, pgoff_t);
 extern struct page *swapin_readahead(swp_entry_t, gfp_t,
-			struct vm_area_struct *vma, unsigned long addr);
+					struct mempolicy *, pgoff_t);
 
 /* linux/mm/swapfile.c */
 extern long nr_swap_pages;
@@ -427,7 +427,7 @@ static inline void swapcache_free(swp_en
 }
 
 static inline struct page *swapin_readahead(swp_entry_t swp, gfp_t gfp_mask,
-			struct vm_area_struct *vma, unsigned long addr)
+					struct mempolicy *pol, pgoff_t pgoff)
 {
 	return NULL;
 }
Index: linux-2.6.36-mmotm-101103-1217/mm/mempolicy.c
===================================================================
--- linux-2.6.36-mmotm-101103-1217.orig/mm/mempolicy.c
+++ linux-2.6.36-mmotm-101103-1217/mm/mempolicy.c
@@ -1571,7 +1571,7 @@ struct mempolicy *get_file_policy(struct
  * freeing by another task.  It is the caller's responsibility to free the
  * extra reference for shared policies.
  */
-static struct mempolicy *get_vma_policy(struct task_struct *task,
+struct mempolicy *get_vma_policy(struct task_struct *task,
 		struct vm_area_struct *vma, unsigned long addr)
 {
 	struct mempolicy *pol = task->mempolicy;
Index: linux-2.6.36-mmotm-101103-1217/include/linux/mempolicy.h
===================================================================
--- linux-2.6.36-mmotm-101103-1217.orig/include/linux/mempolicy.h
+++ linux-2.6.36-mmotm-101103-1217/include/linux/mempolicy.h
@@ -193,6 +193,8 @@ extern void mpol_rebind_task(struct task
 extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
 extern void mpol_fix_fork_child_flag(struct task_struct *p);
 
+extern struct mempolicy *get_vma_policy(struct task_struct *,
+				struct vm_area_struct *, unsigned long);
 extern struct mempolicy *get_file_policy(struct address_space *, pgoff_t);
 extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
 				unsigned long addr, gfp_t gfp_flags,
@@ -324,6 +326,12 @@ static inline bool mempolicy_nodemask_in
 	return false;
 }
 
+static inline struct mempolicy *get_vma_policy(struct task_struct *task,
+		struct vm_area_struct *vma, unsigned long addr)
+{
+	return NULL;
+}
+
 static inline struct mempolicy *get_file_policy(struct address_space *, pgoff_t)
 {
 	return NULL;
Index: linux-2.6.36-mmotm-101103-1217/mm/swapfile.c
===================================================================
--- linux-2.6.36-mmotm-101103-1217.orig/mm/swapfile.c
+++ linux-2.6.36-mmotm-101103-1217/mm/swapfile.c
@@ -31,6 +31,7 @@
 #include <linux/syscalls.h>
 #include <linux/memcontrol.h>
 #include <linux/poll.h>
+#include <linux/mempolicy.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -1096,6 +1097,7 @@ static int try_to_unuse(unsigned int typ
 	struct mm_struct *start_mm;
 	unsigned char *swap_map;
 	unsigned char swcount;
+	struct mempolicy *pol;
 	struct page *page;
 	swp_entry_t entry;
 	unsigned int i = 0;
@@ -1132,12 +1134,18 @@ static int try_to_unuse(unsigned int typ
 		/*
 		 * Get a page for the entry, using the existing swap
 		 * cache page if there is one.  Otherwise, get a clean
-		 * page and read the swap into it.
+		 * page and read the swap into it.  Use dummy policy
+		 * [current task's policy or system default] with swap
+		 * cache index for interleaving to allocate new page.
+		 * Note:  read_swap_cache_async() drops reference on policy.
+		 *        need to refetch policy for each call.  Not a
+		 *        performance concern in this loop.
 		 */
 		swap_map = &si->swap_map[i];
 		entry = swp_entry(type, i);
-		page = read_swap_cache_async(entry,
-					GFP_HIGHUSER_MOVABLE, NULL, 0);
+		pol = get_vma_policy(current, NULL, 0);
+		page = read_swap_cache_async(entry, GFP_HIGHUSER_MOVABLE,
+							 pol, i);
 		if (!page) {
 			/*
 			 * Either swap_duplicate() failed because entry
Index: linux-2.6.36-mmotm-101103-1217/mm/memory.c
===================================================================
--- linux-2.6.36-mmotm-101103-1217.orig/mm/memory.c
+++ linux-2.6.36-mmotm-101103-1217/mm/memory.c
@@ -2651,9 +2651,12 @@ static int do_swap_page(struct mm_struct
 	delayacct_set_flag(DELAYACCT_PF_SWAPIN);
 	page = lookup_swap_cache(entry);
 	if (!page) {
+		struct mempolicy *pol = get_vma_policy(current, vma, address);
+		pgoff_t pgoff = vma_mpol_pgoff(vma, address);
+
 		grab_swap_token(mm); /* Contend for token _before_ read-in */
 		page = swapin_readahead(entry,
-					GFP_HIGHUSER_MOVABLE, vma, address);
+					GFP_HIGHUSER_MOVABLE, pol, pgoff);
 		if (!page) {
 			/*
 			 * Back out if somebody else faulted in this pte
Index: linux-2.6.36-mmotm-101103-1217/mm/shmem.c
===================================================================
--- linux-2.6.36-mmotm-101103-1217.orig/mm/shmem.c
+++ linux-2.6.36-mmotm-101103-1217/mm/shmem.c
@@ -1146,39 +1146,21 @@ static struct mempolicy *shmem_get_sbmpo
 }
 #endif /* CONFIG_TMPFS */
 
-struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp,
-				struct shared_policy *sp, unsigned long idx)
+struct page *shmem_swapin(swp_entry_t entry,
+			struct address_space *mapping, unsigned long idx)
 {
-	struct mempolicy mpol, *spol;
-	struct vm_area_struct pvma;
-	struct page *page;
-
-	spol = mpol_cond_copy(&mpol, mpol_shared_policy_lookup(sp, idx));
-
-	/* Create a pseudo vma that just contains the policy */
-	pvma.vm_start = 0;
-	pvma.vm_pgoff = idx;
-	pvma.vm_file = NULL;
-	pvma.vm_policy = spol;
-	page = swapin_readahead(entry, gfp, &pvma, 0);
-	return page;
+	return swapin_readahead(entry, mapping_gfp_mask(mapping),
+	                                   get_file_policy(mapping, idx), idx);
 }
 
-static struct page *shmem_alloc_page(gfp_t gfp, struct shared_policy *sp,
-				unsigned long idx)
+static inline struct page *shmem_alloc_page(struct address_space *mapping,
+					    unsigned long idx)
 {
-	struct vm_area_struct pvma;
-
-	/* Create a pseudo vma that just contains the policy */
-	pvma.vm_start = 0;
-	pvma.vm_pgoff = idx;
-	pvma.vm_file = NULL;
-	pvma.vm_policy = mpol_shared_policy_lookup(sp, idx);
-
 	/*
-	 * alloc_page_vma() will drop the shared policy reference
+	 * alloc_page_pol() will drop the shared policy reference
 	 */
-	return alloc_page_vma(gfp, &pvma, 0);
+	return alloc_page_pol(mapping_gfp_mask(mapping) | __GFP_ZERO,
+				 get_file_policy(mapping, idx), idx);
 }
 #else /* !CONFIG_NUMA */
 #ifdef CONFIG_TMPFS
@@ -1187,16 +1169,17 @@ static inline void shmem_show_mpol(struc
 }
 #endif /* CONFIG_TMPFS */
 
-static inline struct page *shmem_swapin(swp_entry_t entry, gfp_t gfp, void *sp,
-						unsigned long idx)
+static inline struct page *shmem_swapin(swp_entry_t entry,
+					struct address_space *mapping,
+					unsigned long idx)
 {
-	return swapin_readahead(entry, gfp, NULL, 0);
+ 	return swapin_readahead(entry, mapping_gfp_mask(mapping), NULL, 0);
 }
 
-static inline struct page *shmem_alloc_page(gfp_t gfp, void *sp,
-						unsigned long idx)
+static inline struct page *shmem_alloc_page(struct address_space *mapping,
+					    unsigned long idx)
 {
-	return alloc_page(gfp);
+	return alloc_page(mapping_gfp_mask(mapping) | __GFP_ZERO);
 }
 #endif /* CONFIG_NUMA */
 
@@ -1259,8 +1242,7 @@ repeat:
 		radix_tree_preload_end();
 		if (sgp != SGP_READ && !prealloc_page) {
 			/* We don't care if this fails */
-			prealloc_page = shmem_alloc_page(gfp,
-					mapping_shared_policy(mapping), idx);
+			prealloc_page = shmem_alloc_page(mapping, idx);
 			if (prealloc_page) {
 				if (mem_cgroup_cache_charge(prealloc_page,
 						current->mm, GFP_KERNEL)) {
@@ -1293,8 +1275,7 @@ repeat:
 				*type |= VM_FAULT_MAJOR;
 			}
 			spin_unlock(&info->lock);
-			swappage = shmem_swapin(swap, gfp,
-					mapping_shared_policy(mapping), idx);
+			swappage = shmem_swapin(swap, mapping, idx);
 			if (!swappage) {
 				spin_lock(&info->lock);
 				entry = shmem_swp_alloc(info, idx, sgp);
@@ -1421,8 +1402,7 @@ repeat:
 
 			if (!prealloc_page) {
 				spin_unlock(&info->lock);
-				filepage = shmem_alloc_page(gfp,
-						mapping_shared_policy(mapping), idx);
+				filepage = shmem_alloc_page(mapping, idx);
 				if (!filepage) {
 					shmem_unacct_blocks(info->flags, 1);
 					shmem_free_blocks(inode, 1);

  parent reply	other threads:[~2010-11-11 19:12 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-11-11 19:11 [PATCH/RFC 0/14] Shared Policy Overview Lee Schermerhorn
2010-11-11 19:11 ` [PATCH/RFC 1/14] Shared Policy: Miscellaneous Cleanup Lee Schermerhorn
2010-11-11 19:12 ` [PATCH/RFC 2/14] Shared Policy: move shared policy to inode/mapping Lee Schermerhorn
2010-11-11 19:12 ` [PATCH/RFC 3/14] Shared Policy: allocate shared policies as needed Lee Schermerhorn
2010-11-11 19:12 ` [PATCH/RFC 4/14] Shared Policy: let vma policy ops handle sub-vma policies Lee Schermerhorn
2010-11-11 19:12 ` [PATCH/RFC 5/14] Shared Policy: fix show_numa_maps() Lee Schermerhorn
2010-11-11 19:12 ` [PATCH/RFC 6/14] Shared Policy: Factor alloc_page_pol routine Lee Schermerhorn
2010-11-11 19:12 ` [PATCH/RFC 7/14] Shared Policy: use shared policy for page cache allocations Lee Schermerhorn
2010-11-11 19:12 ` Lee Schermerhorn [this message]
2010-11-11 19:13 ` [PATCH/RFC 9/14] Shared Policy: per cpuset huge file policy control Lee Schermerhorn
2010-11-11 19:13 ` [PATCH/RFC 10/14] Shared Policy: Add hugepage shmem policy vm_ops Lee Schermerhorn
2010-11-11 19:13 ` [PATCH/RFC 11/14] Shared Policy: fix migration of private mappings Lee Schermerhorn
2010-11-11 19:13 ` [PATCH/RFC 12/14] Shared Policy: mapped file policy persistence model Lee Schermerhorn
2010-11-11 19:13 ` [PATCH/RFC 13/14] Shared Policy: per cpuset mapped file policy control Lee Schermerhorn
2010-11-11 19:13 ` [PATCH/RFC 14/14] Shared Policy: add generic file set/get policy vm ops Lee Schermerhorn
2010-11-11 19:54 ` [PATCH/RFC 0/14] Shared Policy Overview Andi Kleen
2010-11-11 19:59   ` Lee Schermerhorn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20101111191258.12370.73790.sendpatchset@zaphod.localdomain \
    --to=lee.schermerhorn@hp.com \
    --cc=aarcange@redhat.com \
    --cc=akpm@linux-foundation.org \
    --cc=andi@firstfloor.org \
    --cc=avi@redhat.com \
    --cc=cl@linux-foundation.org \
    --cc=hughd@google.com \
    --cc=kosaki.motohiro@jp.fujitsu.com \
    --cc=linux-numa@vger.kernel.org \
    --cc=mel@csn.ul.ie \
    --cc=npiggin@kernel.dk \
    --cc=rientjes@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox