aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/fadump.c
diff options
context:
space:
mode:
authorMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>2012-02-15 20:15:08 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-02-22 18:50:02 -0500
commitb500afff11f64227ca69fd2d05986d08d9573935 (patch)
tree611abfdfca1a12225f4ffbac7661a80bba3c46a4 /arch/powerpc/kernel/fadump.c
parent162573937679ff36c9acd54268c047199dab564e (diff)
fadump: Invalidate registration and release reserved memory for general use.
This patch introduces an sysfs interface '/sys/kernel/fadump_release_mem' to invalidate the last fadump registration, invalidate '/proc/vmcore', release the reserved memory for general use and re-register for future kernel dump. Once the dump is copied to the disk, unlike phyp dump, the userspace tool can release all the memory reserved for dump with one single operation of echo 1 to '/sys/kernel/fadump_release_mem'. Release the reserved memory region excluding the size of the memory required for future kernel dump registration. And therefore, unlike kdump, Fadump doesn't need a 2nd reboot to get back the system to the production configuration. Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/fadump.c')
-rw-r--r--arch/powerpc/kernel/fadump.c158
1 files changed, 154 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
index a83bc9015c64..cfe7a38708c3 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -33,6 +33,8 @@
33#include <linux/debugfs.h> 33#include <linux/debugfs.h>
34#include <linux/seq_file.h> 34#include <linux/seq_file.h>
35#include <linux/crash_dump.h> 35#include <linux/crash_dump.h>
36#include <linux/kobject.h>
37#include <linux/sysfs.h>
36 38
37#include <asm/page.h> 39#include <asm/page.h>
38#include <asm/prom.h> 40#include <asm/prom.h>
@@ -984,6 +986,132 @@ static int fadump_unregister_dump(struct fadump_mem_struct *fdm)
984 return 0; 986 return 0;
985} 987}
986 988
989static int fadump_invalidate_dump(struct fadump_mem_struct *fdm)
990{
991 int rc = 0;
992 unsigned int wait_time;
993
994 pr_debug("Invalidating firmware-assisted dump registration\n");
995
996 /* TODO: Add upper time limit for the delay */
997 do {
998 rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL,
999 FADUMP_INVALIDATE, fdm,
1000 sizeof(struct fadump_mem_struct));
1001
1002 wait_time = rtas_busy_delay_time(rc);
1003 if (wait_time)
1004 mdelay(wait_time);
1005 } while (wait_time);
1006
1007 if (rc) {
1008 printk(KERN_ERR "Failed to invalidate firmware-assisted dump "
1009 "rgistration. unexpected error(%d).\n", rc);
1010 return rc;
1011 }
1012 fw_dump.dump_active = 0;
1013 fdm_active = NULL;
1014 return 0;
1015}
1016
1017void fadump_cleanup(void)
1018{
1019 /* Invalidate the registration only if dump is active. */
1020 if (fw_dump.dump_active) {
1021 init_fadump_mem_struct(&fdm,
1022 fdm_active->cpu_state_data.destination_address);
1023 fadump_invalidate_dump(&fdm);
1024 }
1025}
1026
1027/*
1028 * Release the memory that was reserved in early boot to preserve the memory
1029 * contents. The released memory will be available for general use.
1030 */
1031static void fadump_release_memory(unsigned long begin, unsigned long end)
1032{
1033 unsigned long addr;
1034 unsigned long ra_start, ra_end;
1035
1036 ra_start = fw_dump.reserve_dump_area_start;
1037 ra_end = ra_start + fw_dump.reserve_dump_area_size;
1038
1039 for (addr = begin; addr < end; addr += PAGE_SIZE) {
1040 /*
1041 * exclude the dump reserve area. Will reuse it for next
1042 * fadump registration.
1043 */
1044 if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start))
1045 continue;
1046
1047 ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT));
1048 init_page_count(pfn_to_page(addr >> PAGE_SHIFT));
1049 free_page((unsigned long)__va(addr));
1050 totalram_pages++;
1051 }
1052}
1053
1054static void fadump_invalidate_release_mem(void)
1055{
1056 unsigned long reserved_area_start, reserved_area_end;
1057 unsigned long destination_address;
1058
1059 mutex_lock(&fadump_mutex);
1060 if (!fw_dump.dump_active) {
1061 mutex_unlock(&fadump_mutex);
1062 return;
1063 }
1064
1065 destination_address = fdm_active->cpu_state_data.destination_address;
1066 fadump_cleanup();
1067 mutex_unlock(&fadump_mutex);
1068
1069 /*
1070 * Save the current reserved memory bounds we will require them
1071 * later for releasing the memory for general use.
1072 */
1073 reserved_area_start = fw_dump.reserve_dump_area_start;
1074 reserved_area_end = reserved_area_start +
1075 fw_dump.reserve_dump_area_size;
1076 /*
1077 * Setup reserve_dump_area_start and its size so that we can
1078 * reuse this reserved memory for Re-registration.
1079 */
1080 fw_dump.reserve_dump_area_start = destination_address;
1081 fw_dump.reserve_dump_area_size = get_fadump_area_size();
1082
1083 fadump_release_memory(reserved_area_start, reserved_area_end);
1084 if (fw_dump.cpu_notes_buf) {
1085 fadump_cpu_notes_buf_free(
1086 (unsigned long)__va(fw_dump.cpu_notes_buf),
1087 fw_dump.cpu_notes_buf_size);
1088 fw_dump.cpu_notes_buf = 0;
1089 fw_dump.cpu_notes_buf_size = 0;
1090 }
1091 /* Initialize the kernel dump memory structure for FAD registration. */
1092 init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);
1093}
1094
1095static ssize_t fadump_release_memory_store(struct kobject *kobj,
1096 struct kobj_attribute *attr,
1097 const char *buf, size_t count)
1098{
1099 if (!fw_dump.dump_active)
1100 return -EPERM;
1101
1102 if (buf[0] == '1') {
1103 /*
1104 * Take away the '/proc/vmcore'. We are releasing the dump
1105 * memory, hence it will not be valid anymore.
1106 */
1107 vmcore_cleanup();
1108 fadump_invalidate_release_mem();
1109
1110 } else
1111 return -EINVAL;
1112 return count;
1113}
1114
987static ssize_t fadump_enabled_show(struct kobject *kobj, 1115static ssize_t fadump_enabled_show(struct kobject *kobj,
988 struct kobj_attribute *attr, 1116 struct kobj_attribute *attr,
989 char *buf) 1117 char *buf)
@@ -1043,10 +1171,13 @@ static int fadump_region_show(struct seq_file *m, void *private)
1043 if (!fw_dump.fadump_enabled) 1171 if (!fw_dump.fadump_enabled)
1044 return 0; 1172 return 0;
1045 1173
1174 mutex_lock(&fadump_mutex);
1046 if (fdm_active) 1175 if (fdm_active)
1047 fdm_ptr = fdm_active; 1176 fdm_ptr = fdm_active;
1048 else 1177 else {
1178 mutex_unlock(&fadump_mutex);
1049 fdm_ptr = &fdm; 1179 fdm_ptr = &fdm;
1180 }
1050 1181
1051 seq_printf(m, 1182 seq_printf(m,
1052 "CPU : [%#016llx-%#016llx] %#llx bytes, " 1183 "CPU : [%#016llx-%#016llx] %#llx bytes, "
@@ -1076,7 +1207,7 @@ static int fadump_region_show(struct seq_file *m, void *private)
1076 if (!fdm_active || 1207 if (!fdm_active ||
1077 (fw_dump.reserve_dump_area_start == 1208 (fw_dump.reserve_dump_area_start ==
1078 fdm_ptr->cpu_state_data.destination_address)) 1209 fdm_ptr->cpu_state_data.destination_address))
1079 return 0; 1210 goto out;
1080 1211
1081 /* Dump is active. Show reserved memory region. */ 1212 /* Dump is active. Show reserved memory region. */
1082 seq_printf(m, 1213 seq_printf(m,
@@ -1088,9 +1219,15 @@ static int fadump_region_show(struct seq_file *m, void *private)
1088 fw_dump.reserve_dump_area_start, 1219 fw_dump.reserve_dump_area_start,
1089 fdm_ptr->cpu_state_data.destination_address - 1220 fdm_ptr->cpu_state_data.destination_address -
1090 fw_dump.reserve_dump_area_start); 1221 fw_dump.reserve_dump_area_start);
1222out:
1223 if (fdm_active)
1224 mutex_unlock(&fadump_mutex);
1091 return 0; 1225 return 0;
1092} 1226}
1093 1227
1228static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem,
1229 0200, NULL,
1230 fadump_release_memory_store);
1094static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled, 1231static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled,
1095 0444, fadump_enabled_show, 1232 0444, fadump_enabled_show,
1096 NULL); 1233 NULL);
@@ -1131,6 +1268,13 @@ static void fadump_init_files(void)
1131 if (!debugfs_file) 1268 if (!debugfs_file)
1132 printk(KERN_ERR "fadump: unable to create debugfs file" 1269 printk(KERN_ERR "fadump: unable to create debugfs file"
1133 " fadump_region\n"); 1270 " fadump_region\n");
1271
1272 if (fw_dump.dump_active) {
1273 rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr);
1274 if (rc)
1275 printk(KERN_ERR "fadump: unable to create sysfs file"
1276 " fadump_release_mem (%d)\n", rc);
1277 }
1134 return; 1278 return;
1135} 1279}
1136 1280
@@ -1153,8 +1297,14 @@ int __init setup_fadump(void)
1153 * If dump data is available then see if it is valid and prepare for 1297 * If dump data is available then see if it is valid and prepare for
1154 * saving it to the disk. 1298 * saving it to the disk.
1155 */ 1299 */
1156 if (fw_dump.dump_active) 1300 if (fw_dump.dump_active) {
1157 process_fadump(fdm_active); 1301 /*
1302 * if dump process fails then invalidate the registration
1303 * and release memory before proceeding for re-registration.
1304 */
1305 if (process_fadump(fdm_active) < 0)
1306 fadump_invalidate_release_mem();
1307 }
1158 /* Initialize the kernel dump memory structure for FAD registration. */ 1308 /* Initialize the kernel dump memory structure for FAD registration. */
1159 else if (fw_dump.reserve_dump_area_size) 1309 else if (fw_dump.reserve_dump_area_size)
1160 init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start); 1310 init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);