From abd4d5587be911f63592537284dad78766d97d62 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Fri, 12 Aug 2011 10:54:51 -0700 Subject: pstore: change mutex locking to spin_locks pstore was using mutex locking to protect read/write access to the backend plug-ins. This causes problems when pstore is executed in an NMI context through panic() -> kmsg_dump(). This patch changes the mutex to a spin_lock_irqsave then also checks to see if we are in an NMI context. If we are in an NMI and can't get the lock, just print a message stating that and blow by the locking. All this is probably a hack around the bigger locking problem but it solves my current situation of trying to sleep in an NMI context. Tested by loading the lkdtm module and executing a HARDLOCKUP which will cause the machine to panic inside the nmi handler. Signed-off-by: Don Zickus Acked-by: Matthew Garrett Signed-off-by: Tony Luck --- drivers/firmware/efivars.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/firmware') diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index eb80b549ed8d..be8bcb035e2a 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -978,7 +978,7 @@ int register_efivars(struct efivars *efivars, if (efivars->efi_pstore_info.buf) { efivars->efi_pstore_info.bufsize = 1024; efivars->efi_pstore_info.data = efivars; - mutex_init(&efivars->efi_pstore_info.buf_mutex); + spin_lock_init(&efivars->efi_pstore_info.buf_lock); pstore_register(&efivars->efi_pstore_info); } -- cgit v1.2.3 From b238b8fa93353ab50c9a2b1e2fa47a0ab01c37cd Mon Sep 17 00:00:00 2001 From: Chen Gong Date: Wed, 12 Oct 2011 09:17:24 -0700 Subject: pstore: make pstore write function return normal success/fail value Currently pstore write interface employs record id as return value, but it is not enough because it can't tell caller if the write operation is successful. Pass the record id back via an argument pointer and return zero for success, non-zero for failure. Signed-off-by: Chen Gong Signed-off-by: Tony Luck --- drivers/acpi/apei/erst.c | 10 ++++++---- drivers/firmware/efivars.c | 17 +++++++++-------- fs/pstore/platform.c | 11 ++++++----- include/linux/pstore.h | 4 ++-- 4 files changed, 23 insertions(+), 19 deletions(-) (limited to 'drivers/firmware') diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 5e820ea35570..127408069ca7 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -933,7 +933,7 @@ static int erst_open_pstore(struct pstore_info *psi); static int erst_close_pstore(struct pstore_info *psi); static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, struct timespec *time, struct pstore_info *psi); -static u64 erst_writer(enum pstore_type_id type, unsigned int part, +static int erst_writer(enum pstore_type_id type, u64 *id, unsigned int part, size_t size, struct pstore_info *psi); static int erst_clearer(enum pstore_type_id type, u64 id, struct pstore_info *psi); @@ -1040,11 +1040,12 @@ out: return (rc < 0) ? rc : (len - sizeof(*rcd)); } -static u64 erst_writer(enum pstore_type_id type, unsigned int part, +static int erst_writer(enum pstore_type_id type, u64 *id, unsigned int part, size_t size, struct pstore_info *psi) { struct cper_pstore_record *rcd = (struct cper_pstore_record *) (erst_info.buf - sizeof(*rcd)); + int ret; memset(rcd, 0, sizeof(*rcd)); memcpy(rcd->hdr.signature, CPER_SIG_RECORD, CPER_SIG_SIZE); @@ -1079,9 +1080,10 @@ static u64 erst_writer(enum pstore_type_id type, unsigned int part, } rcd->sec_hdr.section_severity = CPER_SEV_FATAL; - erst_write(&rcd->hdr); + ret = erst_write(&rcd->hdr); + *id = rcd->hdr.record_id; - return rcd->hdr.record_id; + return ret; } static int erst_clearer(enum pstore_type_id type, u64 id, diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index be8bcb035e2a..8370f72d87ff 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -490,8 +490,8 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, return 0; } -static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part, - size_t size, struct pstore_info *psi) +static int efi_pstore_write(enum pstore_type_id type, u64 *id, + unsigned int part, size_t size, struct pstore_info *psi) { char name[DUMP_NAME_LEN]; char stub_name[DUMP_NAME_LEN]; @@ -499,7 +499,7 @@ static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part, efi_guid_t vendor = LINUX_EFI_CRASH_GUID; struct efivars *efivars = psi->data; struct efivar_entry *entry, *found = NULL; - int i; + int i, ret = 0; sprintf(stub_name, "dump-type%u-%u-", type, part); sprintf(name, "%s%lu", stub_name, get_seconds()); @@ -548,18 +548,19 @@ static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part, efivar_unregister(found); if (size) - efivar_create_sysfs_entry(efivars, + ret = efivar_create_sysfs_entry(efivars, utf16_strsize(efi_name, DUMP_NAME_LEN * 2), efi_name, &vendor); - return part; + *id = part; + return ret; }; static int efi_pstore_erase(enum pstore_type_id type, u64 id, struct pstore_info *psi) { - efi_pstore_write(type, id, 0, psi); + efi_pstore_write(type, &id, (unsigned int)id, 0, psi); return 0; } @@ -580,8 +581,8 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, return -1; } -static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part, - size_t size, struct pstore_info *psi) +static int efi_pstore_write(enum pstore_type_id type, u64 *id, + unsigned int part, size_t size, struct pstore_info *psi) { return 0; } diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 0472924024cc..2bd620f0d796 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c @@ -87,7 +87,7 @@ static void pstore_dump(struct kmsg_dumper *dumper, unsigned long size, total = 0; char *dst, *why; u64 id; - int hsize; + int hsize, ret; unsigned int part = 1; unsigned long flags = 0; int is_locked = 0; @@ -122,9 +122,9 @@ static void pstore_dump(struct kmsg_dumper *dumper, memcpy(dst, s1 + s1_start, l1_cpy); memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy); - id = psinfo->write(PSTORE_TYPE_DMESG, part, + ret = psinfo->write(PSTORE_TYPE_DMESG, &id, part, hsize + l1_cpy + l2_cpy, psinfo); - if (reason == KMSG_DUMP_OOPS && pstore_is_mounted()) + if (ret == 0 && reason == KMSG_DUMP_OOPS && pstore_is_mounted()) pstore_new_entry = 1; l1 -= l1_cpy; l2 -= l2_cpy; @@ -247,6 +247,7 @@ static void pstore_timefunc(unsigned long dummy) int pstore_write(enum pstore_type_id type, char *buf, size_t size) { u64 id; + int ret; unsigned long flags; if (!psinfo) @@ -257,8 +258,8 @@ int pstore_write(enum pstore_type_id type, char *buf, size_t size) spin_lock_irqsave(&psinfo->buf_lock, flags); memcpy(psinfo->buf, buf, size); - id = psinfo->write(type, 0, size, psinfo); - if (pstore_is_mounted()) + ret = psinfo->write(type, &id, 0, size, psinfo); + if (ret == 0 && pstore_is_mounted()) pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf, size, CURRENT_TIME, psinfo); spin_unlock_irqrestore(&psinfo->buf_lock, flags); diff --git a/include/linux/pstore.h b/include/linux/pstore.h index b91440e64d6e..ea567321ae3c 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h @@ -39,8 +39,8 @@ struct pstore_info { int (*close)(struct pstore_info *psi); ssize_t (*read)(u64 *id, enum pstore_type_id *type, struct timespec *time, struct pstore_info *psi); - u64 (*write)(enum pstore_type_id type, unsigned int part, - size_t size, struct pstore_info *psi); + int (*write)(enum pstore_type_id type, u64 *id, + unsigned int part, size_t size, struct pstore_info *psi); int (*erase)(enum pstore_type_id type, u64 id, struct pstore_info *psi); void *data; -- cgit v1.2.3