@@ -177,8 +177,11 @@ static int memtrace_init_debugfs(void)
177
177
178
178
snprintf (ent -> name , 16 , "%08x" , ent -> nid );
179
179
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 );
181
183
return -1 ;
184
+ }
182
185
183
186
ent -> dir = dir ;
184
187
debugfs_create_file ("trace" , 0400 , dir , ent , & memtrace_fops );
@@ -189,18 +192,93 @@ static int memtrace_init_debugfs(void)
189
192
return ret ;
190
193
}
191
194
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
+
192
258
static int memtrace_enable_set (void * data , u64 val )
193
259
{
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 );
195
269
return - EINVAL ;
270
+ }
196
271
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
+ }
199
277
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 ;
203
280
281
+ /* Offline and remove memory */
204
282
if (memtrace_init_regions_runtime (val ))
205
283
return - EINVAL ;
206
284
0 commit comments