NUMA policies for file mappings + MPOL_MF_MOVE
Subsystems (6)
PATCH 1/1 NUMA policies for file mappings + MPOL_MF_MOVE
This is a patch against 2.6.9 that is an update to an earlier patch I posted on 10/13/2004 ("NUMA policy support for file mappings").
The patch allows NUMA policies for file mappings. Page cache pages are allocated using a policy located in a shared_policy Red-Black tree attached to the mapping object (address_space). This involves:
1. add a shared_policy tree to the address_space object in fs.h.
2. modify page_cache_alloc() in pagemap.h to take a page index in addition to a mapping object, and use those to locate the correct policy in the mapping->policy tree when allocating the page.
3. modify filemap.c to pass the additional page offset to page_cache_alloc().
4. Also in filemap.c, implement generic file {set|get}_policy() methods and add those to generic_file_vm_ops.
5. Init the file's shared policy in alloc_inode(), and free the shared policy in destroy_inode().
In addition, the patch adds a new flag to the mbind() syscall, MPOL_MF_MOVE. If this flag is set, any existing mapped anonymous or filemap pagecache pages that are/can be used for the given virtual memory region, that do not satisfy the NUMA policy, are moved to a new page that satisfies the policy. Here's how the new flag works with the existing MPOL_MF_STRICT flag (in the following discussion, "invalid page" means a page that does not satisfy the NUMA policy):
MOVE and STRICT both set:
attempt to move invalid pages, and if any move fails, return mbind() syscall failure.
MOVE set:
attempt to move invalid pages, but do not return error if any move fails.
STRICT set:
do not attempt to move invalid pages, returning mbind() failure (same behavior as before).
neither MOVE or STRICT set:
ignore invalid pages.
Steve
Source: MontaVista Software, Inc., Steve Longerbeam <[email protected]>
Type: Enhancement
Disposition: merge to kernel.org
Description:
Patches NUMA mempolicy to allow policies for file mappings. Also adds a new mbind() flag that attempts to move existing anonymous and filemap pages that do not satisfy a mapping's policy (MPOL_MF_MOVE).
fs/inode.c +4 -1
@@ -150,6 +150,7 @@mapping_set_gfp_mask (mapping,GFP_HIGHUSER ); mapping->assoc_mapping =NULL ; mapping->backing_dev_info = &default_backing_dev_info; +mpol_shared_policy_init (&mapping->policy);/* * If the block_device provides a backing_dev_info for client
@@ -177,8 +178,10 @@security_inode_free (inode);if (inode->i_sb->s_op->destroy_inode) inode->i_sb->s_op->destroy_inode (inode); -else +else { +mpol_free_shared_policy (&inode->i_mapping->policy);kmem_cache_free (inode_cachep, (inode)); + } }
include/linux/fs.h +2 -0
@@ -18,6 +18,7 @@#include <linux/cache.h> #include <linux/prio_tree.h> #include <linux/kobject.h> +#include <linux/mempolicy.h> #include <asm/atomic.h> struct iovec ;
@@ -345,6 +346,7 @@struct address_space_operations *a_ops;/* methods */ unsigned long flags;/* error bits/gfp mask */ struct backing_dev_info *backing_dev_info;/* device readahead, etc */ +struct shared_policy policy;/* page alloc policy */ spinlock_t private_lock;/* for use by the address_space */ struct list_head private_list;/* ditto */ struct address_space *assoc_mapping;/* ditto */
include/linux/mempolicy.h +11 -1
@@ -22,6 +22,8 @@/* Flags for mbind */ #define MPOL_MF_STRICT (1<<0)/* Verify existing pages in the mapping */ +#define MPOL_MF_MOVE (1<<1)/* Attempt to move pages in mapping that do +not satisfy policy */ #ifdef __KERNEL__
@@ -149,7 +151,8 @@void mpol_free_shared_policy (struct shared_policy *p);struct mempolicy *mpol_shared_policy_lookup (struct shared_policy *sp,unsigned long idx); - +struct page *alloc_page_shared_policy (unsigned gfp,struct shared_policy *sp, +unsigned long idx);extern void numa_default_policy (void );extern void numa_policy_init (void );
@@ -215,6 +218,13 @@#define vma_policy (vma) NULL#define vma_set_policy (vma, pol) do {} while(0) +static inline struct page * +alloc_page_shared_policy (unsigned gfp,struct shared_policy *sp, +unsigned long idx) +{ +return alloc_pages (gfp,0 ); +} +static inline void numa_policy_init (void ) { }
include/linux/page-flags.h +6 -0
@@ -74,6 +74,8 @@#define PG_swapcache 16/* Swap page: swp_entry_t in private */ #define PG_mappedtodisk 17/* Has blocks allocated on-disk */ #define PG_reclaim 18/* To be reclaimed asap */ +#define PG_sharedpolicy 19/* Page was allocated for a file +mapping using a shared_policy */ /*
@@ -290,6 +292,10 @@#define SetPageCompound (page) set_bit(PG_compound, &(page)->flags)#define ClearPageCompound (page) clear_bit(PG_compound, &(page)->flags) +#define PageSharedPolicy (page) test_bit(PG_sharedpolicy, &(page)->flags) +#define SetPageSharedPolicy (page) set_bit(PG_sharedpolicy, &(page)->flags) +#define ClearPageSharedPolicy (page) clear_bit(PG_sharedpolicy, &(page)->flags) +#ifdef CONFIG_SWAP #define PageSwapCache (page) test_bit(PG_swapcache, &(page)->flags)#define SetPageSwapCache (page) set_bit(PG_swapcache, &(page)->flags)
include/linux/pagemap.h +14 -4
@@ -50,14 +50,24 @@#define page_cache_release (page) put_page(page)void release_pages (struct page **pages,int nr,int cold); -static inline struct page *page_cache_alloc (struct address_space *x) + +static inline struct page *__page_cache_alloc (struct address_space *x, +unsigned long idx, +unsigned int gfp_mask) +{ +return alloc_page_shared_policy (gfp_mask, &x->policy, idx); +} + +static inline struct page *page_cache_alloc (struct address_space *x, +unsigned long idx) { -return alloc_pages (mapping_gfp_mask (x),0 ); +return __page_cache_alloc (x, idx,mapping_gfp_mask (x)); } -static inline struct page *page_cache_alloc_cold (struct address_space *x) +static inline struct page *page_cache_alloc_cold (struct address_space *x, +unsigned long idx) { -return alloc_pages (mapping_gfp_mask (x)|__GFP_COLD,0 ); +return __page_cache_alloc (x, idx,mapping_gfp_mask (x)|__GFP_COLD); }typedef int filler_t (void *,struct page *);
mm/filemap.c +33 -6
@@ -595,7 +595,8 @@ page =find_lock_page (mapping, index);if (!page) {if (!cached_page) { - cached_page =alloc_page (gfp_mask); + cached_page =__page_cache_alloc (mapping, index, + gfp_mask);if (!cached_page)return NULL ; }
@@ -688,7 +689,7 @@return NULL ; } gfp_mask =mapping_gfp_mask (mapping) & ~__GFP_FS; - page =alloc_pages (gfp_mask,0 ); + page =__page_cache_alloc (mapping, index, gfp_mask);if (page &&add_to_page_cache_lru (page, mapping, index, gfp_mask)) {page_cache_release (page); page =NULL ;
@@ -865,7 +866,7 @@* page.. */ if (!cached_page) { - cached_page =page_cache_alloc_cold (mapping); + cached_page =page_cache_alloc_cold (mapping, index);if (!cached_page) { desc->error = -ENOMEM ; goto out;
@@ -1128,7 +1129,7 @@struct page *page;int error; - page =page_cache_alloc_cold (mapping); + page =page_cache_alloc_cold (mapping, offset);if (!page)return -ENOMEM ;
@@ -1510,9 +1511,35 @@return 0 ; } + +#ifdef CONFIG_NUMA +int generic_file_set_policy (struct vm_area_struct *vma, +struct mempolicy *new) +{ +struct address_space *mapping = vma->vm_file->f_mapping; +return mpol_set_shared_policy (&mapping->policy, vma, new); +} + +struct mempolicy * +generic_file_get_policy (struct vm_area_struct *vma, +unsigned long addr) +{ +struct address_space *mapping = vma->vm_file->f_mapping; +unsigned long idx; + + idx = ((addr - vma->vm_start) >>PAGE_SHIFT ) + vma->vm_pgoff; +return mpol_shared_policy_lookup (&mapping->policy, idx); +} +#endif + +struct vm_operations_struct generic_file_vm_ops = { .nopage = filemap_nopage, .populate = filemap_populate, +#ifdef CONFIG_NUMA + .set_policy = generic_file_set_policy, + .get_policy = generic_file_get_policy, +#endif };/* This is used for a general mmap of a disk file */
@@ -1562,7 +1589,7 @@ page =find_get_page (mapping, index);if (!page) {if (!cached_page) { - cached_page =page_cache_alloc_cold (mapping); + cached_page =page_cache_alloc_cold (mapping, index);if (!cached_page)return ERR_PTR (-ENOMEM ); }
@@ -1644,7 +1671,7 @@ page =find_lock_page (mapping, index);if (!page) {if (!*cached_page) { - *cached_page =page_cache_alloc (mapping); + *cached_page =page_cache_alloc (mapping, index);if (!*cached_page)return NULL ; }
mm/mempolicy.c +268 -59
422 lines not on this page · raw message
mm/readahead.c +1 -1
@@ -245,7 +245,7 @@continue ;spin_unlock_irq (&mapping->tree_lock); - page =page_cache_alloc_cold (mapping); + page =page_cache_alloc_cold (mapping, page_offset);spin_lock_irq (&mapping->tree_lock);if (!page)break ;
mm/shmem.c +1 -10
@@ -841,16 +841,7 @@ shmem_alloc_page(unsigned long gfp, struct shmem_inode_info *info, unsigned long idx) { -struct vm_area_struct pvma; -struct page *page; - -memset (&pvma,0 ,sizeof (struct vm_area_struct )); - pvma.vm_policy =mpol_shared_policy_lookup (&info->policy, idx); - pvma.vm_pgoff = idx; - pvma.vm_end =PAGE_SIZE ; - page =alloc_page_vma (gfp, &pvma,0 ); -mpol_free (pvma.vm_policy); -return page; +return alloc_page_shared_policy (gfp, &info->policy, idx); }#else static inline struct page *