From: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>
To: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Cc: linaro-mm-sig@lists.linaro.org,
"Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
matthew.auld@intel.com,
"Christian König" <christian.koenig@amd.com>
Subject: [Intel-gfx] [RFC PATCH 1/2] dma-fence: Avoid establishing a locking order between fence classes
Date: Tue, 30 Nov 2021 13:19:35 +0100 [thread overview]
Message-ID: <20211130121936.586031-2-thomas.hellstrom@linux.intel.com> (raw)
In-Reply-To: <20211130121936.586031-1-thomas.hellstrom@linux.intel.com>
The locking order for taking two fence locks is implicitly defined in
at least two ways in the code:
1) Fence containers first and other fences next, which is defined by
the enable_signaling() callbacks of dma_fence_chain and
dma_fence_array.
2) Reverse signal order, which is used by __i915_active_fence_set().
Now 1) implies 2), except for the signal_on_any mode of dma_fence_array
and 2) does not imply 1), and also 1) makes locking order between
different containers confusing.
Establish 2) and fix up the signal_on_any mode by calling
enable_signaling() on such fences unlocked at creation.
Cc: linaro-mm-sig@lists.linaro.org
Cc: dri-devel@lists.freedesktop.org
Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
drivers/dma-buf/dma-fence-array.c | 13 +++--
drivers/dma-buf/dma-fence-chain.c | 3 +-
drivers/dma-buf/dma-fence.c | 79 +++++++++++++++++++++----------
include/linux/dma-fence.h | 3 ++
4 files changed, 69 insertions(+), 29 deletions(-)
diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c
index 3e07f961e2f3..0322b92909fe 100644
--- a/drivers/dma-buf/dma-fence-array.c
+++ b/drivers/dma-buf/dma-fence-array.c
@@ -84,8 +84,8 @@ static bool dma_fence_array_enable_signaling(struct dma_fence *fence)
* insufficient).
*/
dma_fence_get(&array->base);
- if (dma_fence_add_callback(array->fences[i], &cb[i].cb,
- dma_fence_array_cb_func)) {
+ if (dma_fence_add_callback_nested(array->fences[i], &cb[i].cb,
+ dma_fence_array_cb_func)) {
int error = array->fences[i]->error;
dma_fence_array_set_pending_error(array, error);
@@ -158,6 +158,7 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
{
struct dma_fence_array *array;
size_t size = sizeof(*array);
+ struct dma_fence *fence;
/* Allocate the callback structures behind the array. */
size += num_fences * sizeof(struct dma_fence_array_cb);
@@ -165,8 +166,9 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
if (!array)
return NULL;
+ fence = &array->base;
spin_lock_init(&array->lock);
- dma_fence_init(&array->base, &dma_fence_array_ops, &array->lock,
+ dma_fence_init(fence, &dma_fence_array_ops, &array->lock,
context, seqno);
init_irq_work(&array->work, irq_dma_fence_array_work);
@@ -174,7 +176,10 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
atomic_set(&array->num_pending, signal_on_any ? 1 : num_fences);
array->fences = fences;
- array->base.error = PENDING_ERROR;
+ fence->error = PENDING_ERROR;
+
+ if (signal_on_any)
+ dma_fence_enable_sw_signaling(fence);
return array;
}
diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma-fence-chain.c
index 1b4cb3e5cec9..0518e53880f6 100644
--- a/drivers/dma-buf/dma-fence-chain.c
+++ b/drivers/dma-buf/dma-fence-chain.c
@@ -152,7 +152,8 @@ static bool dma_fence_chain_enable_signaling(struct dma_fence *fence)
struct dma_fence *f = chain ? chain->fence : fence;
dma_fence_get(f);
- if (!dma_fence_add_callback(f, &head->cb, dma_fence_chain_cb)) {
+ if (!dma_fence_add_callback_nested(f, &head->cb,
+ dma_fence_chain_cb)) {
dma_fence_put(fence);
return true;
}
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 066400ed8841..90a3d5121746 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -610,6 +610,37 @@ void dma_fence_enable_sw_signaling(struct dma_fence *fence)
}
EXPORT_SYMBOL(dma_fence_enable_sw_signaling);
+static int __dma_fence_add_callback(struct dma_fence *fence,
+ struct dma_fence_cb *cb,
+ dma_fence_func_t func,
+ int nest_level)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (WARN_ON(!fence || !func))
+ return -EINVAL;
+
+ if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
+ INIT_LIST_HEAD(&cb->node);
+ return -ENOENT;
+ }
+
+ spin_lock_irqsave_nested(fence->lock, flags, 0);
+
+ if (__dma_fence_enable_signaling(fence)) {
+ cb->func = func;
+ list_add_tail(&cb->node, &fence->cb_list);
+ } else {
+ INIT_LIST_HEAD(&cb->node);
+ ret = -ENOENT;
+ }
+
+ spin_unlock_irqrestore(fence->lock, flags);
+
+ return ret;
+}
+
/**
* dma_fence_add_callback - add a callback to be called when the fence
* is signaled
@@ -635,33 +666,33 @@ EXPORT_SYMBOL(dma_fence_enable_sw_signaling);
int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb,
dma_fence_func_t func)
{
- unsigned long flags;
- int ret = 0;
-
- if (WARN_ON(!fence || !func))
- return -EINVAL;
-
- if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
- INIT_LIST_HEAD(&cb->node);
- return -ENOENT;
- }
-
- spin_lock_irqsave(fence->lock, flags);
-
- if (__dma_fence_enable_signaling(fence)) {
- cb->func = func;
- list_add_tail(&cb->node, &fence->cb_list);
- } else {
- INIT_LIST_HEAD(&cb->node);
- ret = -ENOENT;
- }
-
- spin_unlock_irqrestore(fence->lock, flags);
-
- return ret;
+ return __dma_fence_add_callback(fence, cb, func, 0);
}
EXPORT_SYMBOL(dma_fence_add_callback);
+/**
+ * dma_fence_add_callback_nested - add a callback from within a fence locked
+ * section to be called when the fence is signaled
+ * @fence: the fence to wait on
+ * @cb: the callback to register
+ * @func: the function to call
+ *
+ * This function is identical to dma_fence_add_callback() except it is
+ * intended to be used from within a section where the fence lock of
+ * another fence might be locked, and where it is guaranteed that
+ * other fence will signal _after_ @fence.
+ *
+ * Returns 0 in case of success, -ENOENT if the fence is already signaled
+ * and -EINVAL in case of error.
+ */
+int dma_fence_add_callback_nested(struct dma_fence *fence,
+ struct dma_fence_cb *cb,
+ dma_fence_func_t func)
+{
+ return __dma_fence_add_callback(fence, cb, func, SINGLE_DEPTH_NESTING);
+}
+EXPORT_SYMBOL(dma_fence_add_callback_nested);
+
/**
* dma_fence_get_status - returns the status upon completion
* @fence: the dma_fence to query
diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
index 1ea691753bd3..405cd83936f6 100644
--- a/include/linux/dma-fence.h
+++ b/include/linux/dma-fence.h
@@ -377,6 +377,9 @@ signed long dma_fence_default_wait(struct dma_fence *fence,
int dma_fence_add_callback(struct dma_fence *fence,
struct dma_fence_cb *cb,
dma_fence_func_t func);
+int dma_fence_add_callback_nested(struct dma_fence *fence,
+ struct dma_fence_cb *cb,
+ dma_fence_func_t func);
bool dma_fence_remove_callback(struct dma_fence *fence,
struct dma_fence_cb *cb);
void dma_fence_enable_sw_signaling(struct dma_fence *fence);
--
2.31.1
WARNING: multiple messages have this Message-ID (diff)
From: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>
To: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Cc: linaro-mm-sig@lists.linaro.org,
"Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
matthew.auld@intel.com,
"Christian König" <christian.koenig@amd.com>
Subject: [RFC PATCH 1/2] dma-fence: Avoid establishing a locking order between fence classes
Date: Tue, 30 Nov 2021 13:19:35 +0100 [thread overview]
Message-ID: <20211130121936.586031-2-thomas.hellstrom@linux.intel.com> (raw)
In-Reply-To: <20211130121936.586031-1-thomas.hellstrom@linux.intel.com>
The locking order for taking two fence locks is implicitly defined in
at least two ways in the code:
1) Fence containers first and other fences next, which is defined by
the enable_signaling() callbacks of dma_fence_chain and
dma_fence_array.
2) Reverse signal order, which is used by __i915_active_fence_set().
Now 1) implies 2), except for the signal_on_any mode of dma_fence_array
and 2) does not imply 1), and also 1) makes locking order between
different containers confusing.
Establish 2) and fix up the signal_on_any mode by calling
enable_signaling() on such fences unlocked at creation.
Cc: linaro-mm-sig@lists.linaro.org
Cc: dri-devel@lists.freedesktop.org
Cc: Christian König <christian.koenig@amd.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
---
drivers/dma-buf/dma-fence-array.c | 13 +++--
drivers/dma-buf/dma-fence-chain.c | 3 +-
drivers/dma-buf/dma-fence.c | 79 +++++++++++++++++++++----------
include/linux/dma-fence.h | 3 ++
4 files changed, 69 insertions(+), 29 deletions(-)
diff --git a/drivers/dma-buf/dma-fence-array.c b/drivers/dma-buf/dma-fence-array.c
index 3e07f961e2f3..0322b92909fe 100644
--- a/drivers/dma-buf/dma-fence-array.c
+++ b/drivers/dma-buf/dma-fence-array.c
@@ -84,8 +84,8 @@ static bool dma_fence_array_enable_signaling(struct dma_fence *fence)
* insufficient).
*/
dma_fence_get(&array->base);
- if (dma_fence_add_callback(array->fences[i], &cb[i].cb,
- dma_fence_array_cb_func)) {
+ if (dma_fence_add_callback_nested(array->fences[i], &cb[i].cb,
+ dma_fence_array_cb_func)) {
int error = array->fences[i]->error;
dma_fence_array_set_pending_error(array, error);
@@ -158,6 +158,7 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
{
struct dma_fence_array *array;
size_t size = sizeof(*array);
+ struct dma_fence *fence;
/* Allocate the callback structures behind the array. */
size += num_fences * sizeof(struct dma_fence_array_cb);
@@ -165,8 +166,9 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
if (!array)
return NULL;
+ fence = &array->base;
spin_lock_init(&array->lock);
- dma_fence_init(&array->base, &dma_fence_array_ops, &array->lock,
+ dma_fence_init(fence, &dma_fence_array_ops, &array->lock,
context, seqno);
init_irq_work(&array->work, irq_dma_fence_array_work);
@@ -174,7 +176,10 @@ struct dma_fence_array *dma_fence_array_create(int num_fences,
atomic_set(&array->num_pending, signal_on_any ? 1 : num_fences);
array->fences = fences;
- array->base.error = PENDING_ERROR;
+ fence->error = PENDING_ERROR;
+
+ if (signal_on_any)
+ dma_fence_enable_sw_signaling(fence);
return array;
}
diff --git a/drivers/dma-buf/dma-fence-chain.c b/drivers/dma-buf/dma-fence-chain.c
index 1b4cb3e5cec9..0518e53880f6 100644
--- a/drivers/dma-buf/dma-fence-chain.c
+++ b/drivers/dma-buf/dma-fence-chain.c
@@ -152,7 +152,8 @@ static bool dma_fence_chain_enable_signaling(struct dma_fence *fence)
struct dma_fence *f = chain ? chain->fence : fence;
dma_fence_get(f);
- if (!dma_fence_add_callback(f, &head->cb, dma_fence_chain_cb)) {
+ if (!dma_fence_add_callback_nested(f, &head->cb,
+ dma_fence_chain_cb)) {
dma_fence_put(fence);
return true;
}
diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index 066400ed8841..90a3d5121746 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -610,6 +610,37 @@ void dma_fence_enable_sw_signaling(struct dma_fence *fence)
}
EXPORT_SYMBOL(dma_fence_enable_sw_signaling);
+static int __dma_fence_add_callback(struct dma_fence *fence,
+ struct dma_fence_cb *cb,
+ dma_fence_func_t func,
+ int nest_level)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (WARN_ON(!fence || !func))
+ return -EINVAL;
+
+ if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
+ INIT_LIST_HEAD(&cb->node);
+ return -ENOENT;
+ }
+
+ spin_lock_irqsave_nested(fence->lock, flags, 0);
+
+ if (__dma_fence_enable_signaling(fence)) {
+ cb->func = func;
+ list_add_tail(&cb->node, &fence->cb_list);
+ } else {
+ INIT_LIST_HEAD(&cb->node);
+ ret = -ENOENT;
+ }
+
+ spin_unlock_irqrestore(fence->lock, flags);
+
+ return ret;
+}
+
/**
* dma_fence_add_callback - add a callback to be called when the fence
* is signaled
@@ -635,33 +666,33 @@ EXPORT_SYMBOL(dma_fence_enable_sw_signaling);
int dma_fence_add_callback(struct dma_fence *fence, struct dma_fence_cb *cb,
dma_fence_func_t func)
{
- unsigned long flags;
- int ret = 0;
-
- if (WARN_ON(!fence || !func))
- return -EINVAL;
-
- if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) {
- INIT_LIST_HEAD(&cb->node);
- return -ENOENT;
- }
-
- spin_lock_irqsave(fence->lock, flags);
-
- if (__dma_fence_enable_signaling(fence)) {
- cb->func = func;
- list_add_tail(&cb->node, &fence->cb_list);
- } else {
- INIT_LIST_HEAD(&cb->node);
- ret = -ENOENT;
- }
-
- spin_unlock_irqrestore(fence->lock, flags);
-
- return ret;
+ return __dma_fence_add_callback(fence, cb, func, 0);
}
EXPORT_SYMBOL(dma_fence_add_callback);
+/**
+ * dma_fence_add_callback_nested - add a callback from within a fence locked
+ * section to be called when the fence is signaled
+ * @fence: the fence to wait on
+ * @cb: the callback to register
+ * @func: the function to call
+ *
+ * This function is identical to dma_fence_add_callback() except it is
+ * intended to be used from within a section where the fence lock of
+ * another fence might be locked, and where it is guaranteed that
+ * other fence will signal _after_ @fence.
+ *
+ * Returns 0 in case of success, -ENOENT if the fence is already signaled
+ * and -EINVAL in case of error.
+ */
+int dma_fence_add_callback_nested(struct dma_fence *fence,
+ struct dma_fence_cb *cb,
+ dma_fence_func_t func)
+{
+ return __dma_fence_add_callback(fence, cb, func, SINGLE_DEPTH_NESTING);
+}
+EXPORT_SYMBOL(dma_fence_add_callback_nested);
+
/**
* dma_fence_get_status - returns the status upon completion
* @fence: the dma_fence to query
diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
index 1ea691753bd3..405cd83936f6 100644
--- a/include/linux/dma-fence.h
+++ b/include/linux/dma-fence.h
@@ -377,6 +377,9 @@ signed long dma_fence_default_wait(struct dma_fence *fence,
int dma_fence_add_callback(struct dma_fence *fence,
struct dma_fence_cb *cb,
dma_fence_func_t func);
+int dma_fence_add_callback_nested(struct dma_fence *fence,
+ struct dma_fence_cb *cb,
+ dma_fence_func_t func);
bool dma_fence_remove_callback(struct dma_fence *fence,
struct dma_fence_cb *cb);
void dma_fence_enable_sw_signaling(struct dma_fence *fence);
--
2.31.1
next prev parent reply other threads:[~2021-11-30 12:20 UTC|newest]
Thread overview: 65+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-11-30 12:19 [Intel-gfx] [RFC PATCH 0/2] Attempt to avoid dma-fence-[chain|array] lockdep splats Thomas Hellström
2021-11-30 12:19 ` Thomas Hellström
2021-11-30 12:19 ` Thomas Hellström [this message]
2021-11-30 12:19 ` [RFC PATCH 1/2] dma-fence: Avoid establishing a locking order between fence classes Thomas Hellström
2021-11-30 12:25 ` [Intel-gfx] " Maarten Lankhorst
2021-11-30 12:25 ` Maarten Lankhorst
2021-11-30 12:31 ` [Intel-gfx] " Thomas Hellström
2021-11-30 12:31 ` Thomas Hellström
2021-11-30 12:42 ` [Intel-gfx] " Christian König
2021-11-30 12:42 ` Christian König
2021-11-30 12:56 ` [Intel-gfx] " Thomas Hellström
2021-11-30 12:56 ` Thomas Hellström
2021-11-30 13:26 ` [Intel-gfx] " Christian König
2021-11-30 13:26 ` Christian König
2021-11-30 14:35 ` [Intel-gfx] " Thomas Hellström
2021-11-30 14:35 ` Thomas Hellström
2021-11-30 15:02 ` [Intel-gfx] " Christian König
2021-11-30 15:02 ` Christian König
2021-11-30 18:12 ` [Intel-gfx] " Thomas Hellström
2021-11-30 18:12 ` Thomas Hellström
2021-11-30 19:27 ` [Intel-gfx] " Thomas Hellström
2021-11-30 19:27 ` Thomas Hellström
2021-12-01 7:05 ` [Intel-gfx] " Christian König
2021-12-01 7:05 ` Christian König
2021-12-01 8:23 ` [Intel-gfx] [Linaro-mm-sig] " Thomas Hellström (Intel)
2021-12-01 8:23 ` Thomas Hellström (Intel)
2021-12-01 8:36 ` [Intel-gfx] " Christian König
2021-12-01 8:36 ` Christian König
2021-12-01 10:15 ` [Intel-gfx] " Thomas Hellström (Intel)
2021-12-01 10:15 ` Thomas Hellström (Intel)
2021-12-01 10:32 ` [Intel-gfx] " Christian König
2021-12-01 10:32 ` Christian König
2021-12-01 11:04 ` [Intel-gfx] " Thomas Hellström (Intel)
2021-12-01 11:04 ` Thomas Hellström (Intel)
2021-12-01 11:25 ` [Intel-gfx] " Christian König
2021-12-01 11:25 ` Christian König
2021-12-01 12:16 ` [Intel-gfx] " Thomas Hellström (Intel)
2021-12-01 12:16 ` Thomas Hellström (Intel)
2021-12-03 13:08 ` [Intel-gfx] " Christian König
2021-12-03 13:08 ` Christian König
2021-12-03 14:18 ` [Intel-gfx] " Thomas Hellström
2021-12-03 14:18 ` Thomas Hellström
2021-12-03 14:26 ` [Intel-gfx] " Christian König
2021-12-03 14:26 ` Christian König
2021-12-03 14:50 ` [Intel-gfx] " Thomas Hellström
2021-12-03 14:50 ` Thomas Hellström
2021-12-03 15:00 ` [Intel-gfx] " Christian König
2021-12-03 15:00 ` Christian König
2021-12-03 15:13 ` [Intel-gfx] " Thomas Hellström (Intel)
2021-12-03 15:13 ` Thomas Hellström (Intel)
2021-12-07 18:08 ` [Intel-gfx] " Daniel Vetter
2021-12-07 18:08 ` Daniel Vetter
2021-12-07 20:46 ` Thomas Hellström
2021-12-07 20:46 ` Thomas Hellström
2021-12-20 9:37 ` Daniel Vetter
2021-12-20 9:37 ` Daniel Vetter
2021-11-30 12:32 ` [Intel-gfx] " Thomas Hellström
2021-11-30 12:32 ` Thomas Hellström
2021-11-30 12:19 ` [Intel-gfx] [RFC PATCH 2/2] dma-fence: Avoid excessive recursive fence locking from enable_signaling() callbacks Thomas Hellström
2021-11-30 12:19 ` Thomas Hellström
2021-11-30 12:36 ` [Intel-gfx] [RFC PATCH 0/2] Attempt to avoid dma-fence-[chain|array] lockdep splats Christian König
2021-11-30 12:36 ` Christian König
2021-11-30 13:05 ` [Intel-gfx] ✗ Fi.CI.SPARSE: warning for " Patchwork
2021-11-30 13:48 ` [Intel-gfx] ✓ Fi.CI.BAT: success " Patchwork
2021-11-30 17:47 ` [Intel-gfx] ✓ Fi.CI.IGT: " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211130121936.586031-2-thomas.hellstrom@linux.intel.com \
--to=thomas.hellstrom@linux.intel.com \
--cc=christian.koenig@amd.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-gfx@lists.freedesktop.org \
--cc=linaro-mm-sig@lists.linaro.org \
--cc=matthew.auld@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.