diff options
Diffstat (limited to 'mm/memory_hotplug.c')
-rw-r--r-- | mm/memory_hotplug.c | 55 |
1 files changed, 55 insertions, 0 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 0fb330271271..d5094929766d 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c | |||
@@ -101,6 +101,25 @@ static int __add_section(struct zone *zone, unsigned long phys_start_pfn) | |||
101 | return register_new_memory(__pfn_to_section(phys_start_pfn)); | 101 | return register_new_memory(__pfn_to_section(phys_start_pfn)); |
102 | } | 102 | } |
103 | 103 | ||
104 | static int __remove_section(struct zone *zone, struct mem_section *ms) | ||
105 | { | ||
106 | unsigned long flags; | ||
107 | struct pglist_data *pgdat = zone->zone_pgdat; | ||
108 | int ret = -EINVAL; | ||
109 | |||
110 | if (!valid_section(ms)) | ||
111 | return ret; | ||
112 | |||
113 | ret = unregister_memory_section(ms); | ||
114 | if (ret) | ||
115 | return ret; | ||
116 | |||
117 | pgdat_resize_lock(pgdat, &flags); | ||
118 | sparse_remove_one_section(zone, ms); | ||
119 | pgdat_resize_unlock(pgdat, &flags); | ||
120 | return 0; | ||
121 | } | ||
122 | |||
104 | /* | 123 | /* |
105 | * Reasonably generic function for adding memory. It is | 124 | * Reasonably generic function for adding memory. It is |
106 | * expected that archs that support memory hotplug will | 125 | * expected that archs that support memory hotplug will |
@@ -134,6 +153,42 @@ int __add_pages(struct zone *zone, unsigned long phys_start_pfn, | |||
134 | } | 153 | } |
135 | EXPORT_SYMBOL_GPL(__add_pages); | 154 | EXPORT_SYMBOL_GPL(__add_pages); |
136 | 155 | ||
156 | /** | ||
157 | * __remove_pages() - remove sections of pages from a zone | ||
158 | * @zone: zone from which pages need to be removed | ||
159 | * @phys_start_pfn: starting pageframe (must be aligned to start of a section) | ||
160 | * @nr_pages: number of pages to remove (must be multiple of section size) | ||
161 | * | ||
162 | * Generic helper function to remove section mappings and sysfs entries | ||
163 | * for the section of the memory we are removing. Caller needs to make | ||
164 | * sure that pages are marked reserved and zones are adjust properly by | ||
165 | * calling offline_pages(). | ||
166 | */ | ||
167 | int __remove_pages(struct zone *zone, unsigned long phys_start_pfn, | ||
168 | unsigned long nr_pages) | ||
169 | { | ||
170 | unsigned long i, ret = 0; | ||
171 | int sections_to_remove; | ||
172 | |||
173 | /* | ||
174 | * We can only remove entire sections | ||
175 | */ | ||
176 | BUG_ON(phys_start_pfn & ~PAGE_SECTION_MASK); | ||
177 | BUG_ON(nr_pages % PAGES_PER_SECTION); | ||
178 | |||
179 | release_mem_region(phys_start_pfn << PAGE_SHIFT, nr_pages * PAGE_SIZE); | ||
180 | |||
181 | sections_to_remove = nr_pages / PAGES_PER_SECTION; | ||
182 | for (i = 0; i < sections_to_remove; i++) { | ||
183 | unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION; | ||
184 | ret = __remove_section(zone, __pfn_to_section(pfn)); | ||
185 | if (ret) | ||
186 | break; | ||
187 | } | ||
188 | return ret; | ||
189 | } | ||
190 | EXPORT_SYMBOL_GPL(__remove_pages); | ||
191 | |||
137 | static void grow_zone_span(struct zone *zone, | 192 | static void grow_zone_span(struct zone *zone, |
138 | unsigned long start_pfn, unsigned long end_pfn) | 193 | unsigned long start_pfn, unsigned long end_pfn) |
139 | { | 194 | { |