All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled
@ 2023-06-08 14:30 Tvrtko Ursulin
  2023-06-08 16:45   ` kernel test robot
  2023-06-09  6:32 ` Christian König
  0 siblings, 2 replies; 7+ messages in thread
From: Tvrtko Ursulin @ 2023-06-08 14:30 UTC (permalink / raw)
  To: dri-devel; +Cc: Daniel Vetter, Christian König, Tvrtko Ursulin

From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

For dma_fence_is_signaled signaling critical path annotations are an
annoying cause of false positives when using dma_fence_is_signaled and
indirectly higher level helpers such as dma_resv_test_signaled etc.

Drop the critical path annotation since the "is signaled" API does not
guarantee to ever change the signaled status anyway.

We do that by adding a low level _dma_fence_signal helper and use it from
dma_fence_is_signaled.

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Christian König <christian.koenig@amd.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/dma-buf/dma-fence.c | 26 ++++++++++++++++++++------
 include/linux/dma-fence.h   |  3 ++-
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
index f177c56269bb..ace1415f0566 100644
--- a/drivers/dma-buf/dma-fence.c
+++ b/drivers/dma-buf/dma-fence.c
@@ -444,6 +444,25 @@ int dma_fence_signal_locked(struct dma_fence *fence)
 }
 EXPORT_SYMBOL(dma_fence_signal_locked);
 
