]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - queue-4.4/stm-class-fix-link-list-locking.patch
4.4-stable patches
[thirdparty/kernel/stable-queue.git] / queue-4.4 / stm-class-fix-link-list-locking.patch
1 From 503f811643c4d333e13e11866428dd9dc7cd92d2 Mon Sep 17 00:00:00 2001
2 From: Alexander Shishkin <alexander.shishkin@linux.intel.com>
3 Date: Tue, 22 Dec 2015 17:25:19 +0200
4 Subject: stm class: Fix link list locking
5
6 [ Upstream commit c74f7e8281add80bdfa0ad2998b8df287b13df73 ]
7
8 Currently, the list of stm_sources linked to an stm device is protected by
9 a spinlock, which also means that sources' .unlink() method is called under
10 this spinlock. However, this method may (and does) sleep, which means
11 trouble.
12
13 This patch slightly reworks locking around stm::link_list so that bits that
14 might_sleep() are called with a mutex held instead. Modification of this
15 list requires both mutex and spinlock to be held, while looking at the list
16 can be done under either mutex or spinlock.
17
18 Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com>
19 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
20 Signed-off-by: Sasha Levin <sashal@kernel.org>
21 ---
22 drivers/hwtracing/stm/core.c | 38 +++++++++++++++++++++++++++---------
23 drivers/hwtracing/stm/stm.h | 1 +
24 2 files changed, 30 insertions(+), 9 deletions(-)
25
26 diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c
27 index 92ab51aa8a74..f286de2e86af 100644
28 --- a/drivers/hwtracing/stm/core.c
29 +++ b/drivers/hwtracing/stm/core.c
30 @@ -647,6 +647,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data,
31 if (err)
32 goto err_device;
33
34 + mutex_init(&stm->link_mutex);
35 spin_lock_init(&stm->link_lock);
36 INIT_LIST_HEAD(&stm->link_list);
37
38 @@ -677,11 +678,11 @@ void stm_unregister_device(struct stm_data *stm_data)
39 struct stm_source_device *src, *iter;
40 int i;
41
42 - spin_lock(&stm->link_lock);
43 + mutex_lock(&stm->link_mutex);
44 list_for_each_entry_safe(src, iter, &stm->link_list, link_entry) {
45 __stm_source_link_drop(src, stm);
46 }
47 - spin_unlock(&stm->link_lock);
48 + mutex_unlock(&stm->link_mutex);
49
50 synchronize_srcu(&stm_source_srcu);
51
52 @@ -700,6 +701,17 @@ void stm_unregister_device(struct stm_data *stm_data)
53 }
54 EXPORT_SYMBOL_GPL(stm_unregister_device);
55
56 +/*
57 + * stm::link_list access serialization uses a spinlock and a mutex; holding
58 + * either of them guarantees that the list is stable; modification requires
59 + * holding both of them.
60 + *
61 + * Lock ordering is as follows:
62 + * stm::link_mutex
63 + * stm::link_lock
64 + * src::link_lock
65 + */
66 +
67 /**
68 * stm_source_link_add() - connect an stm_source device to an stm device
69 * @src: stm_source device
70 @@ -716,6 +728,7 @@ static int stm_source_link_add(struct stm_source_device *src,
71 char *id;
72 int err;
73
74 + mutex_lock(&stm->link_mutex);
75 spin_lock(&stm->link_lock);
76 spin_lock(&src->link_lock);
77
78 @@ -725,6 +738,7 @@ static int stm_source_link_add(struct stm_source_device *src,
79
80 spin_unlock(&src->link_lock);
81 spin_unlock(&stm->link_lock);
82 + mutex_unlock(&stm->link_mutex);
83
84 id = kstrdup(src->data->name, GFP_KERNEL);
85 if (id) {
86 @@ -762,6 +776,7 @@ static int stm_source_link_add(struct stm_source_device *src,
87 stm_put_device(stm);
88
89 fail_detach:
90 + mutex_lock(&stm->link_mutex);
91 spin_lock(&stm->link_lock);
92 spin_lock(&src->link_lock);
93
94 @@ -770,6 +785,7 @@ static int stm_source_link_add(struct stm_source_device *src,
95
96 spin_unlock(&src->link_lock);
97 spin_unlock(&stm->link_lock);
98 + mutex_unlock(&stm->link_mutex);
99
100 return err;
101 }
102 @@ -782,13 +798,20 @@ static int stm_source_link_add(struct stm_source_device *src,
103 * If @stm is @src::link, disconnect them from one another and put the
104 * reference on the @stm device.
105 *
106 - * Caller must hold stm::link_lock.
107 + * Caller must hold stm::link_mutex.
108 */
109 static void __stm_source_link_drop(struct stm_source_device *src,
110 struct stm_device *stm)
111 {
112 struct stm_device *link;
113
114 + lockdep_assert_held(&stm->link_mutex);
115 +
116 + if (src->data->unlink)
117 + src->data->unlink(src->data);
118 +
119 + /* for stm::link_list modification, we hold both mutex and spinlock */
120 + spin_lock(&stm->link_lock);
121 spin_lock(&src->link_lock);
122 link = srcu_dereference_check(src->link, &stm_source_srcu, 1);
123 if (WARN_ON_ONCE(link != stm)) {
124 @@ -797,13 +820,13 @@ static void __stm_source_link_drop(struct stm_source_device *src,
125 }
126
127 stm_output_free(link, &src->output);
128 - /* caller must hold stm::link_lock */
129 list_del_init(&src->link_entry);
130 /* matches stm_find_device() from stm_source_link_store() */
131 stm_put_device(link);
132 rcu_assign_pointer(src->link, NULL);
133
134 spin_unlock(&src->link_lock);
135 + spin_unlock(&stm->link_lock);
136 }
137
138 /**
139 @@ -825,12 +848,9 @@ static void stm_source_link_drop(struct stm_source_device *src)
140 stm = srcu_dereference(src->link, &stm_source_srcu);
141
142 if (stm) {
143 - if (src->data->unlink)
144 - src->data->unlink(src->data);
145 -
146 - spin_lock(&stm->link_lock);
147 + mutex_lock(&stm->link_mutex);
148 __stm_source_link_drop(src, stm);
149 - spin_unlock(&stm->link_lock);
150 + mutex_unlock(&stm->link_mutex);
151 }
152
153 srcu_read_unlock(&stm_source_srcu, idx);
154 diff --git a/drivers/hwtracing/stm/stm.h b/drivers/hwtracing/stm/stm.h
155 index 95ece0292c99..97ee02241440 100644
156 --- a/drivers/hwtracing/stm/stm.h
157 +++ b/drivers/hwtracing/stm/stm.h
158 @@ -45,6 +45,7 @@ struct stm_device {
159 int major;
160 unsigned int sw_nmasters;
161 struct stm_data *data;
162 + struct mutex link_mutex;
163 spinlock_t link_lock;
164 struct list_head link_list;
165 /* master allocation */
166 --
167 2.19.1
168