Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 75884fb1 authored by KAMEZAWA Hiroyuki's avatar KAMEZAWA Hiroyuki Committed by Linus Torvalds
Browse files

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: default avatarKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: default avatarBadari Pulavarty <pbadari@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 48f13bf3
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -110,9 +110,6 @@ extern int allocate_resource(struct resource *root, struct resource *new,
int adjust_resource(struct resource *res, resource_size_t start,
		    resource_size_t size);

/* get registered SYSTEM_RAM resources in specified area */
extern int find_next_system_ram(struct resource *res);

/* Convenience shorthand with allocation */
#define request_region(start,n,name)	__request_region(&ioport_resource, (start), (n), (name))
#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name))
+8 −0
Original line number Diff line number Diff line
@@ -63,6 +63,14 @@ extern int online_pages(unsigned long, unsigned long);
extern int __add_pages(struct zone *zone, unsigned long start_pfn,
	unsigned long nr_pages);

/*
 * Walk thorugh all memory which is registered as resource.
 * arg is (start_pfn, nr_pages, private_arg_pointer)
 */
extern int walk_memory_resource(unsigned long start_pfn,
			unsigned long nr_pages, void *arg,
			int (*func)(unsigned long, unsigned long, void *));

#ifdef CONFIG_NUMA
extern int memory_add_physaddr_to_nid(u64 start);
#else
+25 −1
Original line number Diff line number Diff line
@@ -234,7 +234,7 @@ EXPORT_SYMBOL(release_resource);
 * the caller must specify res->start, res->end, res->flags.
 * If found, returns 0, res is overwritten, if not found, returns -1.
 */
int find_next_system_ram(struct resource *res)
static int find_next_system_ram(struct resource *res)
{
	resource_size_t start, end;
	struct resource *p;
@@ -267,6 +267,30 @@ int find_next_system_ram(struct resource *res)
		res->end = p->end;
	return 0;
}
int
walk_memory_resource(unsigned long start_pfn, unsigned long nr_pages, void *arg,
			int (*func)(unsigned long, unsigned long, void *))
{
	struct resource res;
	unsigned long pfn, len;
	u64 orig_end;
	int ret = -1;
	res.start = (u64) start_pfn << PAGE_SHIFT;
	res.end = ((u64)(start_pfn + nr_pages) << PAGE_SHIFT) - 1;
	res.flags = IORESOURCE_MEM;
	orig_end = res.end;
	while ((res.start < res.end) && (find_next_system_ram(&res) >= 0)) {
		pfn = (unsigned long)(res.start >> PAGE_SHIFT);
		len = (unsigned long)((res.end + 1 - res.start) >> PAGE_SHIFT);
		ret = (*func)(pfn, len, arg);
		if (ret)
			break;
		res.start = res.end + 1;
		res.end = orig_end;
	}
	return ret;
}

#endif

/*
+19 −26
Original line number Diff line number Diff line
@@ -161,14 +161,27 @@ static void grow_pgdat_span(struct pglist_data *pgdat,
					pgdat->node_start_pfn;
}

int online_pages(unsigned long pfn, unsigned long nr_pages)
static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
			void *arg)
{
	unsigned long i;
	unsigned long onlined_pages = *(unsigned long *)arg;
	struct page *page;
	if (PageReserved(pfn_to_page(start_pfn)))
		for (i = 0; i < nr_pages; i++) {
			page = pfn_to_page(start_pfn + i);
			online_page(page);
			onlined_pages++;
		}
	*(unsigned long *)arg = onlined_pages;
	return 0;
}


int online_pages(unsigned long pfn, unsigned long nr_pages)
{
	unsigned long flags;
	unsigned long onlined_pages = 0;
	struct resource res;
	u64 section_end;
	unsigned long start_pfn;
	struct zone *zone;
	int need_zonelists_rebuild = 0;

@@ -191,28 +204,8 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
	if (!populated_zone(zone))
		need_zonelists_rebuild = 1;

	res.start = (u64)pfn << PAGE_SHIFT;
	res.end = res.start + ((u64)nr_pages << PAGE_SHIFT) - 1;
	res.flags = IORESOURCE_MEM; /* we just need system ram */
	section_end = res.end;

	while ((res.start < res.end) && (find_next_system_ram(&res) >= 0)) {
		start_pfn = (unsigned long)(res.start >> PAGE_SHIFT);
		nr_pages = (unsigned long)
                           ((res.end + 1 - res.start) >> PAGE_SHIFT);

		if (PageReserved(pfn_to_page(start_pfn))) {
			/* this region's page is not onlined now */
			for (i = 0; i < nr_pages; i++) {
				struct page *page = pfn_to_page(start_pfn + i);
				online_page(page);
				onlined_pages++;
			}
		}

		res.start = res.end + 1;
		res.end = section_end;
	}
	walk_memory_resource(pfn, nr_pages, &onlined_pages,
		online_pages_range);
	zone->present_pages += onlined_pages;
	zone->zone_pgdat->node_present_pages += onlined_pages;