+/**
+ * __dma_fence_signal - signal completion of a fence bypassing critical section annotation
+ * @fence: the fence to signal
+ *
+ * This low-level helper should not be used by code external to dma-fence.h|c!
+ */
+int _dma_fence_signal(struct dma_fence *fence)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(fence->lock, flags);
+	ret = dma_fence_signal_timestamp_locked(fence, ktime_get());
+	spin_unlock_irqrestore(fence->lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(_dma_fence_signal);
+
 /**
  * dma_fence_signal - signal completion of a fence
  * @fence: the fence to signal
@@ -459,7 +478,6 @@ EXPORT_SYMBOL(dma_fence_signal_locked);
  */
 int dma_fence_signal(struct dma_fence *fence)
 {
-	unsigned long flags;
 	int ret;
 	bool tmp;
 
@@ -467,11 +485,7 @@ int dma_fence_signal(struct dma_fence *fence)
 		return -EINVAL;
 
 	tmp = dma_fence_begin_signalling();
-
-	spin_lock_irqsave(fence->lock, flags);
-	ret = dma_fence_signal_timestamp_locked(fence, ktime_get());
-	spin_unlock_irqrestore(fence->lock, flags);
-
+	ret = _dma_fence_signal(fence);
 	dma_fence_end_signalling(tmp);
 
 	return ret;
diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
index d54b595a0fe0..d94768ad70e4 100644
--- a/include/linux/dma-fence.h
+++ b/include/linux/dma-fence.h
@@ -387,6 +387,7 @@ static inline void dma_fence_end_signalling(bool cookie) {}
 static inline void __dma_fence_might_wait(void) {}
 #endif
 
+int _dma_fence_signal(struct dma_fence *fence);
 int dma_fence_signal(struct dma_fence *fence);
 int dma_fence_signal_locked(struct dma_fence *fence);
 int dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp);
@@ -452,7 +453,7 @@ dma_fence_is_signaled(struct dma_fence *fence)
 		return true;
 
 	if (fence->ops->signaled && fence->ops->signaled(fence)) {
-		dma_fence_signal(fence);
+		_dma_fence_signal(fence);
 		return true;
 	}
 
-- 
2.39.2


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled
  2023-06-08 14:30 [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled Tvrtko Ursulin
@ 2023-06-08 16:45   ` kernel test robot
  2023-06-09  6:32 ` Christian König
  1 sibling, 0 replies; 7+ messages in thread
From: kernel test robot @ 2023-06-08 16:45 UTC (permalink / raw)
  To: Tvrtko Ursulin, dri-devel
  Cc: Daniel Vetter, Tvrtko Ursulin, Christian König, oe-kbuild-all

Hi Tvrtko,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on drm-tip/drm-tip linus/master v6.4-rc5 next-20230608]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Tvrtko-Ursulin/dma-fence-Bypass-signaling-annotation-from-dma_fence_is_signaled/20230608-223804
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link:    https://lore.kernel.org/r/20230608143059.1038115-1-tvrtko.ursulin%40linux.intel.com
patch subject: [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled
config: arm-buildonly-randconfig-r006-20230608 (https://download.01.org/0day-ci/archive/20230609/202306090039.JEYvWyVv-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 12.3.0
reproduce (this is a W=1 build):
        mkdir -p ~/bin
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        git remote add drm-misc git://anongit.freedesktop.org/drm/drm-misc
        git fetch drm-misc drm-misc-next
        git checkout drm-misc/drm-misc-next
        b4 shazam https://lore.kernel.org/r/20230608143059.1038115-1-tvrtko.ursulin@linux.intel.com
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=arm olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash drivers/dma-buf/

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306090039.JEYvWyVv-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/dma-buf/dma-fence.c:454: warning: expecting prototype for __dma_fence_signal(). Prototype was for _dma_fence_signal() instead


vim +454 drivers/dma-buf/dma-fence.c

   446	
   447	/**
   448	 * __dma_fence_signal - signal completion of a fence bypassing critical section annotation
   449	 * @fence: the fence to signal
   450	 *
   451	 * This low-level helper should not be used by code external to dma-fence.h|c!
   452	 */
   453	int _dma_fence_signal(struct dma_fence *fence)
 > 454	{
   455		unsigned long flags;
   456		int ret;
   457	
   458		spin_lock_irqsave(fence->lock, flags);
   459		ret = dma_fence_signal_timestamp_locked(fence, ktime_get());
   460		spin_unlock_irqrestore(fence->lock, flags);
   461	
   462		return ret;
   463	}
   464	EXPORT_SYMBOL(_dma_fence_signal);
   465	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled
@ 2023-06-08 16:45   ` kernel test robot
  0 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2023-06-08 16:45 UTC (permalink / raw)
  To: Tvrtko Ursulin, dri-devel
  Cc: oe-kbuild-all, Daniel Vetter, Christian König, Tvrtko Ursulin

Hi Tvrtko,

kernel test robot noticed the following build warnings:

[auto build test WARNING on drm-misc/drm-misc-next]
[also build test WARNING on drm-tip/drm-tip linus/master v6.4-rc5 next-20230608]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Tvrtko-Ursulin/dma-fence-Bypass-signaling-annotation-from-dma_fence_is_signaled/20230608-223804
base:   git://anongit.freedesktop.org/drm/drm-misc drm-misc-next
patch link:    https://lore.kernel.org/r/20230608143059.1038115-1-tvrtko.ursulin%40linux.intel.com
patch subject: [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled
config: arm-buildonly-randconfig-r006-20230608 (https://download.01.org/0day-ci/archive/20230609/202306090039.JEYvWyVv-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 12.3.0
reproduce (this is a W=1 build):
        mkdir -p ~/bin
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        git remote add drm-misc git://anongit.freedesktop.org/drm/drm-misc
        git fetch drm-misc drm-misc-next
        git checkout drm-misc/drm-misc-next
        b4 shazam https://lore.kernel.org/r/20230608143059.1038115-1-tvrtko.ursulin@linux.intel.com
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=arm olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.3.0 ~/bin/make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash drivers/dma-buf/

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306090039.JEYvWyVv-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/dma-buf/dma-fence.c:454: warning: expecting prototype for __dma_fence_signal(). Prototype was for _dma_fence_signal() instead


vim +454 drivers/dma-buf/dma-fence.c

   446	
   447	/**
   448	 * __dma_fence_signal - signal completion of a fence bypassing critical section annotation
   449	 * @fence: the fence to signal
   450	 *
   451	 * This low-level helper should not be used by code external to dma-fence.h|c!
   452	 */
   453	int _dma_fence_signal(struct dma_fence *fence)
 > 454	{
   455		unsigned long flags;
   456		int ret;
   457	
   458		spin_lock_irqsave(fence->lock, flags);
   459		ret = dma_fence_signal_timestamp_locked(fence, ktime_get());
   460		spin_unlock_irqrestore(fence->lock, flags);
   461	
   462		return ret;
   463	}
   464	EXPORT_SYMBOL(_dma_fence_signal);
   465	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled
  2023-06-08 14:30 [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled Tvrtko Ursulin
  2023-06-08 16:45   ` kernel test robot
@ 2023-06-09  6:32 ` Christian König
  2023-06-09 12:09   ` Tvrtko Ursulin
  1 sibling, 1 reply; 7+ messages in thread
From: Christian König @ 2023-06-09  6:32 UTC (permalink / raw)
  To: Tvrtko Ursulin, dri-devel; +Cc: Daniel Vetter, Tvrtko Ursulin

Am 08.06.23 um 16:30 schrieb Tvrtko Ursulin:
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>
> For dma_fence_is_signaled signaling critical path annotations are an
> annoying cause of false positives when using dma_fence_is_signaled and
> indirectly higher level helpers such as dma_resv_test_signaled etc.
>
> Drop the critical path annotation since the "is signaled" API does not
> guarantee to ever change the signaled status anyway.
>
> We do that by adding a low level _dma_fence_signal helper and use it from
> dma_fence_is_signaled.

I have been considering dropping the signaling from the 
dma_fence_is_signaled() function altogether.

Doing this together with the spin locking we have in the dma_fence is 
just utterly nonsense since the purpose of the external spinlock is to 
keep the signaling in order while this here defeats that.

The quick check is ok I think, but signaling the dma_fence and issuing 
the callbacks should always come from the interrupt handler.

Christian.

>
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> Cc: Christian König <christian.koenig@amd.com>
> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>   drivers/dma-buf/dma-fence.c | 26 ++++++++++++++++++++------
>   include/linux/dma-fence.h   |  3 ++-
>   2 files changed, 22 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
> index f177c56269bb..ace1415f0566 100644
> --- a/drivers/dma-buf/dma-fence.c
> +++ b/drivers/dma-buf/dma-fence.c
> @@ -444,6 +444,25 @@ int dma_fence_signal_locked(struct dma_fence *fence)
>   }
>   EXPORT_SYMBOL(dma_fence_signal_locked);
>   
> +/**
> + * __dma_fence_signal - signal completion of a fence bypassing critical section annotation
> + * @fence: the fence to signal
> + *
> + * This low-level helper should not be used by code external to dma-fence.h|c!
> + */
> +int _dma_fence_signal(struct dma_fence *fence)
> +{
> +	unsigned long flags;
> +	int ret;
> +
> +	spin_lock_irqsave(fence->lock, flags);
> +	ret = dma_fence_signal_timestamp_locked(fence, ktime_get());
> +	spin_unlock_irqrestore(fence->lock, flags);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(_dma_fence_signal);
> +
>   /**
>    * dma_fence_signal - signal completion of a fence
>    * @fence: the fence to signal
> @@ -459,7 +478,6 @@ EXPORT_SYMBOL(dma_fence_signal_locked);
>    */
>   int dma_fence_signal(struct dma_fence *fence)
>   {
> -	unsigned long flags;
>   	int ret;
>   	bool tmp;
>   
> @@ -467,11 +485,7 @@ int dma_fence_signal(struct dma_fence *fence)
>   		return -EINVAL;
>   
>   	tmp = dma_fence_begin_signalling();
> -
> -	spin_lock_irqsave(fence->lock, flags);
> -	ret = dma_fence_signal_timestamp_locked(fence, ktime_get());
> -	spin_unlock_irqrestore(fence->lock, flags);
> -
> +	ret = _dma_fence_signal(fence);
>   	dma_fence_end_signalling(tmp);
>   
>   	return ret;
> diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
> index d54b595a0fe0..d94768ad70e4 100644
> --- a/include/linux/dma-fence.h
> +++ b/include/linux/dma-fence.h
> @@ -387,6 +387,7 @@ static inline void dma_fence_end_signalling(bool cookie) {}
>   static inline void __dma_fence_might_wait(void) {}
>   #endif
>   
> +int _dma_fence_signal(struct dma_fence *fence);
>   int dma_fence_signal(struct dma_fence *fence);
>   int dma_fence_signal_locked(struct dma_fence *fence);
>   int dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t timestamp);
> @@ -452,7 +453,7 @@ dma_fence_is_signaled(struct dma_fence *fence)
>   		return true;
>   
>   	if (fence->ops->signaled && fence->ops->signaled(fence)) {
> -		dma_fence_signal(fence);
> +		_dma_fence_signal(fence);
>   		return true;
>   	}
>   


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled
  2023-06-09  6:32 ` Christian König
@ 2023-06-09 12:09   ` Tvrtko Ursulin
  2023-06-09 12:52     ` Christian König
  0 siblings, 1 reply; 7+ messages in thread
From: Tvrtko Ursulin @ 2023-06-09 12:09 UTC (permalink / raw)
  To: Christian König, dri-devel; +Cc: Daniel Vetter, Tvrtko Ursulin


On 09/06/2023 07:32, Christian König wrote:
> Am 08.06.23 um 16:30 schrieb Tvrtko Ursulin:
>> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>
>> For dma_fence_is_signaled signaling critical path annotations are an
>> annoying cause of false positives when using dma_fence_is_signaled and
>> indirectly higher level helpers such as dma_resv_test_signaled etc.
>>
>> Drop the critical path annotation since the "is signaled" API does not
>> guarantee to ever change the signaled status anyway.
>>
>> We do that by adding a low level _dma_fence_signal helper and use it from
>> dma_fence_is_signaled.
> 
> I have been considering dropping the signaling from the 
> dma_fence_is_signaled() function altogether.
> 
> Doing this together with the spin locking we have in the dma_fence is 
> just utterly nonsense since the purpose of the external spinlock is to 
> keep the signaling in order while this here defeats that.
> 
> The quick check is ok I think, but signaling the dma_fence and issuing 
> the callbacks should always come from the interrupt handler.

What do you think is broken with regards to ordering with the current 
code? The unlocked fast check?

Regards,

Tvrtko

> 
> Christian.
> 
>>
>> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>> Cc: Christian König <christian.koenig@amd.com>
>> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
>> ---
>>   drivers/dma-buf/dma-fence.c | 26 ++++++++++++++++++++------
>>   include/linux/dma-fence.h   |  3 ++-
>>   2 files changed, 22 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
>> index f177c56269bb..ace1415f0566 100644
>> --- a/drivers/dma-buf/dma-fence.c
>> +++ b/drivers/dma-buf/dma-fence.c
>> @@ -444,6 +444,25 @@ int dma_fence_signal_locked(struct dma_fence *fence)
>>   }
>>   EXPORT_SYMBOL(dma_fence_signal_locked);
>> +/**
>> + * __dma_fence_signal - signal completion of a fence bypassing 
>> critical section annotation
>> + * @fence: the fence to signal
>> + *
>> + * This low-level helper should not be used by code external to 
>> dma-fence.h|c!
>> + */
>> +int _dma_fence_signal(struct dma_fence *fence)
>> +{
>> +    unsigned long flags;
>> +    int ret;
>> +
>> +    spin_lock_irqsave(fence->lock, flags);
>> +    ret = dma_fence_signal_timestamp_locked(fence, ktime_get());
>> +    spin_unlock_irqrestore(fence->lock, flags);
>> +
>> +    return ret;
>> +}
>> +EXPORT_SYMBOL(_dma_fence_signal);
>> +
>>   /**
>>    * dma_fence_signal - signal completion of a fence
>>    * @fence: the fence to signal
>> @@ -459,7 +478,6 @@ EXPORT_SYMBOL(dma_fence_signal_locked);
>>    */
>>   int dma_fence_signal(struct dma_fence *fence)
>>   {
>> -    unsigned long flags;
>>       int ret;
>>       bool tmp;
>> @@ -467,11 +485,7 @@ int dma_fence_signal(struct dma_fence *fence)
>>           return -EINVAL;
>>       tmp = dma_fence_begin_signalling();
>> -
>> -    spin_lock_irqsave(fence->lock, flags);
>> -    ret = dma_fence_signal_timestamp_locked(fence, ktime_get());
>> -    spin_unlock_irqrestore(fence->lock, flags);
>> -
>> +    ret = _dma_fence_signal(fence);
>>       dma_fence_end_signalling(tmp);
>>       return ret;
>> diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
>> index d54b595a0fe0..d94768ad70e4 100644
>> --- a/include/linux/dma-fence.h
>> +++ b/include/linux/dma-fence.h
>> @@ -387,6 +387,7 @@ static inline void dma_fence_end_signalling(bool 
>> cookie) {}
>>   static inline void __dma_fence_might_wait(void) {}
>>   #endif
>> +int _dma_fence_signal(struct dma_fence *fence);
>>   int dma_fence_signal(struct dma_fence *fence);
>>   int dma_fence_signal_locked(struct dma_fence *fence);
>>   int dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t 
>> timestamp);
>> @@ -452,7 +453,7 @@ dma_fence_is_signaled(struct dma_fence *fence)
>>           return true;
>>       if (fence->ops->signaled && fence->ops->signaled(fence)) {
>> -        dma_fence_signal(fence);
>> +        _dma_fence_signal(fence);
>>           return true;
>>       }
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled
  2023-06-09 12:09   ` Tvrtko Ursulin
@ 2023-06-09 12:52     ` Christian König
  2023-06-09 14:06       ` Tvrtko Ursulin
  0 siblings, 1 reply; 7+ messages in thread
From: Christian König @ 2023-06-09 12:52 UTC (permalink / raw)
  To: Tvrtko Ursulin, dri-devel; +Cc: Daniel Vetter, Tvrtko Ursulin

Am 09.06.23 um 14:09 schrieb Tvrtko Ursulin:
>
> On 09/06/2023 07:32, Christian König wrote:
>> Am 08.06.23 um 16:30 schrieb Tvrtko Ursulin:
>>> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>>
>>> For dma_fence_is_signaled signaling critical path annotations are an
>>> annoying cause of false positives when using dma_fence_is_signaled and
>>> indirectly higher level helpers such as dma_resv_test_signaled etc.
>>>
>>> Drop the critical path annotation since the "is signaled" API does not
>>> guarantee to ever change the signaled status anyway.
>>>
>>> We do that by adding a low level _dma_fence_signal helper and use it 
>>> from
>>> dma_fence_is_signaled.
>>
>> I have been considering dropping the signaling from the 
>> dma_fence_is_signaled() function altogether.
>>
>> Doing this together with the spin locking we have in the dma_fence is 
>> just utterly nonsense since the purpose of the external spinlock is 
>> to keep the signaling in order while this here defeats that.
>>
>> The quick check is ok I think, but signaling the dma_fence and 
>> issuing the callbacks should always come from the interrupt handler.
>
> What do you think is broken with regards to ordering with the current 
> code? The unlocked fast check?

Well it's not broken, the complexity just doesn't make sense.

The dma_fence->lock is a pointer to a spinlock_t instead of a spinlock_t 
itself. That was done to make sure that all dma_fence objects from a 
single context (or in other words hardware device) signal in the order 
of their sequence number, e.g. 1 first, then 2, then 3 etc...

But when somebody uses the dma_fence_is_signaled() function it's 
perfectly possible that this races with an interrupt handler which wants 
to signal fences on another CPU.

In other words we get:
CPU A:
dma_fence_is_signaled(fence with seqno=3)
fence->ops->signaled() returns true
dma_fence_signal()
spin_lock_irqsave(fence->lock)
signal seqno=3
...

CPU B:
device_driver_interrupt_handler()
spin_lock_irqsave(driver->lock) <- busy waits for CPU A to complete
signal seqno=1
signal seqno=2
seqno=3 is already signaled.
signal seqno=4
...

Either fence->lock should not be a pointer or we should not signal the 
fence from dma_fence_is_signaled().

I strongly think that later should be the way to go.

Regards,
Christian.

>
> Regards,
>
> Tvrtko
>
>>
>> Christian.
>>
>>>
>>> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>> Cc: Christian König <christian.koenig@amd.com>
>>> Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
>>> ---
>>>   drivers/dma-buf/dma-fence.c | 26 ++++++++++++++++++++------
>>>   include/linux/dma-fence.h   |  3 ++-
>>>   2 files changed, 22 insertions(+), 7 deletions(-)
>>>
>>> diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c
>>> index f177c56269bb..ace1415f0566 100644
>>> --- a/drivers/dma-buf/dma-fence.c
>>> +++ b/drivers/dma-buf/dma-fence.c
>>> @@ -444,6 +444,25 @@ int dma_fence_signal_locked(struct dma_fence 
>>> *fence)
>>>   }
>>>   EXPORT_SYMBOL(dma_fence_signal_locked);
>>> +/**
>>> + * __dma_fence_signal - signal completion of a fence bypassing 
>>> critical section annotation
>>> + * @fence: the fence to signal
>>> + *
>>> + * This low-level helper should not be used by code external to 
>>> dma-fence.h|c!
>>> + */
>>> +int _dma_fence_signal(struct dma_fence *fence)
>>> +{
>>> +    unsigned long flags;
>>> +    int ret;
>>> +
>>> +    spin_lock_irqsave(fence->lock, flags);
>>> +    ret = dma_fence_signal_timestamp_locked(fence, ktime_get());
>>> +    spin_unlock_irqrestore(fence->lock, flags);
>>> +
>>> +    return ret;
>>> +}
>>> +EXPORT_SYMBOL(_dma_fence_signal);
>>> +
>>>   /**
>>>    * dma_fence_signal - signal completion of a fence
>>>    * @fence: the fence to signal
>>> @@ -459,7 +478,6 @@ EXPORT_SYMBOL(dma_fence_signal_locked);
>>>    */
>>>   int dma_fence_signal(struct dma_fence *fence)
>>>   {
>>> -    unsigned long flags;
>>>       int ret;
>>>       bool tmp;
>>> @@ -467,11 +485,7 @@ int dma_fence_signal(struct dma_fence *fence)
>>>           return -EINVAL;
>>>       tmp = dma_fence_begin_signalling();
>>> -
>>> -    spin_lock_irqsave(fence->lock, flags);
>>> -    ret = dma_fence_signal_timestamp_locked(fence, ktime_get());
>>> -    spin_unlock_irqrestore(fence->lock, flags);
>>> -
>>> +    ret = _dma_fence_signal(fence);
>>>       dma_fence_end_signalling(tmp);
>>>       return ret;
>>> diff --git a/include/linux/dma-fence.h b/include/linux/dma-fence.h
>>> index d54b595a0fe0..d94768ad70e4 100644
>>> --- a/include/linux/dma-fence.h
>>> +++ b/include/linux/dma-fence.h
>>> @@ -387,6 +387,7 @@ static inline void dma_fence_end_signalling(bool 
>>> cookie) {}
>>>   static inline void __dma_fence_might_wait(void) {}
>>>   #endif
>>> +int _dma_fence_signal(struct dma_fence *fence);
>>>   int dma_fence_signal(struct dma_fence *fence);
>>>   int dma_fence_signal_locked(struct dma_fence *fence);
>>>   int dma_fence_signal_timestamp(struct dma_fence *fence, ktime_t 
>>> timestamp);
>>> @@ -452,7 +453,7 @@ dma_fence_is_signaled(struct dma_fence *fence)
>>>           return true;
>>>       if (fence->ops->signaled && fence->ops->signaled(fence)) {
>>> -        dma_fence_signal(fence);
>>> +        _dma_fence_signal(fence);
>>>           return true;
>>>       }
>>


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled
  2023-06-09 12:52     ` Christian König
@ 2023-06-09 14:06       ` Tvrtko Ursulin
  0 siblings, 0 replies; 7+ messages in thread
From: Tvrtko Ursulin @ 2023-06-09 14:06 UTC (permalink / raw)
  To: Christian König, dri-devel; +Cc: Daniel Vetter, Tvrtko Ursulin


On 09/06/2023 13:52, Christian König wrote:
> Am 09.06.23 um 14:09 schrieb Tvrtko Ursulin:
>>
>> On 09/06/2023 07:32, Christian König wrote:
>>> Am 08.06.23 um 16:30 schrieb Tvrtko Ursulin:
>>>> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>>>
>>>> For dma_fence_is_signaled signaling critical path annotations are an
>>>> annoying cause of false positives when using dma_fence_is_signaled and
>>>> indirectly higher level helpers such as dma_resv_test_signaled etc.
>>>>
>>>> Drop the critical path annotation since the "is signaled" API does not
>>>> guarantee to ever change the signaled status anyway.
>>>>
>>>> We do that by adding a low level _dma_fence_signal helper and use it 
>>>> from
>>>> dma_fence_is_signaled.
>>>
>>> I have been considering dropping the signaling from the 
>>> dma_fence_is_signaled() function altogether.
>>>
>>> Doing this together with the spin locking we have in the dma_fence is 
>>> just utterly nonsense since the purpose of the external spinlock is 
>>> to keep the signaling in order while this here defeats that.
>>>
>>> The quick check is ok I think, but signaling the dma_fence and 
>>> issuing the callbacks should always come from the interrupt handler.
>>
>> What do you think is broken with regards to ordering with the current 
>> code? The unlocked fast check?
> 
> Well it's not broken, the complexity just doesn't make sense.
> 
> The dma_fence->lock is a pointer to a spinlock_t instead of a spinlock_t 
> itself. That was done to make sure that all dma_fence objects from a 
> single context (or in other words hardware device) signal in the order 
> of their sequence number, e.g. 1 first, then 2, then 3 etc...
> 
> But when somebody uses the dma_fence_is_signaled() function it's 
> perfectly possible that this races with an interrupt handler which wants 
> to signal fences on another CPU.
> 
> In other words we get:
> CPU A:
> dma_fence_is_signaled(fence with seqno=3)
> fence->ops->signaled() returns true
> dma_fence_signal()
> spin_lock_irqsave(fence->lock)
> signal seqno=3
> ...
> 
> CPU B:
> device_driver_interrupt_handler()
> spin_lock_irqsave(driver->lock) <- busy waits for CPU A to complete
> signal seqno=1
> signal seqno=2
> seqno=3 is already signaled.
> signal seqno=4
> ...

Right I see. However hm.. would the order of be guaranteed anyway, if 
someone would be observing what CPU B is doing via the 
dma_fence_is_signaled->test_bit? And in which scenarios would it matter 
if out of order signaled status could be observed?

> Either fence->lock should not be a pointer or we should not signal the 
> fence from dma_fence_is_signaled().
> 
> I strongly think that later should be the way to go.

Despite having wrote the above, I don't have any objections to removing 
this either. I don't see anything in the contract that requires it, but 
it was probably a bit before my time to know why it was added so I don't 
know if it could cause any subtle issues. It should be okay to try and see.

Regards,

Tvrtko

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2023-06-09 14:07 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-08 14:30 [PATCH] dma-fence: Bypass signaling annotation from dma_fence_is_signaled Tvrtko Ursulin
2023-06-08 16:45 ` kernel test robot
2023-06-08 16:45   ` kernel test robot
2023-06-09  6:32 ` Christian König
2023-06-09 12:09   ` Tvrtko Ursulin
2023-06-09 12:52     ` Christian König
2023-06-09 14:06       ` Tvrtko Ursulin

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.