diff options
Diffstat (limited to 'mm/memory.c')
| -rw-r--r-- | mm/memory.c | 47 |
1 files changed, 42 insertions, 5 deletions
diff --git a/mm/memory.c b/mm/memory.c index 9d073fa0a2d0..0ba224ea6ba4 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #include <linux/delayacct.h> | 50 | #include <linux/delayacct.h> |
| 51 | #include <linux/init.h> | 51 | #include <linux/init.h> |
| 52 | #include <linux/writeback.h> | 52 | #include <linux/writeback.h> |
| 53 | #include <linux/memcontrol.h> | ||
| 53 | 54 | ||
| 54 | #include <asm/pgalloc.h> | 55 | #include <asm/pgalloc.h> |
| 55 | #include <asm/uaccess.h> | 56 | #include <asm/uaccess.h> |
| @@ -1144,16 +1145,20 @@ static int insert_page(struct mm_struct *mm, unsigned long addr, struct page *pa | |||
| 1144 | { | 1145 | { |
| 1145 | int retval; | 1146 | int retval; |
| 1146 | pte_t *pte; | 1147 | pte_t *pte; |
| 1147 | spinlock_t *ptl; | 1148 | spinlock_t *ptl; |
| 1149 | |||
| 1150 | retval = mem_cgroup_charge(page, mm); | ||
| 1151 | if (retval) | ||
| 1152 | goto out; | ||
| 1148 | 1153 | ||
| 1149 | retval = -EINVAL; | 1154 | retval = -EINVAL; |
| 1150 | if (PageAnon(page)) | 1155 | if (PageAnon(page)) |
| 1151 | goto out; | 1156 | goto out_uncharge; |
| 1152 | retval = -ENOMEM; | 1157 | retval = -ENOMEM; |
| 1153 | flush_dcache_page(page); | 1158 | flush_dcache_page(page); |
| 1154 | pte = get_locked_pte(mm, addr, &ptl); | 1159 | pte = get_locked_pte(mm, addr, &ptl); |
| 1155 | if (!pte) | 1160 | if (!pte) |
| 1156 | goto out; | 1161 | goto out_uncharge; |
| 1157 | retval = -EBUSY; | 1162 | retval = -EBUSY; |
| 1158 | if (!pte_none(*pte)) | 1163 | if (!pte_none(*pte)) |
| 1159 | goto out_unlock; | 1164 | goto out_unlock; |
| @@ -1165,8 +1170,12 @@ static int insert_page(struct mm_struct *mm, unsigned long addr, struct page *pa | |||
| 1165 | set_pte_at(mm, addr, pte, mk_pte(page, prot)); | 1170 | set_pte_at(mm, addr, pte, mk_pte(page, prot)); |
| 1166 | 1171 | ||
| 1167 | retval = 0; | 1172 | retval = 0; |
| 1173 | pte_unmap_unlock(pte, ptl); | ||
| 1174 | return retval; | ||
| 1168 | out_unlock: | 1175 | out_unlock: |
| 1169 | pte_unmap_unlock(pte, ptl); | 1176 | pte_unmap_unlock(pte, ptl); |
| 1177 | out_uncharge: | ||
| 1178 | mem_cgroup_uncharge_page(page); | ||
| 1170 | out: | 1179 | out: |
| 1171 | return retval; | 1180 | return retval; |
| 1172 | } | 1181 | } |
| @@ -1641,6 +1650,9 @@ gotten: | |||
| 1641 | cow_user_page(new_page, old_page, address, vma); | 1650 | cow_user_page(new_page, old_page, address, vma); |
| 1642 | __SetPageUptodate(new_page); | 1651 | __SetPageUptodate(new_page); |
| 1643 | 1652 | ||
| 1653 | if (mem_cgroup_charge(new_page, mm)) | ||
| 1654 | goto oom_free_new; | ||
| 1655 | |||
| 1644 | /* | 1656 | /* |
| 1645 | * Re-check the pte - we dropped the lock | 1657 | * Re-check the pte - we dropped the lock |
| 1646 | */ | 1658 | */ |
| @@ -1672,7 +1684,9 @@ gotten: | |||
| 1672 | /* Free the old page.. */ | 1684 | /* Free the old page.. */ |
| 1673 | new_page = old_page; | 1685 | new_page = old_page; |
| 1674 | ret |= VM_FAULT_WRITE; | 1686 | ret |= VM_FAULT_WRITE; |
| 1675 | } | 1687 | } else |
| 1688 | mem_cgroup_uncharge_page(new_page); | ||
| 1689 | |||
| 1676 | if (new_page) | 1690 | if (new_page) |
| 1677 | page_cache_release(new_page); | 1691 | page_cache_release(new_page); |
| 1678 | if (old_page) | 1692 | if (old_page) |
| @@ -1696,6 +1710,8 @@ unlock: | |||
| 1696 | put_page(dirty_page); | 1710 | put_page(dirty_page); |
| 1697 | } | 1711 | } |
| 1698 | return ret; | 1712 | return ret; |
| 1713 | oom_free_new: | ||
| 1714 | __free_page(new_page); | ||
| 1699 | oom: | 1715 | oom: |
| 1700 | if (old_page) | 1716 | if (old_page) |
| 1701 | page_cache_release(old_page); | 1717 | page_cache_release(old_page); |
| @@ -2036,6 +2052,12 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 2036 | count_vm_event(PGMAJFAULT); | 2052 | count_vm_event(PGMAJFAULT); |
| 2037 | } | 2053 | } |
| 2038 | 2054 | ||
| 2055 | if (mem_cgroup_charge(page, mm)) { | ||
| 2056 | delayacct_clear_flag(DELAYACCT_PF_SWAPIN); | ||
| 2057 | ret = VM_FAULT_OOM; | ||
| 2058 | goto out; | ||
| 2059 | } | ||
| 2060 | |||
| 2039 | mark_page_accessed(page); | 2061 | mark_page_accessed(page); |
| 2040 | lock_page(page); | 2062 | lock_page(page); |
| 2041 | delayacct_clear_flag(DELAYACCT_PF_SWAPIN); | 2063 | delayacct_clear_flag(DELAYACCT_PF_SWAPIN); |
| @@ -2073,8 +2095,10 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 2073 | if (write_access) { | 2095 | if (write_access) { |
| 2074 | /* XXX: We could OR the do_wp_page code with this one? */ | 2096 | /* XXX: We could OR the do_wp_page code with this one? */ |
| 2075 | if (do_wp_page(mm, vma, address, | 2097 | if (do_wp_page(mm, vma, address, |
| 2076 | page_table, pmd, ptl, pte) & VM_FAULT_OOM) | 2098 | page_table, pmd, ptl, pte) & VM_FAULT_OOM) { |
| 2099 | mem_cgroup_uncharge_page(page); | ||
| 2077 | ret = VM_FAULT_OOM; | 2100 | ret = VM_FAULT_OOM; |
| 2101 | } | ||
| 2078 | goto out; | 2102 | goto out; |
| 2079 | } | 2103 | } |
| 2080 | 2104 | ||
| @@ -2085,6 +2109,7 @@ unlock: | |||
| 2085 | out: | 2109 | out: |
| 2086 | return ret; | 2110 | return ret; |
| 2087 | out_nomap: | 2111 | out_nomap: |
| 2112 | mem_cgroup_uncharge_page(page); | ||
| 2088 | pte_unmap_unlock(page_table, ptl); | 2113 | pte_unmap_unlock(page_table, ptl); |
| 2089 | unlock_page(page); | 2114 | unlock_page(page); |
| 2090 | page_cache_release(page); | 2115 | page_cache_release(page); |
| @@ -2114,6 +2139,9 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 2114 | goto oom; | 2139 | goto oom; |
| 2115 | __SetPageUptodate(page); | 2140 | __SetPageUptodate(page); |
| 2116 | 2141 | ||
| 2142 | if (mem_cgroup_charge(page, mm)) | ||
| 2143 | goto oom_free_page; | ||
| 2144 | |||
| 2117 | entry = mk_pte(page, vma->vm_page_prot); | 2145 | entry = mk_pte(page, vma->vm_page_prot); |
| 2118 | entry = maybe_mkwrite(pte_mkdirty(entry), vma); | 2146 | entry = maybe_mkwrite(pte_mkdirty(entry), vma); |
| 2119 | 2147 | ||
| @@ -2131,8 +2159,11 @@ unlock: | |||
| 2131 | pte_unmap_unlock(page_table, ptl); | 2159 | pte_unmap_unlock(page_table, ptl); |
| 2132 | return 0; | 2160 | return 0; |
| 2133 | release: | 2161 | release: |
| 2162 | mem_cgroup_uncharge_page(page); | ||
| 2134 | page_cache_release(page); | 2163 | page_cache_release(page); |
| 2135 | goto unlock; | 2164 | goto unlock; |
| 2165 | oom_free_page: | ||
| 2166 | __free_page(page); | ||
| 2136 | oom: | 2167 | oom: |
| 2137 | return VM_FAULT_OOM; | 2168 | return VM_FAULT_OOM; |
| 2138 | } | 2169 | } |
| @@ -2246,6 +2277,11 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 2246 | 2277 | ||
| 2247 | } | 2278 | } |
| 2248 | 2279 | ||
| 2280 | if (mem_cgroup_charge(page, mm)) { | ||
| 2281 | ret = VM_FAULT_OOM; | ||
| 2282 | goto out; | ||
| 2283 | } | ||
| 2284 | |||
| 2249 | page_table = pte_offset_map_lock(mm, pmd, address, &ptl); | 2285 | page_table = pte_offset_map_lock(mm, pmd, address, &ptl); |
| 2250 | 2286 | ||
| 2251 | /* | 2287 | /* |
| @@ -2281,6 +2317,7 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma, | |||
| 2281 | /* no need to invalidate: a not-present page won't be cached */ | 2317 | /* no need to invalidate: a not-present page won't be cached */ |
| 2282 | update_mmu_cache(vma, address, entry); | 2318 | update_mmu_cache(vma, address, entry); |
| 2283 | } else { | 2319 | } else { |
| 2320 | mem_cgroup_uncharge_page(page); | ||
| 2284 | if (anon) | 2321 | if (anon) |
| 2285 | page_cache_release(page); | 2322 | page_cache_release(page); |
| 2286 | else | 2323 | else |
