summaryrefslogtreecommitdiffstats
path: root/drivers/hwtracing/stm
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2015-12-22 10:25:19 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-02-08 01:43:17 -0500
commitc74f7e8281add80bdfa0ad2998b8df287b13df73 (patch)
treefa35e258056567f402ab9fc457c80ef9a03bbf29 /drivers/hwtracing/stm
parent4c127fd16e6b33ecb7badc091480c84ea9aebeb6 (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.c38
-rw-r--r--drivers/hwtracing/stm/stm.h1
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}
695EXPORT_SYMBOL_GPL(stm_unregister_device); 696EXPORT_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
758fail_detach: 772fail_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 */
781static void __stm_source_link_drop(struct stm_source_device *src, 797static 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 */