diff options
Diffstat (limited to 'drivers/firmware/efi/vars.c')
-rw-r--r-- | drivers/firmware/efi/vars.c | 142 |
1 files changed, 88 insertions, 54 deletions
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index d3b751383286..9336ffdf6e2c 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 */ |
38 | static struct efivars *__efivars; | 38 | static 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 | */ | ||
46 | static DEFINE_SEMAPHORE(efivars_lock); | ||
47 | |||
40 | static bool efivar_wq_enabled = true; | 48 | static bool efivar_wq_enabled = true; |
41 | DECLARE_WORK(efivar_work, NULL); | 49 | DECLARE_WORK(efivar_work, NULL); |
42 | EXPORT_SYMBOL_GPL(efivar_work); | 50 | EXPORT_SYMBOL_GPL(efivar_work); |
@@ -434,7 +442,10 @@ 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 | if (down_interruptible(&efivars_lock)) { |
446 | err = -EINTR; | ||
447 | goto free; | ||
448 | } | ||
438 | 449 | ||
439 | /* | 450 | /* |
440 | * Per EFI spec, the maximum storage allocated for both | 451 | * Per EFI spec, the maximum storage allocated for both |
@@ -450,7 +461,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), | |||
450 | switch (status) { | 461 | switch (status) { |
451 | case EFI_SUCCESS: | 462 | case EFI_SUCCESS: |
452 | if (duplicates) | 463 | if (duplicates) |
453 | spin_unlock_irq(&__efivars->lock); | 464 | up(&efivars_lock); |
454 | 465 | ||
455 | variable_name_size = var_name_strnsize(variable_name, | 466 | variable_name_size = var_name_strnsize(variable_name, |
456 | variable_name_size); | 467 | variable_name_size); |
@@ -476,8 +487,12 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), | |||
476 | status = EFI_NOT_FOUND; | 487 | status = EFI_NOT_FOUND; |
477 | } | 488 | } |
478 | 489 | ||
479 | if (duplicates) | 490 | if (duplicates) { |
480 | spin_lock_irq(&__efivars->lock); | 491 | if (down_interruptible(&efivars_lock)) { |
492 | err = -EINTR; | ||
493 | goto free; | ||
494 | } | ||
495 | } | ||
481 | 496 | ||
482 | break; | 497 | break; |
483 | case EFI_NOT_FOUND: | 498 | case EFI_NOT_FOUND: |
@@ -491,8 +506,8 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), | |||
491 | 506 | ||
492 | } while (status != EFI_NOT_FOUND); | 507 | } while (status != EFI_NOT_FOUND); |
493 | 508 | ||
494 | spin_unlock_irq(&__efivars->lock); | 509 | up(&efivars_lock); |
495 | 510 | free: | |
496 | kfree(variable_name); | 511 | kfree(variable_name); |
497 | 512 | ||
498 | return err; | 513 | return err; |
@@ -503,24 +518,34 @@ EXPORT_SYMBOL_GPL(efivar_init); | |||
503 | * efivar_entry_add - add entry to variable list | 518 | * efivar_entry_add - add entry to variable list |
504 | * @entry: entry to add to list | 519 | * @entry: entry to add to list |
505 | * @head: list head | 520 | * @head: list head |
521 | * | ||
522 | * Returns 0 on success, or a kernel error code on failure. | ||
506 | */ | 523 | */ |
507 | void efivar_entry_add(struct efivar_entry *entry, struct list_head *head) | 524 | int efivar_entry_add(struct efivar_entry *entry, struct list_head *head) |
508 | { | 525 | { |
509 | spin_lock_irq(&__efivars->lock); | 526 | if (down_interruptible(&efivars_lock)) |
527 | return -EINTR; | ||
510 | list_add(&entry->list, head); | 528 | list_add(&entry->list, head); |
511 | spin_unlock_irq(&__efivars->lock); | 529 | up(&efivars_lock); |
530 | |||
531 | return 0; | ||
512 | } | 532 | } |
513 | EXPORT_SYMBOL_GPL(efivar_entry_add); | 533 | EXPORT_SYMBOL_GPL(efivar_entry_add); |
514 | 534 | ||
515 | /** | 535 | /** |
516 | * efivar_entry_remove - remove entry from variable list | 536 | * efivar_entry_remove - remove entry from variable list |
517 | * @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. | ||
518 | */ | 540 | */ |
519 | void efivar_entry_remove(struct efivar_entry *entry) | 541 | int efivar_entry_remove(struct efivar_entry *entry) |
520 | { | 542 | { |
521 | spin_lock_irq(&__efivars->lock); | 543 | if (down_interruptible(&efivars_lock)) |
544 | return -EINTR; | ||
522 | list_del(&entry->list); | 545 | list_del(&entry->list); |
523 | spin_unlock_irq(&__efivars->lock); | 546 | up(&efivars_lock); |
547 | |||
548 | return 0; | ||
524 | } | 549 | } |
525 | EXPORT_SYMBOL_GPL(efivar_entry_remove); | 550 | EXPORT_SYMBOL_GPL(efivar_entry_remove); |
526 | 551 | ||
@@ -537,10 +562,8 @@ EXPORT_SYMBOL_GPL(efivar_entry_remove); | |||
537 | */ | 562 | */ |
538 | static void efivar_entry_list_del_unlock(struct efivar_entry *entry) | 563 | static void efivar_entry_list_del_unlock(struct efivar_entry *entry) |
539 | { | 564 | { |
540 | lockdep_assert_held(&__efivars->lock); | ||
541 | |||
542 | list_del(&entry->list); | 565 | list_del(&entry->list); |
543 | spin_unlock_irq(&__efivars->lock); | 566 | up(&efivars_lock); |
544 | } | 567 | } |
545 | 568 | ||
546 | /** | 569 | /** |
@@ -563,8 +586,6 @@ int __efivar_entry_delete(struct efivar_entry *entry) | |||
563 | const struct efivar_operations *ops = __efivars->ops; | 586 | const struct efivar_operations *ops = __efivars->ops; |
564 | efi_status_t status; | 587 | efi_status_t status; |
565 | 588 | ||
566 | lockdep_assert_held(&__efivars->lock); | ||
567 | |||
568 | status = ops->set_variable(entry->var.VariableName, | 589 | status = ops->set_variable(entry->var.VariableName, |
569 | &entry->var.VendorGuid, | 590 | &entry->var.VendorGuid, |
570 | 0, 0, NULL); | 591 | 0, 0, NULL); |
@@ -581,20 +602,22 @@ EXPORT_SYMBOL_GPL(__efivar_entry_delete); | |||
581 | * variable list. It is the caller's responsibility to free @entry | 602 | * variable list. It is the caller's responsibility to free @entry |
582 | * once we return. | 603 | * once we return. |
583 | * | 604 | * |
584 | * Returns 0 on success, or a converted EFI status code if | 605 | * Returns 0 on success, -EINTR if we can't grab the semaphore, |
585 | * set_variable() fails. | 606 | * converted EFI status code if set_variable() fails. |
586 | */ | 607 | */ |
587 | int efivar_entry_delete(struct efivar_entry *entry) | 608 | int efivar_entry_delete(struct efivar_entry *entry) |
588 | { | 609 | { |
589 | const struct efivar_operations *ops = __efivars->ops; | 610 | const struct efivar_operations *ops = __efivars->ops; |
590 | efi_status_t status; | 611 | efi_status_t status; |
591 | 612 | ||
592 | spin_lock_irq(&__efivars->lock); | 613 | if (down_interruptible(&efivars_lock)) |
614 | return -EINTR; | ||
615 | |||
593 | status = ops->set_variable(entry->var.VariableName, | 616 | status = ops->set_variable(entry->var.VariableName, |
594 | &entry->var.VendorGuid, | 617 | &entry->var.VendorGuid, |
595 | 0, 0, NULL); | 618 | 0, 0, NULL); |
596 | if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) { | 619 | if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) { |
597 | spin_unlock_irq(&__efivars->lock); | 620 | up(&efivars_lock); |
598 | return efi_status_to_err(status); | 621 | return efi_status_to_err(status); |
599 | } | 622 | } |
600 | 623 | ||
@@ -620,9 +643,9 @@ EXPORT_SYMBOL_GPL(efivar_entry_delete); | |||
620 | * 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 |
621 | * the entry is already on the list. | 644 | * the entry is already on the list. |
622 | * | 645 | * |
623 | * 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, |
624 | * 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 |
625 | * set_variable() fails. | 648 | * the list, or a converted EFI status code if set_variable() fails. |
626 | */ | 649 | */ |
627 | int efivar_entry_set(struct efivar_entry *entry, u32 attributes, | 650 | int efivar_entry_set(struct efivar_entry *entry, u32 attributes, |
628 | unsigned long size, void *data, struct list_head *head) | 651 | unsigned long size, void *data, struct list_head *head) |
@@ -632,10 +655,10 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes, | |||
632 | efi_char16_t *name = entry->var.VariableName; | 655 | efi_char16_t *name = entry->var.VariableName; |
633 | efi_guid_t vendor = entry->var.VendorGuid; | 656 | efi_guid_t vendor = entry->var.VendorGuid; |
634 | 657 | ||
635 | spin_lock_irq(&__efivars->lock); | 658 | if (down_interruptible(&efivars_lock)) |
636 | 659 | return -EINTR; | |
637 | if (head && efivar_entry_find(name, vendor, head, false)) { | 660 | if (head && efivar_entry_find(name, vendor, head, false)) { |
638 | spin_unlock_irq(&__efivars->lock); | 661 | up(&efivars_lock); |
639 | return -EEXIST; | 662 | return -EEXIST; |
640 | } | 663 | } |
641 | 664 | ||
@@ -644,7 +667,7 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes, | |||
644 | status = ops->set_variable(name, &vendor, | 667 | status = ops->set_variable(name, &vendor, |
645 | attributes, size, data); | 668 | attributes, size, data); |
646 | 669 | ||
647 | spin_unlock_irq(&__efivars->lock); | 670 | up(&efivars_lock); |
648 | 671 | ||
649 | return efi_status_to_err(status); | 672 | return efi_status_to_err(status); |
650 | 673 | ||
@@ -658,30 +681,29 @@ EXPORT_SYMBOL_GPL(efivar_entry_set); | |||
658 | * from crash/panic handlers. | 681 | * from crash/panic handlers. |
659 | * | 682 | * |
660 | * Crucially, this function will not block if it cannot acquire | 683 | * Crucially, this function will not block if it cannot acquire |
661 | * __efivars->lock. Instead, it returns -EBUSY. | 684 | * efivars_lock. Instead, it returns -EBUSY. |
662 | */ | 685 | */ |
663 | static int | 686 | static int |
664 | efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor, | 687 | efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor, |
665 | u32 attributes, unsigned long size, void *data) | 688 | u32 attributes, unsigned long size, void *data) |
666 | { | 689 | { |
667 | const struct efivar_operations *ops = __efivars->ops; | 690 | const struct efivar_operations *ops = __efivars->ops; |
668 | unsigned long flags; | ||
669 | efi_status_t status; | 691 | efi_status_t status; |
670 | 692 | ||
671 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) | 693 | if (down_trylock(&efivars_lock)) |
672 | return -EBUSY; | 694 | return -EBUSY; |
673 | 695 | ||
674 | status = check_var_size_nonblocking(attributes, | 696 | status = check_var_size_nonblocking(attributes, |
675 | size + ucs2_strsize(name, 1024)); | 697 | size + ucs2_strsize(name, 1024)); |
676 | if (status != EFI_SUCCESS) { | 698 | if (status != EFI_SUCCESS) { |
677 | spin_unlock_irqrestore(&__efivars->lock, flags); | 699 | up(&efivars_lock); |
678 | return -ENOSPC; | 700 | return -ENOSPC; |
679 | } | 701 | } |
680 | 702 | ||
681 | status = ops->set_variable_nonblocking(name, &vendor, attributes, | 703 | status = ops->set_variable_nonblocking(name, &vendor, attributes, |
682 | size, data); | 704 | size, data); |
683 | 705 | ||
684 | spin_unlock_irqrestore(&__efivars->lock, flags); | 706 | up(&efivars_lock); |
685 | return efi_status_to_err(status); | 707 | return efi_status_to_err(status); |
686 | } | 708 | } |
687 | 709 | ||
@@ -706,7 +728,6 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, | |||
706 | bool block, unsigned long size, void *data) | 728 | bool block, unsigned long size, void *data) |
707 | { | 729 | { |
708 | const struct efivar_operations *ops = __efivars->ops; | 730 | const struct efivar_operations *ops = __efivars->ops; |
709 | unsigned long flags; | ||
710 | efi_status_t status; | 731 | efi_status_t status; |
711 | 732 | ||
712 | if (!ops->query_variable_store) | 733 | if (!ops->query_variable_store) |
@@ -727,21 +748,22 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, | |||
727 | size, data); | 748 | size, data); |
728 | 749 | ||
729 | if (!block) { | 750 | if (!block) { |
730 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) | 751 | if (down_trylock(&efivars_lock)) |
731 | return -EBUSY; | 752 | return -EBUSY; |
732 | } else { | 753 | } else { |
733 | spin_lock_irqsave(&__efivars->lock, flags); | 754 | if (down_interruptible(&efivars_lock)) |
755 | return -EINTR; | ||
734 | } | 756 | } |
735 | 757 | ||
736 | status = check_var_size(attributes, size + ucs2_strsize(name, 1024)); | 758 | status = check_var_size(attributes, size + ucs2_strsize(name, 1024)); |
737 | if (status != EFI_SUCCESS) { | 759 | if (status != EFI_SUCCESS) { |
738 | spin_unlock_irqrestore(&__efivars->lock, flags); | 760 | up(&efivars_lock); |
739 | return -ENOSPC; | 761 | return -ENOSPC; |
740 | } | 762 | } |
741 | 763 | ||
742 | status = ops->set_variable(name, &vendor, attributes, size, data); | 764 | status = ops->set_variable(name, &vendor, attributes, size, data); |
743 | 765 | ||
744 | spin_unlock_irqrestore(&__efivars->lock, flags); | 766 | up(&efivars_lock); |
745 | 767 | ||
746 | return efi_status_to_err(status); | 768 | return efi_status_to_err(status); |
747 | } | 769 | } |
@@ -771,8 +793,6 @@ struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, | |||
771 | int strsize1, strsize2; | 793 | int strsize1, strsize2; |
772 | bool found = false; | 794 | bool found = false; |
773 | 795 | ||
774 | lockdep_assert_held(&__efivars->lock); | ||
775 | |||
776 | list_for_each_entry_safe(entry, n, head, list) { | 796 | list_for_each_entry_safe(entry, n, head, list) { |
777 | strsize1 = ucs2_strsize(name, 1024); | 797 | strsize1 = ucs2_strsize(name, 1024); |
778 | strsize2 = ucs2_strsize(entry->var.VariableName, 1024); | 798 | strsize2 = ucs2_strsize(entry->var.VariableName, 1024); |
@@ -814,10 +834,11 @@ int efivar_entry_size(struct efivar_entry *entry, unsigned long *size) | |||
814 | 834 | ||
815 | *size = 0; | 835 | *size = 0; |
816 | 836 | ||
817 | spin_lock_irq(&__efivars->lock); | 837 | if (down_interruptible(&efivars_lock)) |
838 | return -EINTR; | ||
818 | status = ops->get_variable(entry->var.VariableName, | 839 | status = ops->get_variable(entry->var.VariableName, |
819 | &entry->var.VendorGuid, NULL, size, NULL); | 840 | &entry->var.VendorGuid, NULL, size, NULL); |
820 | spin_unlock_irq(&__efivars->lock); | 841 | up(&efivars_lock); |
821 | 842 | ||
822 | if (status != EFI_BUFFER_TOO_SMALL) | 843 | if (status != EFI_BUFFER_TOO_SMALL) |
823 | return efi_status_to_err(status); | 844 | return efi_status_to_err(status); |
@@ -843,8 +864,6 @@ int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes, | |||
843 | const struct efivar_operations *ops = __efivars->ops; | 864 | const struct efivar_operations *ops = __efivars->ops; |
844 | efi_status_t status; | 865 | efi_status_t status; |
845 | 866 | ||
846 | lockdep_assert_held(&__efivars->lock); | ||
847 | |||
848 | status = ops->get_variable(entry->var.VariableName, | 867 | status = ops->get_variable(entry->var.VariableName, |
849 | &entry->var.VendorGuid, | 868 | &entry->var.VendorGuid, |
850 | attributes, size, data); | 869 | attributes, size, data); |
@@ -866,11 +885,12 @@ int efivar_entry_get(struct efivar_entry *entry, u32 *attributes, | |||
866 | const struct efivar_operations *ops = __efivars->ops; | 885 | const struct efivar_operations *ops = __efivars->ops; |
867 | efi_status_t status; | 886 | efi_status_t status; |
868 | 887 | ||
869 | spin_lock_irq(&__efivars->lock); | 888 | if (down_interruptible(&efivars_lock)) |
889 | return -EINTR; | ||
870 | status = ops->get_variable(entry->var.VariableName, | 890 | status = ops->get_variable(entry->var.VariableName, |
871 | &entry->var.VendorGuid, | 891 | &entry->var.VendorGuid, |
872 | attributes, size, data); | 892 | attributes, size, data); |
873 | spin_unlock_irq(&__efivars->lock); | 893 | up(&efivars_lock); |
874 | 894 | ||
875 | return efi_status_to_err(status); | 895 | return efi_status_to_err(status); |
876 | } | 896 | } |
@@ -917,7 +937,8 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, | |||
917 | * set_variable call, and removal of the variable from the efivars | 937 | * set_variable call, and removal of the variable from the efivars |
918 | * list (in the case of an authenticated delete). | 938 | * list (in the case of an authenticated delete). |
919 | */ | 939 | */ |
920 | spin_lock_irq(&__efivars->lock); | 940 | if (down_interruptible(&efivars_lock)) |
941 | return -EINTR; | ||
921 | 942 | ||
922 | /* | 943 | /* |
923 | * 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 |
@@ -957,7 +978,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, | |||
957 | if (status == EFI_NOT_FOUND) | 978 | if (status == EFI_NOT_FOUND) |
958 | efivar_entry_list_del_unlock(entry); | 979 | efivar_entry_list_del_unlock(entry); |
959 | else | 980 | else |
960 | spin_unlock_irq(&__efivars->lock); | 981 | up(&efivars_lock); |
961 | 982 | ||
962 | if (status && status != EFI_BUFFER_TOO_SMALL) | 983 | if (status && status != EFI_BUFFER_TOO_SMALL) |
963 | return efi_status_to_err(status); | 984 | return efi_status_to_err(status); |
@@ -965,7 +986,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, | |||
965 | return 0; | 986 | return 0; |
966 | 987 | ||
967 | out: | 988 | out: |
968 | spin_unlock_irq(&__efivars->lock); | 989 | up(&efivars_lock); |
969 | return err; | 990 | return err; |
970 | 991 | ||
971 | } | 992 | } |
@@ -978,9 +999,9 @@ EXPORT_SYMBOL_GPL(efivar_entry_set_get_size); | |||
978 | * 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 |
979 | * conjunction with __efivar_entry_iter() or efivar_entry_iter(). | 1000 | * conjunction with __efivar_entry_iter() or efivar_entry_iter(). |
980 | */ | 1001 | */ |
981 | void efivar_entry_iter_begin(void) | 1002 | int efivar_entry_iter_begin(void) |
982 | { | 1003 | { |
983 | spin_lock_irq(&__efivars->lock); | 1004 | return down_interruptible(&efivars_lock); |
984 | } | 1005 | } |
985 | EXPORT_SYMBOL_GPL(efivar_entry_iter_begin); | 1006 | EXPORT_SYMBOL_GPL(efivar_entry_iter_begin); |
986 | 1007 | ||
@@ -991,7 +1012,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_iter_begin); | |||
991 | */ | 1012 | */ |
992 | void efivar_entry_iter_end(void) | 1013 | void efivar_entry_iter_end(void) |
993 | { | 1014 | { |
994 | spin_unlock_irq(&__efivars->lock); | 1015 | up(&efivars_lock); |
995 | } | 1016 | } |
996 | EXPORT_SYMBOL_GPL(efivar_entry_iter_end); | 1017 | EXPORT_SYMBOL_GPL(efivar_entry_iter_end); |
997 | 1018 | ||
@@ -1067,7 +1088,9 @@ int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), | |||
1067 | { | 1088 | { |
1068 | int err = 0; | 1089 | int err = 0; |
1069 | 1090 | ||
1070 | efivar_entry_iter_begin(); | 1091 | err = efivar_entry_iter_begin(); |
1092 | if (err) | ||
1093 | return err; | ||
1071 | err = __efivar_entry_iter(func, head, data, NULL); | 1094 | err = __efivar_entry_iter(func, head, data, NULL); |
1072 | efivar_entry_iter_end(); | 1095 | efivar_entry_iter_end(); |
1073 | 1096 | ||
@@ -1112,12 +1135,18 @@ int efivars_register(struct efivars *efivars, | |||
1112 | const struct efivar_operations *ops, | 1135 | const struct efivar_operations *ops, |
1113 | struct kobject *kobject) | 1136 | struct kobject *kobject) |
1114 | { | 1137 | { |
1115 | spin_lock_init(&efivars->lock); | 1138 | if (down_interruptible(&efivars_lock)) |
1139 | return -EINTR; | ||
1140 | |||
1116 | efivars->ops = ops; | 1141 | efivars->ops = ops; |
1117 | efivars->kobject = kobject; | 1142 | efivars->kobject = kobject; |
1118 | 1143 | ||
1119 | __efivars = efivars; | 1144 | __efivars = efivars; |
1120 | 1145 | ||
1146 | pr_info("Registered efivars operations\n"); | ||
1147 | |||
1148 | up(&efivars_lock); | ||
1149 | |||
1121 | return 0; | 1150 | return 0; |
1122 | } | 1151 | } |
1123 | EXPORT_SYMBOL_GPL(efivars_register); | 1152 | EXPORT_SYMBOL_GPL(efivars_register); |
@@ -1133,6 +1162,9 @@ int efivars_unregister(struct efivars *efivars) | |||
1133 | { | 1162 | { |
1134 | int rv; | 1163 | int rv; |
1135 | 1164 | ||
1165 | if (down_interruptible(&efivars_lock)) | ||
1166 | return -EINTR; | ||
1167 | |||
1136 | if (!__efivars) { | 1168 | if (!__efivars) { |
1137 | printk(KERN_ERR "efivars not registered\n"); | 1169 | printk(KERN_ERR "efivars not registered\n"); |
1138 | rv = -EINVAL; | 1170 | rv = -EINVAL; |
@@ -1144,10 +1176,12 @@ int efivars_unregister(struct efivars *efivars) | |||
1144 | goto out; | 1176 | goto out; |
1145 | } | 1177 | } |
1146 | 1178 | ||
1179 | pr_info("Unregistered efivars operations\n"); | ||
1147 | __efivars = NULL; | 1180 | __efivars = NULL; |
1148 | 1181 | ||
1149 | rv = 0; | 1182 | rv = 0; |
1150 | out: | 1183 | out: |
1184 | up(&efivars_lock); | ||
1151 | return rv; | 1185 | return rv; |
1152 | } | 1186 | } |
1153 | EXPORT_SYMBOL_GPL(efivars_unregister); | 1187 | EXPORT_SYMBOL_GPL(efivars_unregister); |