Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+300 -38
+6
Documentation/ABI/testing/pstore
··· 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. 47 +
+2
Documentation/kernel-parameters.txt
··· 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
+15 -5
drivers/acpi/apei/erst.c
··· 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, ··· 945 942 .close = erst_close_pstore, 946 943 .read = erst_reader, 947 944 .write = erst_writer, 948 - .erase = erst_clear 945 + .erase = erst_clearer 949 946 }; 950 947 951 948 #define CPER_CREATOR_PSTORE \ ··· 986 983 } 987 984 988 985 static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, 989 - struct timespec *time) 986 + struct timespec *time, struct pstore_info *psi) 990 987 { 991 988 int rc; 992 989 ssize_t len = 0; ··· 1040 1037 return (rc < 0) ? rc : (len - sizeof(*rcd)); 1041 1038 } 1042 1039 1043 - static u64 erst_writer(enum pstore_type_id type, size_t size) 1040 + static u64 erst_writer(enum pstore_type_id type, unsigned int part, 1041 + size_t size, struct pstore_info *psi) 1044 1042 { 1045 1043 struct cper_pstore_record *rcd = (struct cper_pstore_record *) 1046 1044 (erst_info.buf - sizeof(*rcd)); ··· 1082 1078 erst_write(&rcd->hdr); 1083 1079 1084 1080 return rcd->hdr.record_id; 1081 + } 1082 + 1083 + static int erst_clearer(enum pstore_type_id type, u64 id, 1084 + struct pstore_info *psi) 1085 + { 1086 + return erst_clear(id); 1085 1087 } 1086 1088 1087 1089 static int __init erst_init(void)
+235 -16
drivers/firmware/efivars.c
··· 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 88 MODULE_DESCRIPTION("sysfs interface to EFI Variables"); 90 89 MODULE_LICENSE("GPL"); 91 90 MODULE_VERSION(EFIVARS_VERSION); 91 + 92 + #define DUMP_NAME_LEN 52 92 93 93 94 /* 94 95 * The maximum size of VariableName + Data = 1024 ··· 122 119 ssize_t (*store)(struct efivar_entry *entry, const char *buf, size_t count); 123 120 }; 124 121 122 + #define PSTORE_EFI_ATTRIBUTES \ 123 + (EFI_VARIABLE_NON_VOLATILE | \ 124 + EFI_VARIABLE_BOOTSERVICE_ACCESS | \ 125 + EFI_VARIABLE_RUNTIME_ACCESS) 125 126 126 127 #define EFIVAR_ATTR(_name, _mode, _show, _store) \ 127 128 struct efivar_attribute efivar_attr_##_name = { \ ··· 148 141 149 142 /* Return the number of unicode characters in data */ 150 143 static unsigned long 151 - utf8_strlen(efi_char16_t *data, unsigned long maxlength) 144 + utf16_strnlen(efi_char16_t *s, size_t maxlength) 152 145 { 153 146 unsigned long length = 0; 154 147 155 - while (*data++ != 0 && length < maxlength) 148 + while (*s++ != 0 && length < maxlength) 156 149 length++; 157 150 return length; 151 + } 152 + 153 + static unsigned long 154 + utf16_strlen(efi_char16_t *s) 155 + { 156 + return utf16_strnlen(s, ~0UL); 158 157 } 159 158 160 159 /* ··· 168 155 * Note: this is NOT the same as the number of unicode characters 169 156 */ 170 157 static inline unsigned long 171 - utf8_strsize(efi_char16_t *data, unsigned long maxlength) 158 + utf16_strsize(efi_char16_t *data, unsigned long maxlength) 172 159 { 173 - return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); 160 + return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); 161 + } 162 + 163 + static inline int 164 + utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len) 165 + { 166 + while (1) { 167 + if (len == 0) 168 + return 0; 169 + if (*a < *b) 170 + return -1; 171 + if (*a > *b) 172 + return 1; 173 + if (*a == 0) /* implies *b == 0 */ 174 + return 0; 175 + a++; 176 + b++; 177 + len--; 178 + } 179 + } 180 + 181 + static efi_status_t 182 + get_var_data_locked(struct efivars *efivars, struct efi_variable *var) 183 + { 184 + efi_status_t status; 185 + 186 + var->DataSize = 1024; 187 + status = efivars->ops->get_variable(var->VariableName, 188 + &var->VendorGuid, 189 + &var->Attributes, 190 + &var->DataSize, 191 + var->Data); 192 + return status; 174 193 } 175 194 176 195 static efi_status_t ··· 211 166 efi_status_t status; 212 167 213 168 spin_lock(&efivars->lock); 214 - var->DataSize = 1024; 215 - status = efivars->ops->get_variable(var->VariableName, 216 - &var->VendorGuid, 217 - &var->Attributes, 218 - &var->DataSize, 219 - var->Data); 169 + status = get_var_data_locked(efivars, var); 220 170 spin_unlock(&efivars->lock); 171 + 221 172 if (status != EFI_SUCCESS) { 222 173 printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n", 223 174 status); ··· 428 387 .default_attrs = def_attrs, 429 388 }; 430 389 390 + static struct pstore_info efi_pstore_info; 391 + 431 392 static inline void 432 393 efivar_unregister(struct efivar_entry *var) 433 394 { 434 395 kobject_put(&var->kobj); 435 396 } 436 397 398 + #ifdef CONFIG_PSTORE 399 + 400 + static int efi_pstore_open(struct pstore_info *psi) 401 + { 402 + struct efivars *efivars = psi->data; 403 + 404 + spin_lock(&efivars->lock); 405 + efivars->walk_entry = list_first_entry(&efivars->list, 406 + struct efivar_entry, list); 407 + return 0; 408 + } 409 + 410 + static int efi_pstore_close(struct pstore_info *psi) 411 + { 412 + struct efivars *efivars = psi->data; 413 + 414 + spin_unlock(&efivars->lock); 415 + return 0; 416 + } 417 + 418 + static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, 419 + struct timespec *timespec, struct pstore_info *psi) 420 + { 421 + efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 422 + struct efivars *efivars = psi->data; 423 + char name[DUMP_NAME_LEN]; 424 + int i; 425 + unsigned int part, size; 426 + unsigned long time; 427 + 428 + while (&efivars->walk_entry->list != &efivars->list) { 429 + if (!efi_guidcmp(efivars->walk_entry->var.VendorGuid, 430 + vendor)) { 431 + for (i = 0; i < DUMP_NAME_LEN; i++) { 432 + name[i] = efivars->walk_entry->var.VariableName[i]; 433 + } 434 + if (sscanf(name, "dump-type%u-%u-%lu", type, &part, &time) == 3) { 435 + *id = part; 436 + timespec->tv_sec = time; 437 + timespec->tv_nsec = 0; 438 + get_var_data_locked(efivars, &efivars->walk_entry->var); 439 + size = efivars->walk_entry->var.DataSize; 440 + memcpy(psi->buf, efivars->walk_entry->var.Data, size); 441 + efivars->walk_entry = list_entry(efivars->walk_entry->list.next, 442 + struct efivar_entry, list); 443 + return size; 444 + } 445 + } 446 + efivars->walk_entry = list_entry(efivars->walk_entry->list.next, 447 + struct efivar_entry, list); 448 + } 449 + return 0; 450 + } 451 + 452 + static u64 efi_pstore_write(enum pstore_type_id type, unsigned int part, 453 + size_t size, struct pstore_info *psi) 454 + { 455 + char name[DUMP_NAME_LEN]; 456 + char stub_name[DUMP_NAME_LEN]; 457 + efi_char16_t efi_name[DUMP_NAME_LEN]; 458 + efi_guid_t vendor = LINUX_EFI_CRASH_GUID; 459 + struct efivars *efivars = psi->data; 460 + struct efivar_entry *entry, *found = NULL; 461 + int i; 462 + 463 + sprintf(stub_name, "dump-type%u-%u-", type, part); 464 + sprintf(name, "%s%lu", stub_name, get_seconds()); 465 + 466 + spin_lock(&efivars->lock); 467 + 468 + for (i = 0; i < DUMP_NAME_LEN; i++) 469 + efi_name[i] = stub_name[i]; 470 + 471 + /* 472 + * Clean up any entries with the same name 473 + */ 474 + 475 + list_for_each_entry(entry, &efivars->list, list) { 476 + get_var_data_locked(efivars, &entry->var); 477 + 478 + if (efi_guidcmp(entry->var.VendorGuid, vendor)) 479 + continue; 480 + if (utf16_strncmp(entry->var.VariableName, efi_name, 481 + utf16_strlen(efi_name))) 482 + continue; 483 + /* Needs to be a prefix */ 484 + if (entry->var.VariableName[utf16_strlen(efi_name)] == 0) 485 + continue; 486 + 487 + /* found */ 488 + found = entry; 489 + efivars->ops->set_variable(entry->var.VariableName, 490 + &entry->var.VendorGuid, 491 + PSTORE_EFI_ATTRIBUTES, 492 + 0, NULL); 493 + } 494 + 495 + if (found) 496 + list_del(&found->list); 497 + 498 + for (i = 0; i < DUMP_NAME_LEN; i++) 499 + efi_name[i] = name[i]; 500 + 501 + efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES, 502 + size, psi->buf); 503 + 504 + spin_unlock(&efivars->lock); 505 + 506 + if (found) 507 + efivar_unregister(found); 508 + 509 + if (size) 510 + efivar_create_sysfs_entry(efivars, 511 + utf16_strsize(efi_name, 512 + DUMP_NAME_LEN * 2), 513 + efi_name, &vendor); 514 + 515 + return part; 516 + }; 517 + 518 + static int efi_pstore_erase(enum pstore_type_id type, u64 id, 519 + struct pstore_info *psi) 520 + { 521 + efi_pstore_write(type, id, 0, psi); 522 + 523 + return 0; 524 + } 525 + #else 526 + static int efi_pstore_open(struct pstore_info *psi) 527 + { 528 + return 0; 529 + } 530 + 531 + static int efi_pstore_close(struct pstore_info *psi) 532 + { 533 + return 0; 534 + } 535 + 536 + static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, 537 + struct timespec *time, struct pstore_info *psi) 538 + { 539 + return -1; 540 + } 541 + 542 + static u64 efi_pstore_write(enum pstore_type_id type, int part, size_t size, 543 + struct pstore_info *psi) 544 + { 545 + return 0; 546 + } 547 + 548 + static int efi_pstore_erase(enum pstore_type_id type, u64 id, 549 + struct pstore_info *psi) 550 + { 551 + return 0; 552 + } 553 + #endif 554 + 555 + static struct pstore_info efi_pstore_info = { 556 + .owner = THIS_MODULE, 557 + .name = "efi", 558 + .open = efi_pstore_open, 559 + .close = efi_pstore_close, 560 + .read = efi_pstore_read, 561 + .write = efi_pstore_write, 562 + .erase = efi_pstore_erase, 563 + }; 437 564 438 565 static ssize_t efivar_create(struct file *filp, struct kobject *kobj, 439 566 struct bin_attribute *bin_attr, ··· 623 414 * Does this variable already exist? 624 415 */ 625 416 list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { 626 - strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); 627 - strsize2 = utf8_strsize(new_var->VariableName, 1024); 417 + strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); 418 + strsize2 = utf16_strsize(new_var->VariableName, 1024); 628 419 if (strsize1 == strsize2 && 629 420 !memcmp(&(search_efivar->var.VariableName), 630 421 new_var->VariableName, strsize1) && ··· 656 447 657 448 /* Create the entry in sysfs. Locking is not required here */ 658 449 status = efivar_create_sysfs_entry(efivars, 659 - utf8_strsize(new_var->VariableName, 660 - 1024), 450 + utf16_strsize(new_var->VariableName, 451 + 1024), 661 452 new_var->VariableName, 662 453 &new_var->VendorGuid); 663 454 if (status) { ··· 686 477 * Does this variable already exist? 687 478 */ 688 479 list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { 689 - strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); 690 - strsize2 = utf8_strsize(del_var->VariableName, 1024); 480 + strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); 481 + strsize2 = utf16_strsize(del_var->VariableName, 1024); 691 482 if (strsize1 == strsize2 && 692 483 !memcmp(&(search_efivar->var.VariableName), 693 484 del_var->VariableName, strsize1) && ··· 971 762 error = create_efivars_bin_attributes(efivars); 972 763 if (error) 973 764 unregister_efivars(efivars); 765 + 766 + efivars->efi_pstore_info = efi_pstore_info; 767 + 768 + efivars->efi_pstore_info.buf = kmalloc(4096, GFP_KERNEL); 769 + if (efivars->efi_pstore_info.buf) { 770 + efivars->efi_pstore_info.bufsize = 1024; 771 + efivars->efi_pstore_info.data = efivars; 772 + mutex_init(&efivars->efi_pstore_info.buf_mutex); 773 + pstore_register(&efivars->efi_pstore_info); 774 + } 974 775 975 776 out: 976 777 kfree(variable_name);
+7 -5
fs/pstore/inode.c
··· 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 }; ··· 74 73 { 75 74 struct pstore_private *p = dentry->d_inode->i_private; 76 75 77 - p->erase(p->id); 76 + p->psi->erase(p->type, p->id, p->psi); 78 77 79 78 return simple_unlink(dir, dentry); 80 79 } ··· 176 175 * Set the mtime & ctime to the date that this record was originally stored. 177 176 */ 178 177 int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, 179 - char *data, size_t size, 180 - struct timespec time, int (*erase)(u64)) 178 + char *data, size_t size, struct timespec time, 179 + struct pstore_info *psi) 181 180 { 182 181 struct dentry *root = pstore_sb->s_root; 183 182 struct dentry *dentry; ··· 193 192 private = kmalloc(sizeof *private + size, GFP_KERNEL); 194 193 if (!private) 195 194 goto fail_alloc; 195 + private->type = type; 196 196 private->id = id; 197 - private->erase = erase; 197 + private->psi = psi; 198 198 199 199 switch (type) { 200 200 case PSTORE_TYPE_DMESG:
+1 -1
fs/pstore/internal.h
··· 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);
+22 -8
fs/pstore/platform.c
··· 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 ··· 69 67 unsigned long size, total = 0; 70 68 char *dst, *why; 71 69 u64 id; 72 - int hsize, part = 1; 70 + int hsize; 71 + unsigned int part = 1; 73 72 74 73 if (reason < ARRAY_SIZE(reason_str)) 75 74 why = reason_str[reason]; ··· 81 78 oopscount++; 82 79 while (total < kmsg_bytes) { 83 80 dst = psinfo->buf; 84 - hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part++); 81 + hsize = sprintf(dst, "%s#%d Part%d\n", why, oopscount, part); 85 82 size = psinfo->bufsize - hsize; 86 83 dst += hsize; 87 84 ··· 97 94 memcpy(dst, s1 + s1_start, l1_cpy); 98 95 memcpy(dst + l1_cpy, s2 + s2_start, l2_cpy); 99 96 100 - id = psinfo->write(PSTORE_TYPE_DMESG, hsize + l1_cpy + l2_cpy); 97 + id = psinfo->write(PSTORE_TYPE_DMESG, part, 98 + hsize + l1_cpy + l2_cpy, psinfo); 101 99 if (reason == KMSG_DUMP_OOPS && pstore_is_mounted()) 102 100 pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, 103 101 psinfo->buf, hsize + l1_cpy + l2_cpy, 104 - CURRENT_TIME, psinfo->erase); 102 + CURRENT_TIME, psinfo); 105 103 l1 -= l1_cpy; 106 104 l2 -= l2_cpy; 107 105 total += l1_cpy + l2_cpy; 106 + part++; 108 107 } 109 108 mutex_unlock(&psinfo->buf_mutex); 110 109 } ··· 133 128 spin_unlock(&pstore_lock); 134 129 return -EBUSY; 135 130 } 131 + 132 + if (backend && strcmp(backend, psi->name)) { 133 + spin_unlock(&pstore_lock); 134 + return -EINVAL; 135 + } 136 + 136 137 psinfo = psi; 137 138 spin_unlock(&pstore_lock); 138 139 ··· 177 166 if (rc) 178 167 goto out; 179 168 180 - while ((size = psi->read(&id, &type, &time)) > 0) { 169 + while ((size = psi->read(&id, &type, &time, psi)) > 0) { 181 170 if (pstore_mkfile(type, psi->name, id, psi->buf, (size_t)size, 182 - time, psi->erase)) 171 + time, psi)) 183 172 failed++; 184 173 } 185 174 psi->close(psi); ··· 207 196 208 197 mutex_lock(&psinfo->buf_mutex); 209 198 memcpy(psinfo->buf, buf, size); 210 - id = psinfo->write(type, size); 199 + id = psinfo->write(type, 0, size, psinfo); 211 200 if (pstore_is_mounted()) 212 201 pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf, 213 - size, CURRENT_TIME, psinfo->erase); 202 + size, CURRENT_TIME, psinfo); 214 203 mutex_unlock(&psinfo->buf_mutex); 215 204 216 205 return 0; 217 206 } 218 207 EXPORT_SYMBOL_GPL(pstore_write); 208 + 209 + module_param(backend, charp, 0444); 210 + MODULE_PARM_DESC(backend, "Pstore backend to use");
+6
include/linux/efi.h
··· 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 231 233 232 #define UV_SYSTEM_TABLE_GUID \ 234 233 EFI_GUID( 0x3b13a7d4, 0x633e, 0x11dd, 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93 ) 234 + 235 + #define LINUX_EFI_CRASH_GUID \ 236 + EFI_GUID( 0xcfc8fc79, 0xbe2e, 0x4ddc, 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0 ) 235 237 236 238 typedef struct { 237 239 efi_guid_t guid; ··· 462 458 struct kset *kset; 463 459 struct bin_attribute *new_var, *del_var; 464 460 const struct efivar_operations *ops; 461 + struct efivar_entry *walk_entry; 462 + struct pstore_info efi_pstore_info; 465 463 }; 466 464 467 465 int register_efivars(struct efivars *efivars,
+6 -3
include/linux/pstore.h
··· 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