Skip to content

Commit d3da701

Browse files
RashmicaGmpe
authored andcommitted
powerpc/powernv: Allow memory that has been hot-removed to be hot-added
This patch allows the memory removed by memtrace to be readded to the kernel. So now you don't have to reboot your system to add the memory back to the kernel or to have a different amount of memory removed. Signed-off-by: Rashmica Gupta <[email protected]> Tested-by: Michael Neuling <[email protected]> Signed-off-by: Michael Ellerman <[email protected]>
1 parent 7c27a26 commit d3da701

File tree

1 file changed

+85
-7
lines changed

1 file changed

+85
-7
lines changed

arch/powerpc/platforms/powernv/memtrace.c

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,11 @@ static int memtrace_init_debugfs(void)
177177

178178
snprintf(ent->name, 16, "%08x", ent->nid);
179179
dir = debugfs_create_dir(ent->name, memtrace_debugfs_dir);
180-
if (!dir)
180+
if (!dir) {
181+
pr_err("Failed to create debugfs directory for node %d\n",
182+
ent->nid);
181183
return -1;
184+
}
182185

183186
ent->dir = dir;
184187
debugfs_create_file("trace", 0400, dir, ent, &memtrace_fops);
@@ -189,18 +192,93 @@ static int memtrace_init_debugfs(void)
189192
return ret;
190193
}
191194

195+
static int online_mem_block(struct memory_block *mem, void *arg)
196+
{
197+
return device_online(&mem->dev);
198+
}
199+
200+
/*
201+
* Iterate through the chunks of memory we have removed from the kernel
202+
* and attempt to add them back to the kernel.
203+
*/
204+
static int memtrace_online(void)
205+
{
206+
int i, ret = 0;
207+
struct memtrace_entry *ent;
208+
209+
for (i = memtrace_array_nr - 1; i >= 0; i--) {
210+
ent = &memtrace_array[i];
211+
212+
/* We have onlined this chunk previously */
213+
if (ent->nid == -1)
214+
continue;
215+
216+
/* Remove from io mappings */
217+
if (ent->mem) {
218+
iounmap(ent->mem);
219+
ent->mem = 0;
220+
}
221+
222+
if (add_memory(ent->nid, ent->start, ent->size)) {
223+
pr_err("Failed to add trace memory to node %d\n",
224+
ent->nid);
225+
ret += 1;
226+
continue;
227+
}
228+
229+
/*
230+
* If kernel isn't compiled with the auto online option
231+
* we need to online the memory ourselves.
232+
*/
233+
if (!memhp_auto_online) {
234+
walk_memory_range(PFN_DOWN(ent->start),
235+
PFN_UP(ent->start + ent->size - 1),
236+
NULL, online_mem_block);
237+
}
238+
239+
/*
240+
* Memory was added successfully so clean up references to it
241+
* so on reentry we can tell that this chunk was added.
242+
*/
243+
debugfs_remove_recursive(ent->dir);
244+
pr_info("Added trace memory back to node %d\n", ent->nid);
245+
ent->size = ent->start = ent->nid = -1;
246+
}
247+
if (ret)
248+
return ret;
249+
250+
/* If all chunks of memory were added successfully, reset globals */
251+
kfree(memtrace_array);
252+
memtrace_array = NULL;
253+
memtrace_size = 0;
254+
memtrace_array_nr = 0;
255+
return 0;
256+
}
257+
192258
static int memtrace_enable_set(void *data, u64 val)
193259
{
194-
if (memtrace_size)
260+
u64 bytes;
261+
262+
/*
263+
* Don't attempt to do anything if size isn't aligned to a memory
264+
* block or equal to zero.
265+
*/
266+
bytes = memory_block_size_bytes();
267+
if (val & (bytes - 1)) {
268+
pr_err("Value must be aligned with 0x%llx\n", bytes);
195269
return -EINVAL;
270+
}
196271

197-
if (!val)
198-
return -EINVAL;
272+
/* Re-add/online previously removed/offlined memory */
273+
if (memtrace_size) {
274+
if (memtrace_online())
275+
return -EAGAIN;
276+
}
199277

200-
/* Make sure size is aligned to a memory block */
201-
if (val & (memory_block_size_bytes() - 1))
202-
return -EINVAL;
278+
if (!val)
279+
return 0;
203280

281+
/* Offline and remove memory */
204282
if (memtrace_init_regions_runtime(val))
205283
return -EINVAL;
206284

0 commit comments

Comments
 (0)