summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSylvain Chouleur <sylvain.chouleur@intel.com>2016-07-15 15:36:30 -0400
committerMatt Fleming <matt@codeblueprint.co.uk>2016-09-09 11:08:42 -0400
commit21b3ddd39feecd2f4d6c52bcd30f0a4fa14f125a (patch)
tree40773635e6415ce23293c67eda0327dddec90ae7
parent217b27d4671a0a3f34147f1b341683d36b7457db (diff)
efi: Don't use spinlocks for efi vars
All efivars operations are protected by a spinlock which prevents interruptions and preemption. This is too restricted, we just need a lock preventing concurrency. The idea is to use a semaphore of count 1 and to have two ways of locking, depending on the context: - In interrupt context, we call down_trylock(), if it fails we return an error - In normal context, we call down_interruptible() We don't use a mutex here because the mutex_trylock() function must not be called from interrupt context, whereas the down_trylock() can. 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>
-rw-r--r--drivers/firmware/efi/efi-pstore.c36
-rw-r--r--drivers/firmware/efi/efivars.c22
-rw-r--r--drivers/firmware/efi/vars.c137
-rw-r--r--fs/efivarfs/inode.c5
-rw-r--r--fs/efivarfs/super.c9
-rw-r--r--include/linux/efi.h6
6 files changed, 139 insertions, 76 deletions
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c
index 30a24d09ea6c..1c33d7469e4a 100644
--- a/drivers/firmware/efi/efi-pstore.c
+++ b/drivers/firmware/efi/efi-pstore.c
@@ -125,16 +125,19 @@ static void efi_pstore_scan_sysfs_enter(struct efivar_entry *pos,
125 * @entry: deleting entry 125 * @entry: deleting entry
126 * @turn_off_scanning: Check if a scanning flag should be turned off 126 * @turn_off_scanning: Check if a scanning flag should be turned off
127 */ 127 */
128static inline void __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry, 128static inline int __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry,
129 bool turn_off_scanning) 129 bool turn_off_scanning)
130{ 130{
131 if (entry->deleting) { 131 if (entry->deleting) {
132 list_del(&entry->list); 132 list_del(&entry->list);
133 efivar_entry_iter_end(); 133 efivar_entry_iter_end();
134 efivar_unregister(entry); 134 efivar_unregister(entry);
135 efivar_entry_iter_begin(); 135 if (efivar_entry_iter_begin())
136 return -EINTR;
136 } else if (turn_off_scanning) 137 } else if (turn_off_scanning)
137 entry->scanning = false; 138 entry->scanning = false;
139
140 return 0;
138} 141}
139 142
140/** 143/**
@@ -144,13 +147,18 @@ static inline void __efi_pstore_scan_sysfs_exit(struct efivar_entry *entry,
144 * @head: list head 147 * @head: list head
145 * @stop: a flag checking if scanning will stop 148 * @stop: a flag checking if scanning will stop
146 */ 149 */
147static void efi_pstore_scan_sysfs_exit(struct efivar_entry *pos, 150static int efi_pstore_scan_sysfs_exit(struct efivar_entry *pos,
148 struct efivar_entry *next, 151 struct efivar_entry *next,
149 struct list_head *head, bool stop) 152 struct list_head *head, bool stop)
150{ 153{
151 __efi_pstore_scan_sysfs_exit(pos, true); 154 int ret = __efi_pstore_scan_sysfs_exit(pos, true);
155
156 if (ret)
157 return ret;
158
152 if (stop) 159 if (stop)
153 __efi_pstore_scan_sysfs_exit(next, &next->list != head); 160 ret = __efi_pstore_scan_sysfs_exit(next, &next->list != head);
161 return ret;
154} 162}
155 163
156/** 164/**
@@ -172,13 +180,17 @@ static int efi_pstore_sysfs_entry_iter(void *data, struct efivar_entry **pos)
172 struct efivar_entry *entry, *n; 180 struct efivar_entry *entry, *n;
173 struct list_head *head = &efivar_sysfs_list; 181 struct list_head *head = &efivar_sysfs_list;
174 int size = 0; 182 int size = 0;
183 int ret;
175 184
176 if (!*pos) { 185 if (!*pos) {
177 list_for_each_entry_safe(entry, n, head, list) { 186 list_for_each_entry_safe(entry, n, head, list) {
178 efi_pstore_scan_sysfs_enter(entry, n, head); 187 efi_pstore_scan_sysfs_enter(entry, n, head);
179 188
180 size = efi_pstore_read_func(entry, data); 189 size = efi_pstore_read_func(entry, data);
181 efi_pstore_scan_sysfs_exit(entry, n, head, size < 0); 190 ret = efi_pstore_scan_sysfs_exit(entry, n, head,
191 size < 0);
192 if (ret)
193 return ret;
182 if (size) 194 if (size)
183 break; 195 break;
184 } 196 }
@@ -190,7 +202,9 @@ static int efi_pstore_sysfs_entry_iter(void *data, struct efivar_entry **pos)
190 efi_pstore_scan_sysfs_enter((*pos), n, head); 202 efi_pstore_scan_sysfs_enter((*pos), n, head);
191 203
192 size = efi_pstore_read_func((*pos), data); 204 size = efi_pstore_read_func((*pos), data);
193 efi_pstore_scan_sysfs_exit((*pos), n, head, size < 0); 205 ret = efi_pstore_scan_sysfs_exit((*pos), n, head, size < 0);
206 if (ret)
207 return ret;
194 if (size) 208 if (size)
195 break; 209 break;
196 } 210 }
@@ -232,7 +246,10 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
232 if (!*data.buf) 246 if (!*data.buf)
233 return -ENOMEM; 247 return -ENOMEM;
234 248
235 efivar_entry_iter_begin(); 249 if (efivar_entry_iter_begin()) {
250 kfree(*data.buf);
251 return -EINTR;
252 }
236 size = efi_pstore_sysfs_entry_iter(&data, 253 size = efi_pstore_sysfs_entry_iter(&data,
237 (struct efivar_entry **)&psi->data); 254 (struct efivar_entry **)&psi->data);
238 efivar_entry_iter_end(); 255 efivar_entry_iter_end();
@@ -347,7 +364,8 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
347 edata.time = time; 364 edata.time = time;
348 edata.name = efi_name; 365 edata.name = efi_name;
349 366
350 efivar_entry_iter_begin(); 367 if (efivar_entry_iter_begin())
368 return -EINTR;
351 found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry); 369 found = __efivar_entry_iter(efi_pstore_erase_func, &efivar_sysfs_list, &edata, &entry);
352 370
353 if (found && !entry->scanning) { 371 if (found && !entry->scanning) {
diff --git a/drivers/firmware/efi/efivars.c b/drivers/firmware/efi/efivars.c
index 116b244dee68..3e626fd9bd4e 100644
--- a/drivers/firmware/efi/efivars.c
+++ b/drivers/firmware/efi/efivars.c
@@ -510,7 +510,8 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
510 vendor = del_var->VendorGuid; 510 vendor = del_var->VendorGuid;
511 } 511 }
512 512
513 efivar_entry_iter_begin(); 513 if (efivar_entry_iter_begin())
514 return -EINTR;
514 entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true); 515 entry = efivar_entry_find(name, vendor, &efivar_sysfs_list, true);
515 if (!entry) 516 if (!entry)
516 err = -EINVAL; 517 err = -EINVAL;
@@ -575,7 +576,10 @@ efivar_create_sysfs_entry(struct efivar_entry *new_var)
575 return ret; 576 return ret;
576 577
577 kobject_uevent(&new_var->kobj, KOBJ_ADD); 578 kobject_uevent(&new_var->kobj, KOBJ_ADD);
578 efivar_entry_add(new_var, &efivar_sysfs_list); 579 if (efivar_entry_add(new_var, &efivar_sysfs_list)) {
580 efivar_unregister(new_var);
581 return -EINTR;
582 }
579 583
580 return 0; 584 return 0;
581} 585}
@@ -690,7 +694,10 @@ static int efivars_sysfs_callback(efi_char16_t *name, efi_guid_t vendor,
690 694
691static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data) 695static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data)
692{ 696{
693 efivar_entry_remove(entry); 697 int err = efivar_entry_remove(entry);
698
699 if (err)
700 return err;
694 efivar_unregister(entry); 701 efivar_unregister(entry);
695 return 0; 702 return 0;
696} 703}
@@ -698,7 +705,14 @@ static int efivar_sysfs_destroy(struct efivar_entry *entry, void *data)
698static void efivars_sysfs_exit(void) 705static void efivars_sysfs_exit(void)
699{ 706{
700 /* Remove all entries and destroy */ 707 /* Remove all entries and destroy */
701 __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list, NULL, NULL); 708 int err;
709
710 err = __efivar_entry_iter(efivar_sysfs_destroy, &efivar_sysfs_list,
711 NULL, NULL);
712 if (err) {
713 pr_err("efivars: Failed to destroy sysfs entries\n");
714 return;
715 }
702 716
703 if (efivars_new_var) 717 if (efivars_new_var)
704 sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var); 718 sysfs_remove_bin_file(&efivars_kset->kobj, efivars_new_var);
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index d0d807e1287e..9336ffdf6e2c 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -43,7 +43,7 @@ static struct efivars *__efivars;
43 * 2) ->ops calls 43 * 2) ->ops calls
44 * 3) (un)registration of __efivars 44 * 3) (un)registration of __efivars
45 */ 45 */
46static DEFINE_SPINLOCK(efivars_lock); 46static DEFINE_SEMAPHORE(efivars_lock);
47 47
48static bool efivar_wq_enabled = true; 48static bool efivar_wq_enabled = true;
49DECLARE_WORK(efivar_work, NULL); 49DECLARE_WORK(efivar_work, NULL);
@@ -442,7 +442,10 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
442 return -ENOMEM; 442 return -ENOMEM;
443 } 443 }
444 444
445 spin_lock_irq(&efivars_lock); 445 if (down_interruptible(&efivars_lock)) {
446 err = -EINTR;
447 goto free;
448 }
446 449
447 /* 450 /*
448 * Per EFI spec, the maximum storage allocated for both 451 * Per EFI spec, the maximum storage allocated for both
@@ -458,7 +461,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
458 switch (status) { 461 switch (status) {
459 case EFI_SUCCESS: 462 case EFI_SUCCESS:
460 if (duplicates) 463 if (duplicates)
461 spin_unlock_irq(&efivars_lock); 464 up(&efivars_lock);
462 465
463 variable_name_size = var_name_strnsize(variable_name, 466 variable_name_size = var_name_strnsize(variable_name,
464 variable_name_size); 467 variable_name_size);
@@ -484,8 +487,12 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
484 status = EFI_NOT_FOUND; 487 status = EFI_NOT_FOUND;
485 } 488 }
486 489
487 if (duplicates) 490 if (duplicates) {
488 spin_lock_irq(&efivars_lock); 491 if (down_interruptible(&efivars_lock)) {
492 err = -EINTR;
493 goto free;
494 }
495 }
489 496
490 break; 497 break;
491 case EFI_NOT_FOUND: 498 case EFI_NOT_FOUND:
@@ -499,8 +506,8 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
499 506
500 } while (status != EFI_NOT_FOUND); 507 } while (status != EFI_NOT_FOUND);
501 508
502 spin_unlock_irq(&efivars_lock); 509 up(&efivars_lock);
503 510free:
504 kfree(variable_name); 511 kfree(variable_name);
505 512
506 return err; 513 return err;
@@ -511,24 +518,34 @@ EXPORT_SYMBOL_GPL(efivar_init);
511 * efivar_entry_add - add entry to variable list 518 * efivar_entry_add - add entry to variable list
512 * @entry: entry to add to list 519 * @entry: entry to add to list
513 * @head: list head 520 * @head: list head
521 *
522 * Returns 0 on success, or a kernel error code on failure.
514 */ 523 */
515void efivar_entry_add(struct efivar_entry *entry, struct list_head *head) 524int efivar_entry_add(struct efivar_entry *entry, struct list_head *head)
516{ 525{
517 spin_lock_irq(&efivars_lock); 526 if (down_interruptible(&efivars_lock))
527 return -EINTR;
518 list_add(&entry->list, head); 528 list_add(&entry->list, head);
519 spin_unlock_irq(&efivars_lock); 529 up(&efivars_lock);
530
531 return 0;
520} 532}
521EXPORT_SYMBOL_GPL(efivar_entry_add); 533EXPORT_SYMBOL_GPL(efivar_entry_add);
522 534
523/** 535/**
524 * efivar_entry_remove - remove entry from variable list 536 * efivar_entry_remove - remove entry from variable list
525 * @entry: entry to remove from list 537 * @entry: entry to remove from list
538 *
539 * Returns 0 on success, or a kernel error code on failure.
526 */ 540 */
527void efivar_entry_remove(struct efivar_entry *entry) 541int efivar_entry_remove(struct efivar_entry *entry)
528{ 542{
529 spin_lock_irq(&efivars_lock); 543 if (down_interruptible(&efivars_lock))
544 return -EINTR;
530 list_del(&entry->list); 545 list_del(&entry->list);
531 spin_unlock_irq(&efivars_lock); 546 up(&efivars_lock);
547
548 return 0;
532} 549}
533EXPORT_SYMBOL_GPL(efivar_entry_remove); 550EXPORT_SYMBOL_GPL(efivar_entry_remove);
534 551
@@ -545,10 +562,8 @@ EXPORT_SYMBOL_GPL(efivar_entry_remove);
545 */ 562 */
546static void efivar_entry_list_del_unlock(struct efivar_entry *entry) 563static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
547{ 564{
548 lockdep_assert_held(&efivars_lock);
549
550 list_del(&entry->list); 565 list_del(&entry->list);
551 spin_unlock_irq(&efivars_lock); 566 up(&efivars_lock);
552} 567}
553 568
554/** 569/**
@@ -571,8 +586,6 @@ int __efivar_entry_delete(struct efivar_entry *entry)
571 const struct efivar_operations *ops = __efivars->ops; 586 const struct efivar_operations *ops = __efivars->ops;
572 efi_status_t status; 587 efi_status_t status;
573 588
574 lockdep_assert_held(&efivars_lock);
575
576 status = ops->set_variable(entry->var.VariableName, 589 status = ops->set_variable(entry->var.VariableName,
577 &entry->var.VendorGuid, 590 &entry->var.VendorGuid,
578 0, 0, NULL); 591 0, 0, NULL);
@@ -589,20 +602,22 @@ EXPORT_SYMBOL_GPL(__efivar_entry_delete);
589 * variable list. It is the caller's responsibility to free @entry 602 * variable list. It is the caller's responsibility to free @entry
590 * once we return. 603 * once we return.
591 * 604 *
592 * Returns 0 on success, or a converted EFI status code if 605 * Returns 0 on success, -EINTR if we can't grab the semaphore,
593 * set_variable() fails. 606 * converted EFI status code if set_variable() fails.
594 */ 607 */
595int efivar_entry_delete(struct efivar_entry *entry) 608int efivar_entry_delete(struct efivar_entry *entry)
596{ 609{
597 const struct efivar_operations *ops = __efivars->ops; 610 const struct efivar_operations *ops = __efivars->ops;
598 efi_status_t status; 611 efi_status_t status;
599 612
600 spin_lock_irq(&efivars_lock); 613 if (down_interruptible(&efivars_lock))
614 return -EINTR;
615
601 status = ops->set_variable(entry->var.VariableName, 616 status = ops->set_variable(entry->var.VariableName,
602 &entry->var.VendorGuid, 617 &entry->var.VendorGuid,
603 0, 0, NULL); 618 0, 0, NULL);
604 if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) { 619 if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) {
605 spin_unlock_irq(&efivars_lock); 620 up(&efivars_lock);
606 return efi_status_to_err(status); 621 return efi_status_to_err(status);
607 } 622 }
608 623
@@ -628,9 +643,9 @@ EXPORT_SYMBOL_GPL(efivar_entry_delete);
628 * If @head is not NULL a lookup is performed to determine whether 643 * If @head is not NULL a lookup is performed to determine whether
629 * the entry is already on the list. 644 * the entry is already on the list.
630 * 645 *
631 * Returns 0 on success, -EEXIST if a lookup is performed and the entry 646 * Returns 0 on success, -EINTR if we can't grab the semaphore,
632 * already exists on the list, or a converted EFI status code if 647 * -EEXIST if a lookup is performed and the entry already exists on
633 * set_variable() fails. 648 * the list, or a converted EFI status code if set_variable() fails.
634 */ 649 */
635int efivar_entry_set(struct efivar_entry *entry, u32 attributes, 650int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
636 unsigned long size, void *data, struct list_head *head) 651 unsigned long size, void *data, struct list_head *head)
@@ -640,10 +655,10 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
640 efi_char16_t *name = entry->var.VariableName; 655 efi_char16_t *name = entry->var.VariableName;
641 efi_guid_t vendor = entry->var.VendorGuid; 656 efi_guid_t vendor = entry->var.VendorGuid;
642 657
643 spin_lock_irq(&efivars_lock); 658 if (down_interruptible(&efivars_lock))
644 659 return -EINTR;
645 if (head && efivar_entry_find(name, vendor, head, false)) { 660 if (head && efivar_entry_find(name, vendor, head, false)) {
646 spin_unlock_irq(&efivars_lock); 661 up(&efivars_lock);
647 return -EEXIST; 662 return -EEXIST;
648 } 663 }
649 664
@@ -652,7 +667,7 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
652 status = ops->set_variable(name, &vendor, 667 status = ops->set_variable(name, &vendor,
653 attributes, size, data); 668 attributes, size, data);
654 669
655 spin_unlock_irq(&efivars_lock); 670 up(&efivars_lock);
656 671
657 return efi_status_to_err(status); 672 return efi_status_to_err(status);
658 673
@@ -673,23 +688,22 @@ efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
673 u32 attributes, unsigned long size, void *data) 688 u32 attributes, unsigned long size, void *data)
674{ 689{
675 const struct efivar_operations *ops = __efivars->ops; 690 const struct efivar_operations *ops = __efivars->ops;
676 unsigned long flags;
677 efi_status_t status; 691 efi_status_t status;
678 692
679 if (!spin_trylock_irqsave(&efivars_lock, flags)) 693 if (down_trylock(&efivars_lock))
680 return -EBUSY; 694 return -EBUSY;
681 695
682 status = check_var_size_nonblocking(attributes, 696 status = check_var_size_nonblocking(attributes,
683 size + ucs2_strsize(name, 1024)); 697 size + ucs2_strsize(name, 1024));
684 if (status != EFI_SUCCESS) { 698 if (status != EFI_SUCCESS) {
685 spin_unlock_irqrestore(&efivars_lock, flags); 699 up(&efivars_lock);
686 return -ENOSPC; 700 return -ENOSPC;
687 } 701 }
688 702
689 status = ops->set_variable_nonblocking(name, &vendor, attributes, 703 status = ops->set_variable_nonblocking(name, &vendor, attributes,
690 size, data); 704 size, data);
691 705
692 spin_unlock_irqrestore(&efivars_lock, flags); 706 up(&efivars_lock);
693 return efi_status_to_err(status); 707 return efi_status_to_err(status);
694} 708}
695 709
@@ -714,7 +728,6 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
714 bool block, unsigned long size, void *data) 728 bool block, unsigned long size, void *data)
715{ 729{
716 const struct efivar_operations *ops = __efivars->ops; 730 const struct efivar_operations *ops = __efivars->ops;
717 unsigned long flags;
718 efi_status_t status; 731 efi_status_t status;
719 732
720 if (!ops->query_variable_store) 733 if (!ops->query_variable_store)
@@ -735,21 +748,22 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
735 size, data); 748 size, data);
736 749
737 if (!block) { 750 if (!block) {
738 if (!spin_trylock_irqsave(&efivars_lock, flags)) 751 if (down_trylock(&efivars_lock))
739 return -EBUSY; 752 return -EBUSY;
740 } else { 753 } else {
741 spin_lock_irqsave(&efivars_lock, flags); 754 if (down_interruptible(&efivars_lock))
755 return -EINTR;
742 } 756 }
743 757
744 status = check_var_size(attributes, size + ucs2_strsize(name, 1024)); 758 status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
745 if (status != EFI_SUCCESS) { 759 if (status != EFI_SUCCESS) {
746 spin_unlock_irqrestore(&efivars_lock, flags); 760 up(&efivars_lock);
747 return -ENOSPC; 761 return -ENOSPC;
748 } 762 }
749 763
750 status = ops->set_variable(name, &vendor, attributes, size, data); 764 status = ops->set_variable(name, &vendor, attributes, size, data);
751 765
752 spin_unlock_irqrestore(&efivars_lock, flags); 766 up(&efivars_lock);
753 767
754 return efi_status_to_err(status); 768 return efi_status_to_err(status);
755} 769}
@@ -779,8 +793,6 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid,
779 int strsize1, strsize2; 793 int strsize1, strsize2;
780 bool found = false; 794 bool found = false;
781 795
782 lockdep_assert_held(&efivars_lock);
783
784 list_for_each_entry_safe(entry, n, head, list) { 796 list_for_each_entry_safe(entry, n, head, list) {
785 strsize1 = ucs2_strsize(name, 1024); 797 strsize1 = ucs2_strsize(name, 1024);
786 strsize2 = ucs2_strsize(entry->var.VariableName, 1024); 798 strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
@@ -822,10 +834,11 @@ int efivar_entry_size(struct efivar_entry *entry, unsigned long *size)
822 834
823 *size = 0; 835 *size = 0;
824 836
825 spin_lock_irq(&efivars_lock); 837 if (down_interruptible(&efivars_lock))
838 return -EINTR;
826 status = ops->get_variable(entry->var.VariableName, 839 status = ops->get_variable(entry->var.VariableName,
827 &entry->var.VendorGuid, NULL, size, NULL); 840 &entry->var.VendorGuid, NULL, size, NULL);
828 spin_unlock_irq(&efivars_lock); 841 up(&efivars_lock);
829 842
830 if (status != EFI_BUFFER_TOO_SMALL) 843 if (status != EFI_BUFFER_TOO_SMALL)
831 return efi_status_to_err(status); 844 return efi_status_to_err(status);
@@ -851,8 +864,6 @@ int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
851 const struct efivar_operations *ops = __efivars->ops; 864 const struct efivar_operations *ops = __efivars->ops;
852 efi_status_t status; 865 efi_status_t status;
853 866
854 lockdep_assert_held(&efivars_lock);
855
856 status = ops->get_variable(entry->var.VariableName, 867 status = ops->get_variable(entry->var.VariableName,
857 &entry->var.VendorGuid, 868 &entry->var.VendorGuid,
858 attributes, size, data); 869 attributes, size, data);
@@ -874,11 +885,12 @@ int efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
874 const struct efivar_operations *ops = __efivars->ops; 885 const struct efivar_operations *ops = __efivars->ops;
875 efi_status_t status; 886 efi_status_t status;
876 887
877 spin_lock_irq(&efivars_lock); 888 if (down_interruptible(&efivars_lock))
889 return -EINTR;
878 status = ops->get_variable(entry->var.VariableName, 890 status = ops->get_variable(entry->var.VariableName,
879 &entry->var.VendorGuid, 891 &entry->var.VendorGuid,
880 attributes, size, data); 892 attributes, size, data);
881 spin_unlock_irq(&efivars_lock); 893 up(&efivars_lock);
882 894
883 return efi_status_to_err(status); 895 return efi_status_to_err(status);
884} 896}
@@ -925,7 +937,8 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
925 * set_variable call, and removal of the variable from the efivars 937 * set_variable call, and removal of the variable from the efivars
926 * list (in the case of an authenticated delete). 938 * list (in the case of an authenticated delete).
927 */ 939 */
928 spin_lock_irq(&efivars_lock); 940 if (down_interruptible(&efivars_lock))
941 return -EINTR;
929 942
930 /* 943 /*
931 * Ensure that the available space hasn't shrunk below the safe level 944 * Ensure that the available space hasn't shrunk below the safe level
@@ -965,7 +978,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
965 if (status == EFI_NOT_FOUND) 978 if (status == EFI_NOT_FOUND)
966 efivar_entry_list_del_unlock(entry); 979 efivar_entry_list_del_unlock(entry);
967 else 980 else
968 spin_unlock_irq(&efivars_lock); 981 up(&efivars_lock);
969 982
970 if (status && status != EFI_BUFFER_TOO_SMALL) 983 if (status && status != EFI_BUFFER_TOO_SMALL)
971 return efi_status_to_err(status); 984 return efi_status_to_err(status);
@@ -973,7 +986,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
973 return 0; 986 return 0;
974 987
975out: 988out:
976 spin_unlock_irq(&efivars_lock); 989 up(&efivars_lock);
977 return err; 990 return err;
978 991
979} 992}
@@ -986,9 +999,9 @@ EXPORT_SYMBOL_GPL(efivar_entry_set_get_size);
986 * efivar_entry_iter_end() is called. This function is usually used in 999 * efivar_entry_iter_end() is called. This function is usually used in
987 * conjunction with __efivar_entry_iter() or efivar_entry_iter(). 1000 * conjunction with __efivar_entry_iter() or efivar_entry_iter().
988 */ 1001 */
989void efivar_entry_iter_begin(void) 1002int efivar_entry_iter_begin(void)
990{ 1003{
991 spin_lock_irq(&efivars_lock); 1004 return down_interruptible(&efivars_lock);
992} 1005}
993EXPORT_SYMBOL_GPL(efivar_entry_iter_begin); 1006EXPORT_SYMBOL_GPL(efivar_entry_iter_begin);
994 1007
@@ -999,7 +1012,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_iter_begin);
999 */ 1012 */
1000void efivar_entry_iter_end(void) 1013void efivar_entry_iter_end(void)
1001{ 1014{
1002 spin_unlock_irq(&efivars_lock); 1015 up(&efivars_lock);
1003} 1016}
1004EXPORT_SYMBOL_GPL(efivar_entry_iter_end); 1017EXPORT_SYMBOL_GPL(efivar_entry_iter_end);
1005 1018
@@ -1075,7 +1088,9 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *),
1075{ 1088{
1076 int err = 0; 1089 int err = 0;
1077 1090
1078 efivar_entry_iter_begin(); 1091 err = efivar_entry_iter_begin();
1092 if (err)
1093 return err;
1079 err = __efivar_entry_iter(func, head, data, NULL); 1094 err = __efivar_entry_iter(func, head, data, NULL);
1080 efivar_entry_iter_end(); 1095 efivar_entry_iter_end();
1081 1096
@@ -1120,12 +1135,17 @@ int efivars_register(struct efivars *efivars,
1120 const struct efivar_operations *ops, 1135 const struct efivar_operations *ops,
1121 struct kobject *kobject) 1136 struct kobject *kobject)
1122{ 1137{
1123 spin_lock_irq(&efivars_lock); 1138 if (down_interruptible(&efivars_lock))
1139 return -EINTR;
1140
1124 efivars->ops = ops; 1141 efivars->ops = ops;
1125 efivars->kobject = kobject; 1142 efivars->kobject = kobject;
1126 1143
1127 __efivars = efivars; 1144 __efivars = efivars;
1128 spin_unlock_irq(&efivars_lock); 1145
1146 pr_info("Registered efivars operations\n");
1147
1148 up(&efivars_lock);
1129 1149
1130 return 0; 1150 return 0;
1131} 1151}
@@ -1142,7 +1162,9 @@ int efivars_unregister(struct efivars *efivars)
1142{ 1162{
1143 int rv; 1163 int rv;
1144 1164
1145 spin_lock_irq(&efivars_lock); 1165 if (down_interruptible(&efivars_lock))
1166 return -EINTR;
1167
1146 if (!__efivars) { 1168 if (!__efivars) {
1147 printk(KERN_ERR "efivars not registered\n"); 1169 printk(KERN_ERR "efivars not registered\n");
1148 rv = -EINVAL; 1170 rv = -EINVAL;
@@ -1154,11 +1176,12 @@ int efivars_unregister(struct efivars *efivars)
1154 goto out; 1176 goto out;
1155 } 1177 }
1156 1178
1179 pr_info("Unregistered efivars operations\n");
1157 __efivars = NULL; 1180 __efivars = NULL;
1158 1181
1159 rv = 0; 1182 rv = 0;
1160out: 1183out:
1161 spin_unlock_irq(&efivars_lock); 1184 up(&efivars_lock);
1162 return rv; 1185 return rv;
1163} 1186}
1164EXPORT_SYMBOL_GPL(efivars_unregister); 1187EXPORT_SYMBOL_GPL(efivars_unregister);
diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c
index 1d73fc6dba13..cbb50cadcffc 100644
--- a/fs/efivarfs/inode.c
+++ b/fs/efivarfs/inode.c
@@ -105,7 +105,10 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
105 105
106 inode->i_private = var; 106 inode->i_private = var;
107 107
108 efivar_entry_add(var, &efivarfs_list); 108 err = efivar_entry_add(var, &efivarfs_list);
109 if (err)
110 goto out;
111
109 d_instantiate(dentry, inode); 112 d_instantiate(dentry, inode);
110 dget(dentry); 113 dget(dentry);
111out: 114out:
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index 688ccc16b702..01e3d6e53944 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -161,7 +161,9 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor,
161 kfree(name); 161 kfree(name);
162 162
163 efivar_entry_size(entry, &size); 163 efivar_entry_size(entry, &size);
164 efivar_entry_add(entry, &efivarfs_list); 164 err = efivar_entry_add(entry, &efivarfs_list);
165 if (err)
166 goto fail_inode;
165 167
166 inode_lock(inode); 168 inode_lock(inode);
167 inode->i_private = entry; 169 inode->i_private = entry;
@@ -182,7 +184,10 @@ fail:
182 184
183static int efivarfs_destroy(struct efivar_entry *entry, void *data) 185static int efivarfs_destroy(struct efivar_entry *entry, void *data)
184{ 186{
185 efivar_entry_remove(entry); 187 int err = efivar_entry_remove(entry);
188
189 if (err)
190 return err;
186 kfree(entry); 191 kfree(entry);
187 return 0; 192 return 0;
188} 193}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index deecb2902715..4d6da7b66c19 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1297,8 +1297,8 @@ struct kobject *efivars_kobject(void);
1297int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), 1297int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
1298 void *data, bool duplicates, struct list_head *head); 1298 void *data, bool duplicates, struct list_head *head);
1299 1299
1300void efivar_entry_add(struct efivar_entry *entry, struct list_head *head); 1300int efivar_entry_add(struct efivar_entry *entry, struct list_head *head);
1301void efivar_entry_remove(struct efivar_entry *entry); 1301int efivar_entry_remove(struct efivar_entry *entry);
1302 1302
1303int __efivar_entry_delete(struct efivar_entry *entry); 1303int __efivar_entry_delete(struct efivar_entry *entry);
1304int efivar_entry_delete(struct efivar_entry *entry); 1304int efivar_entry_delete(struct efivar_entry *entry);
@@ -1315,7 +1315,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
1315int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, 1315int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
1316 bool block, unsigned long size, void *data); 1316 bool block, unsigned long size, void *data);
1317 1317
1318void efivar_entry_iter_begin(void); 1318int efivar_entry_iter_begin(void);
1319void efivar_entry_iter_end(void); 1319void efivar_entry_iter_end(void);
1320 1320
1321int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *), 1321int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *),