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
This commit is contained in:
parent
998a7aa1bd
commit
4be0542073
|
@ -182,6 +182,16 @@ void fence_init(struct fence *fence, const struct fence_ops *ops,
|
|||
void fence_release(struct kref *kref);
|
||||
void fence_free(struct fence *fence);
|
||||
|
||||
/**
|
||||
* fence_put - decreases refcount of the fence
|
||||
* @fence: [in] fence to reduce refcount of
|
||||
*/
|
||||
static inline void fence_put(struct fence *fence)
|
||||
{
|
||||
if (fence)
|
||||
kref_put(&fence->refcount, fence_release);
|
||||
}
|
||||
|
||||
/**
|
||||
* fence_get - increases refcount of the fence
|
||||
* @fence: [in] fence to increase refcount of
|
||||
|
@ -210,13 +220,49 @@ static inline struct fence *fence_get_rcu(struct fence *fence)
|
|||
}
|
||||
|
||||
/**
|
||||
* fence_put - decreases refcount of the fence
|
||||
* @fence: [in] fence to reduce refcount of
|
||||
* fence_get_rcu_safe - acquire a reference to an RCU tracked fence
|
||||
* @fence: [in] pointer to fence to increase refcount of
|
||||
*
|
||||
* Function returns NULL if no refcount could be obtained, or the fence.
|
||||
* This function handles acquiring a reference to a fence that may be
|
||||
* reallocated within the RCU grace period (such as with SLAB_DESTROY_BY_RCU),
|
||||
* so long as the caller is using RCU on the pointer to the fence.
|
||||
*
|
||||
* An alternative mechanism is to employ a seqlock to protect a bunch of
|
||||
* fences, such as used by struct reservation_object. When using a seqlock,
|
||||
* the seqlock must be taken before and checked after a reference to the
|
||||
* fence is acquired (as shown here).
|
||||
*
|
||||
* The caller is required to hold the RCU read lock.
|
||||
*/
|
||||
static inline void fence_put(struct fence *fence)
|
||||
static inline struct fence *fence_get_rcu_safe(struct fence * __rcu *fencep)
|
||||
{
|
||||
if (fence)
|
||||
kref_put(&fence->refcount, fence_release);
|
||||
do {
|
||||
struct fence *fence;
|
||||
|
||||
fence = rcu_dereference(*fencep);
|
||||
if (!fence || !fence_get_rcu(fence))
|
||||
return NULL;
|
||||
|
||||
/* The atomic_inc_not_zero() inside fence_get_rcu()
|
||||
* provides a full memory barrier upon success (such as now).
|
||||
* This is paired with the write barrier from assigning
|
||||
* to the __rcu protected fence pointer so that if that
|
||||
* pointer still matches the current fence, we know we
|
||||
* have successfully acquire a reference to it. If it no
|
||||
* longer matches, we are holding a reference to some other
|
||||
* reallocated pointer. This is possible if the allocator
|
||||
* is using a freelist like SLAB_DESTROY_BY_RCU where the
|
||||
* fence remains valid for the RCU grace period, but it
|
||||
* may be reallocated. When using such allocators, we are
|
||||
* responsible for ensuring the reference we get is to
|
||||
* the right fence, as below.
|
||||
*/
|
||||
if (fence == rcu_access_pointer(*fencep))
|
||||
return rcu_pointer_handoff(fence);
|
||||
|
||||
fence_put(fence);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
int fence_signal(struct fence *fence);
|
||||
|
|
Loading…
Reference in New Issue