aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/apei/erst.c31
-rw-r--r--drivers/firmware/efivars.c9
-rw-r--r--fs/pstore/platform.c13
-rw-r--r--include/linux/pstore.h4
4 files changed, 40 insertions, 17 deletions
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 127408069ca7..631b9477b99c 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -932,7 +932,8 @@ static int erst_check_table(struct acpi_table_erst *erst_tab)
932static int erst_open_pstore(struct pstore_info *psi); 932static int erst_open_pstore(struct pstore_info *psi);
933static int erst_close_pstore(struct pstore_info *psi); 933static int erst_close_pstore(struct pstore_info *psi);
934static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, 934static ssize_t erst_reader(u64 *id, enum pstore_type_id *type,
935 struct timespec *time, struct pstore_info *psi); 935 struct timespec *time, char **buf,
936 struct pstore_info *psi);
936static int erst_writer(enum pstore_type_id type, u64 *id, unsigned int part, 937static int erst_writer(enum pstore_type_id type, u64 *id, unsigned int part,
937 size_t size, struct pstore_info *psi); 938 size_t size, struct pstore_info *psi);
938static int erst_clearer(enum pstore_type_id type, u64 id, 939static int erst_clearer(enum pstore_type_id type, u64 id,
@@ -986,17 +987,23 @@ static int erst_close_pstore(struct pstore_info *psi)
986} 987}
987 988
988static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, 989static ssize_t erst_reader(u64 *id, enum pstore_type_id *type,
989 struct timespec *time, struct pstore_info *psi) 990 struct timespec *time, char **buf,
991 struct pstore_info *psi)
990{ 992{
991 int rc; 993 int rc;
992 ssize_t len = 0; 994 ssize_t len = 0;
993 u64 record_id; 995 u64 record_id;
994 struct cper_pstore_record *rcd = (struct cper_pstore_record *) 996 struct cper_pstore_record *rcd;
995 (erst_info.buf - sizeof(*rcd)); 997 size_t rcd_len = sizeof(*rcd) + erst_info.bufsize;
996 998
997 if (erst_disable) 999 if (erst_disable)
998 return -ENODEV; 1000 return -ENODEV;
999 1001
1002 rcd = kmalloc(rcd_len, GFP_KERNEL);
1003 if (!rcd) {
1004 rc = -ENOMEM;
1005 goto out;
1006 }
1000skip: 1007skip:
1001 rc = erst_get_record_id_next(&reader_pos, &record_id); 1008 rc = erst_get_record_id_next(&reader_pos, &record_id);
1002 if (rc) 1009 if (rc)
@@ -1004,22 +1011,27 @@ skip:
1004 1011
1005 /* no more record */ 1012 /* no more record */
1006 if (record_id == APEI_ERST_INVALID_RECORD_ID) { 1013 if (record_id == APEI_ERST_INVALID_RECORD_ID) {
1007 rc = -1; 1014 rc = -EINVAL;
1008 goto out; 1015 goto out;
1009 } 1016 }
1010 1017
1011 len = erst_read(record_id, &rcd->hdr, sizeof(*rcd) + 1018 len = erst_read(record_id, &rcd->hdr, rcd_len);
1012 erst_info.bufsize);
1013 /* The record may be cleared by others, try read next record */ 1019 /* The record may be cleared by others, try read next record */
1014 if (len == -ENOENT) 1020 if (len == -ENOENT)
1015 goto skip; 1021 goto skip;
1016 else if (len < 0) { 1022 else if (len < sizeof(*rcd)) {
1017 rc = -1; 1023 rc = -EIO;
1018 goto out; 1024 goto out;
1019 } 1025 }
1020 if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0) 1026 if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0)
1021 goto skip; 1027 goto skip;
1022 1028
1029 *buf = kmalloc(len, GFP_KERNEL);
1030 if (*buf == NULL) {
1031 rc = -ENOMEM;
1032 goto out;
1033 }
1034 memcpy(*buf, rcd->data, len - sizeof(*rcd));
1023 *id = record_id; 1035 *id = record_id;
1024 if (uuid_le_cmp(rcd->sec_hdr.section_type, 1036 if (uuid_le_cmp(rcd->sec_hdr.section_type,
1025 CPER_SECTION_TYPE_DMESG) == 0) 1037 CPER_SECTION_TYPE_DMESG) == 0)
@@ -1037,6 +1049,7 @@ skip:
1037 time->tv_nsec = 0; 1049 time->tv_nsec = 0;
1038 1050
1039out: 1051out:
1052 kfree(rcd);
1040 return (rc < 0) ? rc : (len - sizeof(*rcd)); 1053 return (rc < 0) ? rc : (len - sizeof(*rcd));
1041} 1054}
1042 1055
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 8370f72d87ff..a54a6b972ced 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -457,7 +457,8 @@ static int efi_pstore_close(struct pstore_info *psi)
457} 457}
458 458
459static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, 459static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
460 struct timespec *timespec, struct pstore_info *psi) 460 struct timespec *timespec,
461 char **buf, struct pstore_info *psi)
461{ 462{
462 efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 463 efi_guid_t vendor = LINUX_EFI_CRASH_GUID;
463 struct efivars *efivars = psi->data; 464 struct efivars *efivars = psi->data;
@@ -478,7 +479,11 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
478 timespec->tv_nsec = 0; 479 timespec->tv_nsec = 0;
479 get_var_data_locked(efivars, &efivars->walk_entry->var); 480 get_var_data_locked(efivars, &efivars->walk_entry->var);
480 size = efivars->walk_entry->var.DataSize; 481 size = efivars->walk_entry->var.DataSize;
481 memcpy(psi->buf, efivars->walk_entry->var.Data, size); 482 *buf = kmalloc(size, GFP_KERNEL);
483 if (*buf == NULL)
484 return -ENOMEM;
485 memcpy(*buf, efivars->walk_entry->var.Data,
486 size);
482 efivars->walk_entry = list_entry(efivars->walk_entry->list.next, 487 efivars->walk_entry = list_entry(efivars->walk_entry->list.next,
483 struct efivar_entry, list); 488 struct efivar_entry, list);
484 return size; 489 return size;
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 2bd620f0d796..57bbf9078ac8 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -167,6 +167,7 @@ int pstore_register(struct pstore_info *psi)
167 } 167 }
168 168
169 psinfo = psi; 169 psinfo = psi;
170 mutex_init(&psinfo->read_mutex);
170 spin_unlock(&pstore_lock); 171 spin_unlock(&pstore_lock);
171 172
172 if (owner && !try_module_get(owner)) { 173 if (owner && !try_module_get(owner)) {
@@ -195,30 +196,32 @@ EXPORT_SYMBOL_GPL(pstore_register);
195void pstore_get_records(int quiet) 196void pstore_get_records(int quiet)
196{ 197{
197 struct pstore_info *psi = psinfo; 198 struct pstore_info *psi = psinfo;
199 char *buf = NULL;
198 ssize_t size; 200 ssize_t size;
199 u64 id; 201 u64 id;
200 enum pstore_type_id type; 202 enum pstore_type_id type;
201 struct timespec time; 203 struct timespec time;
202 int failed = 0, rc; 204 int failed = 0, rc;
203 unsigned long flags;
204 205
205 if (!psi) 206 if (!psi)
206 return; 207 return;
207 208
208 spin_lock_irqsave(&psinfo->buf_lock, flags); 209 mutex_lock(&psi->read_mutex);
209 rc = psi->open(psi); 210 rc = psi->open(psi);
210 if (rc) 211 if (rc)
211 goto out; 212 goto out;
212 213
213 while ((size = psi->read(&id, &type, &time, psi)) > 0) { 214 while ((size = psi->read(&id, &type, &time, &buf, psi)) > 0) {
214 rc = pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size, 215 rc = pstore_mkfile(type, psi->name, id, buf, (size_t)size,
215 time, psi); 216 time, psi);
217 kfree(buf);
218 buf = NULL;
216 if (rc && (rc != -EEXIST || !quiet)) 219 if (rc && (rc != -EEXIST || !quiet))
217 failed++; 220 failed++;
218 } 221 }
219 psi->close(psi); 222 psi->close(psi);
220out: 223out:
221 spin_unlock_irqrestore(&psinfo->buf_lock, flags); 224 mutex_unlock(&psi->read_mutex);
222 225
223 if (failed) 226 if (failed)
224 printk(KERN_WARNING "pstore: failed to load %d record(s) from '%s'\n", 227 printk(KERN_WARNING "pstore: failed to load %d record(s) from '%s'\n",
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index ea567321ae3c..2ca8cde5459d 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -35,10 +35,12 @@ struct pstore_info {
35 spinlock_t buf_lock; /* serialize access to 'buf' */ 35 spinlock_t buf_lock; /* serialize access to 'buf' */
36 char *buf; 36 char *buf;
37 size_t bufsize; 37 size_t bufsize;
38 struct mutex read_mutex; /* serialize open/read/close */
38 int (*open)(struct pstore_info *psi); 39 int (*open)(struct pstore_info *psi);
39 int (*close)(struct pstore_info *psi); 40 int (*close)(struct pstore_info *psi);
40 ssize_t (*read)(u64 *id, enum pstore_type_id *type, 41 ssize_t (*read)(u64 *id, enum pstore_type_id *type,
41 struct timespec *time, struct pstore_info *psi); 42 struct timespec *time, char **buf,
43 struct pstore_info *psi);
42 int (*write)(enum pstore_type_id type, u64 *id, 44 int (*write)(enum pstore_type_id type, u64 *id,
43 unsigned int part, size_t size, struct pstore_info *psi); 45 unsigned int part, size_t size, struct pstore_info *psi);
44 int (*erase)(enum pstore_type_id type, u64 id, 46 int (*erase)(enum pstore_type_id type, u64 id,