diff options
Diffstat (limited to 'mm/hugetlb.c')
| -rw-r--r-- | mm/hugetlb.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 36db012b38dd..eb7180db3033 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
| @@ -140,6 +140,8 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma, | |||
| 140 | return page; | 140 | return page; |
| 141 | 141 | ||
| 142 | fail: | 142 | fail: |
| 143 | if (vma->vm_flags & VM_MAYSHARE) | ||
| 144 | resv_huge_pages++; | ||
| 143 | spin_unlock(&hugetlb_lock); | 145 | spin_unlock(&hugetlb_lock); |
| 144 | return NULL; | 146 | return NULL; |
| 145 | } | 147 | } |
| @@ -172,6 +174,17 @@ static int __init hugetlb_setup(char *s) | |||
| 172 | } | 174 | } |
| 173 | __setup("hugepages=", hugetlb_setup); | 175 | __setup("hugepages=", hugetlb_setup); |
| 174 | 176 | ||
| 177 | static unsigned int cpuset_mems_nr(unsigned int *array) | ||
| 178 | { | ||
| 179 | int node; | ||
| 180 | unsigned int nr = 0; | ||
| 181 | |||
| 182 | for_each_node_mask(node, cpuset_current_mems_allowed) | ||
| 183 | nr += array[node]; | ||
| 184 | |||
| 185 | return nr; | ||
| 186 | } | ||
| 187 | |||
| 175 | #ifdef CONFIG_SYSCTL | 188 | #ifdef CONFIG_SYSCTL |
| 176 | static void update_and_free_page(struct page *page) | 189 | static void update_and_free_page(struct page *page) |
| 177 | { | 190 | { |
| @@ -817,6 +830,26 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to) | |||
| 817 | chg = region_chg(&inode->i_mapping->private_list, from, to); | 830 | chg = region_chg(&inode->i_mapping->private_list, from, to); |
| 818 | if (chg < 0) | 831 | if (chg < 0) |
| 819 | return chg; | 832 | return chg; |
| 833 | /* | ||
| 834 | * When cpuset is configured, it breaks the strict hugetlb page | ||
| 835 | * reservation as the accounting is done on a global variable. Such | ||
| 836 | * reservation is completely rubbish in the presence of cpuset because | ||
| 837 | * the reservation is not checked against page availability for the | ||
| 838 | * current cpuset. Application can still potentially OOM'ed by kernel | ||
| 839 | * with lack of free htlb page in cpuset that the task is in. | ||
| 840 | * Attempt to enforce strict accounting with cpuset is almost | ||
| 841 | * impossible (or too ugly) because cpuset is too fluid that | ||
| 842 | * task or memory node can be dynamically moved between cpusets. | ||
| 843 | * | ||
| 844 | * The change of semantics for shared hugetlb mapping with cpuset is | ||
| 845 | * undesirable. However, in order to preserve some of the semantics, | ||
| 846 | * we fall back to check against current free page availability as | ||
| 847 | * a best attempt and hopefully to minimize the impact of changing | ||
| 848 | * semantics that cpuset has. | ||
| 849 | */ | ||
| 850 | if (chg > cpuset_mems_nr(free_huge_pages_node)) | ||
| 851 | return -ENOMEM; | ||
| 852 | |||
| 820 | ret = hugetlb_acct_memory(chg); | 853 | ret = hugetlb_acct_memory(chg); |
| 821 | if (ret < 0) | 854 | if (ret < 0) |
| 822 | return ret; | 855 | return ret; |
