diff --git a/include/linux/fence.h b/include/linux/fence.h index 8499ace..33a265d 100644 --- a/include/linux/fence.h +++ b/include/linux/fence.h @@ -200,10 +200,13 @@ static inline void fence_get(struct fence *fence) */ static inline struct fence *fence_get_rcu(struct fence *fence) { - struct fence *f = ACCESS_ONCE(fence); + /* + * Either we make the function operate on __rcu pointers + * or remove ACCESS_ONCE + */ - if (kref_get_unless_zero(&f->refcount)) - return f; + if (kref_get_unless_zero(&fence->refcount)) + return fence; else return NULL; } diff --git a/include/linux/reservation.h b/include/linux/reservation.h index d6e1f62..ab586a6 100644 --- a/include/linux/reservation.h +++ b/include/linux/reservation.h @@ -50,16 +50,26 @@ extern struct lock_class_key reservation_seqcount_class; struct reservation_object_list { struct rcu_head rcu; + /* Protected by reservation_object::seq */ u32 shared_count, shared_max; - struct fence *shared[]; + /* + * Immutable. Individual pointers in the array are protected + * by reservation_object::seq and rcu. Hence while assigning those + * pointers, rcu_assign_pointer is needed. When reading them + * inside the seqlock, you may use rcu_dereference_protected(). + */ + struct fence __rcu *shared[]; }; struct reservation_object { struct ww_mutex lock; seqcount_t seq; + /* protected by @seq */ struct fence *fence_excl; - struct reservation_object_list *fence; + /* rcu protected by @lock */ + struct reservation_object_list __rcu *fence; + /* Protected by @lock */ struct reservation_object_list *staged; }; @@ -109,7 +119,7 @@ reservation_object_get_list(struct reservation_object *obj) { reservation_object_assert_held(obj); - return obj->fence; + return rcu_dereference_protected(obj->fence, 1); } static inline struct fence *