aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware/efi
diff options
context:
space:
mode:
authorSylvain Chouleur <sylvain.chouleur@intel.com>2016-07-15 15:36:29 -0400
committerMatt Fleming <matt@codeblueprint.co.uk>2016-09-09 11:08:41 -0400
commit217b27d4671a0a3f34147f1b341683d36b7457db (patch)
tree0a862c4f0829553ca238482d2c3f383e349d25e2 /drivers/firmware/efi
parent2ead3084e3fc37d42f379cca8753b458d8f9ba25 (diff)
efi: Use a file local lock for efivars
This patch replaces the spinlock in the efivars struct with a single lock for the whole vars.c file. The goal of this lock is to protect concurrent calls to efi variable services, registering and unregistering. This allows us to register new efivars operations without having in-progress call. Signed-off-by: Sylvain Chouleur <sylvain.chouleur@intel.com> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Leif Lindholm <leif.lindholm@linaro.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Sylvain Chouleur <sylvain.chouleur@gmail.com> Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
Diffstat (limited to 'drivers/firmware/efi')
-rw-r--r--drivers/firmware/efi/vars.c83
1 files changed, 47 insertions, 36 deletions
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index d3b751383286..d0d807e1287e 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -37,6 +37,14 @@
37/* Private pointer to registered efivars */ 37/* Private pointer to registered efivars */
38static struct efivars *__efivars; 38static struct efivars *__efivars;
39 39
40/*
41 * efivars_lock protects three things:
42 * 1) efivarfs_list and efivars_sysfs_list
43 * 2) ->ops calls
44 * 3) (un)registration of __efivars
45 */
46static DEFINE_SPINLOCK(efivars_lock);
47
40static bool efivar_wq_enabled = true; 48static bool efivar_wq_enabled = true;
41DECLARE_WORK(efivar_work, NULL); 49DECLARE_WORK(efivar_work, NULL);
42EXPORT_SYMBOL_GPL(efivar_work); 50EXPORT_SYMBOL_GPL(efivar_work);
@@ -434,7 +442,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
434 return -ENOMEM; 442 return -ENOMEM;
435 } 443 }
436 444
437 spin_lock_irq(&__efivars->lock); 445 spin_lock_irq(&efivars_lock);
438 446
439 /* 447 /*
440 * Per EFI spec, the maximum storage allocated for both 448 * Per EFI spec, the maximum storage allocated for both
@@ -450,7 +458,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
450 switch (status) { 458 switch (status) {
451 case EFI_SUCCESS: 459 case EFI_SUCCESS:
452 if (duplicates) 460 if (duplicates)
453 spin_unlock_irq(&__efivars->lock); 461 spin_unlock_irq(&efivars_lock);
454 462
455 variable_name_size = var_name_strnsize(variable_name, 463 variable_name_size = var_name_strnsize(variable_name,
456 variable_name_size); 464 variable_name_size);
@@ -477,7 +485,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
477 } 485 }
478 486
479 if (duplicates) 487 if (duplicates)
480 spin_lock_irq(&__efivars->lock); 488 spin_lock_irq(&efivars_lock);
481 489
482 break; 490 break;
483 case EFI_NOT_FOUND: 491 case EFI_NOT_FOUND:
@@ -491,7 +499,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
491 499
492 } while (status != EFI_NOT_FOUND); 500 } while (status != EFI_NOT_FOUND);
493 501
494 spin_unlock_irq(&__efivars->lock); 502 spin_unlock_irq(&efivars_lock);
495 503
496 kfree(variable_name); 504 kfree(variable_name);
497 505
@@ -506,9 +514,9 @@ EXPORT_SYMBOL_GPL(efivar_init);
506 */ 514 */
507void efivar_entry_add(struct efivar_entry *entry, struct list_head *head) 515void efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
508{ 516{
509 spin_lock_irq(&__efivars->lock); 517 spin_lock_irq(&efivars_lock);
510 list_add(&entry->list, head); 518 list_add(&entry->list, head);
511 spin_unlock_irq(&__efivars->lock); 519 spin_unlock_irq(&efivars_lock);
512} 520}
513EXPORT_SYMBOL_GPL(efivar_entry_add); 521EXPORT_SYMBOL_GPL(efivar_entry_add);
514 522
@@ -518,9 +526,9 @@ EXPORT_SYMBOL_GPL(efivar_entry_add);
518 */ 526 */
519void efivar_entry_remove(struct efivar_entry *entry) 527void efivar_entry_remove(struct efivar_entry *entry)
520{ 528{
521 spin_lock_irq(&__efivars->lock); 529 spin_lock_irq(&efivars_lock);
522 list_del(&entry->list); 530 list_del(&entry->list);
523 spin_unlock_irq(&__efivars->lock); 531 spin_unlock_irq(&efivars_lock);
524} 532}
525EXPORT_SYMBOL_GPL(efivar_entry_remove); 533EXPORT_SYMBOL_GPL(efivar_entry_remove);
526 534
@@ -537,10 +545,10 @@ EXPORT_SYMBOL_GPL(efivar_entry_remove);
537 */ 545 */
538static void efivar_entry_list_del_unlock(struct efivar_entry *entry) 546static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
539{ 547{
540 lockdep_assert_held(&__efivars->lock); 548 lockdep_assert_held(&efivars_lock);
541 549
542 list_del(&entry->list); 550 list_del(&entry->list);
543 spin_unlock_irq(&__efivars->lock); 551 spin_unlock_irq(&efivars_lock);
544} 552}
545 553
546/** 554/**
@@ -563,7 +571,7 @@ int __efivar_entry_delete(struct efivar_entry *entry)
563 const struct efivar_operations *ops = __efivars->ops; 571 const struct efivar_operations *ops = __efivars->ops;
564 efi_status_t status; 572 efi_status_t status;
565 573
566 lockdep_assert_held(&__efivars->lock); 574 lockdep_assert_held(&efivars_lock);
567 575
568 status = ops->set_variable(entry->var.VariableName, 576 status = ops->set_variable(entry->var.VariableName,
569 &entry->var.VendorGuid, 577 &entry->var.VendorGuid,
@@ -589,12 +597,12 @@ int efivar_entry_delete(struct efivar_entry *entry)
589 const struct efivar_operations *ops = __efivars->ops; 597 const struct efivar_operations *ops = __efivars->ops;
590 efi_status_t status; 598 efi_status_t status;
591 599
592 spin_lock_irq(&__efivars->lock); 600 spin_lock_irq(&efivars_lock);
593 status = ops->set_variable(entry->var.VariableName, 601 status = ops->set_variable(entry->var.VariableName,
594 &entry->var.VendorGuid, 602 &entry->var.VendorGuid,
595 0, 0, NULL); 603 0, 0, NULL);
596 if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) { 604 if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) {
597 spin_unlock_irq(&__efivars->lock); 605 spin_unlock_irq(&efivars_lock);
598 return efi_status_to_err(status); 606 return efi_status_to_err(status);
599 } 607 }
600 608
@@ -632,10 +640,10 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
632 efi_char16_t *name = entry->var.VariableName; 640 efi_char16_t *name = entry->var.VariableName;
633 efi_guid_t vendor = entry->var.VendorGuid; 641 efi_guid_t vendor = entry->var.VendorGuid;
634 642
635 spin_lock_irq(&__efivars->lock); 643 spin_lock_irq(&efivars_lock);
636 644
637 if (head && efivar_entry_find(name, vendor, head, false)) { 645 if (head && efivar_entry_find(name, vendor, head, false)) {
638 spin_unlock_irq(&__efivars->lock); 646 spin_unlock_irq(&efivars_lock);
639 return -EEXIST; 647 return -EEXIST;
640 } 648 }
641 649
@@ -644,7 +652,7 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
644 status = ops->set_variable(name, &vendor, 652 status = ops->set_variable(name, &vendor,
645 attributes, size, data); 653 attributes, size, data);
646 654
647 spin_unlock_irq(&__efivars->lock); 655 spin_unlock_irq(&efivars_lock);
648 656
649 return efi_status_to_err(status); 657 return efi_status_to_err(status);
650 658
@@ -658,7 +666,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_set);
658 * from crash/panic handlers. 666 * from crash/panic handlers.
659 * 667 *
660 * Crucially, this function will not block if it cannot acquire 668 * Crucially, this function will not block if it cannot acquire
661 * __efivars->lock. Instead, it returns -EBUSY. 669 * efivars_lock. Instead, it returns -EBUSY.
662 */ 670 */
663static int 671static int
664efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor, 672efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
@@ -668,20 +676,20 @@ efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
668 unsigned long flags; 676 unsigned long flags;
669 efi_status_t status; 677 efi_status_t status;
670 678
671 if (!spin_trylock_irqsave(&__efivars->lock, flags)) 679 if (!spin_trylock_irqsave(&efivars_lock, flags))
672 return -EBUSY; 680 return -EBUSY;
673 681
674 status = check_var_size_nonblocking(attributes, 682 status = check_var_size_nonblocking(attributes,
675 size + ucs2_strsize(name, 1024)); 683 size + ucs2_strsize(name, 1024));
676 if (status != EFI_SUCCESS) { 684 if (status != EFI_SUCCESS) {
677 spin_unlock_irqrestore(&__efivars->lock, flags); 685 spin_unlock_irqrestore(&efivars_lock, flags);
678 return -ENOSPC; 686 return -ENOSPC;
679 } 687 }
680 688
681 status = ops->set_variable_nonblocking(name, &vendor, attributes, 689 status = ops->set_variable_nonblocking(name, &vendor, attributes,
682 size, data); 690 size, data);
683 691
684 spin_unlock_irqrestore(&__efivars->lock, flags); 692 spin_unlock_irqrestore(&efivars_lock, flags);
685 return efi_status_to_err(status); 693 return efi_status_to_err(status);
686} 694}
687 695
@@ -727,21 +735,21 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
727 size, data); 735 size, data);
728 736
729 if (!block) { 737 if (!block) {
730 if (!spin_trylock_irqsave(&__efivars->lock, flags)) 738 if (!spin_trylock_irqsave(&efivars_lock, flags))
731 return -EBUSY; 739 return -EBUSY;
732 } else { 740 } else {
733 spin_lock_irqsave(&__efivars->lock, flags); 741 spin_lock_irqsave(&efivars_lock, flags);
734 } 742 }
735 743
736 status = check_var_size(attributes, size + ucs2_strsize(name, 1024)); 744 status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
737 if (status != EFI_SUCCESS) { 745 if (status != EFI_SUCCESS) {
738 spin_unlock_irqrestore(&__efivars->lock, flags); 746 spin_unlock_irqrestore(&efivars_lock, flags);
739 return -ENOSPC; 747 return -ENOSPC;
740 } 748 }
741 749
742 status = ops->set_variable(name, &vendor, attributes, size, data); 750 status = ops->set_variable(name, &vendor, attributes, size, data);
743 751
744 spin_unlock_irqrestore(&__efivars->lock, flags); 752 spin_unlock_irqrestore(&efivars_lock, flags);
745 753
746 return efi_status_to_err(status); 754 return efi_status_to_err(status);
747} 755}
@@ -771,7 +779,7 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
771 int strsize1, strsize2; 779 int strsize1, strsize2;
772 bool found = false; 780 bool found = false;
773 781
774 lockdep_assert_held(&__efivars->lock); 782 lockdep_assert_held(&efivars_lock);
775 783
776 list_for_each_entry_safe(entry, n, head, list) { 784 list_for_each_entry_safe(entry, n, head, list) {
777 strsize1 = ucs2_strsize(name, 1024); 785 strsize1 = ucs2_strsize(name, 1024);
@@ -814,10 +822,10 @@ int efivar_entry_size(struct efivar_entry *entry, unsigned long *size)
814 822
815 *size = 0; 823 *size = 0;
816 824
817 spin_lock_irq(&__efivars->lock); 825 spin_lock_irq(&efivars_lock);
818 status = ops->get_variable(entry->var.VariableName, 826 status = ops->get_variable(entry->var.VariableName,
819 &entry->var.VendorGuid, NULL, size, NULL); 827 &entry->var.VendorGuid, NULL, size, NULL);
820 spin_unlock_irq(&__efivars->lock); 828 spin_unlock_irq(&efivars_lock);
821 829
822 if (status != EFI_BUFFER_TOO_SMALL) 830 if (status != EFI_BUFFER_TOO_SMALL)
823 return efi_status_to_err(status); 831 return efi_status_to_err(status);
@@ -843,7 +851,7 @@ int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
843 const struct efivar_operations *ops = __efivars->ops; 851 const struct efivar_operations *ops = __efivars->ops;
844 efi_status_t status; 852 efi_status_t status;
845 853
846 lockdep_assert_held(&__efivars->lock); 854 lockdep_assert_held(&efivars_lock);
847 855
848 status = ops->get_variable(entry->var.VariableName, 856 status = ops->get_variable(entry->var.VariableName,
849 &entry->var.VendorGuid, 857 &entry->var.VendorGuid,
@@ -866,11 +874,11 @@ int efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
866 const struct efivar_operations *ops = __efivars->ops; 874 const struct efivar_operations *ops = __efivars->ops;
867 efi_status_t status; 875 efi_status_t status;
868 876
869 spin_lock_irq(&__efivars->lock); 877 spin_lock_irq(&efivars_lock);
870 status = ops->get_variable(entry->var.VariableName, 878 status = ops->get_variable(entry->var.VariableName,
871 &entry->var.VendorGuid, 879 &entry->var.VendorGuid,
872 attributes, size, data); 880 attributes, size, data);
873 spin_unlock_irq(&__efivars->lock); 881 spin_unlock_irq(&efivars_lock);
874 882
875 return efi_status_to_err(status); 883 return efi_status_to_err(status);
876} 884}
@@ -917,7 +925,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
917 * set_variable call, and removal of the variable from the efivars 925 * set_variable call, and removal of the variable from the efivars
918 * list (in the case of an authenticated delete). 926 * list (in the case of an authenticated delete).
919 */ 927 */
920 spin_lock_irq(&__efivars->lock); 928 spin_lock_irq(&efivars_lock);
921 929
922 /* 930 /*
923 * Ensure that the available space hasn't shrunk below the safe level 931 * Ensure that the available space hasn't shrunk below the safe level
@@ -957,7 +965,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
957 if (status == EFI_NOT_FOUND) 965 if (status == EFI_NOT_FOUND)
958 efivar_entry_list_del_unlock(entry); 966 efivar_entry_list_del_unlock(entry);
959 else 967 else
960 spin_unlock_irq(&__efivars->lock); 968 spin_unlock_irq(&efivars_lock);
961 969
962 if (status && status != EFI_BUFFER_TOO_SMALL) 970 if (status && status != EFI_BUFFER_TOO_SMALL)
963 return efi_status_to_err(status); 971 return efi_status_to_err(status);
@@ -965,7 +973,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
965 return 0; 973 return 0;
966 974
967out: 975out:
968 spin_unlock_irq(&__efivars->lock); 976 spin_unlock_irq(&efivars_lock);
969 return err; 977 return err;
970 978
971} 979}
@@ -980,7 +988,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_set_get_size);
980 */ 988 */
981void efivar_entry_iter_begin(void) 989void efivar_entry_iter_begin(void)
982{ 990{
983 spin_lock_irq(&__efivars->lock); 991 spin_lock_irq(&efivars_lock);
984} 992}
985EXPORT_SYMBOL_GPL(efivar_entry_iter_begin); 993EXPORT_SYMBOL_GPL(efivar_entry_iter_begin);
986 994
@@ -991,7 +999,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_iter_begin);
991 */ 999 */
992void efivar_entry_iter_end(void) 1000void efivar_entry_iter_end(void)
993{ 1001{
994 spin_unlock_irq(&__efivars->lock); 1002 spin_unlock_irq(&efivars_lock);
995} 1003}
996EXPORT_SYMBOL_GPL(efivar_entry_iter_end); 1004EXPORT_SYMBOL_GPL(efivar_entry_iter_end);
997 1005
@@ -1112,11 +1120,12 @@ int efivars_register(struct efivars *efivars,
1112 const struct efivar_operations *ops, 1120 const struct efivar_operations *ops,
1113 struct kobject *kobject) 1121 struct kobject *kobject)
1114{ 1122{
1115 spin_lock_init(&efivars->lock); 1123 spin_lock_irq(&efivars_lock);
1116 efivars->ops = ops; 1124 efivars->ops = ops;
1117 efivars->kobject = kobject; 1125 efivars->kobject = kobject;
1118 1126
1119 __efivars = efivars; 1127 __efivars = efivars;
1128 spin_unlock_irq(&efivars_lock);
1120 1129
1121 return 0; 1130 return 0;
1122} 1131}
@@ -1133,6 +1142,7 @@ int efivars_unregister(struct efivars *efivars)
1133{ 1142{
1134 int rv; 1143 int rv;
1135 1144
1145 spin_lock_irq(&efivars_lock);
1136 if (!__efivars) { 1146 if (!__efivars) {
1137 printk(KERN_ERR "efivars not registered\n"); 1147 printk(KERN_ERR "efivars not registered\n");
1138 rv = -EINVAL; 1148 rv = -EINVAL;
@@ -1148,6 +1158,7 @@ int efivars_unregister(struct efivars *efivars)
1148 1158
1149 rv = 0; 1159 rv = 0;
1150out: 1160out:
1161 spin_unlock_irq(&efivars_lock);
1151 return rv; 1162 return rv;
1152} 1163}
1153EXPORT_SYMBOL_GPL(efivars_unregister); 1164EXPORT_SYMBOL_GPL(efivars_unregister);