aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page_cgroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/page_cgroup.c')
-rw-r--r--mm/page_cgroup.c63
1 files changed, 41 insertions, 22 deletions
diff --git a/mm/page_cgroup.c b/mm/page_cgroup.c
index f59d797dc5a9..ab27ff750519 100644
--- a/mm/page_cgroup.c
+++ b/mm/page_cgroup.c
@@ -21,7 +21,7 @@ static unsigned long total_usage;
21#if !defined(CONFIG_SPARSEMEM) 21#if !defined(CONFIG_SPARSEMEM)
22 22
23 23
24void __init pgdat_page_cgroup_init(struct pglist_data *pgdat) 24void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat)
25{ 25{
26 pgdat->node_page_cgroup = NULL; 26 pgdat->node_page_cgroup = NULL;
27} 27}
@@ -49,6 +49,9 @@ static int __init alloc_node_page_cgroup(int nid)
49 start_pfn = NODE_DATA(nid)->node_start_pfn; 49 start_pfn = NODE_DATA(nid)->node_start_pfn;
50 nr_pages = NODE_DATA(nid)->node_spanned_pages; 50 nr_pages = NODE_DATA(nid)->node_spanned_pages;
51 51
52 if (!nr_pages)
53 return 0;
54
52 table_size = sizeof(struct page_cgroup) * nr_pages; 55 table_size = sizeof(struct page_cgroup) * nr_pages;
53 56
54 base = __alloc_bootmem_node_nopanic(NODE_DATA(nid), 57 base = __alloc_bootmem_node_nopanic(NODE_DATA(nid),
@@ -97,7 +100,8 @@ struct page_cgroup *lookup_page_cgroup(struct page *page)
97 return section->page_cgroup + pfn; 100 return section->page_cgroup + pfn;
98} 101}
99 102
100int __meminit init_section_page_cgroup(unsigned long pfn) 103/* __alloc_bootmem...() is protected by !slab_available() */
104int __init_refok init_section_page_cgroup(unsigned long pfn)
101{ 105{
102 struct mem_section *section; 106 struct mem_section *section;
103 struct page_cgroup *base, *pc; 107 struct page_cgroup *base, *pc;
@@ -106,19 +110,29 @@ int __meminit init_section_page_cgroup(unsigned long pfn)
106 110
107 section = __pfn_to_section(pfn); 111 section = __pfn_to_section(pfn);
108 112
109 if (section->page_cgroup) 113 if (!section->page_cgroup) {
110 return 0; 114 nid = page_to_nid(pfn_to_page(pfn));
111 115 table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION;
112 nid = page_to_nid(pfn_to_page(pfn)); 116 if (slab_is_available()) {
113 117 base = kmalloc_node(table_size, GFP_KERNEL, nid);
114 table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION; 118 if (!base)
115 if (slab_is_available()) { 119 base = vmalloc_node(table_size, nid);
116 base = kmalloc_node(table_size, GFP_KERNEL, nid); 120 } else {
117 if (!base) 121 base = __alloc_bootmem_node_nopanic(NODE_DATA(nid),
118 base = vmalloc_node(table_size, nid); 122 table_size,
119 } else {
120 base = __alloc_bootmem_node_nopanic(NODE_DATA(nid), table_size,
121 PAGE_SIZE, __pa(MAX_DMA_ADDRESS)); 123 PAGE_SIZE, __pa(MAX_DMA_ADDRESS));
124 }
125 } else {
126 /*
127 * We don't have to allocate page_cgroup again, but
128 * address of memmap may be changed. So, we have to initialize
129 * again.
130 */
131 base = section->page_cgroup + pfn;
132 table_size = 0;
133 /* check address of memmap is changed or not. */
134 if (base->page == pfn_to_page(pfn))
135 return 0;
122 } 136 }
123 137
124 if (!base) { 138 if (!base) {
@@ -158,14 +172,14 @@ void __free_page_cgroup(unsigned long pfn)
158 } 172 }
159} 173}
160 174
161int online_page_cgroup(unsigned long start_pfn, 175int __meminit online_page_cgroup(unsigned long start_pfn,
162 unsigned long nr_pages, 176 unsigned long nr_pages,
163 int nid) 177 int nid)
164{ 178{
165 unsigned long start, end, pfn; 179 unsigned long start, end, pfn;
166 int fail = 0; 180 int fail = 0;
167 181
168 start = start_pfn & (PAGES_PER_SECTION - 1); 182 start = start_pfn & ~(PAGES_PER_SECTION - 1);
169 end = ALIGN(start_pfn + nr_pages, PAGES_PER_SECTION); 183 end = ALIGN(start_pfn + nr_pages, PAGES_PER_SECTION);
170 184
171 for (pfn = start; !fail && pfn < end; pfn += PAGES_PER_SECTION) { 185 for (pfn = start; !fail && pfn < end; pfn += PAGES_PER_SECTION) {
@@ -183,12 +197,12 @@ int online_page_cgroup(unsigned long start_pfn,
183 return -ENOMEM; 197 return -ENOMEM;
184} 198}
185 199
186int offline_page_cgroup(unsigned long start_pfn, 200int __meminit offline_page_cgroup(unsigned long start_pfn,
187 unsigned long nr_pages, int nid) 201 unsigned long nr_pages, int nid)
188{ 202{
189 unsigned long start, end, pfn; 203 unsigned long start, end, pfn;
190 204
191 start = start_pfn & (PAGES_PER_SECTION - 1); 205 start = start_pfn & ~(PAGES_PER_SECTION - 1);
192 end = ALIGN(start_pfn + nr_pages, PAGES_PER_SECTION); 206 end = ALIGN(start_pfn + nr_pages, PAGES_PER_SECTION);
193 207
194 for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION) 208 for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION)
@@ -197,7 +211,7 @@ int offline_page_cgroup(unsigned long start_pfn,
197 211
198} 212}
199 213
200static int page_cgroup_callback(struct notifier_block *self, 214static int __meminit page_cgroup_callback(struct notifier_block *self,
201 unsigned long action, void *arg) 215 unsigned long action, void *arg)
202{ 216{
203 struct memory_notify *mn = arg; 217 struct memory_notify *mn = arg;
@@ -207,18 +221,23 @@ static int page_cgroup_callback(struct notifier_block *self,
207 ret = online_page_cgroup(mn->start_pfn, 221 ret = online_page_cgroup(mn->start_pfn,
208 mn->nr_pages, mn->status_change_nid); 222 mn->nr_pages, mn->status_change_nid);
209 break; 223 break;
210 case MEM_CANCEL_ONLINE:
211 case MEM_OFFLINE: 224 case MEM_OFFLINE:
212 offline_page_cgroup(mn->start_pfn, 225 offline_page_cgroup(mn->start_pfn,
213 mn->nr_pages, mn->status_change_nid); 226 mn->nr_pages, mn->status_change_nid);
214 break; 227 break;
228 case MEM_CANCEL_ONLINE:
215 case MEM_GOING_OFFLINE: 229 case MEM_GOING_OFFLINE:
216 break; 230 break;
217 case MEM_ONLINE: 231 case MEM_ONLINE:
218 case MEM_CANCEL_OFFLINE: 232 case MEM_CANCEL_OFFLINE:
219 break; 233 break;
220 } 234 }
221 ret = notifier_from_errno(ret); 235
236 if (ret)
237 ret = notifier_from_errno(ret);
238 else
239 ret = NOTIFY_OK;
240
222 return ret; 241 return ret;
223} 242}
224 243
@@ -248,7 +267,7 @@ void __init page_cgroup_init(void)
248 " want\n"); 267 " want\n");
249} 268}
250 269
251void __init pgdat_page_cgroup_init(struct pglist_data *pgdat) 270void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat)
252{ 271{
253 return; 272 return;
254} 273}