diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
index 13884474d158..6b816cd505d6 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -244,7 +244,10 @@ static __poll_t dma_buf_poll(struct file *file, poll_table *poll)
 			goto out;
 
 		for (i = 0; i < shared_count; ++i) {
-			struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
+			struct dma_fence *fence;
+
+			fence = reservation_object_shared_fence(
+				rcu_dereference(fobj->shared[i]));
 
 			if (!dma_fence_get_rcu(fence)) {
 				/*
@@ -1062,7 +1065,8 @@ static int dma_buf_debug_show(struct seq_file *s, void *unused)
 				   fence->ops->get_timeline_name(fence),
 				   dma_fence_is_signaled(fence) ? "" : "un");
 		for (i = 0; i < shared_count; i++) {
-			fence = rcu_dereference(fobj->shared[i]);
+			fence = reservation_object_shared_fence(
+				rcu_dereference(fobj->shared[i]));
 			if (!dma_fence_get_rcu(fence))
 				continue;
 			seq_printf(s, "\tShared fence: %s %s %ssignalled\n",
diff --git a/drivers/dma-buf/reservation.c b/drivers/dma-buf/reservation.c
index 1f0c61b540ba..0f98384b86d4 100644
--- a/drivers/dma-buf/reservation.c
+++ b/drivers/dma-buf/reservation.c
@@ -93,14 +93,14 @@ int reservation_object_reserve_shared(struct reservation_object *obj)
 	 * the new.
 	 */
 	for (i = 0, j = 0, k = max; i < (old ? old->shared_count : 0); ++i) {
-		struct dma_fence *fence;
+		void *e;
 
-		fence = rcu_dereference_protected(old->shared[i],
-						  reservation_object_held(obj));
-		if (dma_fence_is_signaled(fence))
-			RCU_INIT_POINTER(new->shared[--k], fence);
+		e = rcu_dereference_protected(old->shared[i],
+					      reservation_object_held(obj));
+		if (dma_fence_is_signaled(reservation_object_shared_fence(e)))
+			RCU_INIT_POINTER(new->shared[--k], e);
 		else
-			RCU_INIT_POINTER(new->shared[j++], fence);
+			RCU_INIT_POINTER(new->shared[j++], e);
 	}
 	new->shared_count = j;
 	new->shared_max = max;
@@ -120,11 +120,11 @@ int reservation_object_reserve_shared(struct reservation_object *obj)
 
 	/* Drop the references to the signaled fences */
 	for (i = k; i < new->shared_max; ++i) {
-		struct dma_fence *fence;
+		void *e;
 
-		fence = rcu_dereference_protected(new->shared[i],
-						  reservation_object_held(obj));
-		dma_fence_put(fence);
+		e = rcu_dereference_protected(new->shared[i],
+					      reservation_object_held(obj));
+		dma_fence_put(reservation_object_shared_fence(e));
 	}
 	kfree_rcu(old, rcu);
 
@@ -141,7 +141,8 @@ EXPORT_SYMBOL(reservation_object_reserve_shared);
  * reservation_object_reserve_shared() has been called.
  */
 void reservation_object_add_shared_fence(struct reservation_object *obj,
-					 struct dma_fence *fence)
+					 struct dma_fence *fence,
+					 bool is_write)
 {
 	struct reservation_object_list *fobj;
 	unsigned int i;
@@ -155,13 +156,17 @@ void reservation_object_add_shared_fence(struct reservation_object *obj,
 
 	for (i = 0; i < fobj->shared_count; ++i) {
 		struct dma_fence *old_fence;
+		void *e;
 
-		old_fence = rcu_dereference_protected(fobj->shared[i],
-						      reservation_object_held(obj));
-		if (old_fence->context == fence->context ||
+		e = rcu_dereference_protected(fobj->shared[i],
+					      reservation_object_held(obj));
+		old_fence = reservation_object_shared_fence(e);
+		if ((old_fence->context == fence->context &&
+		    reservation_object_shared_is_write(e) == is_write) ||
 		    dma_fence_is_signaled(old_fence)) {
 			/* memory barrier is added by write_seqcount_begin */
-			RCU_INIT_POINTER(fobj->shared[i], fence);
+			RCU_INIT_POINTER(fobj->shared[i],
+					 (void *)(is_write | (long)fence));
 			write_seqcount_end(&obj->seq);
 			preempt_enable();
 			dma_fence_put(old_fence);
@@ -173,7 +178,8 @@ void reservation_object_add_shared_fence(struct reservation_object *obj,
 	 * memory barrier is added by write_seqcount_begin,
 	 * fobj->shared_count is protected by this lock too
 	 */
-	RCU_INIT_POINTER(fobj->shared[fobj->shared_count], fence);
+	RCU_INIT_POINTER(fobj->shared[fobj->shared_count],
+			 (void *)(is_write | (long)fence));
 	fobj->shared_count++;
 
 	write_seqcount_end(&obj->seq);
@@ -213,8 +219,7 @@ void reservation_object_add_excl_fence(struct reservation_object *obj,
 
 	/* inplace update, no shared fences */
 	while (i--)
-		dma_fence_put(rcu_dereference_protected(old->shared[i],
-						reservation_object_held(obj)));
+		dma_fence_put(reservation_object_get_shared_fence(obj, old, i));
 
 	dma_fence_put(old_fence);
 }
@@ -260,8 +265,10 @@ int reservation_object_copy_fences(struct reservation_object *dst,
 		dst_list->shared_max = shared_count;
 		for (i = 0; i < src_list->shared_count; ++i) {
 			struct dma_fence *fence;
+			void *e;
 
-			fence = rcu_dereference(src_list->shared[i]);
+			e = rcu_dereference(src_list->shared[i]);
+			fence = reservation_object_shared_fence(e);
 			if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
 				     &fence->flags))
 				continue;
@@ -277,7 +284,7 @@ int reservation_object_copy_fences(struct reservation_object *dst,
 				continue;
 			}
 
-			rcu_assign_pointer(dst_list->shared[dst_list->shared_count++], fence);
+			rcu_assign_pointer(dst_list->shared[dst_list->shared_count++], e);
 		}
 	} else {
 		dst_list = NULL;
@@ -368,7 +375,9 @@ int reservation_object_get_fences_rcu(struct reservation_object *obj,
 			shared = nshared;
 			shared_count = fobj ? fobj->shared_count : 0;
 			for (i = 0; i < shared_count; ++i) {
-				shared[i] = rcu_dereference(fobj->shared[i]);
+				void *e = rcu_dereference(fobj->shared[i]);
+
+				shared[i] = reservation_object_shared_fence(e);
 				if (!dma_fence_get_rcu(shared[i]))
 					break;
 			}
@@ -456,8 +465,10 @@ long reservation_object_wait_timeout_rcu(struct reservation_object *obj,
 			shared_count = fobj->shared_count;
 
 		for (i = 0; !fence && i < shared_count; ++i) {
-			struct dma_fence *lfence = rcu_dereference(fobj->shared[i]);
+			void *e = rcu_dereference(fobj->shared[i]);
+			struct dma_fence *lfence;
 
+			lfence = reservation_object_shared_fence(e);
 			if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
 				     &lfence->flags))
 				continue;
@@ -545,8 +556,10 @@ bool reservation_object_test_signaled_rcu(struct reservation_object *obj,
 			shared_count = fobj->shared_count;
 
 		for (i = 0; i < shared_count; ++i) {
-			struct dma_fence *fence = rcu_dereference(fobj->shared[i]);
+			void *e = rcu_dereference(fobj->shared[i]);
+			struct dma_fence *fence;
 
+			fence = reservation_object_shared_fence(e);
 			ret = reservation_object_test_signaled_single(fence);
 			if (ret < 0)
 				goto retry;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index b0e14a3d54ef..303143b89275 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -1342,7 +1342,7 @@ void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
 	struct reservation_object *resv = bo->tbo.resv;
 
 	if (shared)
-		reservation_object_add_shared_fence(resv, fence);
+		reservation_object_add_shared_fence(resv, fence, true);
 	else
 		reservation_object_add_excl_fence(resv, fence);
 }
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
index 46ecd3e66ac9..5f4a872a88dd 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gem_submit.c
@@ -214,7 +214,8 @@ static void submit_attach_object_fences(struct etnaviv_gem_submit *submit)
 							  submit->out_fence);
 		else
 			reservation_object_add_shared_fence(etnaviv_obj->resv,
-							    submit->out_fence);
+							    submit->out_fence,
+							    false);
 
 		submit_unlock_object(submit, i);
 	}
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 86f1f9aaa119..0415420e1cfd 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4552,8 +4552,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
 		unsigned int shared_count = list->shared_count, i;
 
 		for (i = 0; i < shared_count; ++i) {
-			struct dma_fence *fence =
-				rcu_dereference(list->shared[i]);
+			struct dma_fence *fence;
+
+			fence = reservation_object_shared_fence(
+				rcu_dereference(list->shared[i]));
 
 			args->busy |= busy_check_reader(fence);
 		}
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index eefd449502e2..85e3f92e87f8 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -1771,7 +1771,7 @@ static void eb_export_fence(struct i915_vma *vma,
 	if (flags & EXEC_OBJECT_WRITE)
 		reservation_object_add_excl_fence(resv, &rq->fence);
 	else if (reservation_object_reserve_shared(resv) == 0)
-		reservation_object_add_shared_fence(resv, &rq->fence);
+		reservation_object_add_shared_fence(resv, &rq->fence, false);
 	reservation_object_unlock(resv);
 }
 
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 95d25dbfde2b..fdee77627a0f 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -672,7 +672,8 @@ void msm_gem_move_to_active(struct drm_gem_object *obj,
 	if (exclusive)
 		reservation_object_add_excl_fence(msm_obj->resv, fence);
 	else
-		reservation_object_add_shared_fence(msm_obj->resv, fence);
+		reservation_object_add_shared_fence(msm_obj->resv, fence,
+						    false);
 	list_del_init(&msm_obj->mm_list);
 	list_add_tail(&msm_obj->mm_list, &gpu->active_list);
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 7214022dfb91..741faead4c7f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -1657,7 +1657,7 @@ nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence, bool excl
 	if (exclusive)
 		reservation_object_add_excl_fence(resv, &fence->base);
 	else if (fence)
-		reservation_object_add_shared_fence(resv, &fence->base);
+		reservation_object_add_shared_fence(resv, &fence->base, false);
 }
 
 struct ttm_bo_driver nouveau_bo_driver = {
diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c
index 7cb214577275..e68ab1efd809 100644
--- a/drivers/gpu/drm/qxl/qxl_release.c
+++ b/drivers/gpu/drm/qxl/qxl_release.c
@@ -466,7 +466,8 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release)
 		bo = entry->bo;
 		qbo = to_qxl_bo(bo);
 
-		reservation_object_add_shared_fence(bo->resv, &release->base);
+		reservation_object_add_shared_fence(bo->resv, &release->base,
+						    false);
 		ttm_bo_add_to_lru(bo);
 		reservation_object_unlock(bo->resv);
 	}
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index ba2fd295697f..11114ffb7495 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -870,7 +870,7 @@ void radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence,
 	struct reservation_object *resv = bo->tbo.resv;
 
 	if (shared)
-		reservation_object_add_shared_fence(resv, &fence->base);
+		reservation_object_add_shared_fence(resv, &fence->base, false);
 	else
 		reservation_object_add_excl_fence(resv, &fence->base);
 }
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 820d97d3e8b9..9e98d8977cd0 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -794,7 +794,7 @@ static int ttm_bo_add_move_fence(struct ttm_buffer_object *bo,
 	spin_unlock(&man->move_lock);
 
 	if (fence) {
-		reservation_object_add_shared_fence(bo->resv, fence);
+		reservation_object_add_shared_fence(bo->resv, fence, true);
 
 		ret = reservation_object_reserve_shared(bo->resv);
 		if (unlikely(ret))
diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
index e73ae0d22897..f82a460d106b 100644
--- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c
+++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c
@@ -202,7 +202,8 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
 	list_for_each_entry(entry, list, head) {
 		bo = entry->bo;
 		if (entry->shared)
-			reservation_object_add_shared_fence(bo->resv, fence);
+			reservation_object_add_shared_fence(bo->resv, fence,
+							    true);
 		else
 			reservation_object_add_excl_fence(bo->resv, fence);
 		ttm_bo_add_to_lru(bo);
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 7910b9acedd6..9db15a76c25f 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -536,7 +536,8 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno)
 		bo = to_vc4_bo(&exec->bo[i]->base);
 		bo->seqno = seqno;
 
-		reservation_object_add_shared_fence(bo->resv, exec->fence);
+		reservation_object_add_shared_fence(bo->resv, exec->fence,
+						    false);
 	}
 
 	list_for_each_entry(bo, &exec->unref_list, unref_head) {
diff --git a/drivers/gpu/drm/vgem/vgem_fence.c b/drivers/gpu/drm/vgem/vgem_fence.c
index b28876c222b4..5d8b47056be6 100644
--- a/drivers/gpu/drm/vgem/vgem_fence.c
+++ b/drivers/gpu/drm/vgem/vgem_fence.c
@@ -194,7 +194,7 @@ int vgem_fence_attach_ioctl(struct drm_device *dev,
 	if (arg->flags & VGEM_FENCE_WRITE)
 		reservation_object_add_excl_fence(resv, fence);
 	else if ((ret = reservation_object_reserve_shared(resv)) == 0)
-		reservation_object_add_shared_fence(resv, fence);
+		reservation_object_add_shared_fence(resv, fence, false);
 	reservation_object_unlock(resv);
 
 	/* Record the fence in our idr for later signaling */
diff --git a/include/linux/reservation.h b/include/linux/reservation.h
index 8a3298574bf5..d73bf025df4b 100644
--- a/include/linux/reservation.h
+++ b/include/linux/reservation.h
@@ -59,7 +59,7 @@ extern const char reservation_seqcount_string[];
 struct reservation_object_list {
 	struct rcu_head rcu;
 	u32 shared_count, shared_max;
-	struct dma_fence __rcu *shared[];
+	void * __rcu *shared[];
 };
 
 /**
@@ -80,6 +80,8 @@ struct reservation_object {
 #define reservation_object_held(obj) lockdep_is_held(&(obj)->lock.base)
 #define reservation_object_assert_held(obj) \
 	lockdep_assert_held(&(obj)->lock.base)
+#define reservation_object_shared_fence(e) ((struct dma_fence *)((long)e & ~1ul))
+#define reservation_object_shared_is_write(e) ((long)e & 1)
 
 /**
  * reservation_object_init - initialize a reservation object
@@ -116,8 +118,11 @@ reservation_object_fini(struct reservation_object *obj)
 
 	fobj = rcu_dereference_protected(obj->fence, 1);
 	if (fobj) {
-		for (i = 0; i < fobj->shared_count; ++i)
-			dma_fence_put(rcu_dereference_protected(fobj->shared[i], 1));
+		for (i = 0; i < fobj->shared_count; ++i) {
+			void *e = rcu_dereference_protected(fobj->shared[i], 1);
+
+			dma_fence_put(reservation_object_shared_fence(e));
+		}
 
 		kfree(fobj);
 	}
@@ -155,8 +160,10 @@ reservation_object_get_shared_fence(struct reservation_object *obj,
 				    struct reservation_object_list *list,
 				    unsigned int idx)
 {
-	return rcu_dereference_protected(list->shared[idx],
-					 reservation_object_held(obj));
+	void *e = rcu_dereference_protected(list->shared[idx],
+					    reservation_object_held(obj));
+
+	return reservation_object_shared_fence(e);
 }
 
 /**
@@ -282,7 +289,8 @@ reservation_object_get_excl_rcu(struct reservation_object *obj)
 
 int reservation_object_reserve_shared(struct reservation_object *obj);
 void reservation_object_add_shared_fence(struct reservation_object *obj,
-					 struct dma_fence *fence);
+					 struct dma_fence *fence,
+					 bool as_write);
 
 void reservation_object_add_excl_fence(struct reservation_object *obj,
 				       struct dma_fence *fence);
