From patchwork Sat Dec 10 06:51:13 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mahesh J Salgaonkar X-Patchwork-Id: 130509 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from ozlabs.org (localhost [IPv6:::1]) by ozlabs.org (Postfix) with ESMTP id 0E7051022CF for ; Sat, 10 Dec 2011 17:53:38 +1100 (EST) Received: by ozlabs.org (Postfix) id 274FE1011F0; Sat, 10 Dec 2011 17:51:40 +1100 (EST) Delivered-To: linuxppc-dev@ozlabs.org Received: from e23smtp06.au.ibm.com (e23smtp06.au.ibm.com [202.81.31.148]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "e23smtp06.au.ibm.com", Issuer "GeoTrust SSL CA" (verified OK)) by ozlabs.org (Postfix) with ESMTPS id 1538D1011EA for ; Sat, 10 Dec 2011 17:51:40 +1100 (EST) Received: from /spool/local by e23smtp06.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 10 Dec 2011 06:49:26 +1000 Received: from d23relay04.au.ibm.com ([202.81.31.246]) by e23smtp06.au.ibm.com ([202.81.31.212]) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Sat, 10 Dec 2011 06:49:04 +1000 Received: from d23av01.au.ibm.com (d23av01.au.ibm.com [9.190.234.96]) by d23relay04.au.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id pBA6lc6I2363446 for ; Sat, 10 Dec 2011 17:47:38 +1100 Received: from d23av01.au.ibm.com (loopback [127.0.0.1]) by d23av01.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id pBA6pHFu000969 for ; Sat, 10 Dec 2011 17:51:17 +1100 Received: from mars.in.ibm.com ([9.124.210.148]) by d23av01.au.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id pBA6pDZF000775; Sat, 10 Dec 2011 17:51:14 +1100 Subject: [RFC PATCH v6 08/10] fadump: Invalidate registration and release reserved memory for general use. To: linuxppc-dev , Linux Kernel , Benjamin Herrenschmidt From: Mahesh J Salgaonkar Date: Sat, 10 Dec 2011 12:21:13 +0530 Message-ID: <20111210065113.10195.38504.stgit@mars.in.ibm.com> In-Reply-To: <20111210064301.10195.3344.stgit@mars.in.ibm.com> References: <20111210064301.10195.3344.stgit@mars.in.ibm.com> User-Agent: StGit/0.15-1-ged5e-dirty MIME-Version: 1.0 x-cbid: 11120920-7014-0000-0000-0000003CF4D4 Cc: Anton Blanchard , Amerigo Wang , Kexec-ml , Milton Miller , Randy Dunlap , "Eric W. Biederman" , Vivek Goyal X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org From: Mahesh Salgaonkar 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, the userspace tool will 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. Signed-off-by: Mahesh Salgaonkar --- arch/powerpc/include/asm/fadump.h | 3 + arch/powerpc/kernel/fadump.c | 158 ++++++++++++++++++++++++++++++++++++- 2 files changed, 157 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h index 6768195..88dbf96 100644 --- a/arch/powerpc/include/asm/fadump.h +++ b/arch/powerpc/include/asm/fadump.h @@ -208,6 +208,9 @@ extern int fadump_reserve_mem(void); extern int setup_fadump(void); extern int is_fadump_active(void); extern void crash_fadump(struct pt_regs *, const char *); +extern void fadump_cleanup(void); + +extern void vmcore_cleanup(void); #else /* CONFIG_FA_DUMP */ static inline int is_fadump_active(void) { return 0; } static inline void crash_fadump(struct pt_regs *regs, const char *str) { } diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 5689954..8874d6b 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -984,6 +986,132 @@ static int fadump_unregister_dump(struct fadump_mem_struct *fdm) return 0; } +static int fadump_invalidate_dump(struct fadump_mem_struct *fdm) +{ + int rc = 0; + unsigned int wait_time; + + pr_debug("Invalidating firmware-assisted dump registration\n"); + + /* TODO: Add upper time limit for the delay */ + do { + rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL, + FADUMP_INVALIDATE, fdm, + sizeof(struct fadump_mem_struct)); + + wait_time = rtas_busy_delay_time(rc); + if (wait_time) + mdelay(wait_time); + } while (wait_time); + + if (rc) { + printk(KERN_ERR "Failed to invalidate firmware-assisted dump " + "rgistration. unexpected error(%d).\n", rc); + return rc; + } + fw_dump.dump_active = 0; + fdm_active = NULL; + return 0; +} + +void fadump_cleanup(void) +{ + /* Invalidate the registration only if dump is active. */ + if (fw_dump.dump_active) { + init_fadump_mem_struct(&fdm, + fdm_active->cpu_state_data.destination_address); + fadump_invalidate_dump(&fdm); + } +} + +/* + * Release the memory that was reserved in early boot to preserve the memory + * contents. The released memory will be available for general use. + */ +static void fadump_release_memory(unsigned long begin, unsigned long end) +{ + unsigned long addr; + unsigned long ra_start, ra_end; + + ra_start = fw_dump.reserve_dump_area_start; + ra_end = ra_start + fw_dump.reserve_dump_area_size; + + for (addr = begin; addr < end; addr += PAGE_SIZE) { + /* + * exclude the dump reserve area. Will reuse it for next + * fadump registration. + */ + if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start)) + continue; + + ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT)); + init_page_count(pfn_to_page(addr >> PAGE_SHIFT)); + free_page((unsigned long)__va(addr)); + totalram_pages++; + } +} + +static void fadump_invalidate_release_mem(void) +{ + unsigned long reserved_area_start, reserved_area_end; + unsigned long destination_address; + + mutex_lock(&fadump_mutex); + if (!fw_dump.dump_active) { + mutex_unlock(&fadump_mutex); + return; + } + + destination_address = fdm_active->cpu_state_data.destination_address; + fadump_cleanup(); + mutex_unlock(&fadump_mutex); + + /* + * Save the current reserved memory bounds we will require them + * later for releasing the memory for general use. + */ + reserved_area_start = fw_dump.reserve_dump_area_start; + reserved_area_end = reserved_area_start + + fw_dump.reserve_dump_area_size; + /* + * Setup reserve_dump_area_start and its size so that we can + * reuse this reserved memory for Re-registration. + */ + fw_dump.reserve_dump_area_start = destination_address; + fw_dump.reserve_dump_area_size = get_fadump_area_size(); + + fadump_release_memory(reserved_area_start, reserved_area_end); + if (fw_dump.cpu_notes_buf) { + fadump_cpu_notes_buf_free( + (unsigned long)__va(fw_dump.cpu_notes_buf), + fw_dump.cpu_notes_buf_size); + fw_dump.cpu_notes_buf = 0; + fw_dump.cpu_notes_buf_size = 0; + } + /* Initialize the kernel dump memory structure for FAD registration. */ + init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start); +} + +static ssize_t fadump_release_memory_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + if (!fw_dump.dump_active) + return -EPERM; + + if (buf[0] == '1') { + /* + * Take away the '/proc/vmcore'. We are releasing the dump + * memory, hence it will not be valid anymore. + */ + vmcore_cleanup(); + fadump_invalidate_release_mem(); + + } else + return -EINVAL; + return count; +} + static ssize_t fadump_enabled_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -1043,10 +1171,13 @@ static int fadump_region_show(struct seq_file *m, void *private) if (!fw_dump.fadump_enabled) return 0; + mutex_lock(&fadump_mutex); if (fdm_active) fdm_ptr = fdm_active; - else + else { + mutex_unlock(&fadump_mutex); fdm_ptr = &fdm; + } seq_printf(m, "CPU : [%#016llx-%#016llx] %#llx bytes, " @@ -1076,7 +1207,7 @@ static int fadump_region_show(struct seq_file *m, void *private) if (!fdm_active || (fw_dump.reserve_dump_area_start == fdm_ptr->cpu_state_data.destination_address)) - return 0; + goto out; /* Dump is active. Show reserved memory region. */ seq_printf(m, @@ -1088,9 +1219,15 @@ static int fadump_region_show(struct seq_file *m, void *private) fw_dump.reserve_dump_area_start, fdm_ptr->cpu_state_data.destination_address - fw_dump.reserve_dump_area_start); +out: + if (fdm_active) + mutex_unlock(&fadump_mutex); return 0; } +static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem, + 0200, NULL, + fadump_release_memory_store); static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled, 0444, fadump_enabled_show, NULL); @@ -1131,6 +1268,13 @@ static void fadump_init_files(void) if (!debugfs_file) printk(KERN_ERR "fadump: unable to create debugfs file" " fadump_region\n"); + + if (fw_dump.dump_active) { + rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr); + if (rc) + printk(KERN_ERR "fadump: unable to create sysfs file" + " fadump_release_mem (%d)\n", rc); + } return; } @@ -1150,8 +1294,14 @@ int __init setup_fadump(void) * If dump data is available then see if it is valid and prepare for * saving it to the disk. */ - if (fw_dump.dump_active) - process_fadump(fdm_active); + if (fw_dump.dump_active) { + /* + * if dump process fails then invalidate the registration + * and release memory before proceeding for re-registration. + */ + if (process_fadump(fdm_active) < 0) + fadump_invalidate_release_mem(); + } /* Initialize the kernel dump memory structure for FAD registration. */ else if (fw_dump.reserve_dump_area_size) init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start);