diff mbox series

[v4,12/12] xen/spinlock: support higher number of cpus

Message ID 20231212094725.22184-13-jgross@suse.com (mailing list archive)
State New
Headers show
Series xen/spinlock: make recursive spinlocks a dedicated type | expand

Commit Message

Jürgen Groß Dec. 12, 2023, 9:47 a.m. UTC
Allow 16 bits per cpu number, which is the limit imposed by
spinlock_tickets_t.

This will allow up to 65535 cpus, while increasing only the size of
recursive spinlocks in debug builds from 8 to 12 bytes.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 xen/common/spinlock.c      |  1 +
 xen/include/xen/spinlock.h | 18 +++++++++---------
 2 files changed, 10 insertions(+), 9 deletions(-)

Comments

Julien Grall Dec. 12, 2023, 10:10 a.m. UTC | #1
Hi Juergen,

On 12/12/2023 09:47, Juergen Gross wrote:
> Allow 16 bits per cpu number, which is the limit imposed by
> spinlock_tickets_t.
> 
> This will allow up to 65535 cpus, while increasing only the size of
> recursive spinlocks in debug builds from 8 to 12 bytes.
Looking at arch/Kconfig, it looks like we are limiting NR_CPUS to 
maximum 4096. So can you outline why we need this?

Just to be clear is I am not against this change, but alone it seems a 
little bit odd to increase the size in debug when that limit can never 
be reached (at least today).

Cheers,

