diff options
| -rw-r--r-- | Documentation/filesystems/tmpfs.txt | 12 | ||||
| -rw-r--r-- | fs/hugetlbfs/inode.c | 2 | ||||
| -rw-r--r-- | include/linux/mempolicy.h | 11 | ||||
| -rw-r--r-- | include/linux/shmem_fs.h | 2 | ||||
| -rw-r--r-- | mm/mempolicy.c | 24 | ||||
| -rw-r--r-- | mm/shmem.c | 39 |
6 files changed, 75 insertions, 15 deletions
diff --git a/Documentation/filesystems/tmpfs.txt b/Documentation/filesystems/tmpfs.txt index 0d783c504ead..dbe4d87d2615 100644 --- a/Documentation/filesystems/tmpfs.txt +++ b/Documentation/filesystems/tmpfs.txt | |||
| @@ -78,6 +78,18 @@ use up all the memory on the machine; but enhances the scalability of | |||
| 78 | that instance in a system with many cpus making intensive use of it. | 78 | that instance in a system with many cpus making intensive use of it. |
| 79 | 79 | ||
| 80 | 80 | ||
| 81 | tmpfs has a mount option to set the NUMA memory allocation policy for | ||
| 82 | all files in that instance: | ||
| 83 | mpol=interleave prefers to allocate memory from each node in turn | ||
| 84 | mpol=default prefers to allocate memory from the local node | ||
| 85 | mpol=bind prefers to allocate from mpol_nodelist | ||
| 86 | mpol=preferred prefers to allocate from first node in mpol_nodelist | ||
| 87 | |||
| 88 | The following mount option is used in conjunction with mpol=interleave, | ||
| 89 | mpol=bind or mpol=preferred: | ||
| 90 | mpol_nodelist: nodelist suitable for parsing with nodelist_parse. | ||
| 91 | |||
| 92 | |||
| 81 | To specify the initial root directory you can use the following mount | 93 | To specify the initial root directory you can use the following mount |
| 82 | options: | 94 | options: |
| 83 | 95 | ||
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index ab4c3a9d51b8..f568102da1e8 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
| @@ -402,7 +402,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, | |||
| 402 | inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info; | 402 | inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info; |
| 403 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 403 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
| 404 | info = HUGETLBFS_I(inode); | 404 | info = HUGETLBFS_I(inode); |
| 405 | mpol_shared_policy_init(&info->policy); | 405 | mpol_shared_policy_init(&info->policy, MPOL_DEFAULT, NULL); |
| 406 | switch (mode & S_IFMT) { | 406 | switch (mode & S_IFMT) { |
| 407 | default: | 407 | default: |
| 408 | init_special_inode(inode, mode, dev); | 408 | init_special_inode(inode, mode, dev); |
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index c7ac77e873b3..d6a53ed6ab6c 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h | |||
| @@ -132,12 +132,8 @@ struct shared_policy { | |||
| 132 | spinlock_t lock; | 132 | spinlock_t lock; |
| 133 | }; | 133 | }; |
| 134 | 134 | ||
| 135 | static inline void mpol_shared_policy_init(struct shared_policy *info) | 135 | void mpol_shared_policy_init(struct shared_policy *info, int policy, |
| 136 | { | 136 | nodemask_t *nodes); |
| 137 | info->root = RB_ROOT; | ||
| 138 | spin_lock_init(&info->lock); | ||
| 139 | } | ||
| 140 | |||
| 141 | int mpol_set_shared_policy(struct shared_policy *info, | 137 | int mpol_set_shared_policy(struct shared_policy *info, |
| 142 | struct vm_area_struct *vma, | 138 | struct vm_area_struct *vma, |
| 143 | struct mempolicy *new); | 139 | struct mempolicy *new); |
| @@ -211,7 +207,8 @@ static inline int mpol_set_shared_policy(struct shared_policy *info, | |||
| 211 | return -EINVAL; | 207 | return -EINVAL; |
| 212 | } | 208 | } |
| 213 | 209 | ||
| 214 | static inline void mpol_shared_policy_init(struct shared_policy *info) | 210 | static inline void mpol_shared_policy_init(struct shared_policy *info, |
| 211 | int policy, nodemask_t *nodes) | ||
| 215 | { | 212 | { |
| 216 | } | 213 | } |
| 217 | 214 | ||
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index c3e598276e78..c057f0b32318 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h | |||
| @@ -26,6 +26,8 @@ struct shmem_sb_info { | |||
| 26 | unsigned long free_blocks; /* How many are left for allocation */ | 26 | unsigned long free_blocks; /* How many are left for allocation */ |
| 27 | unsigned long max_inodes; /* How many inodes are allowed */ | 27 | unsigned long max_inodes; /* How many inodes are allowed */ |
| 28 | unsigned long free_inodes; /* How many are left for allocation */ | 28 | unsigned long free_inodes; /* How many are left for allocation */ |
| 29 | int policy; /* Default NUMA memory alloc policy */ | ||
| 30 | nodemask_t policy_nodes; /* nodemask for preferred and bind */ | ||
| 29 | spinlock_t stat_lock; | 31 | spinlock_t stat_lock; |
| 30 | }; | 32 | }; |
| 31 | 33 | ||
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index b62cab575a84..3171f884d245 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
| @@ -1359,6 +1359,30 @@ restart: | |||
| 1359 | return 0; | 1359 | return 0; |
| 1360 | } | 1360 | } |
| 1361 | 1361 | ||
| 1362 | void mpol_shared_policy_init(struct shared_policy *info, int policy, | ||
| 1363 | nodemask_t *policy_nodes) | ||
| 1364 | { | ||
| 1365 | info->root = RB_ROOT; | ||
| 1366 | spin_lock_init(&info->lock); | ||
| 1367 | |||
| 1368 | if (policy != MPOL_DEFAULT) { | ||
| 1369 | struct mempolicy *newpol; | ||
| 1370 | |||
| 1371 | /* Falls back to MPOL_DEFAULT on any error */ | ||
| 1372 | newpol = mpol_new(policy, policy_nodes); | ||
| 1373 | if (!IS_ERR(newpol)) { | ||
| 1374 | /* Create pseudo-vma that contains just the policy */ | ||
| 1375 | struct vm_area_struct pvma; | ||
| 1376 | |||
| 1377 | memset(&pvma, 0, sizeof(struct vm_area_struct)); | ||
| 1378 | /* Policy covers entire file */ | ||
| 1379 | pvma.vm_end = TASK_SIZE; | ||
| 1380 | mpol_set_shared_policy(info, &pvma, newpol); | ||
| 1381 | mpol_free(newpol); | ||
| 1382 | } | ||
| 1383 | } | ||
| 1384 | } | ||
| 1385 | |||
| 1362 | int mpol_set_shared_policy(struct shared_policy *info, | 1386 | int mpol_set_shared_policy(struct shared_policy *info, |
| 1363 | struct vm_area_struct *vma, struct mempolicy *npol) | 1387 | struct vm_area_struct *vma, struct mempolicy *npol) |
| 1364 | { | 1388 | { |
diff --git a/mm/shmem.c b/mm/shmem.c index 343b3c0937e5..ce501bce1c2e 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
| @@ -1316,7 +1316,8 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) | |||
| 1316 | case S_IFREG: | 1316 | case S_IFREG: |
| 1317 | inode->i_op = &shmem_inode_operations; | 1317 | inode->i_op = &shmem_inode_operations; |
| 1318 | inode->i_fop = &shmem_file_operations; | 1318 | inode->i_fop = &shmem_file_operations; |
| 1319 | mpol_shared_policy_init(&info->policy); | 1319 | mpol_shared_policy_init(&info->policy, sbinfo->policy, |
| 1320 | &sbinfo->policy_nodes); | ||
| 1320 | break; | 1321 | break; |
| 1321 | case S_IFDIR: | 1322 | case S_IFDIR: |
| 1322 | inode->i_nlink++; | 1323 | inode->i_nlink++; |
| @@ -1330,7 +1331,8 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) | |||
| 1330 | * Must not load anything in the rbtree, | 1331 | * Must not load anything in the rbtree, |
| 1331 | * mpol_free_shared_policy will not be called. | 1332 | * mpol_free_shared_policy will not be called. |
| 1332 | */ | 1333 | */ |
| 1333 | mpol_shared_policy_init(&info->policy); | 1334 | mpol_shared_policy_init(&info->policy, MPOL_DEFAULT, |
| 1335 | NULL); | ||
| 1334 | break; | 1336 | break; |
| 1335 | } | 1337 | } |
| 1336 | } else if (sbinfo->max_inodes) { | 1338 | } else if (sbinfo->max_inodes) { |
| @@ -1843,7 +1845,9 @@ static struct inode_operations shmem_symlink_inode_operations = { | |||
| 1843 | .put_link = shmem_put_link, | 1845 | .put_link = shmem_put_link, |
| 1844 | }; | 1846 | }; |
| 1845 | 1847 | ||
| 1846 | static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, unsigned long *blocks, unsigned long *inodes) | 1848 | static int shmem_parse_options(char *options, int *mode, uid_t *uid, |
| 1849 | gid_t *gid, unsigned long *blocks, unsigned long *inodes, | ||
| 1850 | int *policy, nodemask_t *policy_nodes) | ||
| 1847 | { | 1851 | { |
| 1848 | char *this_char, *value, *rest; | 1852 | char *this_char, *value, *rest; |
| 1849 | 1853 | ||
| @@ -1897,6 +1901,19 @@ static int shmem_parse_options(char *options, int *mode, uid_t *uid, gid_t *gid, | |||
| 1897 | *gid = simple_strtoul(value,&rest,0); | 1901 | *gid = simple_strtoul(value,&rest,0); |
| 1898 | if (*rest) | 1902 | if (*rest) |
| 1899 | goto bad_val; | 1903 | goto bad_val; |
| 1904 | } else if (!strcmp(this_char,"mpol")) { | ||
| 1905 | if (!strcmp(value,"default")) | ||
| 1906 | *policy = MPOL_DEFAULT; | ||
| 1907 | else if (!strcmp(value,"preferred")) | ||
| 1908 | *policy = MPOL_PREFERRED; | ||
| 1909 | else if (!strcmp(value,"bind")) | ||
| 1910 | *policy = MPOL_BIND; | ||
| 1911 | else if (!strcmp(value,"interleave")) | ||
| 1912 | *policy = MPOL_INTERLEAVE; | ||
| 1913 | else | ||
| 1914 | goto bad_val; | ||
| 1915 | } else if (!strcmp(this_char,"mpol_nodelist")) { | ||
| 1916 | nodelist_parse(value, *policy_nodes); | ||
| 1900 | } else { | 1917 | } else { |
| 1901 | printk(KERN_ERR "tmpfs: Bad mount option %s\n", | 1918 | printk(KERN_ERR "tmpfs: Bad mount option %s\n", |
| 1902 | this_char); | 1919 | this_char); |
| @@ -1917,12 +1934,14 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) | |||
| 1917 | struct shmem_sb_info *sbinfo = SHMEM_SB(sb); | 1934 | struct shmem_sb_info *sbinfo = SHMEM_SB(sb); |
| 1918 | unsigned long max_blocks = sbinfo->max_blocks; | 1935 | unsigned long max_blocks = sbinfo->max_blocks; |
| 1919 | unsigned long max_inodes = sbinfo->max_inodes; | 1936 | unsigned long max_inodes = sbinfo->max_inodes; |
| 1937 | int policy = sbinfo->policy; | ||
| 1938 | nodemask_t policy_nodes = sbinfo->policy_nodes; | ||
| 1920 | unsigned long blocks; | 1939 | unsigned long blocks; |
| 1921 | unsigned long inodes; | 1940 | unsigned long inodes; |
| 1922 | int error = -EINVAL; | 1941 | int error = -EINVAL; |
| 1923 | 1942 | ||
| 1924 | if (shmem_parse_options(data, NULL, NULL, NULL, | 1943 | if (shmem_parse_options(data, NULL, NULL, NULL, &max_blocks, |
| 1925 | &max_blocks, &max_inodes)) | 1944 | &max_inodes, &policy, &policy_nodes)) |
| 1926 | return error; | 1945 | return error; |
| 1927 | 1946 | ||
| 1928 | spin_lock(&sbinfo->stat_lock); | 1947 | spin_lock(&sbinfo->stat_lock); |
| @@ -1948,6 +1967,8 @@ static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) | |||
| 1948 | sbinfo->free_blocks = max_blocks - blocks; | 1967 | sbinfo->free_blocks = max_blocks - blocks; |
| 1949 | sbinfo->max_inodes = max_inodes; | 1968 | sbinfo->max_inodes = max_inodes; |
| 1950 | sbinfo->free_inodes = max_inodes - inodes; | 1969 | sbinfo->free_inodes = max_inodes - inodes; |
| 1970 | sbinfo->policy = policy; | ||
| 1971 | sbinfo->policy_nodes = policy_nodes; | ||
| 1951 | out: | 1972 | out: |
| 1952 | spin_unlock(&sbinfo->stat_lock); | 1973 | spin_unlock(&sbinfo->stat_lock); |
| 1953 | return error; | 1974 | return error; |
| @@ -1972,6 +1993,8 @@ static int shmem_fill_super(struct super_block *sb, | |||
| 1972 | struct shmem_sb_info *sbinfo; | 1993 | struct shmem_sb_info *sbinfo; |
| 1973 | unsigned long blocks = 0; | 1994 | unsigned long blocks = 0; |
| 1974 | unsigned long inodes = 0; | 1995 | unsigned long inodes = 0; |
| 1996 | int policy = MPOL_DEFAULT; | ||
| 1997 | nodemask_t policy_nodes = node_online_map; | ||
| 1975 | 1998 | ||
| 1976 | #ifdef CONFIG_TMPFS | 1999 | #ifdef CONFIG_TMPFS |
| 1977 | /* | 2000 | /* |
| @@ -1984,8 +2007,8 @@ static int shmem_fill_super(struct super_block *sb, | |||
| 1984 | inodes = totalram_pages - totalhigh_pages; | 2007 | inodes = totalram_pages - totalhigh_pages; |
| 1985 | if (inodes > blocks) | 2008 | if (inodes > blocks) |
| 1986 | inodes = blocks; | 2009 | inodes = blocks; |
| 1987 | if (shmem_parse_options(data, &mode, &uid, &gid, | 2010 | if (shmem_parse_options(data, &mode, &uid, &gid, &blocks, |
| 1988 | &blocks, &inodes)) | 2011 | &inodes, &policy, &policy_nodes)) |
| 1989 | return -EINVAL; | 2012 | return -EINVAL; |
| 1990 | } | 2013 | } |
| 1991 | #else | 2014 | #else |
| @@ -2003,6 +2026,8 @@ static int shmem_fill_super(struct super_block *sb, | |||
| 2003 | sbinfo->free_blocks = blocks; | 2026 | sbinfo->free_blocks = blocks; |
| 2004 | sbinfo->max_inodes = inodes; | 2027 | sbinfo->max_inodes = inodes; |
| 2005 | sbinfo->free_inodes = inodes; | 2028 | sbinfo->free_inodes = inodes; |
| 2029 | sbinfo->policy = policy; | ||
| 2030 | sbinfo->policy_nodes = policy_nodes; | ||
| 2006 | 2031 | ||
| 2007 | sb->s_fs_info = sbinfo; | 2032 | sb->s_fs_info = sbinfo; |
| 2008 | sb->s_maxbytes = SHMEM_MAX_BYTES; | 2033 | sb->s_maxbytes = SHMEM_MAX_BYTES; |
