diff options
-rw-r--r-- | Documentation/ABI/testing/pstore | 10 | ||||
-rw-r--r-- | drivers/firmware/efivars.c | 180 | ||||
-rw-r--r-- | fs/pstore/inode.c | 18 | ||||
-rw-r--r-- | fs/pstore/platform.c | 35 | ||||
-rw-r--r-- | include/linux/efi.h | 3 | ||||
-rw-r--r-- | include/linux/pstore.h | 6 |
6 files changed, 192 insertions, 60 deletions
diff --git a/Documentation/ABI/testing/pstore b/Documentation/ABI/testing/pstore index ff1df4e3b059..5fca9f5e10a3 100644 --- a/Documentation/ABI/testing/pstore +++ b/Documentation/ABI/testing/pstore | |||
@@ -1,4 +1,4 @@ | |||
1 | Where: /dev/pstore/... | 1 | Where: /sys/fs/pstore/... (or /dev/pstore/...) |
2 | Date: March 2011 | 2 | Date: March 2011 |
3 | Kernel Version: 2.6.39 | 3 | Kernel Version: 2.6.39 |
4 | Contact: tony.luck@intel.com | 4 | Contact: tony.luck@intel.com |
@@ -11,9 +11,9 @@ Description: Generic interface to platform dependent persistent storage. | |||
11 | of the console log is captured, but other interesting | 11 | of the console log is captured, but other interesting |
12 | data can also be saved. | 12 | data can also be saved. |
13 | 13 | ||
14 | # mount -t pstore -o kmsg_bytes=8000 - /dev/pstore | 14 | # mount -t pstore -o kmsg_bytes=8000 - /sys/fs/pstore |
15 | 15 | ||
16 | $ ls -l /dev/pstore | 16 | $ ls -l /sys/fs/pstore/ |
17 | total 0 | 17 | total 0 |
18 | -r--r--r-- 1 root root 7896 Nov 30 15:38 dmesg-erst-1 | 18 | -r--r--r-- 1 root root 7896 Nov 30 15:38 dmesg-erst-1 |
19 | 19 | ||
@@ -27,9 +27,9 @@ Description: Generic interface to platform dependent persistent storage. | |||
27 | the file will signal to the underlying persistent storage | 27 | the file will signal to the underlying persistent storage |
28 | device that it can reclaim the space for later re-use. | 28 | device that it can reclaim the space for later re-use. |
29 | 29 | ||
30 | $ rm /dev/pstore/dmesg-erst-1 | 30 | $ rm /sys/fs/pstore/dmesg-erst-1 |
31 | 31 | ||
32 | The expectation is that all files in /dev/pstore | 32 | The expectation is that all files in /sys/fs/pstore/ |
33 | will be saved elsewhere and erased from persistent store | 33 | will be saved elsewhere and erased from persistent store |
34 | soon after boot to free up space ready for the next | 34 | soon after boot to free up space ready for the next |
35 | catastrophe. | 35 | catastrophe. |
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index f5596db0cf58..fed08b661711 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c | |||
@@ -158,6 +158,13 @@ efivar_create_sysfs_entry(struct efivars *efivars, | |||
158 | efi_char16_t *variable_name, | 158 | efi_char16_t *variable_name, |
159 | efi_guid_t *vendor_guid); | 159 | efi_guid_t *vendor_guid); |
160 | 160 | ||
161 | /* | ||
162 | * Prototype for workqueue functions updating sysfs entry | ||
163 | */ | ||
164 | |||
165 | static void efivar_update_sysfs_entries(struct work_struct *); | ||
166 | static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); | ||
167 | |||
161 | /* Return the number of unicode characters in data */ | 168 | /* Return the number of unicode characters in data */ |
162 | static unsigned long | 169 | static unsigned long |
163 | utf16_strnlen(efi_char16_t *s, size_t maxlength) | 170 | utf16_strnlen(efi_char16_t *s, size_t maxlength) |
@@ -405,10 +412,11 @@ static efi_status_t | |||
405 | get_var_data(struct efivars *efivars, struct efi_variable *var) | 412 | get_var_data(struct efivars *efivars, struct efi_variable *var) |
406 | { | 413 | { |
407 | efi_status_t status; | 414 | efi_status_t status; |
415 | unsigned long flags; | ||
408 | 416 | ||
409 | spin_lock(&efivars->lock); | 417 | spin_lock_irqsave(&efivars->lock, flags); |
410 | status = get_var_data_locked(efivars, var); | 418 | status = get_var_data_locked(efivars, var); |
411 | spin_unlock(&efivars->lock); | 419 | spin_unlock_irqrestore(&efivars->lock, flags); |
412 | 420 | ||
413 | if (status != EFI_SUCCESS) { | 421 | if (status != EFI_SUCCESS) { |
414 | printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n", | 422 | printk(KERN_WARNING "efivars: get_variable() failed 0x%lx!\n", |
@@ -537,14 +545,14 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) | |||
537 | return -EINVAL; | 545 | return -EINVAL; |
538 | } | 546 | } |
539 | 547 | ||
540 | spin_lock(&efivars->lock); | 548 | spin_lock_irq(&efivars->lock); |
541 | status = efivars->ops->set_variable(new_var->VariableName, | 549 | status = efivars->ops->set_variable(new_var->VariableName, |
542 | &new_var->VendorGuid, | 550 | &new_var->VendorGuid, |
543 | new_var->Attributes, | 551 | new_var->Attributes, |
544 | new_var->DataSize, | 552 | new_var->DataSize, |
545 | new_var->Data); | 553 | new_var->Data); |
546 | 554 | ||
547 | spin_unlock(&efivars->lock); | 555 | spin_unlock_irq(&efivars->lock); |
548 | 556 | ||
549 | if (status != EFI_SUCCESS) { | 557 | if (status != EFI_SUCCESS) { |
550 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", | 558 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", |
@@ -713,7 +721,7 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
713 | * amounts of memory. Pick a default size of 64K if | 721 | * amounts of memory. Pick a default size of 64K if |
714 | * QueryVariableInfo() isn't supported by the firmware. | 722 | * QueryVariableInfo() isn't supported by the firmware. |
715 | */ | 723 | */ |
716 | spin_lock(&efivars->lock); | 724 | spin_lock_irq(&efivars->lock); |
717 | 725 | ||
718 | if (!efivars->ops->query_variable_info) | 726 | if (!efivars->ops->query_variable_info) |
719 | status = EFI_UNSUPPORTED; | 727 | status = EFI_UNSUPPORTED; |
@@ -723,7 +731,7 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
723 | &remaining_size, &max_size); | 731 | &remaining_size, &max_size); |
724 | } | 732 | } |
725 | 733 | ||
726 | spin_unlock(&efivars->lock); | 734 | spin_unlock_irq(&efivars->lock); |
727 | 735 | ||
728 | if (status != EFI_SUCCESS) { | 736 | if (status != EFI_SUCCESS) { |
729 | if (status != EFI_UNSUPPORTED) | 737 | if (status != EFI_UNSUPPORTED) |
@@ -754,7 +762,7 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
754 | * set_variable call, and removal of the variable from the efivars | 762 | * set_variable call, and removal of the variable from the efivars |
755 | * list (in the case of an authenticated delete). | 763 | * list (in the case of an authenticated delete). |
756 | */ | 764 | */ |
757 | spin_lock(&efivars->lock); | 765 | spin_lock_irq(&efivars->lock); |
758 | 766 | ||
759 | status = efivars->ops->set_variable(var->var.VariableName, | 767 | status = efivars->ops->set_variable(var->var.VariableName, |
760 | &var->var.VendorGuid, | 768 | &var->var.VendorGuid, |
@@ -762,7 +770,7 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
762 | data); | 770 | data); |
763 | 771 | ||
764 | if (status != EFI_SUCCESS) { | 772 | if (status != EFI_SUCCESS) { |
765 | spin_unlock(&efivars->lock); | 773 | spin_unlock_irq(&efivars->lock); |
766 | kfree(data); | 774 | kfree(data); |
767 | 775 | ||
768 | return efi_status_to_err(status); | 776 | return efi_status_to_err(status); |
@@ -783,21 +791,21 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
783 | NULL); | 791 | NULL); |
784 | 792 | ||
785 | if (status == EFI_BUFFER_TOO_SMALL) { | 793 | if (status == EFI_BUFFER_TOO_SMALL) { |
786 | spin_unlock(&efivars->lock); | 794 | spin_unlock_irq(&efivars->lock); |
787 | mutex_lock(&inode->i_mutex); | 795 | mutex_lock(&inode->i_mutex); |
788 | i_size_write(inode, newdatasize + sizeof(attributes)); | 796 | i_size_write(inode, newdatasize + sizeof(attributes)); |
789 | mutex_unlock(&inode->i_mutex); | 797 | mutex_unlock(&inode->i_mutex); |
790 | 798 | ||
791 | } else if (status == EFI_NOT_FOUND) { | 799 | } else if (status == EFI_NOT_FOUND) { |
792 | list_del(&var->list); | 800 | list_del(&var->list); |
793 | spin_unlock(&efivars->lock); | 801 | spin_unlock_irq(&efivars->lock); |
794 | efivar_unregister(var); | 802 | efivar_unregister(var); |
795 | drop_nlink(inode); | 803 | drop_nlink(inode); |
796 | d_delete(file->f_dentry); | 804 | d_delete(file->f_dentry); |
797 | dput(file->f_dentry); | 805 | dput(file->f_dentry); |
798 | 806 | ||
799 | } else { | 807 | } else { |
800 | spin_unlock(&efivars->lock); | 808 | spin_unlock_irq(&efivars->lock); |
801 | pr_warn("efivarfs: inconsistent EFI variable implementation? " | 809 | pr_warn("efivarfs: inconsistent EFI variable implementation? " |
802 | "status = %lx\n", status); | 810 | "status = %lx\n", status); |
803 | } | 811 | } |
@@ -819,11 +827,11 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, | |||
819 | void *data; | 827 | void *data; |
820 | ssize_t size = 0; | 828 | ssize_t size = 0; |
821 | 829 | ||
822 | spin_lock(&efivars->lock); | 830 | spin_lock_irq(&efivars->lock); |
823 | status = efivars->ops->get_variable(var->var.VariableName, | 831 | status = efivars->ops->get_variable(var->var.VariableName, |
824 | &var->var.VendorGuid, | 832 | &var->var.VendorGuid, |
825 | &attributes, &datasize, NULL); | 833 | &attributes, &datasize, NULL); |
826 | spin_unlock(&efivars->lock); | 834 | spin_unlock_irq(&efivars->lock); |
827 | 835 | ||
828 | if (status != EFI_BUFFER_TOO_SMALL) | 836 | if (status != EFI_BUFFER_TOO_SMALL) |
829 | return efi_status_to_err(status); | 837 | return efi_status_to_err(status); |
@@ -833,12 +841,12 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, | |||
833 | if (!data) | 841 | if (!data) |
834 | return -ENOMEM; | 842 | return -ENOMEM; |
835 | 843 | ||
836 | spin_lock(&efivars->lock); | 844 | spin_lock_irq(&efivars->lock); |
837 | status = efivars->ops->get_variable(var->var.VariableName, | 845 | status = efivars->ops->get_variable(var->var.VariableName, |
838 | &var->var.VendorGuid, | 846 | &var->var.VendorGuid, |
839 | &attributes, &datasize, | 847 | &attributes, &datasize, |
840 | (data + sizeof(attributes))); | 848 | (data + sizeof(attributes))); |
841 | spin_unlock(&efivars->lock); | 849 | spin_unlock_irq(&efivars->lock); |
842 | 850 | ||
843 | if (status != EFI_SUCCESS) { | 851 | if (status != EFI_SUCCESS) { |
844 | size = efi_status_to_err(status); | 852 | size = efi_status_to_err(status); |
@@ -966,9 +974,9 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry, | |||
966 | goto out; | 974 | goto out; |
967 | 975 | ||
968 | kobject_uevent(&var->kobj, KOBJ_ADD); | 976 | kobject_uevent(&var->kobj, KOBJ_ADD); |
969 | spin_lock(&efivars->lock); | 977 | spin_lock_irq(&efivars->lock); |
970 | list_add(&var->list, &efivars->list); | 978 | list_add(&var->list, &efivars->list); |
971 | spin_unlock(&efivars->lock); | 979 | spin_unlock_irq(&efivars->lock); |
972 | d_instantiate(dentry, inode); | 980 | d_instantiate(dentry, inode); |
973 | dget(dentry); | 981 | dget(dentry); |
974 | out: | 982 | out: |
@@ -985,7 +993,7 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) | |||
985 | struct efivars *efivars = var->efivars; | 993 | struct efivars *efivars = var->efivars; |
986 | efi_status_t status; | 994 | efi_status_t status; |
987 | 995 | ||
988 | spin_lock(&efivars->lock); | 996 | spin_lock_irq(&efivars->lock); |
989 | 997 | ||
990 | status = efivars->ops->set_variable(var->var.VariableName, | 998 | status = efivars->ops->set_variable(var->var.VariableName, |
991 | &var->var.VendorGuid, | 999 | &var->var.VendorGuid, |
@@ -993,14 +1001,14 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) | |||
993 | 1001 | ||
994 | if (status == EFI_SUCCESS || status == EFI_NOT_FOUND) { | 1002 | if (status == EFI_SUCCESS || status == EFI_NOT_FOUND) { |
995 | list_del(&var->list); | 1003 | list_del(&var->list); |
996 | spin_unlock(&efivars->lock); | 1004 | spin_unlock_irq(&efivars->lock); |
997 | efivar_unregister(var); | 1005 | efivar_unregister(var); |
998 | drop_nlink(dentry->d_inode); | 1006 | drop_nlink(dentry->d_inode); |
999 | dput(dentry); | 1007 | dput(dentry); |
1000 | return 0; | 1008 | return 0; |
1001 | } | 1009 | } |
1002 | 1010 | ||
1003 | spin_unlock(&efivars->lock); | 1011 | spin_unlock_irq(&efivars->lock); |
1004 | return -EINVAL; | 1012 | return -EINVAL; |
1005 | }; | 1013 | }; |
1006 | 1014 | ||
@@ -1066,13 +1074,13 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) | |||
1066 | /* copied by the above to local storage in the dentry. */ | 1074 | /* copied by the above to local storage in the dentry. */ |
1067 | kfree(name); | 1075 | kfree(name); |
1068 | 1076 | ||
1069 | spin_lock(&efivars->lock); | 1077 | spin_lock_irq(&efivars->lock); |
1070 | efivars->ops->get_variable(entry->var.VariableName, | 1078 | efivars->ops->get_variable(entry->var.VariableName, |
1071 | &entry->var.VendorGuid, | 1079 | &entry->var.VendorGuid, |
1072 | &entry->var.Attributes, | 1080 | &entry->var.Attributes, |
1073 | &size, | 1081 | &size, |
1074 | NULL); | 1082 | NULL); |
1075 | spin_unlock(&efivars->lock); | 1083 | spin_unlock_irq(&efivars->lock); |
1076 | 1084 | ||
1077 | mutex_lock(&inode->i_mutex); | 1085 | mutex_lock(&inode->i_mutex); |
1078 | inode->i_private = entry; | 1086 | inode->i_private = entry; |
@@ -1123,7 +1131,7 @@ static int efi_pstore_open(struct pstore_info *psi) | |||
1123 | { | 1131 | { |
1124 | struct efivars *efivars = psi->data; | 1132 | struct efivars *efivars = psi->data; |
1125 | 1133 | ||
1126 | spin_lock(&efivars->lock); | 1134 | spin_lock_irq(&efivars->lock); |
1127 | efivars->walk_entry = list_first_entry(&efivars->list, | 1135 | efivars->walk_entry = list_first_entry(&efivars->list, |
1128 | struct efivar_entry, list); | 1136 | struct efivar_entry, list); |
1129 | return 0; | 1137 | return 0; |
@@ -1133,7 +1141,7 @@ static int efi_pstore_close(struct pstore_info *psi) | |||
1133 | { | 1141 | { |
1134 | struct efivars *efivars = psi->data; | 1142 | struct efivars *efivars = psi->data; |
1135 | 1143 | ||
1136 | spin_unlock(&efivars->lock); | 1144 | spin_unlock_irq(&efivars->lock); |
1137 | return 0; | 1145 | return 0; |
1138 | } | 1146 | } |
1139 | 1147 | ||
@@ -1209,8 +1217,18 @@ static int efi_pstore_write(enum pstore_type_id type, | |||
1209 | int i, ret = 0; | 1217 | int i, ret = 0; |
1210 | u64 storage_space, remaining_space, max_variable_size; | 1218 | u64 storage_space, remaining_space, max_variable_size; |
1211 | efi_status_t status = EFI_NOT_FOUND; | 1219 | efi_status_t status = EFI_NOT_FOUND; |
1212 | 1220 | unsigned long flags; | |
1213 | spin_lock(&efivars->lock); | 1221 | |
1222 | if (pstore_cannot_block_path(reason)) { | ||
1223 | /* | ||
1224 | * If the lock is taken by another cpu in non-blocking path, | ||
1225 | * this driver returns without entering firmware to avoid | ||
1226 | * hanging up. | ||
1227 | */ | ||
1228 | if (!spin_trylock_irqsave(&efivars->lock, flags)) | ||
1229 | return -EBUSY; | ||
1230 | } else | ||
1231 | spin_lock_irqsave(&efivars->lock, flags); | ||
1214 | 1232 | ||
1215 | /* | 1233 | /* |
1216 | * Check if there is a space enough to log. | 1234 | * Check if there is a space enough to log. |
@@ -1222,7 +1240,7 @@ static int efi_pstore_write(enum pstore_type_id type, | |||
1222 | &remaining_space, | 1240 | &remaining_space, |
1223 | &max_variable_size); | 1241 | &max_variable_size); |
1224 | if (status || remaining_space < size + DUMP_NAME_LEN * 2) { | 1242 | if (status || remaining_space < size + DUMP_NAME_LEN * 2) { |
1225 | spin_unlock(&efivars->lock); | 1243 | spin_unlock_irqrestore(&efivars->lock, flags); |
1226 | *id = part; | 1244 | *id = part; |
1227 | return -ENOSPC; | 1245 | return -ENOSPC; |
1228 | } | 1246 | } |
@@ -1236,13 +1254,10 @@ static int efi_pstore_write(enum pstore_type_id type, | |||
1236 | efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES, | 1254 | efivars->ops->set_variable(efi_name, &vendor, PSTORE_EFI_ATTRIBUTES, |
1237 | size, psi->buf); | 1255 | size, psi->buf); |
1238 | 1256 | ||
1239 | spin_unlock(&efivars->lock); | 1257 | spin_unlock_irqrestore(&efivars->lock, flags); |
1240 | 1258 | ||
1241 | if (size) | 1259 | if (reason == KMSG_DUMP_OOPS) |
1242 | ret = efivar_create_sysfs_entry(efivars, | 1260 | schedule_work(&efivar_work); |
1243 | utf16_strsize(efi_name, | ||
1244 | DUMP_NAME_LEN * 2), | ||
1245 | efi_name, &vendor); | ||
1246 | 1261 | ||
1247 | *id = part; | 1262 | *id = part; |
1248 | return ret; | 1263 | return ret; |
@@ -1263,7 +1278,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
1263 | sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, | 1278 | sprintf(name, "dump-type%u-%u-%d-%lu", type, (unsigned int)id, count, |
1264 | time.tv_sec); | 1279 | time.tv_sec); |
1265 | 1280 | ||
1266 | spin_lock(&efivars->lock); | 1281 | spin_lock_irq(&efivars->lock); |
1267 | 1282 | ||
1268 | for (i = 0; i < DUMP_NAME_LEN; i++) | 1283 | for (i = 0; i < DUMP_NAME_LEN; i++) |
1269 | efi_name[i] = name[i]; | 1284 | efi_name[i] = name[i]; |
@@ -1307,7 +1322,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
1307 | if (found) | 1322 | if (found) |
1308 | list_del(&found->list); | 1323 | list_del(&found->list); |
1309 | 1324 | ||
1310 | spin_unlock(&efivars->lock); | 1325 | spin_unlock_irq(&efivars->lock); |
1311 | 1326 | ||
1312 | if (found) | 1327 | if (found) |
1313 | efivar_unregister(found); | 1328 | efivar_unregister(found); |
@@ -1377,7 +1392,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | |||
1377 | return -EINVAL; | 1392 | return -EINVAL; |
1378 | } | 1393 | } |
1379 | 1394 | ||
1380 | spin_lock(&efivars->lock); | 1395 | spin_lock_irq(&efivars->lock); |
1381 | 1396 | ||
1382 | /* | 1397 | /* |
1383 | * Does this variable already exist? | 1398 | * Does this variable already exist? |
@@ -1395,7 +1410,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | |||
1395 | } | 1410 | } |
1396 | } | 1411 | } |
1397 | if (found) { | 1412 | if (found) { |
1398 | spin_unlock(&efivars->lock); | 1413 | spin_unlock_irq(&efivars->lock); |
1399 | return -EINVAL; | 1414 | return -EINVAL; |
1400 | } | 1415 | } |
1401 | 1416 | ||
@@ -1409,10 +1424,10 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | |||
1409 | if (status != EFI_SUCCESS) { | 1424 | if (status != EFI_SUCCESS) { |
1410 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", | 1425 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", |
1411 | status); | 1426 | status); |
1412 | spin_unlock(&efivars->lock); | 1427 | spin_unlock_irq(&efivars->lock); |
1413 | return -EIO; | 1428 | return -EIO; |
1414 | } | 1429 | } |
1415 | spin_unlock(&efivars->lock); | 1430 | spin_unlock_irq(&efivars->lock); |
1416 | 1431 | ||
1417 | /* Create the entry in sysfs. Locking is not required here */ | 1432 | /* Create the entry in sysfs. Locking is not required here */ |
1418 | status = efivar_create_sysfs_entry(efivars, | 1433 | status = efivar_create_sysfs_entry(efivars, |
@@ -1440,7 +1455,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | |||
1440 | if (!capable(CAP_SYS_ADMIN)) | 1455 | if (!capable(CAP_SYS_ADMIN)) |
1441 | return -EACCES; | 1456 | return -EACCES; |
1442 | 1457 | ||
1443 | spin_lock(&efivars->lock); | 1458 | spin_lock_irq(&efivars->lock); |
1444 | 1459 | ||
1445 | /* | 1460 | /* |
1446 | * Does this variable already exist? | 1461 | * Does this variable already exist? |
@@ -1458,7 +1473,7 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | |||
1458 | } | 1473 | } |
1459 | } | 1474 | } |
1460 | if (!found) { | 1475 | if (!found) { |
1461 | spin_unlock(&efivars->lock); | 1476 | spin_unlock_irq(&efivars->lock); |
1462 | return -EINVAL; | 1477 | return -EINVAL; |
1463 | } | 1478 | } |
1464 | /* force the Attributes/DataSize to 0 to ensure deletion */ | 1479 | /* force the Attributes/DataSize to 0 to ensure deletion */ |
@@ -1474,18 +1489,87 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | |||
1474 | if (status != EFI_SUCCESS) { | 1489 | if (status != EFI_SUCCESS) { |
1475 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", | 1490 | printk(KERN_WARNING "efivars: set_variable() failed: status=%lx\n", |
1476 | status); | 1491 | status); |
1477 | spin_unlock(&efivars->lock); | 1492 | spin_unlock_irq(&efivars->lock); |
1478 | return -EIO; | 1493 | return -EIO; |
1479 | } | 1494 | } |
1480 | list_del(&search_efivar->list); | 1495 | list_del(&search_efivar->list); |
1481 | /* We need to release this lock before unregistering. */ | 1496 | /* We need to release this lock before unregistering. */ |
1482 | spin_unlock(&efivars->lock); | 1497 | spin_unlock_irq(&efivars->lock); |
1483 | efivar_unregister(search_efivar); | 1498 | efivar_unregister(search_efivar); |
1484 | 1499 | ||
1485 | /* It's dead Jim.... */ | 1500 | /* It's dead Jim.... */ |
1486 | return count; | 1501 | return count; |
1487 | } | 1502 | } |
1488 | 1503 | ||
1504 | static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor) | ||
1505 | { | ||
1506 | struct efivar_entry *entry, *n; | ||
1507 | struct efivars *efivars = &__efivars; | ||
1508 | unsigned long strsize1, strsize2; | ||
1509 | bool found = false; | ||
1510 | |||
1511 | strsize1 = utf16_strsize(variable_name, 1024); | ||
1512 | list_for_each_entry_safe(entry, n, &efivars->list, list) { | ||
1513 | strsize2 = utf16_strsize(entry->var.VariableName, 1024); | ||
1514 | if (strsize1 == strsize2 && | ||
1515 | !memcmp(variable_name, &(entry->var.VariableName), | ||
1516 | strsize2) && | ||
1517 | !efi_guidcmp(entry->var.VendorGuid, | ||
1518 | *vendor)) { | ||
1519 | found = true; | ||
1520 | break; | ||
1521 | } | ||
1522 | } | ||
1523 | return found; | ||
1524 | } | ||
1525 | |||
1526 | static void efivar_update_sysfs_entries(struct work_struct *work) | ||
1527 | { | ||
1528 | struct efivars *efivars = &__efivars; | ||
1529 | efi_guid_t vendor; | ||
1530 | efi_char16_t *variable_name; | ||
1531 | unsigned long variable_name_size = 1024; | ||
1532 | efi_status_t status = EFI_NOT_FOUND; | ||
1533 | bool found; | ||
1534 | |||
1535 | /* Add new sysfs entries */ | ||
1536 | while (1) { | ||
1537 | variable_name = kzalloc(variable_name_size, GFP_KERNEL); | ||
1538 | if (!variable_name) { | ||
1539 | pr_err("efivars: Memory allocation failed.\n"); | ||
1540 | return; | ||
1541 | } | ||
1542 | |||
1543 | spin_lock_irq(&efivars->lock); | ||
1544 | found = false; | ||
1545 | while (1) { | ||
1546 | variable_name_size = 1024; | ||
1547 | status = efivars->ops->get_next_variable( | ||
1548 | &variable_name_size, | ||
1549 | variable_name, | ||
1550 | &vendor); | ||
1551 | if (status != EFI_SUCCESS) { | ||
1552 | break; | ||
1553 | } else { | ||
1554 | if (!variable_is_present(variable_name, | ||
1555 | &vendor)) { | ||
1556 | found = true; | ||
1557 | break; | ||
1558 | } | ||
1559 | } | ||
1560 | } | ||
1561 | spin_unlock_irq(&efivars->lock); | ||
1562 | |||
1563 | if (!found) { | ||
1564 | kfree(variable_name); | ||
1565 | break; | ||
1566 | } else | ||
1567 | efivar_create_sysfs_entry(efivars, | ||
1568 | variable_name_size, | ||
1569 | variable_name, &vendor); | ||
1570 | } | ||
1571 | } | ||
1572 | |||
1489 | /* | 1573 | /* |
1490 | * Let's not leave out systab information that snuck into | 1574 | * Let's not leave out systab information that snuck into |
1491 | * the efivars driver | 1575 | * the efivars driver |
@@ -1594,9 +1678,9 @@ efivar_create_sysfs_entry(struct efivars *efivars, | |||
1594 | kfree(short_name); | 1678 | kfree(short_name); |
1595 | short_name = NULL; | 1679 | short_name = NULL; |
1596 | 1680 | ||
1597 | spin_lock(&efivars->lock); | 1681 | spin_lock_irq(&efivars->lock); |
1598 | list_add(&new_efivar->list, &efivars->list); | 1682 | list_add(&new_efivar->list, &efivars->list); |
1599 | spin_unlock(&efivars->lock); | 1683 | spin_unlock_irq(&efivars->lock); |
1600 | 1684 | ||
1601 | return 0; | 1685 | return 0; |
1602 | } | 1686 | } |
@@ -1665,9 +1749,9 @@ void unregister_efivars(struct efivars *efivars) | |||
1665 | struct efivar_entry *entry, *n; | 1749 | struct efivar_entry *entry, *n; |
1666 | 1750 | ||
1667 | list_for_each_entry_safe(entry, n, &efivars->list, list) { | 1751 | list_for_each_entry_safe(entry, n, &efivars->list, list) { |
1668 | spin_lock(&efivars->lock); | 1752 | spin_lock_irq(&efivars->lock); |
1669 | list_del(&entry->list); | 1753 | list_del(&entry->list); |
1670 | spin_unlock(&efivars->lock); | 1754 | spin_unlock_irq(&efivars->lock); |
1671 | efivar_unregister(entry); | 1755 | efivar_unregister(entry); |
1672 | } | 1756 | } |
1673 | if (efivars->new_var) | 1757 | if (efivars->new_var) |
@@ -1823,6 +1907,8 @@ err_put: | |||
1823 | static void __exit | 1907 | static void __exit |
1824 | efivars_exit(void) | 1908 | efivars_exit(void) |
1825 | { | 1909 | { |
1910 | cancel_work_sync(&efivar_work); | ||
1911 | |||
1826 | if (efi_enabled(EFI_RUNTIME_SERVICES)) { | 1912 | if (efi_enabled(EFI_RUNTIME_SERVICES)) { |
1827 | unregister_efivars(&__efivars); | 1913 | unregister_efivars(&__efivars); |
1828 | kobject_put(efi_kobj); | 1914 | kobject_put(efi_kobj); |
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c index 67de74ca85f4..e4bcb2cf055a 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c | |||
@@ -418,9 +418,25 @@ static struct file_system_type pstore_fs_type = { | |||
418 | .kill_sb = pstore_kill_sb, | 418 | .kill_sb = pstore_kill_sb, |
419 | }; | 419 | }; |
420 | 420 | ||
421 | static struct kobject *pstore_kobj; | ||
422 | |||
421 | static int __init init_pstore_fs(void) | 423 | static int __init init_pstore_fs(void) |
422 | { | 424 | { |
423 | return register_filesystem(&pstore_fs_type); | 425 | int err = 0; |
426 | |||
427 | /* Create a convenient mount point for people to access pstore */ | ||
428 | pstore_kobj = kobject_create_and_add("pstore", fs_kobj); | ||
429 | if (!pstore_kobj) { | ||
430 | err = -ENOMEM; | ||
431 | goto out; | ||
432 | } | ||
433 | |||
434 | err = register_filesystem(&pstore_fs_type); | ||
435 | if (err < 0) | ||
436 | kobject_put(pstore_kobj); | ||
437 | |||
438 | out: | ||
439 | return err; | ||
424 | } | 440 | } |
425 | module_init(init_pstore_fs) | 441 | module_init(init_pstore_fs) |
426 | 442 | ||
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 5ea2e77ff023..86d1038b5a12 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c | |||
@@ -96,6 +96,27 @@ static const char *get_reason_str(enum kmsg_dump_reason reason) | |||
96 | } | 96 | } |
97 | } | 97 | } |
98 | 98 | ||
99 | bool pstore_cannot_block_path(enum kmsg_dump_reason reason) | ||
100 | { | ||
101 | /* | ||
102 | * In case of NMI path, pstore shouldn't be blocked | ||
103 | * regardless of reason. | ||
104 | */ | ||
105 | if (in_nmi()) | ||
106 | return true; | ||
107 | |||
108 | switch (reason) { | ||
109 | /* In panic case, other cpus are stopped by smp_send_stop(). */ | ||
110 | case KMSG_DUMP_PANIC: | ||
111 | /* Emergency restart shouldn't be blocked by spin lock. */ | ||
112 | case KMSG_DUMP_EMERG: | ||
113 | return true; | ||
114 | default: | ||
115 | return false; | ||
116 | } | ||
117 | } | ||
118 | EXPORT_SYMBOL_GPL(pstore_cannot_block_path); | ||
119 | |||
99 | /* | 120 | /* |
100 | * callback from kmsg_dump. (s2,l2) has the most recently | 121 | * callback from kmsg_dump. (s2,l2) has the most recently |
101 | * written bytes, older bytes are in (s1,l1). Save as much | 122 | * written bytes, older bytes are in (s1,l1). Save as much |
@@ -114,10 +135,12 @@ static void pstore_dump(struct kmsg_dumper *dumper, | |||
114 | 135 | ||
115 | why = get_reason_str(reason); | 136 | why = get_reason_str(reason); |
116 | 137 | ||
117 | if (in_nmi()) { | 138 | if (pstore_cannot_block_path(reason)) { |
118 | is_locked = spin_trylock(&psinfo->buf_lock); | 139 | is_locked = spin_trylock_irqsave(&psinfo->buf_lock, flags); |
119 | if (!is_locked) | 140 | if (!is_locked) { |
120 | pr_err("pstore dump routine blocked in NMI, may corrupt error record\n"); | 141 | pr_err("pstore dump routine blocked in %s path, may corrupt error record\n" |
142 | , in_nmi() ? "NMI" : why); | ||
143 | } | ||
121 | } else | 144 | } else |
122 | spin_lock_irqsave(&psinfo->buf_lock, flags); | 145 | spin_lock_irqsave(&psinfo->buf_lock, flags); |
123 | oopscount++; | 146 | oopscount++; |
@@ -143,9 +166,9 @@ static void pstore_dump(struct kmsg_dumper *dumper, | |||
143 | total += hsize + len; | 166 | total += hsize + len; |
144 | part++; | 167 | part++; |
145 | } | 168 | } |
146 | if (in_nmi()) { | 169 | if (pstore_cannot_block_path(reason)) { |
147 | if (is_locked) | 170 | if (is_locked) |
148 | spin_unlock(&psinfo->buf_lock); | 171 | spin_unlock_irqrestore(&psinfo->buf_lock, flags); |
149 | } else | 172 | } else |
150 | spin_unlock_irqrestore(&psinfo->buf_lock, flags); | 173 | spin_unlock_irqrestore(&psinfo->buf_lock, flags); |
151 | } | 174 | } |
diff --git a/include/linux/efi.h b/include/linux/efi.h index 7a9498ab3c2d..9bf2f1fcae27 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
@@ -740,7 +740,8 @@ struct efivars { | |||
740 | * 1) ->list - adds, removals, reads, writes | 740 | * 1) ->list - adds, removals, reads, writes |
741 | * 2) ops.[gs]et_variable() calls. | 741 | * 2) ops.[gs]et_variable() calls. |
742 | * It must not be held when creating sysfs entries or calling kmalloc. | 742 | * It must not be held when creating sysfs entries or calling kmalloc. |
743 | * ops.get_next_variable() is only called from register_efivars(), | 743 | * ops.get_next_variable() is only called from register_efivars() |
744 | * or efivar_update_sysfs_entries(), | ||
744 | * which is protected by the BKL, so that path is safe. | 745 | * which is protected by the BKL, so that path is safe. |
745 | */ | 746 | */ |
746 | spinlock_t lock; | 747 | spinlock_t lock; |
diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 1788909d9a99..75d01760c911 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h | |||
@@ -68,12 +68,18 @@ struct pstore_info { | |||
68 | 68 | ||
69 | #ifdef CONFIG_PSTORE | 69 | #ifdef CONFIG_PSTORE |
70 | extern int pstore_register(struct pstore_info *); | 70 | extern int pstore_register(struct pstore_info *); |
71 | extern bool pstore_cannot_block_path(enum kmsg_dump_reason reason); | ||
71 | #else | 72 | #else |
72 | static inline int | 73 | static inline int |
73 | pstore_register(struct pstore_info *psi) | 74 | pstore_register(struct pstore_info *psi) |
74 | { | 75 | { |
75 | return -ENODEV; | 76 | return -ENODEV; |
76 | } | 77 | } |
78 | static inline bool | ||
79 | pstore_cannot_block_path(enum kmsg_dump_reason reason) | ||
80 | { | ||
81 | return false; | ||
82 | } | ||
77 | #endif | 83 | #endif |
78 | 84 | ||
79 | #endif /*_LINUX_PSTORE_H*/ | 85 | #endif /*_LINUX_PSTORE_H*/ |