> 
> Signed-off-by: Juergen Gross <jgross@suse.com>
> ---
>   xen/common/spinlock.c      |  1 +
>   xen/include/xen/spinlock.h | 18 +++++++++---------
>   2 files changed, 10 insertions(+), 9 deletions(-)
> 
> diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
> index 296bcf33e6..ae7c7c2086 100644
> --- a/xen/common/spinlock.c
> +++ b/xen/common/spinlock.c
> @@ -481,6 +481,7 @@ int rspin_trylock(rspinlock_t *lock)
>   
>       /* Don't allow overflow of recurse_cpu field. */
>       BUILD_BUG_ON(NR_CPUS > SPINLOCK_NO_CPU);
> +    BUILD_BUG_ON(SPINLOCK_CPU_BITS > sizeof(lock->recurse_cpu) * 8);
>       BUILD_BUG_ON(SPINLOCK_RECURSE_BITS < 3);
>   
>       check_lock(&lock->debug, true);
> diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
> index 87946965b2..d720778cc1 100644
> --- a/xen/include/xen/spinlock.h
> +++ b/xen/include/xen/spinlock.h
> @@ -7,16 +7,16 @@
>   #include <asm/system.h>
>   #include <asm/spinlock.h>
>   
> -#define SPINLOCK_CPU_BITS  12
> +#define SPINLOCK_CPU_BITS  16
>   
>   #ifdef CONFIG_DEBUG_LOCKS
>   union lock_debug {
> -    uint16_t val;
> -#define LOCK_DEBUG_INITVAL 0xffff
> +    uint32_t val;
> +#define LOCK_DEBUG_INITVAL 0xffffffff
>       struct {
> -        uint16_t cpu:SPINLOCK_CPU_BITS;
> -#define LOCK_DEBUG_PAD_BITS (14 - SPINLOCK_CPU_BITS)
> -        uint16_t :LOCK_DEBUG_PAD_BITS;
> +        uint32_t cpu:SPINLOCK_CPU_BITS;
> +#define LOCK_DEBUG_PAD_BITS (30 - SPINLOCK_CPU_BITS)
> +        uint32_t :LOCK_DEBUG_PAD_BITS;
>           bool irq_safe:1;
>           bool unseen:1;
>       };
> @@ -210,10 +210,10 @@ typedef struct spinlock {
>   
>   typedef struct rspinlock {
>       spinlock_tickets_t tickets;
> -    uint16_t recurse_cpu:SPINLOCK_CPU_BITS;
> +    uint16_t recurse_cpu;
>   #define SPINLOCK_NO_CPU        ((1u << SPINLOCK_CPU_BITS) - 1)
> -#define SPINLOCK_RECURSE_BITS  (16 - SPINLOCK_CPU_BITS)
> -    uint16_t recurse_cnt:SPINLOCK_RECURSE_BITS;
> +#define SPINLOCK_RECURSE_BITS  8
> +    uint8_t recurse_cnt;
>   #define SPINLOCK_MAX_RECURSE   ((1u << SPINLOCK_RECURSE_BITS) - 1)
>       union lock_debug debug;
>   #ifdef CONFIG_DEBUG_LOCK_PROFILE
Jürgen Groß Dec. 12, 2023, 11:09 a.m. UTC | #2
On 12.12.23 11:10, Julien Grall wrote:
> Hi Juergen,
> 
> On 12/12/2023 09:47, Juergen Gross wrote:
>> Allow 16 bits per cpu number, which is the limit imposed by
>> spinlock_tickets_t.
>>
>> This will allow up to 65535 cpus, while increasing only the size of
>> recursive spinlocks in debug builds from 8 to 12 bytes.
> Looking at arch/Kconfig, it looks like we are limiting NR_CPUS to maximum 4096. 
> So can you outline why we need this?

The limit of 4096 cpus is dictated by the current limit of the spinlock
implementation. So asking "why do we need to support more than 4096 cpus
in spinlock_t when the current Xen limit is 4096" is kind of the wrong
question.

The correct question would be: why is Xen limited to 4096 cpus? Answer:
because of the limit in spinlock_t.

There are (x86) machines out there with more cpus than 4096, and Javi (added
to Cc:) was already looking into rising the Xen limit.

> 
> Just to be clear is I am not against this change, but alone it seems a little 
> bit odd to increase the size in debug when that limit can never be reached (at 
> least today).


Juergen
Julien Grall Dec. 12, 2023, 11:40 a.m. UTC | #3
Hi Juergen,

On 12/12/2023 11:09, Juergen Gross wrote:
> On 12.12.23 11:10, Julien Grall wrote:
>> Hi Juergen,
>>
>> On 12/12/2023 09:47, Juergen Gross wrote:
>>> Allow 16 bits per cpu number, which is the limit imposed by
>>> spinlock_tickets_t.
>>>
>>> This will allow up to 65535 cpus, while increasing only the size of
>>> recursive spinlocks in debug builds from 8 to 12 bytes.
>> Looking at arch/Kconfig, it looks like we are limiting NR_CPUS to 
>> maximum 4096. So can you outline why we need this?
> 
> The limit of 4096 cpus is dictated by the current limit of the spinlock
> implementation. So asking "why do we need to support more than 4096 cpus
> in spinlock_t when the current Xen limit is 4096" is kind of the wrong
> question. >
> The correct question would be: why is Xen limited to 4096 cpus? Answer:
> because of the limit in spinlock_t.

I thought there was also some lock contention issue in Xen. Hence why I 
asked the question because the commit message doesn't really give any 
clue why we are raising the limit... (This is a hint that it probably 
needs to be expanded a bit).

Cheers,
Jürgen Groß Dec. 12, 2023, 12:11 p.m. UTC | #4
On 12.12.23 12:40, Julien Grall wrote:
> Hi Juergen,
> 
> On 12/12/2023 11:09, Juergen Gross wrote:
>> On 12.12.23 11:10, Julien Grall wrote:
>>> Hi Juergen,
>>>
>>> On 12/12/2023 09:47, Juergen Gross wrote:
>>>> Allow 16 bits per cpu number, which is the limit imposed by
>>>> spinlock_tickets_t.
>>>>
>>>> This will allow up to 65535 cpus, while increasing only the size of
>>>> recursive spinlocks in debug builds from 8 to 12 bytes.
>>> Looking at arch/Kconfig, it looks like we are limiting NR_CPUS to maximum 
>>> 4096. So can you outline why we need this?
>>
>> The limit of 4096 cpus is dictated by the current limit of the spinlock
>> implementation. So asking "why do we need to support more than 4096 cpus
>> in spinlock_t when the current Xen limit is 4096" is kind of the wrong
>> question. >
>> The correct question would be: why is Xen limited to 4096 cpus? Answer:
>> because of the limit in spinlock_t.
> 
> I thought there was also some lock contention issue in Xen. Hence why I asked 
> the question because the commit message doesn't really give any clue why we are 
> raising the limit... (This is a hint that it probably needs to be expanded a bit).

Okay, are you fine with the following addition:

   The current Xen limit of 4095 cpus is imposed by SPINLOCK_CPU_BITS
   being 12. There are machines available with more cpus than the current
   Xen limit, so it makes sense to have the possibility to use more cpus.


Juergen
Julien Grall Dec. 12, 2023, 12:22 p.m. UTC | #5
Hi,

On 12/12/2023 12:11, Juergen Gross wrote:
> On 12.12.23 12:40, Julien Grall wrote:
>> Hi Juergen,
>>
>> On 12/12/2023 11:09, Juergen Gross wrote:
>>> On 12.12.23 11:10, Julien Grall wrote:
>>>> Hi Juergen,
>>>>
>>>> On 12/12/2023 09:47, Juergen Gross wrote:
>>>>> Allow 16 bits per cpu number, which is the limit imposed by
>>>>> spinlock_tickets_t.
>>>>>
>>>>> This will allow up to 65535 cpus, while increasing only the size of
>>>>> recursive spinlocks in debug builds from 8 to 12 bytes.
>>>> Looking at arch/Kconfig, it looks like we are limiting NR_CPUS to 
>>>> maximum 4096. So can you outline why we need this?
>>>
>>> The limit of 4096 cpus is dictated by the current limit of the spinlock
>>> implementation. So asking "why do we need to support more than 4096 cpus
>>> in spinlock_t when the current Xen limit is 4096" is kind of the wrong
>>> question. >
>>> The correct question would be: why is Xen limited to 4096 cpus? Answer:
>>> because of the limit in spinlock_t.
>>
>> I thought there was also some lock contention issue in Xen. Hence why 
>> I asked the question because the commit message doesn't really give 
>> any clue why we are raising the limit... (This is a hint that it 
>> probably needs to be expanded a bit).
> 
> Okay, are you fine with the following addition:
> 
>    The current Xen limit of 4095 cpus is imposed by SPINLOCK_CPU_BITS
>    being 12. There are machines available with more cpus than the current
>    Xen limit, so it makes sense to have the possibility to use more cpus.

Yes. That makes clearer.

Cheers,
Julien Grall Dec. 12, 2023, 12:39 p.m. UTC | #6
Hi,

On 12/12/2023 09:47, Juergen Gross wrote:
> Allow 16 bits per cpu number, which is the limit imposed by
> spinlock_tickets_t.
> 
> This will allow up to 65535 cpus, while increasing only the size of
> recursive spinlocks in debug builds from 8 to 12 bytes.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>
> ---
>   xen/common/spinlock.c      |  1 +
>   xen/include/xen/spinlock.h | 18 +++++++++---------
>   2 files changed, 10 insertions(+), 9 deletions(-)
> 
> diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
> index 296bcf33e6..ae7c7c2086 100644
> --- a/xen/common/spinlock.c
> +++ b/xen/common/spinlock.c
> @@ -481,6 +481,7 @@ int rspin_trylock(rspinlock_t *lock)
>   
>       /* Don't allow overflow of recurse_cpu field. */
>       BUILD_BUG_ON(NR_CPUS > SPINLOCK_NO_CPU);
> +    BUILD_BUG_ON(SPINLOCK_CPU_BITS > sizeof(lock->recurse_cpu) * 8);
>       BUILD_BUG_ON(SPINLOCK_RECURSE_BITS < 3);
>   
>       check_lock(&lock->debug, true);
> diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
> index 87946965b2..d720778cc1 100644
> --- a/xen/include/xen/spinlock.h
> +++ b/xen/include/xen/spinlock.h
> @@ -7,16 +7,16 @@
>   #include <asm/system.h>
>   #include <asm/spinlock.h>
>   
> -#define SPINLOCK_CPU_BITS  12
> +#define SPINLOCK_CPU_BITS  16
>   
>   #ifdef CONFIG_DEBUG_LOCKS
>   union lock_debug {
> -    uint16_t val;
> -#define LOCK_DEBUG_INITVAL 0xffff
> +    uint32_t val;
> +#define LOCK_DEBUG_INITVAL 0xffffffff
>       struct {
> -        uint16_t cpu:SPINLOCK_CPU_BITS;
> -#define LOCK_DEBUG_PAD_BITS (14 - SPINLOCK_CPU_BITS)
> -        uint16_t :LOCK_DEBUG_PAD_BITS;
> +        uint32_t cpu:SPINLOCK_CPU_BITS;
> +#define LOCK_DEBUG_PAD_BITS (30 - SPINLOCK_CPU_BITS)
> +        uint32_t :LOCK_DEBUG_PAD_BITS;
>           bool irq_safe:1;
>           bool unseen:1;
>       };
> @@ -210,10 +210,10 @@ typedef struct spinlock {
>   
>   typedef struct rspinlock {
>       spinlock_tickets_t tickets;
> -    uint16_t recurse_cpu:SPINLOCK_CPU_BITS;
> +    uint16_t recurse_cpu;
>   #define SPINLOCK_NO_CPU        ((1u << SPINLOCK_CPU_BITS) - 1)
> -#define SPINLOCK_RECURSE_BITS  (16 - SPINLOCK_CPU_BITS)
> -    uint16_t recurse_cnt:SPINLOCK_RECURSE_BITS;
> +#define SPINLOCK_RECURSE_BITS  8
> +    uint8_t recurse_cnt;

This patch is also bumping the number of recursion possible from 16 to 
256. It is not clear to me whether this was intended or you just wanted 
to use uint8_t because it was easy to use.

 From above, I also see that we only need 3 bits:

 > BUILD_BUG_ON(SPINLOCK_RECURSE_BITS < 3);

So I would consider to ...

>   #define SPINLOCK_MAX_RECURSE   ((1u << SPINLOCK_RECURSE_BITS) - 1)

... update SPINLOCK_MAX_RECURSE to 16 or at least explain why we want to 
allow up to 256 recursion.

Cheers,
Jürgen Groß Dec. 12, 2023, 1:08 p.m. UTC | #7
On 12.12.23 13:39, Julien Grall wrote:
> Hi,
> 
> On 12/12/2023 09:47, Juergen Gross wrote:
>> Allow 16 bits per cpu number, which is the limit imposed by
>> spinlock_tickets_t.
>>
>> This will allow up to 65535 cpus, while increasing only the size of
>> recursive spinlocks in debug builds from 8 to 12 bytes.
>>
>> Signed-off-by: Juergen Gross <jgross@suse.com>
>> ---
>>   xen/common/spinlock.c      |  1 +
>>   xen/include/xen/spinlock.h | 18 +++++++++---------
>>   2 files changed, 10 insertions(+), 9 deletions(-)
>>
>> diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
>> index 296bcf33e6..ae7c7c2086 100644
>> --- a/xen/common/spinlock.c
>> +++ b/xen/common/spinlock.c
>> @@ -481,6 +481,7 @@ int rspin_trylock(rspinlock_t *lock)
>>       /* Don't allow overflow of recurse_cpu field. */
>>       BUILD_BUG_ON(NR_CPUS > SPINLOCK_NO_CPU);
>> +    BUILD_BUG_ON(SPINLOCK_CPU_BITS > sizeof(lock->recurse_cpu) * 8);
>>       BUILD_BUG_ON(SPINLOCK_RECURSE_BITS < 3);
>>       check_lock(&lock->debug, true);
>> diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
>> index 87946965b2..d720778cc1 100644
>> --- a/xen/include/xen/spinlock.h
>> +++ b/xen/include/xen/spinlock.h
>> @@ -7,16 +7,16 @@
>>   #include <asm/system.h>
>>   #include <asm/spinlock.h>
>> -#define SPINLOCK_CPU_BITS  12
>> +#define SPINLOCK_CPU_BITS  16
>>   #ifdef CONFIG_DEBUG_LOCKS
>>   union lock_debug {
>> -    uint16_t val;
>> -#define LOCK_DEBUG_INITVAL 0xffff
>> +    uint32_t val;
>> +#define LOCK_DEBUG_INITVAL 0xffffffff
>>       struct {
>> -        uint16_t cpu:SPINLOCK_CPU_BITS;
>> -#define LOCK_DEBUG_PAD_BITS (14 - SPINLOCK_CPU_BITS)
>> -        uint16_t :LOCK_DEBUG_PAD_BITS;
>> +        uint32_t cpu:SPINLOCK_CPU_BITS;
>> +#define LOCK_DEBUG_PAD_BITS (30 - SPINLOCK_CPU_BITS)
>> +        uint32_t :LOCK_DEBUG_PAD_BITS;
>>           bool irq_safe:1;
>>           bool unseen:1;
>>       };
>> @@ -210,10 +210,10 @@ typedef struct spinlock {
>>   typedef struct rspinlock {
>>       spinlock_tickets_t tickets;
>> -    uint16_t recurse_cpu:SPINLOCK_CPU_BITS;
>> +    uint16_t recurse_cpu;
>>   #define SPINLOCK_NO_CPU        ((1u << SPINLOCK_CPU_BITS) - 1)
>> -#define SPINLOCK_RECURSE_BITS  (16 - SPINLOCK_CPU_BITS)
>> -    uint16_t recurse_cnt:SPINLOCK_RECURSE_BITS;
>> +#define SPINLOCK_RECURSE_BITS  8
>> +    uint8_t recurse_cnt;
> 
> This patch is also bumping the number of recursion possible from 16 to 256. It 
> is not clear to me whether this was intended or you just wanted to use uint8_t 
> because it was easy to use.

That was the case indeed.

>  From above, I also see that we only need 3 bits:
> 
>  > BUILD_BUG_ON(SPINLOCK_RECURSE_BITS < 3);
> 
> So I would consider to ...
> 
>>   #define SPINLOCK_MAX_RECURSE   ((1u << SPINLOCK_RECURSE_BITS) - 1)
> 
> ... update SPINLOCK_MAX_RECURSE to 16 or at least explain why we want to allow 
> up to 256 recursion.

I think updating SPINLOCK_MAX_RECURSE to 15 (the current value) is fine,
probably with an additional

BUILD_BUG_ON(SPINLOCK_MAX_RECURSE > ((1u << SPINLOCK_RECURSE_BITS) - 1));


Juergen
Julien Grall Dec. 12, 2023, 2:04 p.m. UTC | #8
On 12/12/2023 13:08, Juergen Gross wrote:
> On 12.12.23 13:39, Julien Grall wrote:
>> Hi,
>>
>> On 12/12/2023 09:47, Juergen Gross wrote:
>>> Allow 16 bits per cpu number, which is the limit imposed by
>>> spinlock_tickets_t.
>>>
>>> This will allow up to 65535 cpus, while increasing only the size of
>>> recursive spinlocks in debug builds from 8 to 12 bytes.
>>>
>>> Signed-off-by: Juergen Gross <jgross@suse.com>
>>> ---
>>>   xen/common/spinlock.c      |  1 +
>>>   xen/include/xen/spinlock.h | 18 +++++++++---------
>>>   2 files changed, 10 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
>>> index 296bcf33e6..ae7c7c2086 100644
>>> --- a/xen/common/spinlock.c
>>> +++ b/xen/common/spinlock.c
>>> @@ -481,6 +481,7 @@ int rspin_trylock(rspinlock_t *lock)
>>>       /* Don't allow overflow of recurse_cpu field. */
>>>       BUILD_BUG_ON(NR_CPUS > SPINLOCK_NO_CPU);
>>> +    BUILD_BUG_ON(SPINLOCK_CPU_BITS > sizeof(lock->recurse_cpu) * 8);
>>>       BUILD_BUG_ON(SPINLOCK_RECURSE_BITS < 3);
>>>       check_lock(&lock->debug, true);
>>> diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
>>> index 87946965b2..d720778cc1 100644
>>> --- a/xen/include/xen/spinlock.h
>>> +++ b/xen/include/xen/spinlock.h
>>> @@ -7,16 +7,16 @@
>>>   #include <asm/system.h>
>>>   #include <asm/spinlock.h>
>>> -#define SPINLOCK_CPU_BITS  12
>>> +#define SPINLOCK_CPU_BITS  16
>>>   #ifdef CONFIG_DEBUG_LOCKS
>>>   union lock_debug {
>>> -    uint16_t val;
>>> -#define LOCK_DEBUG_INITVAL 0xffff
>>> +    uint32_t val;
>>> +#define LOCK_DEBUG_INITVAL 0xffffffff
>>>       struct {
>>> -        uint16_t cpu:SPINLOCK_CPU_BITS;
>>> -#define LOCK_DEBUG_PAD_BITS (14 - SPINLOCK_CPU_BITS)
>>> -        uint16_t :LOCK_DEBUG_PAD_BITS;
>>> +        uint32_t cpu:SPINLOCK_CPU_BITS;
>>> +#define LOCK_DEBUG_PAD_BITS (30 - SPINLOCK_CPU_BITS)
>>> +        uint32_t :LOCK_DEBUG_PAD_BITS;
>>>           bool irq_safe:1;
>>>           bool unseen:1;
>>>       };
>>> @@ -210,10 +210,10 @@ typedef struct spinlock {
>>>   typedef struct rspinlock {
>>>       spinlock_tickets_t tickets;
>>> -    uint16_t recurse_cpu:SPINLOCK_CPU_BITS;
>>> +    uint16_t recurse_cpu;
>>>   #define SPINLOCK_NO_CPU        ((1u << SPINLOCK_CPU_BITS) - 1)
>>> -#define SPINLOCK_RECURSE_BITS  (16 - SPINLOCK_CPU_BITS)
>>> -    uint16_t recurse_cnt:SPINLOCK_RECURSE_BITS;
>>> +#define SPINLOCK_RECURSE_BITS  8
>>> +    uint8_t recurse_cnt;
>>
>> This patch is also bumping the number of recursion possible from 16 to 
>> 256. It is not clear to me whether this was intended or you just 
>> wanted to use uint8_t because it was easy to use.
> 
> That was the case indeed.
> 
>>  From above, I also see that we only need 3 bits:
>>
>>  > BUILD_BUG_ON(SPINLOCK_RECURSE_BITS < 3);
>>
>> So I would consider to ...
>>
>>>   #define SPINLOCK_MAX_RECURSE   ((1u << SPINLOCK_RECURSE_BITS) - 1)
>>
>> ... update SPINLOCK_MAX_RECURSE to 16 or at least explain why we want 
>> to allow up to 256 recursion.
> 
> I think updating SPINLOCK_MAX_RECURSE to 15 (the current value) is fine,
> probably with an additional
> 
> BUILD_BUG_ON(SPINLOCK_MAX_RECURSE > ((1u << SPINLOCK_RECURSE_BITS) - 1));

It sounds good to me.

Cheers,
Jan Beulich Feb. 29, 2024, 3:46 p.m. UTC | #9
On 12.12.2023 10:47, Juergen Gross wrote:
> Allow 16 bits per cpu number, which is the limit imposed by
> spinlock_tickets_t.
> 
> This will allow up to 65535 cpus, while increasing only the size of
> recursive spinlocks in debug builds from 8 to 12 bytes.

I think we want to be more conservative here, for the case of there
being bugs: The CPU holding a lock may wrongly try to acquire it a
2nd time. That's the 65536th ticket then, wrapping the value.
Therefore my suggestion would be to only (mention) go(ing) up to 32k.

> Signed-off-by: Juergen Gross <jgross@suse.com>
> ---
>  xen/common/spinlock.c      |  1 +
>  xen/include/xen/spinlock.h | 18 +++++++++---------
>  2 files changed, 10 insertions(+), 9 deletions(-)

Shouldn't this also bump the upper bound of the NR_CPUS range then
in xen/arch/Kconfig?

Jan
Jürgen Groß Feb. 29, 2024, 4:29 p.m. UTC | #10
On 29.02.24 16:46, Jan Beulich wrote:
> On 12.12.2023 10:47, Juergen Gross wrote:
>> Allow 16 bits per cpu number, which is the limit imposed by
>> spinlock_tickets_t.
>>
>> This will allow up to 65535 cpus, while increasing only the size of
>> recursive spinlocks in debug builds from 8 to 12 bytes.
> 
> I think we want to be more conservative here, for the case of there
> being bugs: The CPU holding a lock may wrongly try to acquire it a
> 2nd time. That's the 65536th ticket then, wrapping the value.

Is this really a problem? There will be no other cpu left seeing the lock
as "free" in this case, as all others will be waiting for the head to reach
their private tail value.

> Therefore my suggestion would be to only (mention) go(ing) up to 32k.
> 
>> Signed-off-by: Juergen Gross <jgross@suse.com>
>> ---
>>   xen/common/spinlock.c      |  1 +
>>   xen/include/xen/spinlock.h | 18 +++++++++---------
>>   2 files changed, 10 insertions(+), 9 deletions(-)
> 
> Shouldn't this also bump the upper bound of the NR_CPUS range then
> in xen/arch/Kconfig?

Fine with me, I can add another patch to the series doing that.


Juergen
Jan Beulich Feb. 29, 2024, 4:31 p.m. UTC | #11
On 29.02.2024 17:29, Jürgen Groß wrote:
> On 29.02.24 16:46, Jan Beulich wrote:
>> On 12.12.2023 10:47, Juergen Gross wrote:
>>> Allow 16 bits per cpu number, which is the limit imposed by
>>> spinlock_tickets_t.
>>>
>>> This will allow up to 65535 cpus, while increasing only the size of
>>> recursive spinlocks in debug builds from 8 to 12 bytes.
>>
>> I think we want to be more conservative here, for the case of there
>> being bugs: The CPU holding a lock may wrongly try to acquire it a
>> 2nd time. That's the 65536th ticket then, wrapping the value.
> 
> Is this really a problem? There will be no other cpu left seeing the lock
> as "free" in this case, as all others will be waiting for the head to reach
> their private tail value.

But isn't said CPU then going to make progress, rather than indefinitely
spinning on the lock?

>> Therefore my suggestion would be to only (mention) go(ing) up to 32k.
>>
>>> Signed-off-by: Juergen Gross <jgross@suse.com>
>>> ---
>>>   xen/common/spinlock.c      |  1 +
>>>   xen/include/xen/spinlock.h | 18 +++++++++---------
>>>   2 files changed, 10 insertions(+), 9 deletions(-)
>>
>> Shouldn't this also bump the upper bound of the NR_CPUS range then
>> in xen/arch/Kconfig?
> 
> Fine with me, I can add another patch to the series doing that.

Why not do it right here? The upper bound there is like it is only
because of the restriction that's lifted here.

Jan
Jürgen Groß Feb. 29, 2024, 4:45 p.m. UTC | #12
On 29.02.24 17:31, Jan Beulich wrote:
> On 29.02.2024 17:29, Jürgen Groß wrote:
>> On 29.02.24 16:46, Jan Beulich wrote:
>>> On 12.12.2023 10:47, Juergen Gross wrote:
>>>> Allow 16 bits per cpu number, which is the limit imposed by
>>>> spinlock_tickets_t.
>>>>
>>>> This will allow up to 65535 cpus, while increasing only the size of
>>>> recursive spinlocks in debug builds from 8 to 12 bytes.
>>>
>>> I think we want to be more conservative here, for the case of there
>>> being bugs: The CPU holding a lock may wrongly try to acquire it a
>>> 2nd time. That's the 65536th ticket then, wrapping the value.
>>
>> Is this really a problem? There will be no other cpu left seeing the lock
>> as "free" in this case, as all others will be waiting for the head to reach
>> their private tail value.
> 
> But isn't said CPU then going to make progress, rather than indefinitely
> spinning on the lock?

No, I don't think so.

The limit isn't 65535 because of the ticket mechanism, but because of the
rspin mechanism, where we need a "no cpu is owning the lock" value. Without
the recursive locks the limit would be 65536 (or 4096 today).

> 
>>> Therefore my suggestion would be to only (mention) go(ing) up to 32k.
>>>
>>>> Signed-off-by: Juergen Gross <jgross@suse.com>
>>>> ---
>>>>    xen/common/spinlock.c      |  1 +
>>>>    xen/include/xen/spinlock.h | 18 +++++++++---------
>>>>    2 files changed, 10 insertions(+), 9 deletions(-)
>>>
>>> Shouldn't this also bump the upper bound of the NR_CPUS range then
>>> in xen/arch/Kconfig?
>>
>> Fine with me, I can add another patch to the series doing that.
> 
> Why not do it right here? The upper bound there is like it is only
> because of the restriction that's lifted here.

I'd prefer splitting the two instances, but if you prefer it to be in a
single patch, so be it.


Juergen
Jan Beulich Feb. 29, 2024, 4:54 p.m. UTC | #13
On 29.02.2024 17:45, Juergen Gross wrote:
> On 29.02.24 17:31, Jan Beulich wrote:
>> On 29.02.2024 17:29, Jürgen Groß wrote:
>>> On 29.02.24 16:46, Jan Beulich wrote:
>>>> On 12.12.2023 10:47, Juergen Gross wrote:
>>>>> Allow 16 bits per cpu number, which is the limit imposed by
>>>>> spinlock_tickets_t.
>>>>>
>>>>> This will allow up to 65535 cpus, while increasing only the size of
>>>>> recursive spinlocks in debug builds from 8 to 12 bytes.
>>>>
>>>> I think we want to be more conservative here, for the case of there
>>>> being bugs: The CPU holding a lock may wrongly try to acquire it a
>>>> 2nd time. That's the 65536th ticket then, wrapping the value.
>>>
>>> Is this really a problem? There will be no other cpu left seeing the lock
>>> as "free" in this case, as all others will be waiting for the head to reach
>>> their private tail value.
>>
>> But isn't said CPU then going to make progress, rather than indefinitely
>> spinning on the lock?
> 
> No, I don't think so.

Hmm. If CPU0 takes a pristine lock, it'll get ticket 0x0000. All other
CPUs will get tickets 0x0001 ... 0xffff. Then CPU0 trying to take the lock
again will get ticket 0x0000 again, which equals what .head still has (no
unlocks so far), thus signalling the lock to be free when it isn't.

> The limit isn't 65535 because of the ticket mechanism, but because of the
> rspin mechanism, where we need a "no cpu is owning the lock" value. Without
> the recursive locks the limit would be 65536 (or 4096 today).

I think this rather belongs ...

>>>> Therefore my suggestion would be to only (mention) go(ing) up to 32k.
>>>>
>>>>> Signed-off-by: Juergen Gross <jgross@suse.com>
>>>>> ---
>>>>>    xen/common/spinlock.c      |  1 +
>>>>>    xen/include/xen/spinlock.h | 18 +++++++++---------
>>>>>    2 files changed, 10 insertions(+), 9 deletions(-)
>>>>
>>>> Shouldn't this also bump the upper bound of the NR_CPUS range then
>>>> in xen/arch/Kconfig?
>>>
>>> Fine with me, I can add another patch to the series doing that.
>>
>> Why not do it right here? The upper bound there is like it is only
>> because of the restriction that's lifted here.

... here (for having nothing to do with the supposed lack of hanging
that I'm seeing)?

> I'd prefer splitting the two instances, but if you prefer it to be in a
> single patch, so be it.

I'm not going to insist - if want to do it separately, please do.
Perhaps others would actually prefer it that way ...

Jan
Jürgen Groß Feb. 29, 2024, 5:04 p.m. UTC | #14
On 29.02.24 17:54, Jan Beulich wrote:
> On 29.02.2024 17:45, Juergen Gross wrote:
>> On 29.02.24 17:31, Jan Beulich wrote:
>>> On 29.02.2024 17:29, Jürgen Groß wrote:
>>>> On 29.02.24 16:46, Jan Beulich wrote:
>>>>> On 12.12.2023 10:47, Juergen Gross wrote:
>>>>>> Allow 16 bits per cpu number, which is the limit imposed by
>>>>>> spinlock_tickets_t.
>>>>>>
>>>>>> This will allow up to 65535 cpus, while increasing only the size of
>>>>>> recursive spinlocks in debug builds from 8 to 12 bytes.
>>>>>
>>>>> I think we want to be more conservative here, for the case of there
>>>>> being bugs: The CPU holding a lock may wrongly try to acquire it a
>>>>> 2nd time. That's the 65536th ticket then, wrapping the value.
>>>>
>>>> Is this really a problem? There will be no other cpu left seeing the lock
>>>> as "free" in this case, as all others will be waiting for the head to reach
>>>> their private tail value.
>>>
>>> But isn't said CPU then going to make progress, rather than indefinitely
>>> spinning on the lock?
>>
>> No, I don't think so.
> 
> Hmm. If CPU0 takes a pristine lock, it'll get ticket 0x0000. All other
> CPUs will get tickets 0x0001 ... 0xffff. Then CPU0 trying to take the lock

No, they'll get 0x0001 ... 0xfffe (only 65535 cpus are supported).

> again will get ticket 0x0000 again, which equals what .head still has (no

And the first cpu will get 0xffff when trying to get the lock again.

> unlocks so far), thus signalling the lock to be free when it isn't.
> 
>> The limit isn't 65535 because of the ticket mechanism, but because of the
>> rspin mechanism, where we need a "no cpu is owning the lock" value. Without
>> the recursive locks the limit would be 65536 (or 4096 today).
> 
> I think this rather belongs ...

No, that was meant to tell you that without programming bug 65536 cpus would
be perfectly fine for the ticket mechanism, and with bug 65535 cpus are fine.

> 
>>>>> Therefore my suggestion would be to only (mention) go(ing) up to 32k.
>>>>>
>>>>>> Signed-off-by: Juergen Gross <jgross@suse.com>
>>>>>> ---
>>>>>>     xen/common/spinlock.c      |  1 +
>>>>>>     xen/include/xen/spinlock.h | 18 +++++++++---------
>>>>>>     2 files changed, 10 insertions(+), 9 deletions(-)
>>>>>
>>>>> Shouldn't this also bump the upper bound of the NR_CPUS range then
>>>>> in xen/arch/Kconfig?
>>>>
>>>> Fine with me, I can add another patch to the series doing that.
>>>
>>> Why not do it right here? The upper bound there is like it is only
>>> because of the restriction that's lifted here.
> 
> ... here (for having nothing to do with the supposed lack of hanging
> that I'm seeing)?
> 
>> I'd prefer splitting the two instances, but if you prefer it to be in a
>> single patch, so be it.
> 
> I'm not going to insist - if want to do it separately, please do.
> Perhaps others would actually prefer it that way ...

Okay. I'll do it in another patch.


Juergen
Jan Beulich Feb. 29, 2024, 5:07 p.m. UTC | #15
On 29.02.2024 18:04, Jürgen Groß wrote:
> On 29.02.24 17:54, Jan Beulich wrote:
>> On 29.02.2024 17:45, Juergen Gross wrote:
>>> On 29.02.24 17:31, Jan Beulich wrote:
>>>> On 29.02.2024 17:29, Jürgen Groß wrote:
>>>>> On 29.02.24 16:46, Jan Beulich wrote:
>>>>>> On 12.12.2023 10:47, Juergen Gross wrote:
>>>>>>> Allow 16 bits per cpu number, which is the limit imposed by
>>>>>>> spinlock_tickets_t.
>>>>>>>
>>>>>>> This will allow up to 65535 cpus, while increasing only the size of
>>>>>>> recursive spinlocks in debug builds from 8 to 12 bytes.
>>>>>>
>>>>>> I think we want to be more conservative here, for the case of there
>>>>>> being bugs: The CPU holding a lock may wrongly try to acquire it a
>>>>>> 2nd time. That's the 65536th ticket then, wrapping the value.
>>>>>
>>>>> Is this really a problem? There will be no other cpu left seeing the lock
>>>>> as "free" in this case, as all others will be waiting for the head to reach
>>>>> their private tail value.
>>>>
>>>> But isn't said CPU then going to make progress, rather than indefinitely
>>>> spinning on the lock?
>>>
>>> No, I don't think so.
>>
>> Hmm. If CPU0 takes a pristine lock, it'll get ticket 0x0000. All other
>> CPUs will get tickets 0x0001 ... 0xffff. Then CPU0 trying to take the lock
> 
> No, they'll get 0x0001 ... 0xfffe (only 65535 cpus are supported).
> 
>> again will get ticket 0x0000 again, which equals what .head still has (no
> 
> And the first cpu will get 0xffff when trying to get the lock again.

Oh, right. Still a little too close to the boundary for my taste ...

Jan
diff mbox series

Patch

diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
index 296bcf33e6..ae7c7c2086 100644
--- a/xen/common/spinlock.c
+++ b/xen/common/spinlock.c
@@ -481,6 +481,7 @@  int rspin_trylock(rspinlock_t *lock)
 
     /* Don't allow overflow of recurse_cpu field. */
     BUILD_BUG_ON(NR_CPUS > SPINLOCK_NO_CPU);
+    BUILD_BUG_ON(SPINLOCK_CPU_BITS > sizeof(lock->recurse_cpu) * 8);
     BUILD_BUG_ON(SPINLOCK_RECURSE_BITS < 3);
 
     check_lock(&lock->debug, true);
diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index 87946965b2..d720778cc1 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -7,16 +7,16 @@ 
 #include <asm/system.h>
 #include <asm/spinlock.h>
 
-#define SPINLOCK_CPU_BITS  12
+#define SPINLOCK_CPU_BITS  16
 
 #ifdef CONFIG_DEBUG_LOCKS
 union lock_debug {
-    uint16_t val;
-#define LOCK_DEBUG_INITVAL 0xffff
+    uint32_t val;
+#define LOCK_DEBUG_INITVAL 0xffffffff
     struct {
-        uint16_t cpu:SPINLOCK_CPU_BITS;
-#define LOCK_DEBUG_PAD_BITS (14 - SPINLOCK_CPU_BITS)
-        uint16_t :LOCK_DEBUG_PAD_BITS;
+        uint32_t cpu:SPINLOCK_CPU_BITS;
+#define LOCK_DEBUG_PAD_BITS (30 - SPINLOCK_CPU_BITS)
+        uint32_t :LOCK_DEBUG_PAD_BITS;
         bool irq_safe:1;
         bool unseen:1;
     };
@@ -210,10 +210,10 @@  typedef struct spinlock {
 
 typedef struct rspinlock {
     spinlock_tickets_t tickets;
-    uint16_t recurse_cpu:SPINLOCK_CPU_BITS;
+    uint16_t recurse_cpu;
 #define SPINLOCK_NO_CPU        ((1u << SPINLOCK_CPU_BITS) - 1)
-#define SPINLOCK_RECURSE_BITS  (16 - SPINLOCK_CPU_BITS)
-    uint16_t recurse_cnt:SPINLOCK_RECURSE_BITS;
+#define SPINLOCK_RECURSE_BITS  8
+    uint8_t recurse_cnt;
 #define SPINLOCK_MAX_RECURSE   ((1u << SPINLOCK_RECURSE_BITS) - 1)
     union lock_debug debug;
 #ifdef CONFIG_DEBUG_LOCK_PROFILE