diff options
author | Alexander Shishkin <alexander.shishkin@linux.intel.com> | 2015-12-22 10:25:19 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-02-08 01:43:17 -0500 |
commit | c74f7e8281add80bdfa0ad2998b8df287b13df73 (patch) | |
tree | fa35e258056567f402ab9fc457c80ef9a03bbf29 /drivers/hwtracing/stm | |
parent | 4c127fd16e6b33ecb7badc091480c84ea9aebeb6 (diff) |
stm class: Fix link list locking
Currently, the list of stm_sources linked to an stm device is protected by
a spinlock, which also means that sources' .unlink() method is called under
this spinlock. However, this method may (and does) sleep, which means
trouble.
This patch slightly reworks locking around stm::link_list so that bits that
might_sleep() are called with a mutex held instead. Modification of this
list requires both mutex and spinlock to be held, while looking at the list
can be done under either mutex or spinlock.
Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/hwtracing/stm')
-rw-r--r-- | drivers/hwtracing/stm/core.c | 38 | ||||
-rw-r--r-- | drivers/hwtracing/stm/stm.h | 1 |
2 files changed, 30 insertions, 9 deletions
diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index b6445d9e5453..ddcb606acea6 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c | |||
@@ -641,6 +641,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, | |||
641 | if (err) | 641 | if (err) |
642 | goto err_device; | 642 | goto err_device; |
643 | 643 | ||
644 | mutex_init(&stm->link_mutex); | ||
644 | spin_lock_init(&stm->link_lock); | 645 | spin_lock_init(&stm->link_lock); |
645 | INIT_LIST_HEAD(&stm->link_list); | 646 | INIT_LIST_HEAD(&stm->link_list); |
646 | 647 | ||
@@ -671,11 +672,11 @@ void stm_unregister_device(struct stm_data *stm_data) | |||
671 | struct stm_source_device *src, *iter; | 672 | struct stm_source_device *src, *iter; |
672 | int i; | 673 | int i; |
673 | 674 | ||
674 | spin_lock(&stm->link_lock); | 675 | mutex_lock(&stm->link_mutex); |
675 | list_for_each_entry_safe(src, iter, &stm->link_list, link_entry) { | 676 | list_for_each_entry_safe(src, iter, &stm->link_list, link_entry) { |
676 | __stm_source_link_drop(src, stm); | 677 | __stm_source_link_drop(src, stm); |
677 | } | 678 | } |
678 | spin_unlock(&stm->link_lock); | 679 | mutex_unlock(&stm->link_mutex); |
679 | 680 | ||
680 | synchronize_srcu(&stm_source_srcu); | 681 | synchronize_srcu(&stm_source_srcu); |
681 | 682 | ||
@@ -694,6 +695,17 @@ void stm_unregister_device(struct stm_data *stm_data) | |||
694 | } | 695 | } |
695 | EXPORT_SYMBOL_GPL(stm_unregister_device); | 696 | EXPORT_SYMBOL_GPL(stm_unregister_device); |
696 | 697 | ||
698 | /* | ||
699 | * stm::link_list access serialization uses a spinlock and a mutex; holding | ||
700 | * either of them guarantees that the list is stable; modification requires | ||
701 | * holding both of them. | ||
702 | * | ||
703 | * Lock ordering is as follows: | ||
704 | * stm::link_mutex | ||
705 | * stm::link_lock | ||
706 | * src::link_lock | ||
707 | */ | ||
708 | |||
697 | /** | 709 | /** |
698 | * stm_source_link_add() - connect an stm_source device to an stm device | 710 | * stm_source_link_add() - connect an stm_source device to an stm device |
699 | * @src: stm_source device | 711 | * @src: stm_source device |
@@ -710,6 +722,7 @@ static int stm_source_link_add(struct stm_source_device *src, | |||
710 | char *id; | 722 | char *id; |
711 | int err; | 723 | int err; |
712 | 724 | ||
725 | mutex_lock(&stm->link_mutex); | ||
713 | spin_lock(&stm->link_lock); | 726 | spin_lock(&stm->link_lock); |
714 | spin_lock(&src->link_lock); | 727 | spin_lock(&src->link_lock); |
715 | 728 | ||
@@ -719,6 +732,7 @@ static int stm_source_link_add(struct stm_source_device *src, | |||
719 | 732 | ||
720 | spin_unlock(&src->link_lock); | 733 | spin_unlock(&src->link_lock); |
721 | spin_unlock(&stm->link_lock); | 734 | spin_unlock(&stm->link_lock); |
735 | mutex_unlock(&stm->link_mutex); | ||
722 | 736 | ||
723 | id = kstrdup(src->data->name, GFP_KERNEL); | 737 | id = kstrdup(src->data->name, GFP_KERNEL); |
724 | if (id) { | 738 | if (id) { |
@@ -756,6 +770,7 @@ fail_free_output: | |||
756 | stm_put_device(stm); | 770 | stm_put_device(stm); |
757 | 771 | ||
758 | fail_detach: | 772 | fail_detach: |
773 | mutex_lock(&stm->link_mutex); | ||
759 | spin_lock(&stm->link_lock); | 774 | spin_lock(&stm->link_lock); |
760 | spin_lock(&src->link_lock); | 775 | spin_lock(&src->link_lock); |
761 | 776 | ||
@@ -764,6 +779,7 @@ fail_detach: | |||
764 | 779 | ||
765 | spin_unlock(&src->link_lock); | 780 | spin_unlock(&src->link_lock); |
766 | spin_unlock(&stm->link_lock); | 781 | spin_unlock(&stm->link_lock); |
782 | mutex_unlock(&stm->link_mutex); | ||
767 | 783 | ||
768 | return err; | 784 | return err; |
769 | } | 785 | } |
@@ -776,13 +792,20 @@ fail_detach: | |||
776 | * If @stm is @src::link, disconnect them from one another and put the | 792 | * If @stm is @src::link, disconnect them from one another and put the |
777 | * reference on the @stm device. | 793 | * reference on the @stm device. |
778 | * | 794 | * |
779 | * Caller must hold stm::link_lock. | 795 | * Caller must hold stm::link_mutex. |
780 | */ | 796 | */ |
781 | static void __stm_source_link_drop(struct stm_source_device *src, | 797 | static void __stm_source_link_drop(struct stm_source_device *src, |
782 | struct stm_device *stm) | 798 | struct stm_device *stm) |
783 | { | 799 | { |
784 | struct stm_device *link; | 800 | struct stm_device *link; |
785 | 801 | ||
802 | lockdep_assert_held(&stm->link_mutex); | ||
803 | |||
804 | if (src->data->unlink) | ||
805 | src->data->unlink(src->data); | ||
806 | |||
807 | /* for stm::link_list modification, we hold both mutex and spinlock */ | ||
808 | spin_lock(&stm->link_lock); | ||
786 | spin_lock(&src->link_lock); | 809 | spin_lock(&src->link_lock); |
787 | link = srcu_dereference_check(src->link, &stm_source_srcu, 1); | 810 | link = srcu_dereference_check(src->link, &stm_source_srcu, 1); |
788 | if (WARN_ON_ONCE(link != stm)) { | 811 | if (WARN_ON_ONCE(link != stm)) { |
@@ -791,13 +814,13 @@ static void __stm_source_link_drop(struct stm_source_device *src, | |||
791 | } | 814 | } |
792 | 815 | ||
793 | stm_output_free(link, &src->output); | 816 | stm_output_free(link, &src->output); |
794 | /* caller must hold stm::link_lock */ | ||
795 | list_del_init(&src->link_entry); | 817 | list_del_init(&src->link_entry); |
796 | /* matches stm_find_device() from stm_source_link_store() */ | 818 | /* matches stm_find_device() from stm_source_link_store() */ |
797 | stm_put_device(link); | 819 | stm_put_device(link); |
798 | rcu_assign_pointer(src->link, NULL); | 820 | rcu_assign_pointer(src->link, NULL); |
799 | 821 | ||
800 | spin_unlock(&src->link_lock); | 822 | spin_unlock(&src->link_lock); |
823 | spin_unlock(&stm->link_lock); | ||
801 | } | 824 | } |
802 | 825 | ||
803 | /** | 826 | /** |
@@ -819,12 +842,9 @@ static void stm_source_link_drop(struct stm_source_device *src) | |||
819 | stm = srcu_dereference(src->link, &stm_source_srcu); | 842 | stm = srcu_dereference(src->link, &stm_source_srcu); |
820 | 843 | ||
821 | if (stm) { | 844 | if (stm) { |
822 | if (src->data->unlink) | 845 | mutex_lock(&stm->link_mutex); |
823 | src->data->unlink(src->data); | ||
824 | |||
825 | spin_lock(&stm->link_lock); | ||
826 | __stm_source_link_drop(src, stm); | 846 | __stm_source_link_drop(src, stm); |
827 | spin_unlock(&stm->link_lock); | 847 | mutex_unlock(&stm->link_mutex); |
828 | } | 848 | } |
829 | 849 | ||
830 | srcu_read_unlock(&stm_source_srcu, idx); | 850 | srcu_read_unlock(&stm_source_srcu, idx); |
diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h index 95ece0292c99..97ee02241440 100644 --- a/drivers/hwtracing/stm/stm.h +++ b/drivers/hwtracing/stm/stm.h | |||
@@ -45,6 +45,7 @@ struct stm_device { | |||
45 | int major; | 45 | int major; |
46 | unsigned int sw_nmasters; | 46 | unsigned int sw_nmasters; |
47 | struct stm_data *data; | 47 | struct stm_data *data; |
48 | struct mutex link_mutex; | ||
48 | spinlock_t link_lock; | 49 | spinlock_t link_lock; |
49 | struct list_head link_list; | 50 | struct list_head link_list; |
50 | /* master allocation */ | 51 | /* master allocation */ |