Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

memory unplug: memory hotplug cleanup

A clean up patch for "scanning memory resource [start, end)" operation.

Now, find_next_system_ram() function is used in memory hotplug, but this
interface is not easy to use and codes are complicated.

This patch adds walk_memory_resouce(start,len,arg,func) function.
The function 'func' is called per valid memory resouce range in [start,pfn).

[pbadari@us.ibm.com: Error handling in walk_memory_resource()]
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Badari Pulavarty <pbadari@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

KAMEZAWA Hiroyuki and committed by
Linus Torvalds
75884fb1 48f13bf3

+52 -30
-3
include/linux/ioport.h
··· 110 110 int adjust_resource(struct resource *res, resource_size_t start, 111 111 resource_size_t size); 112 112 113 - /* get registered SYSTEM_RAM resources in specified area */ 114 - extern int find_next_system_ram(struct resource *res); 115 - 116 113 /* Convenience shorthand with allocation */ 117 114 #define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) 118 115 #define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))
+8
include/linux/memory_hotplug.h
··· 63 63 extern int __add_pages(struct zone *zone, unsigned long start_pfn, 64 64 unsigned long nr_pages); 65 65 66 + /* 67 + * Walk thorugh all memory which is registered as resource. 68 + * arg is (start_pfn, nr_pages, private_arg_pointer) 69 + */ 70 + extern int walk_memory_resource(unsigned long start_pfn, 71 + unsigned long nr_pages, void *arg, 72 + int (*func)(unsigned long, unsigned long, void *)); 73 + 66 74 #ifdef CONFIG_NUMA 67 75 extern int memory_add_physaddr_to_nid(u64 start); 68 76 #else
+25 -1
kernel/resource.c
··· 234 234 * the caller must specify res->start, res->end, res->flags. 235 235 * If found, returns 0, res is overwritten, if not found, returns -1. 236 236 */ 237 - int find_next_system_ram(struct resource *res) 237 + static int find_next_system_ram(struct resource *res) 238 238 { 239 239 resource_size_t start, end; 240 240 struct resource *p; ··· 267 267 res->end = p->end; 268 268 return 0; 269 269 } 270 + int 271 + walk_memory_resource(unsigned long start_pfn, unsigned long nr_pages, void *arg, 272 + int (*func)(unsigned long, unsigned long, void *)) 273 + { 274 + struct resource res; 275 + unsigned long pfn, len; 276 + u64 orig_end; 277 + int ret = -1; 278 + res.start = (u64) start_pfn << PAGE_SHIFT; 279 + res.end = ((u64)(start_pfn + nr_pages) << PAGE_SHIFT) - 1; 280 + res.flags = IORESOURCE_MEM; 281 + orig_end = res.end; 282 + while ((res.start < res.end) && (find_next_system_ram(&res) >= 0)) { 283 + pfn = (unsigned long)(res.start >> PAGE_SHIFT); 284 + len = (unsigned long)((res.end + 1 - res.start) >> PAGE_SHIFT); 285 + ret = (*func)(pfn, len, arg); 286 + if (ret) 287 + break; 288 + res.start = res.end + 1; 289 + res.end = orig_end; 290 + } 291 + return ret; 292 + } 293 + 270 294 #endif 271 295 272 296 /*
+19 -26
mm/memory_hotplug.c
··· 161 161 pgdat->node_start_pfn; 162 162 } 163 163 164 - int online_pages(unsigned long pfn, unsigned long nr_pages) 164 + static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages, 165 + void *arg) 165 166 { 166 167 unsigned long i; 168 + unsigned long onlined_pages = *(unsigned long *)arg; 169 + struct page *page; 170 + if (PageReserved(pfn_to_page(start_pfn))) 171 + for (i = 0; i < nr_pages; i++) { 172 + page = pfn_to_page(start_pfn + i); 173 + online_page(page); 174 + onlined_pages++; 175 + } 176 + *(unsigned long *)arg = onlined_pages; 177 + return 0; 178 + } 179 + 180 + 181 + int online_pages(unsigned long pfn, unsigned long nr_pages) 182 + { 167 183 unsigned long flags; 168 184 unsigned long onlined_pages = 0; 169 - struct resource res; 170 - u64 section_end; 171 - unsigned long start_pfn; 172 185 struct zone *zone; 173 186 int need_zonelists_rebuild = 0; 174 187 ··· 204 191 if (!populated_zone(zone)) 205 192 need_zonelists_rebuild = 1; 206 193 207 - res.start = (u64)pfn << PAGE_SHIFT; 208 - res.end = res.start + ((u64)nr_pages << PAGE_SHIFT) - 1; 209 - res.flags = IORESOURCE_MEM; /* we just need system ram */ 210 - section_end = res.end; 211 - 212 - while ((res.start < res.end) && (find_next_system_ram(&res) >= 0)) { 213 - start_pfn = (unsigned long)(res.start >> PAGE_SHIFT); 214 - nr_pages = (unsigned long) 215 - ((res.end + 1 - res.start) >> PAGE_SHIFT); 216 - 217 - if (PageReserved(pfn_to_page(start_pfn))) { 218 - /* this region's page is not onlined now */ 219 - for (i = 0; i < nr_pages; i++) { 220 - struct page *page = pfn_to_page(start_pfn + i); 221 - online_page(page); 222 - onlined_pages++; 223 - } 224 - } 225 - 226 - res.start = res.end + 1; 227 - res.end = section_end; 228 - } 194 + walk_memory_resource(pfn, nr_pages, &onlined_pages, 195 + online_pages_range); 229 196 zone->present_pages += onlined_pages; 230 197 zone->zone_pgdat->node_present_pages += onlined_pages; 231 198