Commit 4be05420 authored by Chris Wilson's avatar Chris Wilson Committed by Sumit Semwal
Browse files

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: default avatarChris 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: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarSumit Semwal <sumit.semwal@linaro.org>
Link: http://patchwork.freedesktop.org/patch/msgid/20160829070834.22296-6-chris@chris-wilson.co.uk
parent 998a7aa1
Loading
Loading
Loading
Loading
+51 −5
Original line number Original line Diff line number Diff line
@@ -182,6 +182,16 @@ void fence_init(struct fence *fence, const struct fence_ops *ops,
void fence_release(struct kref *kref);
void fence_release(struct kref *kref);
void fence_free(struct fence *fence);
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_get - increases refcount of the fence
 * @fence:	[in]	fence to increase refcount of
 * @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_get_rcu_safe  - acquire a reference to an RCU tracked fence
 * @fence:	[in]	fence to reduce refcount of
 * @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)
	do {
		kref_put(&fence->refcount, fence_release);
		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);
int fence_signal(struct fence *fence);