]> bbs.cooldavid.org Git - net-next-2.6.git/blame - mm/page_cgroup.c
mm: vmalloc fix lazy unmapping cache aliasing
[net-next-2.6.git] / mm / page_cgroup.c
CommitLineData
52d4b9ac
KH
1#include <linux/mm.h>
2#include <linux/mmzone.h>
3#include <linux/bootmem.h>
4#include <linux/bit_spinlock.h>
5#include <linux/page_cgroup.h>
6#include <linux/hash.h>
94b6da5a 7#include <linux/slab.h>
52d4b9ac 8#include <linux/memory.h>
4c821042 9#include <linux/vmalloc.h>
94b6da5a 10#include <linux/cgroup.h>
52d4b9ac
KH
11
12static void __meminit
13__init_page_cgroup(struct page_cgroup *pc, unsigned long pfn)
14{
15 pc->flags = 0;
16 pc->mem_cgroup = NULL;
17 pc->page = pfn_to_page(pfn);
18}
19static unsigned long total_usage;
20
21#if !defined(CONFIG_SPARSEMEM)
22
23
31168481 24void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat)
52d4b9ac
KH
25{
26 pgdat->node_page_cgroup = NULL;
27}
28
29struct page_cgroup *lookup_page_cgroup(struct page *page)
30{
31 unsigned long pfn = page_to_pfn(page);
32 unsigned long offset;
33 struct page_cgroup *base;
34
35 base = NODE_DATA(page_to_nid(page))->node_page_cgroup;
36 if (unlikely(!base))
37 return NULL;
38
39 offset = pfn - NODE_DATA(page_to_nid(page))->node_start_pfn;
40 return base + offset;
41}
42
43static int __init alloc_node_page_cgroup(int nid)
44{
45 struct page_cgroup *base, *pc;
46 unsigned long table_size;
47 unsigned long start_pfn, nr_pages, index;
48
49 start_pfn = NODE_DATA(nid)->node_start_pfn;
50 nr_pages = NODE_DATA(nid)->node_spanned_pages;
51
52 table_size = sizeof(struct page_cgroup) * nr_pages;
53
54 base = __alloc_bootmem_node_nopanic(NODE_DATA(nid),
55 table_size, PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
56 if (!base)
57 return -ENOMEM;
58 for (index = 0; index < nr_pages; index++) {
59 pc = base + index;
60 __init_page_cgroup(pc, start_pfn + index);
61 }
62 NODE_DATA(nid)->node_page_cgroup = base;
63 total_usage += table_size;
64 return 0;
65}
66
67void __init page_cgroup_init(void)
68{
69
70 int nid, fail;
71
94b6da5a
KH
72 if (mem_cgroup_subsys.disabled)
73 return;
74
52d4b9ac
KH
75 for_each_online_node(nid) {
76 fail = alloc_node_page_cgroup(nid);
77 if (fail)
78 goto fail;
79 }
80 printk(KERN_INFO "allocated %ld bytes of page_cgroup\n", total_usage);
81 printk(KERN_INFO "please try cgroup_disable=memory option if you"
82 " don't want\n");
83 return;
84fail:
85 printk(KERN_CRIT "allocation of page_cgroup was failed.\n");
86 printk(KERN_CRIT "please try cgroup_disable=memory boot option\n");
87 panic("Out of memory");
88}
89
90#else /* CONFIG_FLAT_NODE_MEM_MAP */
91
92struct page_cgroup *lookup_page_cgroup(struct page *page)
93{
94 unsigned long pfn = page_to_pfn(page);
95 struct mem_section *section = __pfn_to_section(pfn);
96
97 return section->page_cgroup + pfn;
98}
99
31168481
AV
100/* __alloc_bootmem...() is protected by !slab_available() */
101int __init_refok init_section_page_cgroup(unsigned long pfn)
52d4b9ac
KH
102{
103 struct mem_section *section;
104 struct page_cgroup *base, *pc;
105 unsigned long table_size;
106 int nid, index;
107
108 section = __pfn_to_section(pfn);
109
110 if (section->page_cgroup)
111 return 0;
112
113 nid = page_to_nid(pfn_to_page(pfn));
114
115 table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION;
94b6da5a
KH
116 if (slab_is_available()) {
117 base = kmalloc_node(table_size, GFP_KERNEL, nid);
118 if (!base)
119 base = vmalloc_node(table_size, nid);
120 } else {
121 base = __alloc_bootmem_node_nopanic(NODE_DATA(nid), table_size,
122 PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
123 }
52d4b9ac
KH
124
125 if (!base) {
126 printk(KERN_ERR "page cgroup allocation failure\n");
127 return -ENOMEM;
128 }
129
130 for (index = 0; index < PAGES_PER_SECTION; index++) {
131 pc = base + index;
132 __init_page_cgroup(pc, pfn + index);
133 }
134
135 section = __pfn_to_section(pfn);
136 section->page_cgroup = base - pfn;
137 total_usage += table_size;
138 return 0;
139}
140#ifdef CONFIG_MEMORY_HOTPLUG
141void __free_page_cgroup(unsigned long pfn)
142{
143 struct mem_section *ms;
144 struct page_cgroup *base;
145
146 ms = __pfn_to_section(pfn);
147 if (!ms || !ms->page_cgroup)
148 return;
149 base = ms->page_cgroup + pfn;
94b6da5a 150 if (is_vmalloc_addr(base)) {
52d4b9ac 151 vfree(base);
94b6da5a
KH
152 ms->page_cgroup = NULL;
153 } else {
154 struct page *page = virt_to_page(base);
155 if (!PageReserved(page)) { /* Is bootmem ? */
156 kfree(base);
157 ms->page_cgroup = NULL;
158 }
159 }
52d4b9ac
KH
160}
161
31168481 162int __meminit online_page_cgroup(unsigned long start_pfn,
52d4b9ac
KH
163 unsigned long nr_pages,
164 int nid)
165{
166 unsigned long start, end, pfn;
167 int fail = 0;
168
33c5d3d6 169 start = start_pfn & ~(PAGES_PER_SECTION - 1);
52d4b9ac
KH
170 end = ALIGN(start_pfn + nr_pages, PAGES_PER_SECTION);
171
172 for (pfn = start; !fail && pfn < end; pfn += PAGES_PER_SECTION) {
173 if (!pfn_present(pfn))
174 continue;
175 fail = init_section_page_cgroup(pfn);
176 }
177 if (!fail)
178 return 0;
179
180 /* rollback */
181 for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION)
182 __free_page_cgroup(pfn);
183
184 return -ENOMEM;
185}
186
31168481 187int __meminit offline_page_cgroup(unsigned long start_pfn,
52d4b9ac
KH
188 unsigned long nr_pages, int nid)
189{
190 unsigned long start, end, pfn;
191
33c5d3d6 192 start = start_pfn & ~(PAGES_PER_SECTION - 1);
52d4b9ac
KH
193 end = ALIGN(start_pfn + nr_pages, PAGES_PER_SECTION);
194
195 for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION)
196 __free_page_cgroup(pfn);
197 return 0;
198
199}
200
31168481 201static int __meminit page_cgroup_callback(struct notifier_block *self,
52d4b9ac
KH
202 unsigned long action, void *arg)
203{
204 struct memory_notify *mn = arg;
205 int ret = 0;
206 switch (action) {
207 case MEM_GOING_ONLINE:
208 ret = online_page_cgroup(mn->start_pfn,
209 mn->nr_pages, mn->status_change_nid);
210 break;
211 case MEM_CANCEL_ONLINE:
212 case MEM_OFFLINE:
213 offline_page_cgroup(mn->start_pfn,
214 mn->nr_pages, mn->status_change_nid);
215 break;
216 case MEM_GOING_OFFLINE:
217 break;
218 case MEM_ONLINE:
219 case MEM_CANCEL_OFFLINE:
220 break;
221 }
222 ret = notifier_from_errno(ret);
223 return ret;
224}
225
226#endif
227
228void __init page_cgroup_init(void)
229{
230 unsigned long pfn;
231 int fail = 0;
232
94b6da5a
KH
233 if (mem_cgroup_subsys.disabled)
234 return;
235
52d4b9ac
KH
236 for (pfn = 0; !fail && pfn < max_pfn; pfn += PAGES_PER_SECTION) {
237 if (!pfn_present(pfn))
238 continue;
239 fail = init_section_page_cgroup(pfn);
240 }
241 if (fail) {
242 printk(KERN_CRIT "try cgroup_disable=memory boot option\n");
243 panic("Out of memory");
244 } else {
245 hotplug_memory_notifier(page_cgroup_callback, 0);
246 }
247 printk(KERN_INFO "allocated %ld bytes of page_cgroup\n", total_usage);
248 printk(KERN_INFO "please try cgroup_disable=memory option if you don't"
249 " want\n");
250}
251
31168481 252void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat)
52d4b9ac
KH
253{
254 return;
255}
256
257#endif