diff options
-rw-r--r-- | drivers/acpi/apei/erst.c | 31 | ||||
-rw-r--r-- | drivers/firmware/efivars.c | 9 | ||||
-rw-r--r-- | fs/pstore/platform.c | 13 | ||||
-rw-r--r-- | include/linux/pstore.h | 4 |
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) | |||
932 | static int erst_open_pstore(struct pstore_info *psi); | 932 | static int erst_open_pstore(struct pstore_info *psi); |
933 | static int erst_close_pstore(struct pstore_info *psi); | 933 | static int erst_close_pstore(struct pstore_info *psi); |
934 | static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, | 934 | static 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); | ||
936 | static int erst_writer(enum pstore_type_id type, u64 *id, unsigned int part, | 937 | static 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); |
938 | static int erst_clearer(enum pstore_type_id type, u64 id, | 939 | static 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 | ||
988 | static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, | 989 | static 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 | } | ||
1000 | skip: | 1007 | skip: |
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 | ||
1039 | out: | 1051 | out: |
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 | ||
459 | static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | 459 | static 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); | |||
195 | void pstore_get_records(int quiet) | 196 | void 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); |
220 | out: | 223 | out: |
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, |