aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorMichael Holzheu <holzheu@linux.vnet.ibm.com>2015-04-01 12:49:11 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2015-04-15 06:23:49 -0400
commit8741ce6d114873e482b1ef298d6537d18ff393d3 (patch)
tree1841f0865c446b72cc530a53900b31676b309538 /drivers/s390
parent054623105728b06852f077299e2bf1bf3d5f2b0b (diff)
s390/mm: Fix memory hotplug for unaligned standby memory
Commit 27356f54c8c3 ("mm/hotplug: verify hotplug memory range") introduced a check that makes add_memory() only accept section size aligned memory. Therefore on z/VM systems, where standby memory is not aligned, no standby memory is registered at all. Example: #cp def store 3504M standby 2336M 00: CP Q V STORE 00: STORAGE = 3504M MAX = 6G INC = 8M STANDBY = 2336M RESERVED = 0 For this setup the following error message is printed: Section-unaligned hotplug range: start 0xdb000000, size 0x92000000 So fix this and register aligned memory in "sclp_cmd.c". This means that for the corner cases where the standby memory is not aligned we loose some memory. In order to inform the user about the potential loss of standby memory, we add a new message for each added standby block and print how much of the standby memory is usable, for example: sclp_cmd.4336b4: Standby memory at 0x50000000 (256M of 256M usable) sclp_cmd.4336b4: Standby memory at 0xb0000000 (256M of 256M usable) sclp_cmd.4336b4: Standby memory at 0xdb000000 (2048M of 2336M usable) We also ensure that a potential memory block that contains both "assigned" and "standby" memory cannot be setup offline. Reviewed-by: Gerald Schaefer <gerald.schaefer@de.ibm.com> Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/char/sclp_cmd.c48
1 files changed, 46 insertions, 2 deletions
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 6e14999f9e8f..7be782116dab 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -315,10 +315,29 @@ static int sclp_mem_change_state(unsigned long start, unsigned long size,
315 rc |= sclp_assign_storage(incr->rn); 315 rc |= sclp_assign_storage(incr->rn);
316 else 316 else
317 sclp_unassign_storage(incr->rn); 317 sclp_unassign_storage(incr->rn);
318 if (rc == 0)
319 incr->standby = online ? 0 : 1;
318 } 320 }
319 return rc ? -EIO : 0; 321 return rc ? -EIO : 0;
320} 322}
321 323
324static bool contains_standby_increment(unsigned long start, unsigned long end)
325{
326 struct memory_increment *incr;
327 unsigned long istart;
328
329 list_for_each_entry(incr, &sclp_mem_list, list) {
330 istart = rn2addr(incr->rn);
331 if (end - 1 < istart)
332 continue;
333 if (start > istart + sclp_rzm - 1)
334 continue;
335 if (incr->standby)
336 return true;
337 }
338 return false;
339}
340
322static int sclp_mem_notifier(struct notifier_block *nb, 341static int sclp_mem_notifier(struct notifier_block *nb,
323 unsigned long action, void *data) 342 unsigned long action, void *data)
324{ 343{
@@ -334,8 +353,16 @@ static int sclp_mem_notifier(struct notifier_block *nb,
334 for_each_clear_bit(id, sclp_storage_ids, sclp_max_storage_id + 1) 353 for_each_clear_bit(id, sclp_storage_ids, sclp_max_storage_id + 1)
335 sclp_attach_storage(id); 354 sclp_attach_storage(id);
336 switch (action) { 355 switch (action) {
337 case MEM_ONLINE:
338 case MEM_GOING_OFFLINE: 356 case MEM_GOING_OFFLINE:
357 /*
358 * We do not allow to set memory blocks offline that contain
359 * standby memory. This is done to simplify the "memory online"
360 * case.
361 */
362 if (contains_standby_increment(start, start + size))
363 rc = -EPERM;
364 break;
365 case MEM_ONLINE:
339 case MEM_CANCEL_OFFLINE: 366 case MEM_CANCEL_OFFLINE:
340 break; 367 break;
341 case MEM_GOING_ONLINE: 368 case MEM_GOING_ONLINE:
@@ -361,6 +388,21 @@ static struct notifier_block sclp_mem_nb = {
361 .notifier_call = sclp_mem_notifier, 388 .notifier_call = sclp_mem_notifier,
362}; 389};
363 390
391static void __init align_to_block_size(unsigned long long *start,
392 unsigned long long *size)
393{
394 unsigned long long start_align, size_align, alignment;
395
396 alignment = memory_block_size_bytes();
397 start_align = roundup(*start, alignment);
398 size_align = rounddown(*start + *size, alignment) - start_align;
399
400 pr_info("Standby memory at 0x%llx (%lluM of %lluM usable)\n",
401 *start, size_align >> 20, *size >> 20);
402 *start = start_align;
403 *size = size_align;
404}
405
364static void __init add_memory_merged(u16 rn) 406static void __init add_memory_merged(u16 rn)
365{ 407{
366 static u16 first_rn, num; 408 static u16 first_rn, num;
@@ -382,7 +424,9 @@ static void __init add_memory_merged(u16 rn)
382 goto skip_add; 424 goto skip_add;
383 if (memory_end_set && (start + size > memory_end)) 425 if (memory_end_set && (start + size > memory_end))
384 size = memory_end - start; 426 size = memory_end - start;
385 add_memory(0, start, size); 427 align_to_block_size(&start, &size);
428 if (size)
429 add_memory(0, start, size);
386skip_add: 430skip_add:
387 first_rn = rn; 431 first_rn = rn;
388 num = 1; 432 num = 1;