diff -drupN a/include/linux/fence.h b/include/linux/fence.h --- a/include/linux/fence.h 2018-08-06 17:23:04.000000000 +0300 +++ b/include/linux/fence.h 2022-06-12 05:28:14.000000000 +0300 @@ -108,6 +108,7 @@ struct fence_cb { * @get_driver_name: returns the driver name. * @get_timeline_name: return the name of the context this fence belongs to. * @enable_signaling: enable software signaling of fence. + * @disable_signaling: disable software signaling of fence (optional). * @signaled: [optional] peek whether the fence is signaled, can be null. * @wait: custom wait implementation, or fence_default_wait. * @release: [optional] called on destruction of fence, can be null @@ -167,6 +168,7 @@ struct fence_ops { const char * (*get_driver_name)(struct fence *fence); const char * (*get_timeline_name)(struct fence *fence); bool (*enable_signaling)(struct fence *fence); + void (*disable_signaling)(struct fence *fence); bool (*signaled)(struct fence *fence); signed long (*wait)(struct fence *fence, bool intr, signed long timeout); void (*release)(struct fence *fence); @@ -183,6 +185,16 @@ 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 +222,49 @@ static inline struct fence *fence_get_rc } /** - * 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);