Commit a2d773023552f68baa2db2226dfd6d761c0df5da
Exists in
master
and in
4 other branches
Merge branch 'pstore-efi' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
* 'pstore-efi' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6: efivars: Introduce PSTORE_EFI_ATTRIBUTES efivars: Use string functions in pstore_write efivars: introduce utf16_strncmp efivars: String functions efi: Add support for using efivars as a pstore backend pstore: Allow the user to explicitly choose a backend pstore: Make "part" unsigned pstore: Add extra context for writes and erases pstore: Extend API for more flexibility in new backends
Showing 9 changed files Side-by-side Diff
Documentation/ABI/testing/pstore
... | ... | @@ -39,4 +39,9 @@ |
39 | 39 | multiple) files based on the record size of the underlying |
40 | 40 | persistent storage until at least this amount is reached. |
41 | 41 | Default is 10 Kbytes. |
42 | + | |
43 | + Pstore only supports one backend at a time. If multiple | |
44 | + backends are available, the preferred backend may be | |
45 | + set by passing the pstore.backend= argument to the kernel at | |
46 | + boot time. |
Documentation/kernel-parameters.txt
... | ... | @@ -2153,6 +2153,8 @@ |
2153 | 2153 | [HW,MOUSE] Controls Logitech smartscroll autorepeat. |
2154 | 2154 | 0 = disabled, 1 = enabled (default). |
2155 | 2155 | |
2156 | + pstore.backend= Specify the name of the pstore backend to use | |
2157 | + | |
2156 | 2158 | pt. [PARIDE] |
2157 | 2159 | See Documentation/blockdev/paride.txt. |
2158 | 2160 |
drivers/acpi/apei/erst.c
... | ... | @@ -932,8 +932,11 @@ |
932 | 932 | static int erst_open_pstore(struct pstore_info *psi); |
933 | 933 | static int erst_close_pstore(struct pstore_info *psi); |
934 | 934 | static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, |
935 | - struct timespec *time); | |
936 | -static u64 erst_writer(enum pstore_type_id type, size_t size); | |
935 | + struct timespec *time, struct pstore_info *psi); | |
936 | +static u64 erst_writer(enum pstore_type_id type, unsigned int part, | |
937 | + size_t size, struct pstore_info *psi); | |
938 | +static int erst_clearer(enum pstore_type_id type, u64 id, | |
939 | + struct pstore_info *psi); | |
937 | 940 | |
938 | 941 | static struct pstore_info erst_info = { |
939 | 942 | .owner = THIS_MODULE, |
... | ... | @@ -942,7 +945,7 @@ |
942 | 945 | .close = erst_close_pstore, |
943 | 946 | .read = erst_reader, |
944 | 947 | .write = erst_writer, |
945 | - .erase = erst_clear | |
948 | + .erase = erst_clearer | |
946 | 949 | }; |
947 | 950 | |
948 | 951 | #define CPER_CREATOR_PSTORE \ |
... | ... | @@ -983,7 +986,7 @@ |
983 | 986 | } |
984 | 987 | |
985 | 988 | static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, |
986 | - struct timespec *time) | |
989 | + struct timespec *time, struct pstore_info *psi) | |
987 | 990 | { |
988 | 991 | int rc; |
989 | 992 | ssize_t len = 0; |
... | ... | @@ -1037,7 +1040,8 @@ |
1037 | 1040 | return (rc < 0) ? rc : (len - sizeof(*rcd)); |
1038 | 1041 | } |
1039 | 1042 | |
1040 | -static u64 erst_writer(enum pstore_type_id type, size_t size) | |
1043 | +static u64 erst_writer(enum pstore_type_id type, unsigned int part, | |
1044 | + size_t size, struct pstore_info *psi) | |
1041 | 1045 | { |
1042 | 1046 | struct cper_pstore_record *rcd = (struct cper_pstore_record *) |
1043 | 1047 | (erst_info.buf - sizeof(*rcd)); |
... | ... | @@ -1078,6 +1082,12 @@ |
1078 | 1082 | erst_write(&rcd->hdr); |
1079 | 1083 | |
1080 | 1084 | return rcd->hdr.record_id; |
1085 | +} | |
1086 | + | |
1087 | +static int erst_clearer(enum pstore_type_id type, u64 id, | |
1088 | + struct pstore_info *psi) | |
1089 | +{ | |
1090 | + return erst_clear(id); | |
1081 | 1091 | } |
1082 | 1092 | |
1083 | 1093 | static int __init erst_init(void) |
drivers/firmware/efivars.c
... | ... | @@ -78,6 +78,7 @@ |
78 | 78 | #include <linux/kobject.h> |
79 | 79 | #include <linux/device.h> |
80 | 80 | #include <linux/slab.h> |
81 | +#include <linux/pstore.h> | |
81 | 82 | |
82 | 83 | #include <asm/uaccess.h> |
83 | 84 | |
... | ... | @@ -89,6 +90,8 @@ |
89 | 90 | MODULE_LICENSE("GPL"); |
90 | 91 | MODULE_VERSION(EFIVARS_VERSION); |
91 | 92 | |
93 | +#define DUMP_NAME_LEN 52 | |
94 | + | |
92 | 95 | /* |
93 | 96 | * The maximum size of VariableName + Data = 1024 |
94 | 97 | * Therefore, it's reasonable to save that much |
... | ... | @@ -119,6 +122,10 @@ |
119 | 122 | ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count); |
120 | 123 | }; |
121 | 124 | |
125 | +#define PSTORE_EFI_ATTRIBUTES \ | |
126 | + (EFI_VARIABLE_NON_VOLATILE | \ | |
127 | + EFI_VARIABLE_BOOTSERVICE_ACCESS | \ | |
128 | + EFI_VARIABLE_RUNTIME_ACCESS) | |
122 | 129 | |
123 | 130 | #define EFIVAR_ATTR(_name, _mode, _show, _store) \ |
124 | 131 | struct efivar_attribute efivar_attr_##_name = { \ |
125 | 132 | |
126 | 133 | |
127 | 134 | |
128 | 135 | |
129 | 136 | |
130 | 137 | |
131 | 138 | |
132 | 139 | |
133 | 140 | |
... | ... | @@ -141,38 +148,72 @@ |
141 | 148 | |
142 | 149 | /* Return the number of unicode characters in data */ |
143 | 150 | static unsigned long |
144 | -utf8_strlen(efi_char16_t *data, unsigned long maxlength) | |
151 | +utf16_strnlen(efi_char16_t *s, size_t maxlength) | |
145 | 152 | { |
146 | 153 | unsigned long length = 0; |
147 | 154 | |
148 | - while (*data++ != 0 && length < maxlength) | |
155 | + while (*s++ != 0 && length < maxlength) | |
149 | 156 | length++; |
150 | 157 | return length; |
151 | 158 | } |
152 | 159 | |
160 | +static unsigned long | |
161 | +utf16_strlen(efi_char16_t *s) | |
162 | +{ | |
163 | + return utf16_strnlen(s, ~0UL); | |
164 | +} | |
165 | + | |
153 | 166 | /* |
154 | 167 | * Return the number of bytes is the length of this string |
155 | 168 | * Note: this is NOT the same as the number of unicode characters |
156 | 169 | */ |
157 | 170 | static inline unsigned long |
158 | -utf8_strsize(efi_char16_t *data, unsigned long maxlength) | |
171 | +utf16_strsize(efi_char16_t *data, unsigned long maxlength) | |
159 | 172 | { |
160 | - return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); | |
173 | + return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); | |
161 | 174 | } |
162 | 175 | |
176 | +static inline int | |
177 | +utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len) | |
178 | +{ | |
179 | + while (1) { | |
180 | + if (len == 0) | |
181 | + return 0; | |
182 | + if (*a < *b) | |
183 | + return -1; | |
184 | + if (*a > *b) | |
185 | + return 1; | |
186 | + if (*a == 0) /* implies *b == 0 */ | |
187 | + return 0; | |
188 | + a++; | |
189 | + b++; | |
190 | + len--; | |
191 | + } | |
192 | +} | |
193 | + | |
163 | 194 | static efi_status_t |
164 | -get_var_data(struct efivars *efivars, struct efi_variable *var) | |
195 | +get_var_data_locked(struct efivars *efivars, struct efi_variable *var) | |
165 | 196 | { |
166 | 197 | efi_status_t status; |
167 | 198 | |
168 | - spin_lock(&efivars->lock); | |
169 | 199 | var->DataSize = 1024; |
170 | 200 | status = efivars->ops->get_variable(var->VariableName, |
171 | 201 | &var->VendorGuid, |
172 | 202 | &var->Attributes, |
173 | 203 | &var->DataSize, |
174 | 204 | var->Data); |
205 | + return status; | |
206 | +} | |
207 | + | |
208 | +static efi_status_t | |
209 | +get_var_data(struct efivars *efivars, struct efi_variable *var) | |
210 | +{ | |
211 | + efi_status_t status; | |
212 | + | |
213 | + spin_lock(&efivars->lock); | |
214 | + status = get_var_data_locked(efivars, var); | |
175 | 215 | spin_unlock(&efivars->lock); |
216 | + | |
176 | 217 | if (status != EFI_SUCCESS) { |
177 | 218 | printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n", |
178 | 219 | status); |
179 | 220 | |
180 | 221 | |
... | ... | @@ -387,13 +428,181 @@ |
387 | 428 | .default_attrs = def_attrs, |
388 | 429 | }; |
389 | 430 | |
431 | +static struct pstore_info efi_pstore_info; | |
432 | + | |
390 | 433 | static inline void |
391 | 434 | efivar_unregister(struct efivar_entry *var) |
392 | 435 | { |
393 | 436 | kobject_put(&var->kobj); |
394 | 437 | } |
395 | 438 | |
439 | +#ifdef CONFIG_PSTORE | |
396 | 440 | |
441 | +static int efi_pstore_open(struct pstore_info *psi) | |
442 | +{ | |
443 | + struct efivars *efivars = psi->data; | |
444 | + | |
445 | + spin_lock(&efivars->lock); | |
446 | + efivars->walk_entry = list_first_entry(&efivars->list, | |
447 | + struct efivar_entry, list); | |
448 | + return 0; | |
449 | +} | |
450 | + | |
451 | +static int efi_pstore_close(struct pstore_info *psi) | |
452 | +{ | |
453 | + struct efivars *efivars = psi->data; | |
454 | + | |
455 | + spin_unlock(&efivars->lock); | |
456 | + return 0; | |
457 | +} | |
458 | + | |
459 | +static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | |
460 | + struct timespec *timespec, struct pstore_info *psi) | |
461 | +{ | |
462 | + efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | |
463 | + struct efivars *efivars = psi->data; | |
464 | + char name[DUMP_NAME_LEN]; | |
465 | + int i; | |
466 | + unsigned int part, size; | |
467 | + unsigned long time; | |
468 | + | |
469 | + while (&efivars->walk_entry->list != &efivars->list) { | |
470 | + if (!efi_guidcmp(efivars->walk_entry->var.VendorGuid, | |
471 | + vendor)) { | |
472 | + for (i = 0; i < DUMP_NAME_LEN; i++) { | |
473 | + name[i] = efivars->walk_entry->var.VariableName[i]; | |
474 | + } | |
475 | + if (sscanf(name, "dump-type%u-%u-%lu", type, &part, &time) == 3) { | |
476 | + *id = part; | |
477 | + timespec->tv_sec = time; | |
478 | + timespec->tv_nsec = 0; | |
479 | + get_var_data_locked(efivars, &efivars->walk_entry->var); | |
480 | + size = efivars->walk_entry->var.DataSize; | |
481 | + memcpy(psi->buf, efivars->walk_entry->var.Data, size); | |
482 | + efivars->walk_entry = list_entry(efivars->walk_entry->list.next, | |
483 | + struct efivar_entry, list); | |
484 | + return size; | |
485 | + } | |
486 | + } | |
487 | + efivars->walk_entry = list_entry(efivars->walk_entry->list.next, | |
488 | + struct efivar_entry, list); | |
489 | + } | |
490 | + return 0; | |
491 | +} | |
492 | + | |
493 | +static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part, | |
494 | + size_t size, struct pstore_info *psi) | |
495 | +{ | |
496 | + char name[DUMP_NAME_LEN]; | |
497 | + char stub_name[DUMP_NAME_LEN]; | |
498 | + efi_char16_t efi_name[DUMP_NAME_LEN]; | |
499 | + efi_guid_t vendor = LINUX_EFI_CRASH_GUID; | |
500 | + struct efivars *efivars = psi->data; | |
501 | + struct efivar_entry *entry, *found = NULL; | |
502 | + int i; | |
503 | + | |
504 | + sprintf(stub_name, "dump-type%u-%u-", type, part); | |
505 | + sprintf(name, "%s%lu", stub_name, get_seconds()); | |
506 | + | |
507 | + spin_lock(&efivars->lock); | |
508 | + | |
509 | + for (i = 0; i < DUMP_NAME_LEN; i++) | |
510 | + efi_name[i] = stub_name[i]; | |
511 | + | |
512 | + /* | |
513 | + * Clean up any entries with the same name | |
514 | + */ | |
515 | + | |
516 | + list_for_each_entry(entry, &efivars->list, list) { | |
517 | + get_var_data_locked(efivars, &entry->var); | |
518 | + | |
519 | + if (efi_guidcmp(entry->var.VendorGuid, vendor)) | |
520 | + continue; | |
521 | + if (utf16_strncmp(entry->var.VariableName, efi_name, | |
522 | + utf16_strlen(efi_name))) | |
523 | + continue; | |
524 | + /* Needs to be a prefix */ | |
525 | + if (entry->var.VariableName[utf16_strlen(efi_name)] == 0) | |
526 | + continue; | |
527 | + | |
528 | + /* found */ | |
529 | + found = entry; | |
530 | + efivars->ops->set_variable(entry->var.VariableName, | |
531 | + &entry->var.VendorGuid, | |
532 | + PSTORE_EFI_ATTRIBUTES, | |
533 | + 0, NULL); | |
534 | + } | |
535 | + | |
536 | + if (found) | |
537 | + list_del(&found->list); | |
538 | + | |
539 | + for (i = 0; i < DUMP_NAME_LEN; i++) | |
540 | + efi_name[i] = name[i]; | |
541 | + | |
542 | + efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES, | |
543 | + size, psi->buf); | |
544 | + | |
545 | + spin_unlock(&efivars->lock); | |
546 | + | |
547 | + if (found) | |
548 | + efivar_unregister(found); | |
549 | + | |
550 | + if (size) | |
551 | + efivar_create_sysfs_entry(efivars, | |
552 | + utf16_strsize(efi_name, | |
553 | + DUMP_NAME_LEN * 2), | |
554 | + efi_name, &vendor); | |
555 | + | |
556 | + return part; | |
557 | +}; | |
558 | + | |
559 | +static int efi_pstore_erase(enum pstore_type_id type, u64 id, | |
560 | + struct pstore_info *psi) | |
561 | +{ | |
562 | + efi_pstore_write(type, id, 0, psi); | |
563 | + | |
564 | + return 0; | |
565 | +} | |
566 | +#else | |
567 | +static int efi_pstore_open(struct pstore_info *psi) | |
568 | +{ | |
569 | + return 0; | |
570 | +} | |
571 | + | |
572 | +static int efi_pstore_close(struct pstore_info *psi) | |
573 | +{ | |
574 | + return 0; | |
575 | +} | |
576 | + | |
577 | +static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, | |
578 | + struct timespec *time, struct pstore_info *psi) | |
579 | +{ | |
580 | + return -1; | |
581 | +} | |
582 | + | |
583 | +static u64 efi_pstore_write(enum pstore_type_id type, int part, size_t size, | |
584 | + struct pstore_info *psi) | |
585 | +{ | |
586 | + return 0; | |
587 | +} | |
588 | + | |
589 | +static int efi_pstore_erase(enum pstore_type_id type, u64 id, | |
590 | + struct pstore_info *psi) | |
591 | +{ | |
592 | + return 0; | |
593 | +} | |
594 | +#endif | |
595 | + | |
596 | +static struct pstore_info efi_pstore_info = { | |
597 | + .owner = THIS_MODULE, | |
598 | + .name = "efi", | |
599 | + .open = efi_pstore_open, | |
600 | + .close = efi_pstore_close, | |
601 | + .read = efi_pstore_read, | |
602 | + .write = efi_pstore_write, | |
603 | + .erase = efi_pstore_erase, | |
604 | +}; | |
605 | + | |
397 | 606 | static ssize_t efivar_create(struct file *filp, struct kobject *kobj, |
398 | 607 | struct bin_attribute *bin_attr, |
399 | 608 | char *buf, loff_t pos, size_t count) |
... | ... | @@ -414,8 +623,8 @@ |
414 | 623 | * Does this variable already exist? |
415 | 624 | */ |
416 | 625 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { |
417 | - strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); | |
418 | - strsize2 = utf8_strsize(new_var->VariableName, 1024); | |
626 | + strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); | |
627 | + strsize2 = utf16_strsize(new_var->VariableName, 1024); | |
419 | 628 | if (strsize1 == strsize2 && |
420 | 629 | !memcmp(&(search_efivar->var.VariableName), |
421 | 630 | new_var->VariableName, strsize1) && |
... | ... | @@ -447,8 +656,8 @@ |
447 | 656 | |
448 | 657 | /* Create the entry in sysfs. Locking is not required here */ |
449 | 658 | status = efivar_create_sysfs_entry(efivars, |
450 | - utf8_strsize(new_var->VariableName, | |
451 | - 1024), | |
659 | + utf16_strsize(new_var->VariableName, | |
660 | + 1024), | |
452 | 661 | new_var->VariableName, |
453 | 662 | &new_var->VendorGuid); |
454 | 663 | if (status) { |
... | ... | @@ -477,8 +686,8 @@ |
477 | 686 | * Does this variable already exist? |
478 | 687 | */ |
479 | 688 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { |
480 | - strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); | |
481 | - strsize2 = utf8_strsize(del_var->VariableName, 1024); | |
689 | + strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); | |
690 | + strsize2 = utf16_strsize(del_var->VariableName, 1024); | |
482 | 691 | if (strsize1 == strsize2 && |
483 | 692 | !memcmp(&(search_efivar->var.VariableName), |
484 | 693 | del_var->VariableName, strsize1) && |
... | ... | @@ -762,6 +971,16 @@ |
762 | 971 | error = create_efivars_bin_attributes(efivars); |
763 | 972 | if (error) |
764 | 973 | unregister_efivars(efivars); |
974 | + | |
975 | + efivars->efi_pstore_info = efi_pstore_info; | |
976 | + | |
977 | + efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); | |
978 | + if (efivars->efi_pstore_info.buf) { | |
979 | + efivars->efi_pstore_info.bufsize = 1024; | |
980 | + efivars->efi_pstore_info.data = efivars; | |
981 | + mutex_init(&efivars->efi_pstore_info.buf_mutex); | |
982 | + pstore_register(&efivars->efi_pstore_info); | |
983 | + } | |
765 | 984 | |
766 | 985 | out: |
767 | 986 | kfree(variable_name); |
fs/pstore/inode.c
... | ... | @@ -39,8 +39,9 @@ |
39 | 39 | #define PSTORE_NAMELEN 64 |
40 | 40 | |
41 | 41 | struct pstore_private { |
42 | + struct pstore_info *psi; | |
43 | + enum pstore_type_id type; | |
42 | 44 | u64 id; |
43 | - int (*erase)(u64); | |
44 | 45 | ssize_t size; |
45 | 46 | char data[]; |
46 | 47 | }; |
... | ... | @@ -73,7 +74,7 @@ |
73 | 74 | { |
74 | 75 | struct pstore_private *p = dentry->d_inode->i_private; |
75 | 76 | |
76 | - p->erase(p->id); | |
77 | + p->psi->erase(p->type, p->id, p->psi); | |
77 | 78 | |
78 | 79 | return simple_unlink(dir, dentry); |
79 | 80 | } |
... | ... | @@ -175,8 +176,8 @@ |
175 | 176 | * Set the mtime & ctime to the date that this record was originally stored. |
176 | 177 | */ |
177 | 178 | int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, |
178 | - char *data, size_t size, | |
179 | - struct timespec time, int (*erase)(u64)) | |
179 | + char *data, size_t size, struct timespec time, | |
180 | + struct pstore_info *psi) | |
180 | 181 | { |
181 | 182 | struct dentry *root = pstore_sb->s_root; |
182 | 183 | struct dentry *dentry; |
183 | 184 | |
... | ... | @@ -192,8 +193,9 @@ |
192 | 193 | private = kmalloc(sizeof *private + size, GFP_KERNEL); |
193 | 194 | if (!private) |
194 | 195 | goto fail_alloc; |
196 | + private->type = type; | |
195 | 197 | private->id = id; |
196 | - private->erase = erase; | |
198 | + private->psi = psi; | |
197 | 199 | |
198 | 200 | switch (type) { |
199 | 201 | case PSTORE_TYPE_DMESG: |
fs/pstore/internal.h
... | ... | @@ -2,6 +2,6 @@ |
2 | 2 | extern void pstore_get_records(void); |
3 | 3 | extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, |
4 | 4 | char *data, size_t size, |
5 | - struct timespec time, int (*erase)(u64)); | |
5 | + struct timespec time, struct pstore_info *psi); | |
6 | 6 | extern int pstore_is_mounted(void); |
fs/pstore/platform.c
... | ... | @@ -37,6 +37,8 @@ |
37 | 37 | static DEFINE_SPINLOCK(pstore_lock); |
38 | 38 | static struct pstore_info *psinfo; |
39 | 39 | |
40 | +static char *backend; | |
41 | + | |
40 | 42 | /* How much of the console log to snapshot */ |
41 | 43 | static unsigned long kmsg_bytes = 10240; |
42 | 44 | |
... | ... | @@ -67,7 +69,8 @@ |
67 | 69 | unsigned long size, total = 0; |
68 | 70 | char *dst, *why; |
69 | 71 | u64 id; |
70 | - int hsize, part = 1; | |
72 | + int hsize; | |
73 | + unsigned int part = 1; | |
71 | 74 | |
72 | 75 | if (reason < ARRAY_SIZE(reason_str)) |
73 | 76 | why = reason_str[reason]; |
... | ... | @@ -78,7 +81,7 @@ |
78 | 81 | oopscount++; |
79 | 82 | while (total < kmsg_bytes) { |
80 | 83 | dst = psinfo->buf; |
81 | - hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part++); | |
84 | + hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part); | |
82 | 85 | size = psinfo->bufsize - hsize; |
83 | 86 | dst += hsize; |
84 | 87 | |
85 | 88 | |
86 | 89 | |
... | ... | @@ -94,14 +97,16 @@ |
94 | 97 | memcpy(dst, s1 + s1_start, l1_cpy); |
95 | 98 | memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy); |
96 | 99 | |
97 | - id = psinfo->write(PSTORE_TYPE_DMESG, hsize + l1_cpy + l2_cpy); | |
100 | + id = psinfo->write(PSTORE_TYPE_DMESG, part, | |
101 | + hsize + l1_cpy + l2_cpy, psinfo); | |
98 | 102 | if (reason == KMSG_DUMP_OOPS && pstore_is_mounted()) |
99 | 103 | pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, |
100 | 104 | psinfo->buf, hsize + l1_cpy + l2_cpy, |
101 | - CURRENT_TIME, psinfo->erase); | |
105 | + CURRENT_TIME, psinfo); | |
102 | 106 | l1 -= l1_cpy; |
103 | 107 | l2 -= l2_cpy; |
104 | 108 | total += l1_cpy + l2_cpy; |
109 | + part++; | |
105 | 110 | } |
106 | 111 | mutex_unlock(&psinfo->buf_mutex); |
107 | 112 | } |
... | ... | @@ -128,6 +133,12 @@ |
128 | 133 | spin_unlock(&pstore_lock); |
129 | 134 | return -EBUSY; |
130 | 135 | } |
136 | + | |
137 | + if (backend && strcmp(backend, psi->name)) { | |
138 | + spin_unlock(&pstore_lock); | |
139 | + return -EINVAL; | |
140 | + } | |
141 | + | |
131 | 142 | psinfo = psi; |
132 | 143 | spin_unlock(&pstore_lock); |
133 | 144 | |
134 | 145 | |
... | ... | @@ -166,9 +177,9 @@ |
166 | 177 | if (rc) |
167 | 178 | goto out; |
168 | 179 | |
169 | - while ((size = psi->read(&id, &type, &time)) > 0) { | |
180 | + while ((size = psi->read(&id, &type, &time, psi)) > 0) { | |
170 | 181 | if (pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size, |
171 | - time, psi->erase)) | |
182 | + time, psi)) | |
172 | 183 | failed++; |
173 | 184 | } |
174 | 185 | psi->close(psi); |
175 | 186 | |
176 | 187 | |
... | ... | @@ -196,13 +207,16 @@ |
196 | 207 | |
197 | 208 | mutex_lock(&psinfo->buf_mutex); |
198 | 209 | memcpy(psinfo->buf, buf, size); |
199 | - id = psinfo->write(type, size); | |
210 | + id = psinfo->write(type, 0, size, psinfo); | |
200 | 211 | if (pstore_is_mounted()) |
201 | 212 | pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf, |
202 | - size, CURRENT_TIME, psinfo->erase); | |
213 | + size, CURRENT_TIME, psinfo); | |
203 | 214 | mutex_unlock(&psinfo->buf_mutex); |
204 | 215 | |
205 | 216 | return 0; |
206 | 217 | } |
207 | 218 | EXPORT_SYMBOL_GPL(pstore_write); |
219 | + | |
220 | +module_param(backend, charp, 0444); | |
221 | +MODULE_PARM_DESC(backend, "Pstore backend to use"); |
include/linux/efi.h
... | ... | @@ -19,6 +19,7 @@ |
19 | 19 | #include <linux/rtc.h> |
20 | 20 | #include <linux/ioport.h> |
21 | 21 | #include <linux/pfn.h> |
22 | +#include <linux/pstore.h> | |
22 | 23 | |
23 | 24 | #include <asm/page.h> |
24 | 25 | #include <asm/system.h> |
... | ... | @@ -232,6 +233,9 @@ |
232 | 233 | #define UV_SYSTEM_TABLE_GUID \ |
233 | 234 | EFI_GUID( 0x3b13a7d4, 0x633e, 0x11dd, 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93 ) |
234 | 235 | |
236 | +#define LINUX_EFI_CRASH_GUID \ | |
237 | + EFI_GUID( 0xcfc8fc79, 0xbe2e, 0x4ddc, 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0 ) | |
238 | + | |
235 | 239 | typedef struct { |
236 | 240 | efi_guid_t guid; |
237 | 241 | unsigned long table; |
... | ... | @@ -458,6 +462,8 @@ |
458 | 462 | struct kset *kset; |
459 | 463 | struct bin_attribute *new_var, *del_var; |
460 | 464 | const struct efivar_operations *ops; |
465 | + struct efivar_entry *walk_entry; | |
466 | + struct pstore_info efi_pstore_info; | |
461 | 467 | }; |
462 | 468 | |
463 | 469 | int register_efivars(struct efivars *efivars, |
include/linux/pstore.h
... | ... | @@ -38,9 +38,12 @@ |
38 | 38 | int (*open)(struct pstore_info *psi); |
39 | 39 | int (*close)(struct pstore_info *psi); |
40 | 40 | ssize_t (*read)(u64 *id, enum pstore_type_id *type, |
41 | - struct timespec *time); | |
42 | - u64 (*write)(enum pstore_type_id type, size_t size); | |
43 | - int (*erase)(u64 id); | |
41 | + struct timespec *time, struct pstore_info *psi); | |
42 | + u64 (*write)(enum pstore_type_id type, unsigned int part, | |
43 | + size_t size, struct pstore_info *psi); | |
44 | + int (*erase)(enum pstore_type_id type, u64 id, | |
45 | + struct pstore_info *psi); | |
46 | + void *data; | |
44 | 47 | }; |
45 | 48 | |
46 | 49 | #ifdef CONFIG_PSTORE |