Hi everyone,
Since some operations can then lead to recursive handling nesting dma_fence containers into each other is only allowed under some restrictions.
dma_fence_array containers can be attached to dma_fence_chain containers and dma_fence_chain containers by chaining them together.
In all other cases the individual fences should be extracted with the appropriate iterators and added to the new containers individually.
I've separated the i915 cleanup from this change since it is generally a different functionality and the build bots complained about some issues with those patches.
Most patches are already reviewd, but especially the first one still needs an rb tag.
Please review and comment, Christian.
Consolidate the wrapper functions to check for dma_fence subclasses in the dma_fence header.
This makes it easier to document and also check the different requirements for fence containers in the subclasses.
Signed-off-by: Christian König christian.koenig@amd.com --- include/linux/dma-fence-array.h | 15 +------------ include/linux/dma-fence-chain.h | 3 +-- include/linux/dma-fence.h | 38 +++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/include/linux/dma-fence-array.h b/include/linux/dma-fence-array.h index 303dd712220f..fec374f69e12 100644 --- a/include/linux/dma-fence-array.h +++ b/include/linux/dma-fence-array.h @@ -45,19 +45,6 @@ struct dma_fence_array { struct irq_work work; };
-extern const struct dma_fence_ops dma_fence_array_ops; - -/** - * dma_fence_is_array - check if a fence is from the array subsclass - * @fence: fence to test - * - * Return true if it is a dma_fence_array and false otherwise. - */ -static inline bool dma_fence_is_array(struct dma_fence *fence) -{ - return fence->ops == &dma_fence_array_ops; -} - /** * to_dma_fence_array - cast a fence to a dma_fence_array * @fence: fence to cast to a dma_fence_array @@ -68,7 +55,7 @@ static inline bool dma_fence_is_array(struct dma_fence *fence) static inline struct dma_fence_array * to_dma_fence_array(struct dma_fence *fence) { - if (fence->ops != &dma_fence_array_ops) + if (!fence || !dma_fence_is_array(fence)) return NULL;
return container_of(fence, struct dma_fence_array, base); diff --git a/include/linux/dma-fence-chain.h b/include/linux/dma-fence-chain.h index 54fe3443fd2c..ee906b659694 100644 --- a/include/linux/dma-fence-chain.h +++ b/include/linux/dma-fence-chain.h @@ -49,7 +49,6 @@ struct dma_fence_chain { spinlock_t lock; };
-extern const struct dma_fence_ops dma_fence_chain_ops;
/** * to_dma_fence_chain - cast a fence to a dma_fence_chain @@ -61,7 +60,7 @@ extern const struct dma_fence_ops dma_fence_chain_ops; static inline struct dma_fence_chain * to_dma_fence_chain(struct dma_fence *fence) { - if (!fence || fence->ops != &dma_fence_chain_ops) + if (!fence || !dma_fence_is_chain(fence)) return NULL;
return container_of(fence, struct dma_fence_chain, base); diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index 1ea691753bd3..775cdc0b4f24 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -587,4 +587,42 @@ struct dma_fence *dma_fence_get_stub(void); struct dma_fence *dma_fence_allocate_private_stub(void); u64 dma_fence_context_alloc(unsigned num);
+extern const struct dma_fence_ops dma_fence_array_ops; +extern const struct dma_fence_ops dma_fence_chain_ops; + +/** + * dma_fence_is_array - check if a fence is from the array subclass + * @fence: the fence to test + * + * Return true if it is a dma_fence_array and false otherwise. + */ +static inline bool dma_fence_is_array(struct dma_fence *fence) +{ + return fence->ops == &dma_fence_array_ops; +} + +/** + * dma_fence_is_chain - check if a fence is from the chain subclass + * @fence: the fence to test + * + * Return true if it is a dma_fence_chain and false otherwise. + */ +static inline bool dma_fence_is_chain(struct dma_fence *fence) +{ + return fence->ops == &dma_fence_chain_ops; +} + +/** + * dma_fence_is_container - check if a fence is a container for other fences + * @fence: the fence to test + * + * Return true if this fence is a container for other fences, false otherwise. + * This is important since we can't build up large fence structure or otherwise + * we run into recursion during operation on those fences. + */ +static inline bool dma_fence_is_container(struct dma_fence *fence) +{ + return dma_fence_is_array(fence) || dma_fence_is_chain(fence); +} + #endif /* __LINUX_DMA_FENCE_H */
On Fri, 2022-02-04 at 11:04 +0100, Christian König wrote:
Consolidate the wrapper functions to check for dma_fence subclasses in the dma_fence header.
This makes it easier to document and also check the different requirements for fence containers in the subclasses.
Signed-off-by: Christian König christian.koenig@amd.com
I'd probably still opt for a fence ops is_container member, but won't insist.
Reviewed-by: Thomas Hellström thomas.hellstrom@linux.intel.com
include/linux/dma-fence-array.h | 15 +------------ include/linux/dma-fence-chain.h | 3 +-- include/linux/dma-fence.h | 38 +++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 16 deletions(-)
diff --git a/include/linux/dma-fence-array.h b/include/linux/dma- fence-array.h index 303dd712220f..fec374f69e12 100644 --- a/include/linux/dma-fence-array.h +++ b/include/linux/dma-fence-array.h @@ -45,19 +45,6 @@ struct dma_fence_array { struct irq_work work; }; -extern const struct dma_fence_ops dma_fence_array_ops;
-/**
- dma_fence_is_array - check if a fence is from the array subsclass
- @fence: fence to test
- Return true if it is a dma_fence_array and false otherwise.
- */
-static inline bool dma_fence_is_array(struct dma_fence *fence) -{ - return fence->ops == &dma_fence_array_ops; -}
/** * to_dma_fence_array - cast a fence to a dma_fence_array * @fence: fence to cast to a dma_fence_array @@ -68,7 +55,7 @@ static inline bool dma_fence_is_array(struct dma_fence *fence) static inline struct dma_fence_array * to_dma_fence_array(struct dma_fence *fence) { - if (fence->ops != &dma_fence_array_ops) + if (!fence || !dma_fence_is_array(fence)) return NULL; return container_of(fence, struct dma_fence_array, base); diff --git a/include/linux/dma-fence-chain.h b/include/linux/dma- fence-chain.h index 54fe3443fd2c..ee906b659694 100644 --- a/include/linux/dma-fence-chain.h +++ b/include/linux/dma-fence-chain.h @@ -49,7 +49,6 @@ struct dma_fence_chain { spinlock_t lock; }; -extern const struct dma_fence_ops dma_fence_chain_ops; /** * to_dma_fence_chain - cast a fence to a dma_fence_chain @@ -61,7 +60,7 @@ extern const struct dma_fence_ops dma_fence_chain_ops; static inline struct dma_fence_chain * to_dma_fence_chain(struct dma_fence *fence) { - if (!fence || fence->ops != &dma_fence_chain_ops) + if (!fence || !dma_fence_is_chain(fence)) return NULL; return container_of(fence, struct dma_fence_chain, base); diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h index 1ea691753bd3..775cdc0b4f24 100644 --- a/include/linux/dma-fence.h +++ b/include/linux/dma-fence.h @@ -587,4 +587,42 @@ struct dma_fence *dma_fence_get_stub(void); struct dma_fence *dma_fence_allocate_private_stub(void); u64 dma_fence_context_alloc(unsigned num); +extern const struct dma_fence_ops dma_fence_array_ops; +extern const struct dma_fence_ops dma_fence_chain_ops;
+/**
- dma_fence_is_array - check if a fence is from the array subclass
- @fence: the fence to test
- Return true if it is a dma_fence_array and false otherwise.
- */
+static inline bool dma_fence_is_array(struct dma_fence *fence) +{ + return fence->ops == &dma_fence_array_ops; +}
+/**
- dma_fence_is_chain - check if a fence is from the chain subclass
- @fence: the fence to test
- Return true if it is a dma_fence_chain and false otherwise.
- */
+static inline bool dma_fence_is_chain(struct dma_fence *fence) +{ + return fence->ops == &dma_fence_chain_ops; +}
+/**
- dma_fence_is_container - check if a fence is a container for
other fences
- @fence: the fence to test
- Return true if this fence is a container for other fences, false
otherwise.
- This is important since we can't build up large fence structure
or otherwise
- we run into recursion during operation on those fences.
- */
+static inline bool dma_fence_is_container(struct dma_fence *fence) +{ + return dma_fence_is_array(fence) || dma_fence_is_chain(fence); +}
#endif /* __LINUX_DMA_FENCE_H */
It's not allowed to nest another dma_fence container into a dma_fence_array or otherwise we can run into recursion.
Warn about that when we create a dma_fence_array.
v2: fix comment style and typo in the warning pointed out by Thomas
Signed-off-by: Christian König christian.koenig@amd.com Reviewed-by: Daniel Vetter daniel.vetter@ffwll.ch Reviewed-by: Thomas Hellström thomas.hellstrom@linux.intel.com --- drivers/dma-buf/dma-fence-array.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c index 3e07f961e2f3..cb1bacb5a42b 100644 --- a/drivers/dma-buf/dma-fence-array.c +++ b/drivers/dma-buf/dma-fence-array.c @@ -176,6 +176,20 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
array->base.error = PENDING_ERROR;
+ /* + * dma_fence_array objects should never contain any other fence + * containers or otherwise we run into recursion and potential kernel + * stack overflow on operations on the dma_fence_array. + * + * The correct way of handling this is to flatten out the array by the + * caller instead. + * + * Enforce this here by checking that we don't create a dma_fence_array + * with any container inside. + */ + while (num_fences--) + WARN_ON(dma_fence_is_container(fences[num_fences])); + return array; } EXPORT_SYMBOL(dma_fence_array_create);
Chaining of dma_fence_chain objects is only allowed through the prev fence and not through the contained fence.
Warn about that when we create a dma_fence_chain.
v2: fix comment style
Signed-off-by: Christian König christian.koenig@amd.com Reviewed-by: Daniel Vetter daniel.vetter@ffwll.ch Reviewed-by: Thomas Hellström thomas.hellstrom@linux.intel.com --- drivers/dma-buf/dma-fence-chain.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma-fence-chain.c index 1b4cb3e5cec9..084c6927b735 100644 --- a/drivers/dma-buf/dma-fence-chain.c +++ b/drivers/dma-buf/dma-fence-chain.c @@ -254,5 +254,14 @@ void dma_fence_chain_init(struct dma_fence_chain *chain,
dma_fence_init(&chain->base, &dma_fence_chain_ops, &chain->lock, context, seqno); + + /* + * Chaining dma_fence_chain container together is only allowed through + * the prev fence and not through the contained fence. + * + * The correct way of handling this is to flatten out the fence + * structure into a dma_fence_array by the caller instead. + */ + WARN_ON(dma_fence_is_chain(fence)); } EXPORT_SYMBOL(dma_fence_chain_init);
On Fri, 2022-02-04 at 11:04 +0100, Christian König wrote:
Chaining of dma_fence_chain objects is only allowed through the prev fence and not through the contained fence.
Warn about that when we create a dma_fence_chain.
v2: fix comment style
Signed-off-by: Christian König christian.koenig@amd.com Reviewed-by: Daniel Vetter daniel.vetter@ffwll.ch Reviewed-by: Thomas Hellström thomas.hellstrom@linux.intel.com
It looks like this blows up in generic drm code...
https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22201/shard-skl10/igt@syn...
/Thomas
Am 09.02.22 um 15:02 schrieb Thomas Hellström:
On Fri, 2022-02-04 at 11:04 +0100, Christian König wrote:
Chaining of dma_fence_chain objects is only allowed through the prev fence and not through the contained fence.
Warn about that when we create a dma_fence_chain.
v2: fix comment style
Signed-off-by: Christian König christian.koenig@amd.com Reviewed-by: Daniel Vetter daniel.vetter@ffwll.ch Reviewed-by: Thomas Hellström thomas.hellstrom@linux.intel.com
It looks like this blows up in generic drm code...
https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_22201/shard-skl10/igt@syn...
Thanks for the notice. Going to take a look.
I'm wondering why the last CI report I've got didn't showed that.
Christian.
/Thomas
Drivers should not add containers as shared fences to the dma_resv object, instead each fence should be added individually.
Signed-off-by: Christian König christian.koenig@amd.com Reviewed-by: Daniel Vetter daniel.vetter@ffwll.ch Reviewed-by: Thomas Hellström thomas.hellstrom@linux.intel.com --- drivers/dma-buf/dma-resv.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index ee31f15d633a..b51416405e86 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -256,6 +256,11 @@ void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence)
dma_resv_assert_held(obj);
+ /* Drivers should not add containers here, instead add each fence + * individually. + */ + WARN_ON(dma_fence_is_container(fence)); + fobj = dma_resv_shared_list(obj); count = fobj->shared_count;
It's a reoccurring pattern that we need to extract the fence from a dma_fence_chain object. Add a helper for this.
Signed-off-by: Christian König christian.koenig@amd.com --- drivers/dma-buf/dma-fence-chain.c | 6 ++---- include/linux/dma-fence-chain.h | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma-fence-chain.c index 084c6927b735..06f8ef97c6e8 100644 --- a/drivers/dma-buf/dma-fence-chain.c +++ b/drivers/dma-buf/dma-fence-chain.c @@ -148,8 +148,7 @@ static bool dma_fence_chain_enable_signaling(struct dma_fence *fence)
dma_fence_get(&head->base); dma_fence_chain_for_each(fence, &head->base) { - struct dma_fence_chain *chain = to_dma_fence_chain(fence); - struct dma_fence *f = chain ? chain->fence : fence; + struct dma_fence *f = dma_fence_chain_contained(fence);
dma_fence_get(f); if (!dma_fence_add_callback(f, &head->cb, dma_fence_chain_cb)) { @@ -165,8 +164,7 @@ static bool dma_fence_chain_enable_signaling(struct dma_fence *fence) static bool dma_fence_chain_signaled(struct dma_fence *fence) { dma_fence_chain_for_each(fence, fence) { - struct dma_fence_chain *chain = to_dma_fence_chain(fence); - struct dma_fence *f = chain ? chain->fence : fence; + struct dma_fence *f = dma_fence_chain_contained(fence);
if (!dma_fence_is_signaled(f)) { dma_fence_put(fence); diff --git a/include/linux/dma-fence-chain.h b/include/linux/dma-fence-chain.h index ee906b659694..10d51bcdf7b7 100644 --- a/include/linux/dma-fence-chain.h +++ b/include/linux/dma-fence-chain.h @@ -66,6 +66,21 @@ to_dma_fence_chain(struct dma_fence *fence) return container_of(fence, struct dma_fence_chain, base); }
+/** + * dma_fence_chain_contained - return the contained fence + * @fence: the fence to test + * + * If the fence is a dma_fence_chain the function returns the fence contained + * inside the chain object, otherwise it returns the fence itself. + */ +static inline struct dma_fence * +dma_fence_chain_contained(struct dma_fence *fence) +{ + struct dma_fence_chain *chain = to_dma_fence_chain(fence); + + return chain ? chain->fence : fence; +} + /** * dma_fence_chain_alloc *
On Fri, 2022-02-04 at 11:04 +0100, Christian König wrote:
It's a reoccurring pattern that we need to extract the fence from a dma_fence_chain object. Add a helper for this.
Signed-off-by: Christian König christian.koenig@amd.com
I thought I'd reviewed this one already, but in case I didn't
Reviewed-by: Thomas Hellström thomas.hellstrom@linux.intel.com
drivers/dma-buf/dma-fence-chain.c | 6 ++---- include/linux/dma-fence-chain.h | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma- fence-chain.c index 084c6927b735..06f8ef97c6e8 100644 --- a/drivers/dma-buf/dma-fence-chain.c +++ b/drivers/dma-buf/dma-fence-chain.c @@ -148,8 +148,7 @@ static bool dma_fence_chain_enable_signaling(struct dma_fence *fence) dma_fence_get(&head->base); dma_fence_chain_for_each(fence, &head->base) { - struct dma_fence_chain *chain = to_dma_fence_chain(fence); - struct dma_fence *f = chain ? chain->fence : fence; + struct dma_fence *f = dma_fence_chain_contained(fence); dma_fence_get(f); if (!dma_fence_add_callback(f, &head->cb, dma_fence_chain_cb)) { @@ -165,8 +164,7 @@ static bool dma_fence_chain_enable_signaling(struct dma_fence *fence) static bool dma_fence_chain_signaled(struct dma_fence *fence) { dma_fence_chain_for_each(fence, fence) { - struct dma_fence_chain *chain = to_dma_fence_chain(fence); - struct dma_fence *f = chain ? chain->fence : fence; + struct dma_fence *f = dma_fence_chain_contained(fence); if (!dma_fence_is_signaled(f)) { dma_fence_put(fence); diff --git a/include/linux/dma-fence-chain.h b/include/linux/dma- fence-chain.h index ee906b659694..10d51bcdf7b7 100644 --- a/include/linux/dma-fence-chain.h +++ b/include/linux/dma-fence-chain.h @@ -66,6 +66,21 @@ to_dma_fence_chain(struct dma_fence *fence) return container_of(fence, struct dma_fence_chain, base); } +/**
- dma_fence_chain_contained - return the contained fence
- @fence: the fence to test
- If the fence is a dma_fence_chain the function returns the fence
contained
- inside the chain object, otherwise it returns the fence itself.
- */
+static inline struct dma_fence * +dma_fence_chain_contained(struct dma_fence *fence) +{ + struct dma_fence_chain *chain = to_dma_fence_chain(fence);
+ return chain ? chain->fence : fence; +}
/** * dma_fence_chain_alloc *
Instead of manually extracting the fence.
Signed-off-by: Christian König christian.koenig@amd.com --- drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index f7d8487799b2..40e06745fae9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -261,10 +261,9 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync,
dma_resv_for_each_fence(&cursor, resv, true, f) { dma_fence_chain_for_each(f, f) { - struct dma_fence_chain *chain = to_dma_fence_chain(f); + struct dma_fence *tmp = dma_fence_chain_contained(f);
- if (amdgpu_sync_test_fence(adev, mode, owner, chain ? - chain->fence : f)) { + if (amdgpu_sync_test_fence(adev, mode, owner, tmp)) { r = amdgpu_sync_fence(sync, f); dma_fence_put(f); if (r)
On Fri, Feb 4, 2022 at 5:04 AM Christian König ckoenig.leichtzumerken@gmail.com wrote:
Instead of manually extracting the fence.
Signed-off-by: Christian König christian.koenig@amd.com
Reviewed-by: Alex Deucher alexander.deucher@amd.com
drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index f7d8487799b2..40e06745fae9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -261,10 +261,9 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, struct amdgpu_sync *sync,
dma_resv_for_each_fence(&cursor, resv, true, f) { dma_fence_chain_for_each(f, f) {
struct dma_fence_chain *chain = to_dma_fence_chain(f);
struct dma_fence *tmp = dma_fence_chain_contained(f);
if (amdgpu_sync_test_fence(adev, mode, owner, chain ?
chain->fence : f)) {
if (amdgpu_sync_test_fence(adev, mode, owner, tmp)) { r = amdgpu_sync_fence(sync, f); dma_fence_put(f); if (r)
-- 2.25.1
On Fri, 2022-02-04 at 11:04 +0100, Christian König wrote:
Hi everyone,
Since some operations can then lead to recursive handling nesting dma_fence containers into each other is only allowed under some restrictions.
dma_fence_array containers can be attached to dma_fence_chain containers and dma_fence_chain containers by chaining them together.
In all other cases the individual fences should be extracted with the appropriate iterators and added to the new containers individually.
I've separated the i915 cleanup from this change since it is generally a different functionality and the build bots complained about some issues with those patches.
Most patches are already reviewd, but especially the first one still needs an rb tag.
Please review and comment,
I see you dropped the i915 patch (probably due to lack of reviews?), Got distracted with other things, but I'll see if I can resurrect that and get it reviewed and merged.
Thanks, Thomas
Christian.
Am 04.02.22 um 11:40 schrieb Thomas Hellström:
On Fri, 2022-02-04 at 11:04 +0100, Christian König wrote:
Hi everyone,
Since some operations can then lead to recursive handling nesting dma_fence containers into each other is only allowed under some restrictions.
dma_fence_array containers can be attached to dma_fence_chain containers and dma_fence_chain containers by chaining them together.
In all other cases the individual fences should be extracted with the appropriate iterators and added to the new containers individually.
I've separated the i915 cleanup from this change since it is generally a different functionality and the build bots complained about some issues with those patches.
Most patches are already reviewd, but especially the first one still needs an rb tag.
Please review and comment,
I see you dropped the i915 patch (probably due to lack of reviews?), Got distracted with other things, but I'll see if I can resurrect that and get it reviewed and merged.
I was about to send out the i915 patch when that one here is merged.
The CI systems yielded some strange error with that one and I wanted to double check what's that all about.
Regards, Christian.
Thanks, Thomas
Christian.
dri-devel@lists.freedesktop.org