dma-buf: Restore seqlock around dma_resv updates
This reverts67c97fb79a("dma-buf: add reservation_object_fences helper")dd7a7d1ff2("drm/i915: use new reservation_object_fences helper")0e1d8083bd("dma-buf: further relax reservation_object_add_shared_fence")5d344f58da("dma-buf: nuke reservation_object seq number") The scenario that defeats simply grabbing a set of shared/exclusive fences and using them blissfully under RCU is that any of those fences may be reallocated by a SLAB_TYPESAFE_BY_RCU fence slab cache. In this scenario, while keeping the rcu_read_lock we need to establish that no fence was changed in the dma_resv after a read (or full) memory barrier. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Acked-by: Christian König <christian.koenig@amd.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190814182401.25009-1-chris@chris-wilson.co.uk
This commit is contained in:
@@ -46,6 +46,8 @@
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
extern struct ww_class reservation_ww_class;
|
||||
extern struct lock_class_key reservation_seqcount_class;
|
||||
extern const char reservation_seqcount_string[];
|
||||
|
||||
/**
|
||||
* struct dma_resv_list - a list of shared fences
|
||||
@@ -69,6 +71,7 @@ struct dma_resv_list {
|
||||
*/
|
||||
struct dma_resv {
|
||||
struct ww_mutex lock;
|
||||
seqcount_t seq;
|
||||
|
||||
struct dma_fence __rcu *fence_excl;
|
||||
struct dma_resv_list __rcu *fence;
|
||||
@@ -77,24 +80,6 @@ struct dma_resv {
|
||||
#define dma_resv_held(obj) lockdep_is_held(&(obj)->lock.base)
|
||||
#define dma_resv_assert_held(obj) lockdep_assert_held(&(obj)->lock.base)
|
||||
|
||||
/**
|
||||
* dma_resv_get_excl - get the reservation object's
|
||||
* exclusive fence, with update-side lock held
|
||||
* @obj: the reservation object
|
||||
*
|
||||
* Returns the exclusive fence (if any). Does NOT take a
|
||||
* reference. Writers must hold obj->lock, readers may only
|
||||
* hold a RCU read side lock.
|
||||
*
|
||||
* RETURNS
|
||||
* The exclusive fence or NULL
|
||||
*/
|
||||
static inline struct dma_fence *dma_resv_get_excl(struct dma_resv *obj)
|
||||
{
|
||||
return rcu_dereference_protected(obj->fence_excl,
|
||||
dma_resv_held(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_get_list - get the reservation object's
|
||||
* shared fence list, with update-side lock held
|
||||
@@ -109,53 +94,6 @@ static inline struct dma_resv_list *dma_resv_get_list(struct dma_resv *obj)
|
||||
dma_resv_held(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_fences - read consistent fence pointers
|
||||
* @obj: reservation object where we get the fences from
|
||||
* @excl: pointer for the exclusive fence
|
||||
* @list: pointer for the shared fence list
|
||||
*
|
||||
* Make sure we have a consisten exclusive fence and shared fence list.
|
||||
* Must be called with rcu read side lock held.
|
||||
*/
|
||||
static inline void dma_resv_fences(struct dma_resv *obj,
|
||||
struct dma_fence **excl,
|
||||
struct dma_resv_list **list,
|
||||
u32 *shared_count)
|
||||
{
|
||||
do {
|
||||
*excl = rcu_dereference(obj->fence_excl);
|
||||
*list = rcu_dereference(obj->fence);
|
||||
*shared_count = *list ? (*list)->shared_count : 0;
|
||||
smp_rmb(); /* See dma_resv_add_excl_fence */
|
||||
} while (rcu_access_pointer(obj->fence_excl) != *excl);
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_get_excl_rcu - get the reservation object's
|
||||
* exclusive fence, without lock held.
|
||||
* @obj: the reservation object
|
||||
*
|
||||
* If there is an exclusive fence, this atomically increments it's
|
||||
* reference count and returns it.
|
||||
*
|
||||
* RETURNS
|
||||
* The exclusive fence or NULL if none
|
||||
*/
|
||||
static inline struct dma_fence *dma_resv_get_excl_rcu(struct dma_resv *obj)
|
||||
{
|
||||
struct dma_fence *fence;
|
||||
|
||||
if (!rcu_access_pointer(obj->fence_excl))
|
||||
return NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
fence = dma_fence_get_rcu_safe(&obj->fence_excl);
|
||||
rcu_read_unlock();
|
||||
|
||||
return fence;
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_lock - lock the reservation object
|
||||
* @obj: the reservation object
|
||||
@@ -290,6 +228,51 @@ static inline void dma_resv_unlock(struct dma_resv *obj)
|
||||
ww_mutex_unlock(&obj->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_get_excl - get the reservation object's
|
||||
* exclusive fence, with update-side lock held
|
||||
* @obj: the reservation object
|
||||
*
|
||||
* Returns the exclusive fence (if any). Does NOT take a
|
||||
* reference. Writers must hold obj->lock, readers may only
|
||||
* hold a RCU read side lock.
|
||||
*
|
||||
* RETURNS
|
||||
* The exclusive fence or NULL
|
||||
*/
|
||||
static inline struct dma_fence *
|
||||
dma_resv_get_excl(struct dma_resv *obj)
|
||||
{
|
||||
return rcu_dereference_protected(obj->fence_excl,
|
||||
dma_resv_held(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* dma_resv_get_excl_rcu - get the reservation object's
|
||||
* exclusive fence, without lock held.
|
||||
* @obj: the reservation object
|
||||
*
|
||||
* If there is an exclusive fence, this atomically increments it's
|
||||
* reference count and returns it.
|
||||
*
|
||||
* RETURNS
|
||||
* The exclusive fence or NULL if none
|
||||
*/
|
||||
static inline struct dma_fence *
|
||||
dma_resv_get_excl_rcu(struct dma_resv *obj)
|
||||
{
|
||||
struct dma_fence *fence;
|
||||
|
||||
if (!rcu_access_pointer(obj->fence_excl))
|
||||
return NULL;
|
||||
|
||||
rcu_read_lock();
|
||||
fence = dma_fence_get_rcu_safe(&obj->fence_excl);
|
||||
rcu_read_unlock();
|
||||
|
||||
return fence;
|
||||
}
|
||||
|
||||
void dma_resv_init(struct dma_resv *obj);
|
||||
void dma_resv_fini(struct dma_resv *obj);
|
||||
int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences);
|
||||
|
||||
Reference in New Issue
Block a user