diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2016-08-29 03:08:29 -0400 |
---|---|---|
committer | Sumit Semwal <sumit.semwal@linaro.org> | 2016-10-12 10:18:33 -0400 |
commit | 4be0542073a33cc063b6a8f8fb367536e234e7aa (patch) | |
tree | 890cd8132b7075a29d1620c5983c77b116e22e1e | |
parent | 998a7aa1bdeb10e06e4ac7bff533145339fa1256 (diff) |
dma-buf: Introduce fence_get_rcu_safe()
This variant of fence_get_rcu() takes an RCU protected pointer to a
fence and carefully returns a reference to the fence ensuring that it is
not reallocated as it does. This is required when mixing fences and
SLAB_DESTROY_BY_RCU - although it serves a more pedagogical function atm
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: linux-media@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Cc: linaro-mm-sig@lists.linaro.org
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20160829070834.22296-6-chris@chris-wilson.co.uk
-rw-r--r-- | include/linux/fence.h | 56 |
1 files changed, 51 insertions, 5 deletions
diff --git a/include/linux/fence.h b/include/linux/fence.h index 0d763053f97a..c9c5ba98c302 100644 --- a/include/linux/fence.h +++ b/include/linux/fence.h | |||
@@ -183,6 +183,16 @@ void fence_release(struct kref *kref); | |||
183 | void fence_free(struct fence *fence); | 183 | void fence_free(struct fence *fence); |
184 | 184 | ||
185 | /** | 185 | /** |
186 | * fence_put - decreases refcount of the fence | ||
187 | * @fence: [in] fence to reduce refcount of | ||
188 | */ | ||
189 | static inline void fence_put(struct fence *fence) | ||
190 | { | ||
191 | if (fence) | ||
192 | kref_put(&fence->refcount, fence_release); | ||
193 | } | ||
194 | |||
195 | /** | ||
186 | * fence_get - increases refcount of the fence | 196 | * fence_get - increases refcount of the fence |
187 | * @fence: [in] fence to increase refcount of | 197 | * @fence: [in] fence to increase refcount of |
188 | * | 198 | * |
@@ -210,13 +220,49 @@ static inline struct fence *fence_get_rcu(struct fence *fence) | |||
210 | } | 220 | } |
211 | 221 | ||
212 | /** | 222 | /** |
213 | * fence_put - decreases refcount of the fence | 223 | * fence_get_rcu_safe - acquire a reference to an RCU tracked fence |
214 | * @fence: [in] fence to reduce refcount of | 224 | * @fence: [in] pointer to fence to increase refcount of |
225 | * | ||
226 | * Function returns NULL if no refcount could be obtained, or the fence. | ||
227 | * This function handles acquiring a reference to a fence that may be | ||
228 | * reallocated within the RCU grace period (such as with SLAB_DESTROY_BY_RCU), | ||
229 | * so long as the caller is using RCU on the pointer to the fence. | ||
230 | * | ||
231 | * An alternative mechanism is to employ a seqlock to protect a bunch of | ||
232 | * fences, such as used by struct reservation_object. When using a seqlock, | ||
233 | * the seqlock must be taken before and checked after a reference to the | ||
234 | * fence is acquired (as shown here). | ||
235 | * | ||
236 | * The caller is required to hold the RCU read lock. | ||
215 | */ | 237 | */ |
216 | static inline void fence_put(struct fence *fence) | 238 | static inline struct fence *fence_get_rcu_safe(struct fence * __rcu *fencep) |
217 | { | 239 | { |
218 | if (fence) | 240 | do { |
219 | kref_put(&fence->refcount, fence_release); | 241 | struct fence *fence; |
242 | |||
243 | fence = rcu_dereference(*fencep); | ||
244 | if (!fence || !fence_get_rcu(fence)) | ||
245 | return NULL; | ||
246 | |||
247 | /* The atomic_inc_not_zero() inside fence_get_rcu() | ||
248 | * provides a full memory barrier upon success (such as now). | ||
249 | * This is paired with the write barrier from assigning | ||
250 | * to the __rcu protected fence pointer so that if that | ||
251 | * pointer still matches the current fence, we know we | ||
252 | * have successfully acquire a reference to it. If it no | ||
253 | * longer matches, we are holding a reference to some other | ||
254 | * reallocated pointer. This is possible if the allocator | ||
255 | * is using a freelist like SLAB_DESTROY_BY_RCU where the | ||
256 | * fence remains valid for the RCU grace period, but it | ||
257 | * may be reallocated. When using such allocators, we are | ||
258 | * responsible for ensuring the reference we get is to | ||
259 | * the right fence, as below. | ||
260 | */ | ||
261 | if (fence == rcu_access_pointer(*fencep)) | ||
262 | return rcu_pointer_handoff(fence); | ||
263 | |||
264 | fence_put(fence); | ||
265 | } while (1); | ||
220 | } | 266 | } |
221 | 267 | ||
222 | int fence_signal(struct fence *fence); | 268 | int fence_signal(struct fence *fence); |