All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type
@ 2023-12-12  9:47 Juergen Gross
  2023-12-12  9:47 ` [PATCH v4 01/12] xen/spinlock: reduce lock profile ifdefs Juergen Gross
                   ` (11 more replies)
  0 siblings, 12 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Andrew Cooper, George Dunlap, Jan Beulich,
	Julien Grall, Stefano Stabellini, Wei Liu, Roger Pau Monné,
	Paul Durrant, Bertrand Marquis, Michal Orzel, Volodymyr Babchuk,
	Tamas K Lengyel, Lukasz Hawrylko, Daniel P. Smith,
	Mateusz Mówka

Instead of being able to use normal spinlocks as recursive ones, too,
make recursive spinlocks a special lock type.

This will make the spinlock structure smaller in production builds and
add type-safety.

This allows to increase the maximum number of physical cpus from 8191
to 65535 without increasing the size of the lock structure in production
builds (the size of recursive spinlocks in debug builds will grow to
12 bytes due to that change).

Changes in V2:
- addressed comments by Jan Beulich
- lots of additional cleanups
- reorganized complete series

Changes in V3:
- addressed comments by Jan Beulich

Changes in V4:
- former patch 1 has already been applied
- fixed a coding style issue in patch 1

Juergen Gross (12):
  xen/spinlock: reduce lock profile ifdefs
  xen/spinlock: make spinlock initializers more readable
  xen/spinlock: introduce new type for recursive spinlocks
  xen/spinlock: rename recursive lock functions
  xen/spinlock: add rspin_[un]lock_irq[save|restore]()
  xen/spinlock: make struct lock_profile rspinlock_t aware
  xen/spinlock: add explicit non-recursive locking functions
  xen/spinlock: add another function level
  xen/spinlock: add missing rspin_is_locked() and rspin_barrier()
  xen/spinlock: split recursive spinlocks from normal ones
  xen/spinlock: remove indirection through macros for spin_*() functions
  xen/spinlock: support higher number of cpus

 xen/arch/arm/domain.c         |   4 +-
 xen/arch/arm/mm.c             |   4 +-
 xen/arch/x86/domain.c         |  20 +--
 xen/arch/x86/include/asm/mm.h |   2 +-
 xen/arch/x86/mm.c             |  12 +-
 xen/arch/x86/mm/mem_sharing.c |  16 +-
 xen/arch/x86/mm/mm-locks.h    |   6 +-
 xen/arch/x86/mm/p2m-pod.c     |   6 +-
 xen/arch/x86/mm/p2m.c         |   4 +-
 xen/arch/x86/tboot.c          |   4 +-
 xen/arch/x86/traps.c          |  14 +-
 xen/common/domain.c           |   6 +-
 xen/common/domctl.c           |   4 +-
 xen/common/grant_table.c      |  10 +-
 xen/common/ioreq.c            |  54 +++----
 xen/common/memory.c           |   4 +-
 xen/common/numa.c             |   4 +-
 xen/common/page_alloc.c       |  30 ++--
 xen/common/spinlock.c         | 284 ++++++++++++++++++++++++----------
 xen/drivers/char/console.c    |  48 ++----
 xen/drivers/passthrough/pci.c |   8 +-
 xen/include/xen/console.h     |   5 +-
 xen/include/xen/sched.h       |  10 +-
 xen/include/xen/spinlock.h    | 166 +++++++++++++-------
 24 files changed, 437 insertions(+), 288 deletions(-)

-- 
2.35.3



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

* [PATCH v4 01/12] xen/spinlock: reduce lock profile ifdefs
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2023-12-12 12:44   ` Julien Grall
  2023-12-12  9:47 ` [PATCH v4 02/12] xen/spinlock: make spinlock initializers more readable Juergen Gross
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Andrew Cooper, George Dunlap, Jan Beulich,
	Julien Grall, Stefano Stabellini, Wei Liu, Alejandro Vallejo

With some small adjustments to the LOCK_PROFILE_* macros some #ifdefs
can be dropped from spinlock.c.

Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
V2:
- new patch
V3:
- add variable name to macros parameter (Jan Beulich)
V4:
- fix coding style issue (Alejandro Vallejo)
---
 xen/common/spinlock.c | 49 +++++++++++++++++++------------------------
 1 file changed, 21 insertions(+), 28 deletions(-)

diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
index d5fa400b78..09028af864 100644
--- a/xen/common/spinlock.c
+++ b/xen/common/spinlock.c
@@ -267,25 +267,28 @@ void spin_debug_disable(void)
         lock->profile->time_hold += NOW() - lock->profile->time_locked;      \
         lock->profile->lock_cnt++;                                           \
     }
-#define LOCK_PROFILE_VAR    s_time_t block = 0
-#define LOCK_PROFILE_BLOCK  block = block ? : NOW();
-#define LOCK_PROFILE_GOT                                                     \
+#define LOCK_PROFILE_VAR(var, val)    s_time_t var = (val)
+#define LOCK_PROFILE_BLOCK(var)       var = var ? : NOW()
+#define LOCK_PROFILE_BLKACC(tst, val)                                        \
+    if ( tst )                                                               \
+    {                                                                        \
+        lock->profile->time_block += lock->profile->time_locked - (val);     \
+        lock->profile->block_cnt++;                                          \
+    }
+#define LOCK_PROFILE_GOT(val)                                                \
     if ( lock->profile )                                                     \
     {                                                                        \
         lock->profile->time_locked = NOW();                                  \
-        if ( block )                                                         \
-        {                                                                    \
-            lock->profile->time_block += lock->profile->time_locked - block; \
-            lock->profile->block_cnt++;                                      \
-        }                                                                    \
+        LOCK_PROFILE_BLKACC(val, val);                                       \
     }
 
 #else
 
 #define LOCK_PROFILE_REL
-#define LOCK_PROFILE_VAR
-#define LOCK_PROFILE_BLOCK
-#define LOCK_PROFILE_GOT
+#define LOCK_PROFILE_VAR(var, val)
+#define LOCK_PROFILE_BLOCK(var)
+#define LOCK_PROFILE_BLKACC(tst, val)
+#define LOCK_PROFILE_GOT(val)
 
 #endif
 
@@ -308,7 +311,7 @@ static void always_inline spin_lock_common(spinlock_t *lock,
                                            void (*cb)(void *data), void *data)
 {
     spinlock_tickets_t tickets = SPINLOCK_TICKET_INC;
-    LOCK_PROFILE_VAR;
+    LOCK_PROFILE_VAR(block, 0);
 
     check_lock(&lock->debug, false);
     preempt_disable();
@@ -316,14 +319,14 @@ static void always_inline spin_lock_common(spinlock_t *lock,
                                            tickets.head_tail);
     while ( tickets.tail != observe_head(&lock->tickets) )
     {
-        LOCK_PROFILE_BLOCK;
+        LOCK_PROFILE_BLOCK(block);
         if ( cb )
             cb(data);
         arch_lock_relax();
     }
     arch_lock_acquire_barrier();
     got_lock(&lock->debug);
-    LOCK_PROFILE_GOT;
+    LOCK_PROFILE_GOT(block);
 }
 
 void _spin_lock(spinlock_t *lock)
@@ -411,19 +414,15 @@ int _spin_trylock(spinlock_t *lock)
      * arch_lock_acquire_barrier().
      */
     got_lock(&lock->debug);
-#ifdef CONFIG_DEBUG_LOCK_PROFILE
-    if ( lock->profile )
-        lock->profile->time_locked = NOW();
-#endif
+    LOCK_PROFILE_GOT(0);
+
     return 1;
 }
 
 void _spin_barrier(spinlock_t *lock)
 {
     spinlock_tickets_t sample;
-#ifdef CONFIG_DEBUG_LOCK_PROFILE
-    s_time_t block = NOW();
-#endif
+    LOCK_PROFILE_VAR(block, NOW());
 
     check_barrier(&lock->debug);
     smp_mb();
@@ -432,13 +431,7 @@ void _spin_barrier(spinlock_t *lock)
     {
         while ( observe_head(&lock->tickets) == sample.head )
             arch_lock_relax();
-#ifdef CONFIG_DEBUG_LOCK_PROFILE
-        if ( lock->profile )
-        {
-            lock->profile->time_block += NOW() - block;
-            lock->profile->block_cnt++;
-        }
-#endif
+        LOCK_PROFILE_BLKACC(lock->profile, block);
     }
     smp_mb();
 }
-- 
2.35.3



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

* [PATCH v4 02/12] xen/spinlock: make spinlock initializers more readable
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
  2023-12-12  9:47 ` [PATCH v4 01/12] xen/spinlock: reduce lock profile ifdefs Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2023-12-12  9:47 ` [PATCH v4 03/12] xen/spinlock: introduce new type for recursive spinlocks Juergen Gross
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Andrew Cooper, George Dunlap, Jan Beulich,
	Julien Grall, Stefano Stabellini, Wei Liu

Use named member initializers instead of positional ones for the macros
used to initialize structures.

Signed-off-by: Juergen Gross <jgross@suse.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
---
V2:
- new patch
---
 xen/include/xen/spinlock.h | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index c44e7d4929..1cd9120eac 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -21,7 +21,7 @@ union lock_debug {
         bool unseen:1;
     };
 };
-#define _LOCK_DEBUG { LOCK_DEBUG_INITVAL }
+#define _LOCK_DEBUG { .val = LOCK_DEBUG_INITVAL }
 void check_lock(union lock_debug *debug, bool try);
 void lock_enter(const union lock_debug *debug);
 void lock_exit(const union lock_debug *debug);
@@ -94,12 +94,16 @@ struct lock_profile_qhead {
     int32_t                   idx;     /* index for printout */
 };
 
-#define _LOCK_PROFILE(name) { NULL, #name, &name, 0, 0, 0, 0, 0 }
+#define _LOCK_PROFILE(lockname) { .name = #lockname, .lock = &lockname, }
 #define _LOCK_PROFILE_PTR(name)                                               \
     static struct lock_profile * const __lock_profile_##name                  \
     __used_section(".lockprofile.data") =                                     \
     &__lock_profile_data_##name
-#define _SPIN_LOCK_UNLOCKED(x) { { 0 }, SPINLOCK_NO_CPU, 0, _LOCK_DEBUG, x }
+#define _SPIN_LOCK_UNLOCKED(x) {                                              \
+    .recurse_cpu = SPINLOCK_NO_CPU,                                           \
+    .debug =_LOCK_DEBUG,                                                      \
+    .profile = x,                                                             \
+}
 #define SPIN_LOCK_UNLOCKED _SPIN_LOCK_UNLOCKED(NULL)
 #define DEFINE_SPINLOCK(l)                                                    \
     spinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                 \
@@ -142,7 +146,10 @@ extern void cf_check spinlock_profile_reset(unsigned char key);
 
 struct lock_profile_qhead { };
 
-#define SPIN_LOCK_UNLOCKED { { 0 }, SPINLOCK_NO_CPU, 0, _LOCK_DEBUG }
+#define SPIN_LOCK_UNLOCKED {                                                  \
+    .recurse_cpu = SPINLOCK_NO_CPU,                                           \
+    .debug =_LOCK_DEBUG,                                                      \
+}
 #define DEFINE_SPINLOCK(l) spinlock_t l = SPIN_LOCK_UNLOCKED
 
 #define spin_lock_init_prof(s, l) spin_lock_init(&((s)->l))
-- 
2.35.3



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

* [PATCH v4 03/12] xen/spinlock: introduce new type for recursive spinlocks
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
  2023-12-12  9:47 ` [PATCH v4 01/12] xen/spinlock: reduce lock profile ifdefs Juergen Gross
  2023-12-12  9:47 ` [PATCH v4 02/12] xen/spinlock: make spinlock initializers more readable Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2023-12-12 12:57   ` Julien Grall
  2023-12-12  9:47 ` [PATCH v4 04/12] xen/spinlock: rename recursive lock functions Juergen Gross
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Jan Beulich, Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Julien Grall, Stefano Stabellini,
	Paul Durrant

Introduce a new type "rspinlock_t" to be used for recursive spinlocks.

For now it is only an alias of spinlock_t, so both types can still be
used for recursive spinlocks. This will be changed later, though.

Switch all recursive spinlocks to the new type.

Define the initializer helpers and use them where appropriate.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- carved out from V1 patch
---
 xen/arch/x86/include/asm/mm.h |  2 +-
 xen/arch/x86/mm/mm-locks.h    |  2 +-
 xen/common/domain.c           |  4 ++--
 xen/common/ioreq.c            |  2 +-
 xen/drivers/char/console.c    |  4 ++--
 xen/drivers/passthrough/pci.c |  2 +-
 xen/include/xen/sched.h       |  6 +++---
 xen/include/xen/spinlock.h    | 19 +++++++++++++++----
 8 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/xen/arch/x86/include/asm/mm.h b/xen/arch/x86/include/asm/mm.h
index 05dfe35502..8a6e0c283f 100644
--- a/xen/arch/x86/include/asm/mm.h
+++ b/xen/arch/x86/include/asm/mm.h
@@ -596,7 +596,7 @@ unsigned long domain_get_maximum_gpfn(struct domain *d);
 
 /* Definition of an mm lock: spinlock with extra fields for debugging */
 typedef struct mm_lock {
-    spinlock_t         lock;
+    rspinlock_t        lock;
     int                unlock_level;
     int                locker;          /* processor which holds the lock */
     const char        *locker_function; /* func that took it */
diff --git a/xen/arch/x86/mm/mm-locks.h b/xen/arch/x86/mm/mm-locks.h
index 00b1bc402d..b05cad1752 100644
--- a/xen/arch/x86/mm/mm-locks.h
+++ b/xen/arch/x86/mm/mm-locks.h
@@ -20,7 +20,7 @@ DECLARE_PERCPU_RWLOCK_GLOBAL(p2m_percpu_rwlock);
 
 static inline void mm_lock_init(mm_lock_t *l)
 {
-    spin_lock_init(&l->lock);
+    rspin_lock_init(&l->lock);
     l->locker = -1;
     l->locker_function = "nobody";
     l->unlock_level = 0;
diff --git a/xen/common/domain.c b/xen/common/domain.c
index c5954cdb1a..dc97755391 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -627,8 +627,8 @@ struct domain *domain_create(domid_t domid,
 
     atomic_set(&d->refcnt, 1);
     RCU_READ_LOCK_INIT(&d->rcu_lock);
-    spin_lock_init_prof(d, domain_lock);
-    spin_lock_init_prof(d, page_alloc_lock);
+    rspin_lock_init_prof(d, domain_lock);
+    rspin_lock_init_prof(d, page_alloc_lock);
     spin_lock_init(&d->hypercall_deadlock_mutex);
     INIT_PAGE_LIST_HEAD(&d->page_list);
     INIT_PAGE_LIST_HEAD(&d->extra_page_list);
diff --git a/xen/common/ioreq.c b/xen/common/ioreq.c
index 62b907f4c4..652c18a9b5 100644
--- a/xen/common/ioreq.c
+++ b/xen/common/ioreq.c
@@ -1331,7 +1331,7 @@ unsigned int ioreq_broadcast(ioreq_t *p, bool buffered)
 
 void ioreq_domain_init(struct domain *d)
 {
-    spin_lock_init(&d->ioreq_server.lock);
+    rspin_lock_init(&d->ioreq_server.lock);
 
     arch_ioreq_domain_init(d);
 }
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index 0666564ec9..76e455bacd 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -120,7 +120,7 @@ static int __read_mostly sercon_handle = -1;
 int8_t __read_mostly opt_console_xen; /* console=xen */
 #endif
 
-static DEFINE_SPINLOCK(console_lock);
+static DEFINE_RSPINLOCK(console_lock);
 
 /*
  * To control the amount of printing, thresholds are added.
@@ -1178,7 +1178,7 @@ void console_force_unlock(void)
 {
     watchdog_disable();
     spin_debug_disable();
-    spin_lock_init(&console_lock);
+    rspin_lock_init(&console_lock);
     serial_force_unlock(sercon_handle);
     console_locks_busted = 1;
     console_start_sync();
diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index 28ed8ea817..d604ed5634 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -50,7 +50,7 @@ struct pci_seg {
     } bus2bridge[MAX_BUSES];
 };
 
-static spinlock_t _pcidevs_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_RSPINLOCK(_pcidevs_lock);
 
 void pcidevs_lock(void)
 {
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 3609ef88c4..c6604aef78 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -376,9 +376,9 @@ struct domain
 
     rcu_read_lock_t  rcu_lock;
 
-    spinlock_t       domain_lock;
+    rspinlock_t      domain_lock;
 
-    spinlock_t       page_alloc_lock; /* protects all the following fields  */
+    rspinlock_t      page_alloc_lock; /* protects all the following fields  */
     struct page_list_head page_list;  /* linked list */
     struct page_list_head extra_page_list; /* linked list (size extra_pages) */
     struct page_list_head xenpage_list; /* linked list (size xenheap_pages) */
@@ -597,7 +597,7 @@ struct domain
 #ifdef CONFIG_IOREQ_SERVER
     /* Lock protects all other values in the sub-struct */
     struct {
-        spinlock_t              lock;
+        rspinlock_t             lock;
         struct ioreq_server     *server[MAX_NR_IOREQ_SERVERS];
     } ioreq_server;
 #endif
diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index 1cd9120eac..20d15f34dd 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -45,7 +45,7 @@ union lock_debug { };
     lock profiling on:
 
     Global locks which should be subject to profiling must be declared via
-    DEFINE_SPINLOCK.
+    DEFINE_[R]SPINLOCK.
 
     For locks in structures further measures are necessary:
     - the structure definition must include a profile_head with exactly this
@@ -56,7 +56,7 @@ union lock_debug { };
     - the single locks which are subject to profiling have to be initialized
       via
 
-      spin_lock_init_prof(ptr, lock);
+      [r]spin_lock_init_prof(ptr, lock);
 
       with ptr being the main structure pointer and lock the spinlock field
 
@@ -109,12 +109,16 @@ struct lock_profile_qhead {
     spinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                 \
     static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
     _LOCK_PROFILE_PTR(l)
+#define DEFINE_RSPINLOCK(l)                                                   \
+    rspinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                \
+    static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
+    _LOCK_PROFILE_PTR(l)
 
-#define spin_lock_init_prof(s, l)                                             \
+#define __spin_lock_init_prof(s, l, locktype)                                 \
     do {                                                                      \
         struct lock_profile *prof;                                            \
         prof = xzalloc(struct lock_profile);                                  \
-        (s)->l = (spinlock_t)_SPIN_LOCK_UNLOCKED(prof);                       \
+        (s)->l = (locktype)_SPIN_LOCK_UNLOCKED(prof);                         \
         if ( !prof )                                                          \
         {                                                                     \
             printk(XENLOG_WARNING                                             \
@@ -128,6 +132,9 @@ struct lock_profile_qhead {
         (s)->profile_head.elem_q = prof;                                      \
     } while( 0 )
 
+#define spin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, spinlock_t)
+#define rspin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, rspinlock_t)
+
 void _lock_profile_register_struct(
     int32_t type, struct lock_profile_qhead *qhead, int32_t idx);
 void _lock_profile_deregister_struct(int32_t type,
@@ -151,8 +158,10 @@ struct lock_profile_qhead { };
     .debug =_LOCK_DEBUG,                                                      \
 }
 #define DEFINE_SPINLOCK(l) spinlock_t l = SPIN_LOCK_UNLOCKED
+#define DEFINE_RSPINLOCK(l) rspinlock_t l = SPIN_LOCK_UNLOCKED
 
 #define spin_lock_init_prof(s, l) spin_lock_init(&((s)->l))
+#define rspin_lock_init_prof(s, l) rspin_lock_init(&((s)->l))
 #define lock_profile_register_struct(type, ptr, idx)
 #define lock_profile_deregister_struct(type, ptr)
 #define spinlock_profile_printall(key)
@@ -182,8 +191,10 @@ typedef struct spinlock {
 #endif
 } spinlock_t;
 
+typedef spinlock_t rspinlock_t;
 
 #define spin_lock_init(l) (*(l) = (spinlock_t)SPIN_LOCK_UNLOCKED)
+#define rspin_lock_init(l) (*(l) = (rspinlock_t)SPIN_LOCK_UNLOCKED)
 
 void _spin_lock(spinlock_t *lock);
 void _spin_lock_cb(spinlock_t *lock, void (*cb)(void *data), void *data);
-- 
2.35.3



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

* [PATCH v4 04/12] xen/spinlock: rename recursive lock functions
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
                   ` (2 preceding siblings ...)
  2023-12-12  9:47 ` [PATCH v4 03/12] xen/spinlock: introduce new type for recursive spinlocks Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2023-12-12 12:59   ` Julien Grall
  2024-02-28 14:59   ` Jan Beulich
  2023-12-12  9:47 ` [PATCH v4 05/12] xen/spinlock: add rspin_[un]lock_irq[save|restore]() Juergen Gross
                   ` (7 subsequent siblings)
  11 siblings, 2 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Stefano Stabellini, Julien Grall,
	Bertrand Marquis, Michal Orzel, Volodymyr Babchuk, Andrew Cooper,
	George Dunlap, Jan Beulich, Wei Liu, Roger Pau Monné,
	Tamas K Lengyel, Paul Durrant

Rename the recursive spin_lock() functions by replacing the trailing
"_recursive" with a leading "r".

Switch the parameter to be a pointer to rspinlock_t.

Remove the indirection through a macro, as it is adding only complexity
without any gain.

Suggested-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- new patch
---
 xen/arch/arm/domain.c         |  4 +--
 xen/arch/x86/domain.c         |  8 +++---
 xen/arch/x86/mm/mem_sharing.c |  8 +++---
 xen/arch/x86/mm/mm-locks.h    |  4 +--
 xen/common/ioreq.c            | 52 +++++++++++++++++------------------
 xen/common/page_alloc.c       | 12 ++++----
 xen/common/spinlock.c         |  6 ++--
 xen/drivers/char/console.c    | 12 ++++----
 xen/drivers/passthrough/pci.c |  4 +--
 xen/include/xen/sched.h       |  4 +--
 xen/include/xen/spinlock.h    | 24 +++++++---------
 11 files changed, 67 insertions(+), 71 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 5e7a7f3e7e..f38cb5e04c 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -987,7 +987,7 @@ static int relinquish_memory(struct domain *d, struct page_list_head *list)
     int               ret = 0;
 
     /* Use a recursive lock, as we may enter 'free_domheap_page'. */
-    spin_lock_recursive(&d->page_alloc_lock);
+    rspin_lock(&d->page_alloc_lock);
 
     page_list_for_each_safe( page, tmp, list )
     {
@@ -1014,7 +1014,7 @@ static int relinquish_memory(struct domain *d, struct page_list_head *list)
     }
 
   out:
-    spin_unlock_recursive(&d->page_alloc_lock);
+    rspin_unlock(&d->page_alloc_lock);
     return ret;
 }
 
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 3712e36df9..69ce1fd5cf 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -1321,7 +1321,7 @@ int arch_set_info_guest(
         {
             bool done = false;
 
-            spin_lock_recursive(&d->page_alloc_lock);
+            rspin_lock(&d->page_alloc_lock);
 
             for ( i = 0; ; )
             {
@@ -1342,7 +1342,7 @@ int arch_set_info_guest(
                     break;
             }
 
-            spin_unlock_recursive(&d->page_alloc_lock);
+            rspin_unlock(&d->page_alloc_lock);
 
             if ( !done )
                 return -ERESTART;
@@ -2181,7 +2181,7 @@ static int relinquish_memory(
     int               ret = 0;
 
     /* Use a recursive lock, as we may enter 'free_domheap_page'. */
-    spin_lock_recursive(&d->page_alloc_lock);
+    rspin_lock(&d->page_alloc_lock);
 
     while ( (page = page_list_remove_head(list)) )
     {
@@ -2322,7 +2322,7 @@ static int relinquish_memory(
     page_list_move(list, &d->arch.relmem_list);
 
  out:
-    spin_unlock_recursive(&d->page_alloc_lock);
+    rspin_unlock(&d->page_alloc_lock);
     return ret;
 }
 
diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index 4f810706a3..1720079fd9 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -688,7 +688,7 @@ static int page_make_sharable(struct domain *d,
     int rc = 0;
     bool drop_dom_ref = false;
 
-    spin_lock_recursive(&d->page_alloc_lock);
+    rspin_lock(&d->page_alloc_lock);
 
     if ( d->is_dying )
     {
@@ -731,7 +731,7 @@ static int page_make_sharable(struct domain *d,
     }
 
 out:
-    spin_unlock_recursive(&d->page_alloc_lock);
+    rspin_unlock(&d->page_alloc_lock);
 
     if ( drop_dom_ref )
         put_domain(d);
@@ -1942,7 +1942,7 @@ int mem_sharing_fork_reset(struct domain *d, bool reset_state,
         goto state;
 
     /* need recursive lock because we will free pages */
-    spin_lock_recursive(&d->page_alloc_lock);
+    rspin_lock(&d->page_alloc_lock);
     page_list_for_each_safe(page, tmp, &d->page_list)
     {
         shr_handle_t sh;
@@ -1971,7 +1971,7 @@ int mem_sharing_fork_reset(struct domain *d, bool reset_state,
         put_page_alloc_ref(page);
         put_page_and_type(page);
     }
-    spin_unlock_recursive(&d->page_alloc_lock);
+    rspin_unlock(&d->page_alloc_lock);
 
  state:
     if ( reset_state )
diff --git a/xen/arch/x86/mm/mm-locks.h b/xen/arch/x86/mm/mm-locks.h
index b05cad1752..c867ad7d53 100644
--- a/xen/arch/x86/mm/mm-locks.h
+++ b/xen/arch/x86/mm/mm-locks.h
@@ -79,7 +79,7 @@ static inline void _mm_lock(const struct domain *d, mm_lock_t *l,
 {
     if ( !((mm_locked_by_me(l)) && rec) )
         _check_lock_level(d, level);
-    spin_lock_recursive(&l->lock);
+    rspin_lock(&l->lock);
     if ( l->lock.recurse_cnt == 1 )
     {
         l->locker_function = func;
@@ -200,7 +200,7 @@ static inline void mm_unlock(mm_lock_t *l)
         l->locker_function = "nobody";
         _set_lock_level(l->unlock_level);
     }
-    spin_unlock_recursive(&l->lock);
+    rspin_unlock(&l->lock);
 }
 
 static inline void mm_enforce_order_unlock(int unlock_level,
diff --git a/xen/common/ioreq.c b/xen/common/ioreq.c
index 652c18a9b5..1257a3d972 100644
--- a/xen/common/ioreq.c
+++ b/xen/common/ioreq.c
@@ -329,7 +329,7 @@ bool is_ioreq_server_page(struct domain *d, const struct page_info *page)
     unsigned int id;
     bool found = false;
 
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     FOR_EACH_IOREQ_SERVER(d, id, s)
     {
@@ -340,7 +340,7 @@ bool is_ioreq_server_page(struct domain *d, const struct page_info *page)
         }
     }
 
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
 
     return found;
 }
@@ -658,7 +658,7 @@ static int ioreq_server_create(struct domain *d, int bufioreq_handling,
         return -ENOMEM;
 
     domain_pause(d);
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     for ( i = 0; i < MAX_NR_IOREQ_SERVERS; i++ )
     {
@@ -686,13 +686,13 @@ static int ioreq_server_create(struct domain *d, int bufioreq_handling,
     if ( id )
         *id = i;
 
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
     domain_unpause(d);
 
     return 0;
 
  fail:
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
     domain_unpause(d);
 
     xfree(s);
@@ -704,7 +704,7 @@ static int ioreq_server_destroy(struct domain *d, ioservid_t id)
     struct ioreq_server *s;
     int rc;
 
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     s = get_ioreq_server(d, id);
 
@@ -736,7 +736,7 @@ static int ioreq_server_destroy(struct domain *d, ioservid_t id)
     rc = 0;
 
  out:
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
 
     return rc;
 }
@@ -749,7 +749,7 @@ static int ioreq_server_get_info(struct domain *d, ioservid_t id,
     struct ioreq_server *s;
     int rc;
 
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     s = get_ioreq_server(d, id);
 
@@ -783,7 +783,7 @@ static int ioreq_server_get_info(struct domain *d, ioservid_t id,
     rc = 0;
 
  out:
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
 
     return rc;
 }
@@ -796,7 +796,7 @@ int ioreq_server_get_frame(struct domain *d, ioservid_t id,
 
     ASSERT(is_hvm_domain(d));
 
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     s = get_ioreq_server(d, id);
 
@@ -834,7 +834,7 @@ int ioreq_server_get_frame(struct domain *d, ioservid_t id,
     }
 
  out:
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
 
     return rc;
 }
@@ -850,7 +850,7 @@ static int ioreq_server_map_io_range(struct domain *d, ioservid_t id,
     if ( start > end )
         return -EINVAL;
 
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     s = get_ioreq_server(d, id);
 
@@ -886,7 +886,7 @@ static int ioreq_server_map_io_range(struct domain *d, ioservid_t id,
     rc = rangeset_add_range(r, start, end);
 
  out:
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
 
     return rc;
 }
@@ -902,7 +902,7 @@ static int ioreq_server_unmap_io_range(struct domain *d, ioservid_t id,
     if ( start > end )
         return -EINVAL;
 
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     s = get_ioreq_server(d, id);
 
@@ -938,7 +938,7 @@ static int ioreq_server_unmap_io_range(struct domain *d, ioservid_t id,
     rc = rangeset_remove_range(r, start, end);
 
  out:
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
 
     return rc;
 }
@@ -963,7 +963,7 @@ int ioreq_server_map_mem_type(struct domain *d, ioservid_t id,
     if ( flags & ~XEN_DMOP_IOREQ_MEM_ACCESS_WRITE )
         return -EINVAL;
 
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     s = get_ioreq_server(d, id);
 
@@ -978,7 +978,7 @@ int ioreq_server_map_mem_type(struct domain *d, ioservid_t id,
     rc = arch_ioreq_server_map_mem_type(d, s, flags);
 
  out:
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
 
     if ( rc == 0 )
         arch_ioreq_server_map_mem_type_completed(d, s, flags);
@@ -992,7 +992,7 @@ static int ioreq_server_set_state(struct domain *d, ioservid_t id,
     struct ioreq_server *s;
     int rc;
 
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     s = get_ioreq_server(d, id);
 
@@ -1016,7 +1016,7 @@ static int ioreq_server_set_state(struct domain *d, ioservid_t id,
     rc = 0;
 
  out:
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
     return rc;
 }
 
@@ -1026,7 +1026,7 @@ int ioreq_server_add_vcpu_all(struct domain *d, struct vcpu *v)
     unsigned int id;
     int rc;
 
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     FOR_EACH_IOREQ_SERVER(d, id, s)
     {
@@ -1035,7 +1035,7 @@ int ioreq_server_add_vcpu_all(struct domain *d, struct vcpu *v)
             goto fail;
     }
 
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
 
     return 0;
 
@@ -1050,7 +1050,7 @@ int ioreq_server_add_vcpu_all(struct domain *d, struct vcpu *v)
         ioreq_server_remove_vcpu(s, v);
     }
 
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
 
     return rc;
 }
@@ -1060,12 +1060,12 @@ void ioreq_server_remove_vcpu_all(struct domain *d, struct vcpu *v)
     struct ioreq_server *s;
     unsigned int id;
 
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     FOR_EACH_IOREQ_SERVER(d, id, s)
         ioreq_server_remove_vcpu(s, v);
 
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
 }
 
 void ioreq_server_destroy_all(struct domain *d)
@@ -1076,7 +1076,7 @@ void ioreq_server_destroy_all(struct domain *d)
     if ( !arch_ioreq_server_destroy_all(d) )
         return;
 
-    spin_lock_recursive(&d->ioreq_server.lock);
+    rspin_lock(&d->ioreq_server.lock);
 
     /* No need to domain_pause() as the domain is being torn down */
 
@@ -1094,7 +1094,7 @@ void ioreq_server_destroy_all(struct domain *d)
         xfree(s);
     }
 
-    spin_unlock_recursive(&d->ioreq_server.lock);
+    rspin_unlock(&d->ioreq_server.lock);
 }
 
 struct ioreq_server *ioreq_server_select(struct domain *d,
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 9b5df74fdd..8c6a3d9274 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -2497,7 +2497,7 @@ void free_domheap_pages(struct page_info *pg, unsigned int order)
     if ( unlikely(is_xen_heap_page(pg)) )
     {
         /* NB. May recursively lock from relinquish_memory(). */
-        spin_lock_recursive(&d->page_alloc_lock);
+        rspin_lock(&d->page_alloc_lock);
 
         for ( i = 0; i < (1 << order); i++ )
             arch_free_heap_page(d, &pg[i]);
@@ -2505,7 +2505,7 @@ void free_domheap_pages(struct page_info *pg, unsigned int order)
         d->xenheap_pages -= 1 << order;
         drop_dom_ref = (d->xenheap_pages == 0);
 
-        spin_unlock_recursive(&d->page_alloc_lock);
+        rspin_unlock(&d->page_alloc_lock);
     }
     else
     {
@@ -2514,7 +2514,7 @@ void free_domheap_pages(struct page_info *pg, unsigned int order)
         if ( likely(d) && likely(d != dom_cow) )
         {
             /* NB. May recursively lock from relinquish_memory(). */
-            spin_lock_recursive(&d->page_alloc_lock);
+            rspin_lock(&d->page_alloc_lock);
 
             for ( i = 0; i < (1 << order); i++ )
             {
@@ -2537,7 +2537,7 @@ void free_domheap_pages(struct page_info *pg, unsigned int order)
 
             drop_dom_ref = !domain_adjust_tot_pages(d, -(1 << order));
 
-            spin_unlock_recursive(&d->page_alloc_lock);
+            rspin_unlock(&d->page_alloc_lock);
 
             /*
              * Normally we expect a domain to clear pages before freeing them,
@@ -2753,7 +2753,7 @@ void free_domstatic_page(struct page_info *page)
     ASSERT_ALLOC_CONTEXT();
 
     /* NB. May recursively lock from relinquish_memory(). */
-    spin_lock_recursive(&d->page_alloc_lock);
+    rspin_lock(&d->page_alloc_lock);
 
     arch_free_heap_page(d, page);
 
@@ -2764,7 +2764,7 @@ void free_domstatic_page(struct page_info *page)
     /* Add page on the resv_page_list *after* it has been freed. */
     page_list_add_tail(page, &d->resv_page_list);
 
-    spin_unlock_recursive(&d->page_alloc_lock);
+    rspin_unlock(&d->page_alloc_lock);
 
     if ( drop_dom_ref )
         put_domain(d);
diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
index 09028af864..422a7fb1db 100644
--- a/xen/common/spinlock.c
+++ b/xen/common/spinlock.c
@@ -436,7 +436,7 @@ void _spin_barrier(spinlock_t *lock)
     smp_mb();
 }
 
-int _spin_trylock_recursive(spinlock_t *lock)
+int rspin_trylock(rspinlock_t *lock)
 {
     unsigned int cpu = smp_processor_id();
 
@@ -460,7 +460,7 @@ int _spin_trylock_recursive(spinlock_t *lock)
     return 1;
 }
 
-void _spin_lock_recursive(spinlock_t *lock)
+void rspin_lock(rspinlock_t *lock)
 {
     unsigned int cpu = smp_processor_id();
 
@@ -475,7 +475,7 @@ void _spin_lock_recursive(spinlock_t *lock)
     lock->recurse_cnt++;
 }
 
-void _spin_unlock_recursive(spinlock_t *lock)
+void rspin_unlock(rspinlock_t *lock)
 {
     if ( likely(--lock->recurse_cnt == 0) )
     {
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index 76e455bacd..f6f61dc5a1 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -920,7 +920,7 @@ static void vprintk_common(const char *prefix, const char *fmt, va_list args)
 
     /* console_lock can be acquired recursively from __printk_ratelimit(). */
     local_irq_save(flags);
-    spin_lock_recursive(&console_lock);
+    rspin_lock(&console_lock);
     state = &this_cpu(state);
 
     (void)vsnprintf(buf, sizeof(buf), fmt, args);
@@ -956,7 +956,7 @@ static void vprintk_common(const char *prefix, const char *fmt, va_list args)
         state->continued = 1;
     }
 
-    spin_unlock_recursive(&console_lock);
+    rspin_unlock(&console_lock);
     local_irq_restore(flags);
 }
 
@@ -1163,14 +1163,14 @@ unsigned long console_lock_recursive_irqsave(void)
     unsigned long flags;
 
     local_irq_save(flags);
-    spin_lock_recursive(&console_lock);
+    rspin_lock(&console_lock);
 
     return flags;
 }
 
 void console_unlock_recursive_irqrestore(unsigned long flags)
 {
-    spin_unlock_recursive(&console_lock);
+    rspin_unlock(&console_lock);
     local_irq_restore(flags);
 }
 
@@ -1231,12 +1231,12 @@ int __printk_ratelimit(int ratelimit_ms, int ratelimit_burst)
             char lost_str[8];
             snprintf(lost_str, sizeof(lost_str), "%d", lost);
             /* console_lock may already be acquired by printk(). */
-            spin_lock_recursive(&console_lock);
+            rspin_lock(&console_lock);
             printk_start_of_line("(XEN) ");
             __putstr("printk: ");
             __putstr(lost_str);
             __putstr(" messages suppressed.\n");
-            spin_unlock_recursive(&console_lock);
+            rspin_unlock(&console_lock);
         }
         local_irq_restore(flags);
         return 1;
diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index d604ed5634..41444f8e2e 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -54,12 +54,12 @@ static DEFINE_RSPINLOCK(_pcidevs_lock);
 
 void pcidevs_lock(void)
 {
-    spin_lock_recursive(&_pcidevs_lock);
+    rspin_lock(&_pcidevs_lock);
 }
 
 void pcidevs_unlock(void)
 {
-    spin_unlock_recursive(&_pcidevs_lock);
+    rspin_unlock(&_pcidevs_lock);
 }
 
 bool pcidevs_locked(void)
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index c6604aef78..8cf751ad0c 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -358,8 +358,8 @@ struct sched_unit {
           (v) = (v)->next_in_list )
 
 /* Per-domain lock can be recursively acquired in fault handlers. */
-#define domain_lock(d) spin_lock_recursive(&(d)->domain_lock)
-#define domain_unlock(d) spin_unlock_recursive(&(d)->domain_lock)
+#define domain_lock(d) rspin_lock(&(d)->domain_lock)
+#define domain_unlock(d) rspin_unlock(&(d)->domain_lock)
 
 struct evtchn_port_ops;
 
diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index 20d15f34dd..ee536c302c 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -209,9 +209,16 @@ int _spin_is_locked(const spinlock_t *lock);
 int _spin_trylock(spinlock_t *lock);
 void _spin_barrier(spinlock_t *lock);
 
-int _spin_trylock_recursive(spinlock_t *lock);
-void _spin_lock_recursive(spinlock_t *lock);
-void _spin_unlock_recursive(spinlock_t *lock);
+/*
+ * rspin_[un]lock(): Use these forms when the lock can (safely!) be
+ * reentered recursively on the same CPU. All critical regions that may form
+ * part of a recursively-nested set must be protected by these forms. If there
+ * are any critical regions that cannot form part of such a set, they can use
+ * standard spin_[un]lock().
+ */
+int rspin_trylock(rspinlock_t *lock);
+void rspin_lock(rspinlock_t *lock);
+void rspin_unlock(rspinlock_t *lock);
 
 #define spin_lock(l)                  _spin_lock(l)
 #define spin_lock_cb(l, c, d)         _spin_lock_cb(l, c, d)
@@ -241,15 +248,4 @@ void _spin_unlock_recursive(spinlock_t *lock);
 /* Ensure a lock is quiescent between two critical operations. */
 #define spin_barrier(l)               _spin_barrier(l)
 
-/*
- * spin_[un]lock_recursive(): Use these forms when the lock can (safely!) be
- * reentered recursively on the same CPU. All critical regions that may form
- * part of a recursively-nested set must be protected by these forms. If there
- * are any critical regions that cannot form part of such a set, they can use
- * standard spin_[un]lock().
- */
-#define spin_trylock_recursive(l)     _spin_trylock_recursive(l)
-#define spin_lock_recursive(l)        _spin_lock_recursive(l)
-#define spin_unlock_recursive(l)      _spin_unlock_recursive(l)
-
 #endif /* __SPINLOCK_H__ */
-- 
2.35.3



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

* [PATCH v4 05/12] xen/spinlock: add rspin_[un]lock_irq[save|restore]()
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
                   ` (3 preceding siblings ...)
  2023-12-12  9:47 ` [PATCH v4 04/12] xen/spinlock: rename recursive lock functions Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2023-12-12 13:03   ` Julien Grall
  2024-02-28 15:09   ` Jan Beulich
  2023-12-12  9:47 ` [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware Juergen Gross
                   ` (6 subsequent siblings)
  11 siblings, 2 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Jan Beulich, Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Julien Grall, Stefano Stabellini

Instead of special casing rspin_lock_irqsave() and
rspin_unlock_irqrestore() for the console lock, add those functions
to spinlock handling and use them where needed.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- new patch
---
 xen/arch/x86/traps.c       | 14 ++++++++------
 xen/common/spinlock.c      | 16 ++++++++++++++++
 xen/drivers/char/console.c | 18 +-----------------
 xen/include/xen/console.h  |  5 +++--
 xen/include/xen/spinlock.h |  7 +++++++
 5 files changed, 35 insertions(+), 25 deletions(-)

diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 7724306116..21227877b3 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -647,13 +647,15 @@ void show_stack_overflow(unsigned int cpu, const struct cpu_user_regs *regs)
 void show_execution_state(const struct cpu_user_regs *regs)
 {
     /* Prevent interleaving of output. */
-    unsigned long flags = console_lock_recursive_irqsave();
+    unsigned long flags;
+
+    rspin_lock_irqsave(&console_lock, flags);
 
     show_registers(regs);
     show_code(regs);
     show_stack(regs);
 
-    console_unlock_recursive_irqrestore(flags);
+    rspin_unlock_irqrestore(&console_lock, flags);
 }
 
 void cf_check show_execution_state_nonconst(struct cpu_user_regs *regs)
@@ -663,7 +665,7 @@ void cf_check show_execution_state_nonconst(struct cpu_user_regs *regs)
 
 void vcpu_show_execution_state(struct vcpu *v)
 {
-    unsigned long flags = 0;
+    unsigned long flags;
 
     if ( test_bit(_VPF_down, &v->pause_flags) )
     {
@@ -698,7 +700,7 @@ void vcpu_show_execution_state(struct vcpu *v)
 #endif
 
     /* Prevent interleaving of output. */
-    flags = console_lock_recursive_irqsave();
+    rspin_lock_irqsave(&console_lock, flags);
 
     vcpu_show_registers(v);
 
@@ -708,7 +710,7 @@ void vcpu_show_execution_state(struct vcpu *v)
          * Stop interleaving prevention: The necessary P2M lookups involve
          * locking, which has to occur with IRQs enabled.
          */
-        console_unlock_recursive_irqrestore(flags);
+        rspin_unlock_irqrestore(&console_lock, flags);
 
         show_hvm_stack(v, &v->arch.user_regs);
     }
@@ -717,7 +719,7 @@ void vcpu_show_execution_state(struct vcpu *v)
         if ( guest_kernel_mode(v, &v->arch.user_regs) )
             show_guest_stack(v, &v->arch.user_regs);
 
-        console_unlock_recursive_irqrestore(flags);
+        rspin_unlock_irqrestore(&console_lock, flags);
     }
 
 #ifdef CONFIG_HVM
diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
index 422a7fb1db..c1a9ba1304 100644
--- a/xen/common/spinlock.c
+++ b/xen/common/spinlock.c
@@ -475,6 +475,16 @@ void rspin_lock(rspinlock_t *lock)
     lock->recurse_cnt++;
 }
 
+unsigned long __rspin_lock_irqsave(rspinlock_t *lock)
+{
+    unsigned long flags;
+
+    local_irq_save(flags);
+    rspin_lock(lock);
+
+    return flags;
+}
+
 void rspin_unlock(rspinlock_t *lock)
 {
     if ( likely(--lock->recurse_cnt == 0) )
@@ -484,6 +494,12 @@ void rspin_unlock(rspinlock_t *lock)
     }
 }
 
+void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags)
+{
+    rspin_unlock(lock);
+    local_irq_restore(flags);
+}
+
 #ifdef CONFIG_DEBUG_LOCK_PROFILE
 
 struct lock_profile_anc {
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index f6f61dc5a1..1db2bbdb6a 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -120,7 +120,7 @@ static int __read_mostly sercon_handle = -1;
 int8_t __read_mostly opt_console_xen; /* console=xen */
 #endif
 
-static DEFINE_RSPINLOCK(console_lock);
+DEFINE_RSPINLOCK(console_lock);
 
 /*
  * To control the amount of printing, thresholds are added.
@@ -1158,22 +1158,6 @@ void console_end_log_everything(void)
     atomic_dec(&print_everything);
 }
 
-unsigned long console_lock_recursive_irqsave(void)
-{
-    unsigned long flags;
-
-    local_irq_save(flags);
-    rspin_lock(&console_lock);
-
-    return flags;
-}
-
-void console_unlock_recursive_irqrestore(unsigned long flags)
-{
-    rspin_unlock(&console_lock);
-    local_irq_restore(flags);
-}
-
 void console_force_unlock(void)
 {
     watchdog_disable();
diff --git a/xen/include/xen/console.h b/xen/include/xen/console.h
index 68759862e8..583c38f064 100644
--- a/xen/include/xen/console.h
+++ b/xen/include/xen/console.h
@@ -8,8 +8,11 @@
 #define __CONSOLE_H__
 
 #include <xen/inttypes.h>
+#include <xen/spinlock.h>
 #include <public/xen.h>
 
+extern rspinlock_t console_lock;
+
 struct xen_sysctl_readconsole;
 long read_console_ring(struct xen_sysctl_readconsole *op);
 
@@ -20,8 +23,6 @@ void console_init_postirq(void);
 void console_endboot(void);
 int console_has(const char *device);
 
-unsigned long console_lock_recursive_irqsave(void);
-void console_unlock_recursive_irqrestore(unsigned long flags);
 void console_force_unlock(void);
 
 void console_start_sync(void);
diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index ee536c302c..05b97c1e03 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -218,7 +218,14 @@ void _spin_barrier(spinlock_t *lock);
  */
 int rspin_trylock(rspinlock_t *lock);
 void rspin_lock(rspinlock_t *lock);
+#define rspin_lock_irqsave(l, f)                                \
+    ({                                                          \
+        BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long));       \
+        ((f) = __rspin_lock_irqsave(l));                        \
+    })
+unsigned long __rspin_lock_irqsave(rspinlock_t *lock);
 void rspin_unlock(rspinlock_t *lock);
+void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags);
 
 #define spin_lock(l)                  _spin_lock(l)
 #define spin_lock_cb(l, c, d)         _spin_lock_cb(l, c, d)
-- 
2.35.3



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

* [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
                   ` (4 preceding siblings ...)
  2023-12-12  9:47 ` [PATCH v4 05/12] xen/spinlock: add rspin_[un]lock_irq[save|restore]() Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2023-12-12 18:42   ` Julien Grall
  2024-02-28 15:19   ` Jan Beulich
  2023-12-12  9:47 ` [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions Juergen Gross
                   ` (5 subsequent siblings)
  11 siblings, 2 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Andrew Cooper, George Dunlap, Jan Beulich,
	Julien Grall, Stefano Stabellini, Wei Liu, Alejandro Vallejo

Struct lock_profile contains a pointer to the spinlock it is associated
with. Prepare support of differing spinlock_t and rspinlock_t types by
adding a type indicator of the pointer. Use the highest bit of the
block_cnt member for this indicator in order to not grow the struct
while hurting only the slow path with slightly less performant code.

Signed-off-by: Juergen Gross <jgross@suse.com>
Acked-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
---
V2:
- new patch
---
 xen/common/spinlock.c      | 26 +++++++++++++++++++-------
 xen/include/xen/spinlock.h | 10 ++++++++--
 2 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
index c1a9ba1304..7d611d3d7d 100644
--- a/xen/common/spinlock.c
+++ b/xen/common/spinlock.c
@@ -538,19 +538,31 @@ static void spinlock_profile_iterate(lock_profile_subfunc *sub, void *par)
 static void cf_check spinlock_profile_print_elem(struct lock_profile *data,
     int32_t type, int32_t idx, void *par)
 {
-    struct spinlock *lock = data->lock;
+    unsigned int cpu;
+    uint32_t lockval;
+
+    if ( data->is_rlock )
+    {
+        cpu = data->rlock->debug.cpu;
+        lockval = data->rlock->tickets.head_tail;
+    }
+    else
+    {
+        cpu = data->lock->debug.cpu;
+        lockval = data->lock->tickets.head_tail;
+    }
 
     printk("%s ", lock_profile_ancs[type].name);
     if ( type != LOCKPROF_TYPE_GLOBAL )
         printk("%d ", idx);
-    printk("%s: addr=%p, lockval=%08x, ", data->name, lock,
-           lock->tickets.head_tail);
-    if ( lock->debug.cpu == SPINLOCK_NO_CPU )
+    printk("%s: addr=%p, lockval=%08x, ", data->name, data->lock, lockval);
+    if ( cpu == SPINLOCK_NO_CPU )
         printk("not locked\n");
     else
-        printk("cpu=%d\n", lock->debug.cpu);
-    printk("  lock:%" PRId64 "(%" PRI_stime "), block:%" PRId64 "(%" PRI_stime ")\n",
-           data->lock_cnt, data->time_hold, data->block_cnt, data->time_block);
+        printk("cpu=%u\n", cpu);
+    printk("  lock:%" PRIu64 "(%" PRI_stime "), block:%" PRIu64 "(%" PRI_stime ")\n",
+           data->lock_cnt, data->time_hold, (uint64_t)data->block_cnt,
+           data->time_block);
 }
 
 void cf_check spinlock_profile_printall(unsigned char key)
diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index 05b97c1e03..ac3bef267a 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -76,13 +76,19 @@ union lock_debug { };
 */
 
 struct spinlock;
+/* Temporary hack until a dedicated struct rspinlock is existing. */
+#define rspinlock spinlock
 
 struct lock_profile {
     struct lock_profile *next;       /* forward link */
     const char          *name;       /* lock name */
-    struct spinlock     *lock;       /* the lock itself */
+    union {
+        struct spinlock *lock;       /* the lock itself */
+        struct rspinlock *rlock;     /* the recursive lock itself */
+    };
     uint64_t            lock_cnt;    /* # of complete locking ops */
-    uint64_t            block_cnt;   /* # of complete wait for lock */
+    uint64_t            block_cnt:63; /* # of complete wait for lock */
+    uint64_t            is_rlock:1;  /* use rlock pointer */
     s_time_t            time_hold;   /* cumulated lock time */
     s_time_t            time_block;  /* cumulated wait time */
     s_time_t            time_locked; /* system time of last locking */
-- 
2.35.3



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

* [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
                   ` (5 preceding siblings ...)
  2023-12-12  9:47 ` [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2023-12-12 18:49   ` Julien Grall
  2024-02-29 13:49   ` Jan Beulich
  2023-12-12  9:47 ` [PATCH v4 08/12] xen/spinlock: add another function level Juergen Gross
                   ` (4 subsequent siblings)
  11 siblings, 2 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Stefano Stabellini, Julien Grall,
	Bertrand Marquis, Michal Orzel, Volodymyr Babchuk, Andrew Cooper,
	George Dunlap, Jan Beulich, Wei Liu, Roger Pau Monné,
	Tamas K Lengyel, Lukasz Hawrylko, Daniel P. Smith,
	Mateusz Mówka

In order to prepare a type-safe recursive spinlock structure, add
explicitly non-recursive locking functions to be used for non-recursive
locking of spinlocks, which are used recursively, too.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- rename functions (Jan Beulich)
- get rid of !! in pcidevs_locked() (Jan Beulich)
---
 xen/arch/arm/mm.c             |  4 ++--
 xen/arch/x86/domain.c         | 12 ++++++------
 xen/arch/x86/mm.c             | 12 ++++++------
 xen/arch/x86/mm/mem_sharing.c |  8 ++++----
 xen/arch/x86/mm/p2m-pod.c     |  4 ++--
 xen/arch/x86/mm/p2m.c         |  4 ++--
 xen/arch/x86/tboot.c          |  4 ++--
 xen/common/domctl.c           |  4 ++--
 xen/common/grant_table.c      | 10 +++++-----
 xen/common/memory.c           |  4 ++--
 xen/common/numa.c             |  4 ++--
 xen/common/page_alloc.c       | 16 ++++++++--------
 xen/drivers/char/console.c    | 16 ++++++++--------
 xen/include/xen/spinlock.h    | 24 +++++++++++++++++++-----
 14 files changed, 70 insertions(+), 56 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index eeb65ca6bb..7466d12b0c 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -105,7 +105,7 @@ void share_xen_page_with_guest(struct page_info *page, struct domain *d,
     if ( page_get_owner(page) == d )
         return;
 
-    spin_lock(&d->page_alloc_lock);
+    nrspin_lock(&d->page_alloc_lock);
 
     /*
      * The incremented type count pins as writable or read-only.
@@ -136,7 +136,7 @@ void share_xen_page_with_guest(struct page_info *page, struct domain *d,
         page_list_add_tail(page, &d->xenpage_list);
     }
 
-    spin_unlock(&d->page_alloc_lock);
+    nrspin_unlock(&d->page_alloc_lock);
 }
 
 int xenmem_add_to_physmap_one(
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 69ce1fd5cf..998cb53a58 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -212,7 +212,7 @@ void dump_pageframe_info(struct domain *d)
     {
         unsigned long total[MASK_EXTR(PGT_type_mask, PGT_type_mask) + 1] = {};
 
-        spin_lock(&d->page_alloc_lock);
+        nrspin_lock(&d->page_alloc_lock);
         page_list_for_each ( page, &d->page_list )
         {
             unsigned int index = MASK_EXTR(page->u.inuse.type_info,
@@ -231,13 +231,13 @@ void dump_pageframe_info(struct domain *d)
                    _p(mfn_x(page_to_mfn(page))),
                    page->count_info, page->u.inuse.type_info);
         }
-        spin_unlock(&d->page_alloc_lock);
+        nrspin_unlock(&d->page_alloc_lock);
     }
 
     if ( is_hvm_domain(d) )
         p2m_pod_dump_data(d);
 
-    spin_lock(&d->page_alloc_lock);
+    nrspin_lock(&d->page_alloc_lock);
 
     page_list_for_each ( page, &d->xenpage_list )
     {
@@ -253,7 +253,7 @@ void dump_pageframe_info(struct domain *d)
                page->count_info, page->u.inuse.type_info);
     }
 
-    spin_unlock(&d->page_alloc_lock);
+    nrspin_unlock(&d->page_alloc_lock);
 }
 
 void update_guest_memory_policy(struct vcpu *v,
@@ -2446,10 +2446,10 @@ int domain_relinquish_resources(struct domain *d)
             d->arch.auto_unmask = 0;
         }
 
-        spin_lock(&d->page_alloc_lock);
+        nrspin_lock(&d->page_alloc_lock);
         page_list_splice(&d->arch.relmem_list, &d->page_list);
         INIT_PAGE_LIST_HEAD(&d->arch.relmem_list);
-        spin_unlock(&d->page_alloc_lock);
+        nrspin_unlock(&d->page_alloc_lock);
 
     PROGRESS(xen):
 
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 0a66db10b9..c35a68fbd5 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -482,7 +482,7 @@ void share_xen_page_with_guest(struct page_info *page, struct domain *d,
 
     set_gpfn_from_mfn(mfn_x(page_to_mfn(page)), INVALID_M2P_ENTRY);
 
-    spin_lock(&d->page_alloc_lock);
+    nrspin_lock(&d->page_alloc_lock);
 
     /* The incremented type count pins as writable or read-only. */
     page->u.inuse.type_info =
@@ -502,7 +502,7 @@ void share_xen_page_with_guest(struct page_info *page, struct domain *d,
         page_list_add_tail(page, &d->xenpage_list);
     }
 
-    spin_unlock(&d->page_alloc_lock);
+    nrspin_unlock(&d->page_alloc_lock);
 }
 
 void make_cr3(struct vcpu *v, mfn_t mfn)
@@ -3584,11 +3584,11 @@ long do_mmuext_op(
             {
                 bool drop_ref;
 
-                spin_lock(&pg_owner->page_alloc_lock);
+                nrspin_lock(&pg_owner->page_alloc_lock);
                 drop_ref = (pg_owner->is_dying &&
                             test_and_clear_bit(_PGT_pinned,
                                                &page->u.inuse.type_info));
-                spin_unlock(&pg_owner->page_alloc_lock);
+                nrspin_unlock(&pg_owner->page_alloc_lock);
                 if ( drop_ref )
                 {
         pin_drop:
@@ -4411,7 +4411,7 @@ int steal_page(
      * that it might be upon return from alloc_domheap_pages with
      * MEMF_no_owner set.
      */
-    spin_lock(&d->page_alloc_lock);
+    nrspin_lock(&d->page_alloc_lock);
 
     BUG_ON(page->u.inuse.type_info & (PGT_count_mask | PGT_locked |
                                       PGT_pinned));
@@ -4423,7 +4423,7 @@ int steal_page(
     if ( !(memflags & MEMF_no_refcount) && !domain_adjust_tot_pages(d, -1) )
         drop_dom_ref = true;
 
-    spin_unlock(&d->page_alloc_lock);
+    nrspin_unlock(&d->page_alloc_lock);
 
     if ( unlikely(drop_dom_ref) )
         put_domain(d);
diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index 1720079fd9..fa4e56a4df 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -746,11 +746,11 @@ static int page_make_private(struct domain *d, struct page_info *page)
     if ( !get_page(page, dom_cow) )
         return -EINVAL;
 
-    spin_lock(&d->page_alloc_lock);
+    nrspin_lock(&d->page_alloc_lock);
 
     if ( d->is_dying )
     {
-        spin_unlock(&d->page_alloc_lock);
+        nrspin_unlock(&d->page_alloc_lock);
         put_page(page);
         return -EBUSY;
     }
@@ -758,7 +758,7 @@ static int page_make_private(struct domain *d, struct page_info *page)
     expected_type = (PGT_shared_page | PGT_validated | PGT_locked | 2);
     if ( page->u.inuse.type_info != expected_type )
     {
-        spin_unlock(&d->page_alloc_lock);
+        nrspin_unlock(&d->page_alloc_lock);
         put_page(page);
         return -EEXIST;
     }
@@ -775,7 +775,7 @@ static int page_make_private(struct domain *d, struct page_info *page)
     if ( domain_adjust_tot_pages(d, 1) == 1 )
         get_knownalive_domain(d);
     page_list_add_tail(page, &d->page_list);
-    spin_unlock(&d->page_alloc_lock);
+    nrspin_unlock(&d->page_alloc_lock);
 
     put_page(page);
 
diff --git a/xen/arch/x86/mm/p2m-pod.c b/xen/arch/x86/mm/p2m-pod.c
index 9e5ad68df2..61a91f5a94 100644
--- a/xen/arch/x86/mm/p2m-pod.c
+++ b/xen/arch/x86/mm/p2m-pod.c
@@ -27,7 +27,7 @@
 static inline void lock_page_alloc(struct p2m_domain *p2m)
 {
     page_alloc_mm_pre_lock(p2m->domain);
-    spin_lock(&(p2m->domain->page_alloc_lock));
+    nrspin_lock(&(p2m->domain->page_alloc_lock));
     page_alloc_mm_post_lock(p2m->domain,
                             p2m->domain->arch.page_alloc_unlock_level);
 }
@@ -35,7 +35,7 @@ static inline void lock_page_alloc(struct p2m_domain *p2m)
 static inline void unlock_page_alloc(struct p2m_domain *p2m)
 {
     page_alloc_mm_unlock(p2m->domain->arch.page_alloc_unlock_level);
-    spin_unlock(&(p2m->domain->page_alloc_lock));
+    nrspin_unlock(&(p2m->domain->page_alloc_lock));
 }
 
 /*
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 6eb446e437..f188f09b8e 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -2226,7 +2226,7 @@ void audit_p2m(struct domain *d,
 
     /* Audit part two: walk the domain's page allocation list, checking
      * the m2p entries. */
-    spin_lock(&d->page_alloc_lock);
+    nrspin_lock(&d->page_alloc_lock);
     page_list_for_each ( page, &d->page_list )
     {
         mfn = mfn_x(page_to_mfn(page));
@@ -2278,7 +2278,7 @@ void audit_p2m(struct domain *d,
         P2M_PRINTK("OK: mfn=%#lx, gfn=%#lx, p2mfn=%#lx\n",
                        mfn, gfn, mfn_x(p2mfn));
     }
-    spin_unlock(&d->page_alloc_lock);
+    nrspin_unlock(&d->page_alloc_lock);
 
     pod_unlock(p2m);
     p2m_unlock(p2m);
diff --git a/xen/arch/x86/tboot.c b/xen/arch/x86/tboot.c
index 86c4c22cac..5b33a1bf9d 100644
--- a/xen/arch/x86/tboot.c
+++ b/xen/arch/x86/tboot.c
@@ -205,14 +205,14 @@ static void tboot_gen_domain_integrity(const uint8_t key[TB_KEY_SIZE],
             continue;
         printk("MACing Domain %u\n", d->domain_id);
 
-        spin_lock(&d->page_alloc_lock);
+        nrspin_lock(&d->page_alloc_lock);
         page_list_for_each(page, &d->page_list)
         {
             void *pg = __map_domain_page(page);
             vmac_update(pg, PAGE_SIZE, &ctx);
             unmap_domain_page(pg);
         }
-        spin_unlock(&d->page_alloc_lock);
+        nrspin_unlock(&d->page_alloc_lock);
 
         if ( is_iommu_enabled(d) && is_vtd )
         {
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index f5a71ee5f7..cb62b18a9d 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -621,14 +621,14 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
     {
         uint64_t new_max = op->u.max_mem.max_memkb >> (PAGE_SHIFT - 10);
 
-        spin_lock(&d->page_alloc_lock);
+        nrspin_lock(&d->page_alloc_lock);
         /*
          * NB. We removed a check that new_max >= current tot_pages; this means
          * that the domain will now be allowed to "ratchet" down to new_max. In
          * the meantime, while tot > max, all new allocations are disallowed.
          */
         d->max_pages = min(new_max, (uint64_t)(typeof(d->max_pages))-1);
-        spin_unlock(&d->page_alloc_lock);
+        nrspin_unlock(&d->page_alloc_lock);
         break;
     }
 
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 5721eab225..54163d51ea 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -2376,7 +2376,7 @@ gnttab_transfer(
             mfn = page_to_mfn(page);
         }
 
-        spin_lock(&e->page_alloc_lock);
+        nrspin_lock(&e->page_alloc_lock);
 
         /*
          * Check that 'e' will accept the page and has reservation
@@ -2387,7 +2387,7 @@ gnttab_transfer(
              unlikely(domain_tot_pages(e) >= e->max_pages) ||
              unlikely(!(e->tot_pages + 1)) )
         {
-            spin_unlock(&e->page_alloc_lock);
+            nrspin_unlock(&e->page_alloc_lock);
 
             if ( e->is_dying )
                 gdprintk(XENLOG_INFO, "Transferee d%d is dying\n",
@@ -2411,7 +2411,7 @@ gnttab_transfer(
          * safely drop the lock and re-aquire it later to add page to the
          * pagelist.
          */
-        spin_unlock(&e->page_alloc_lock);
+        nrspin_unlock(&e->page_alloc_lock);
         okay = gnttab_prepare_for_transfer(e, d, gop.ref);
 
         /*
@@ -2427,9 +2427,9 @@ gnttab_transfer(
              * Need to grab this again to safely free our "reserved"
              * page in the page total
              */
-            spin_lock(&e->page_alloc_lock);
+            nrspin_lock(&e->page_alloc_lock);
             drop_dom_ref = !domain_adjust_tot_pages(e, -1);
-            spin_unlock(&e->page_alloc_lock);
+            nrspin_unlock(&e->page_alloc_lock);
 
             if ( okay /* i.e. e->is_dying due to the surrounding if() */ )
                 gdprintk(XENLOG_INFO, "Transferee d%d is now dying\n",
diff --git a/xen/common/memory.c b/xen/common/memory.c
index b3b05c2ec0..b4593f5f45 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -770,10 +770,10 @@ static long memory_exchange(XEN_GUEST_HANDLE_PARAM(xen_memory_exchange_t) arg)
                               (1UL << in_chunk_order)) -
                              (j * (1UL << exch.out.extent_order)));
 
-                spin_lock(&d->page_alloc_lock);
+                nrspin_lock(&d->page_alloc_lock);
                 drop_dom_ref = (dec_count &&
                                 !domain_adjust_tot_pages(d, -dec_count));
-                spin_unlock(&d->page_alloc_lock);
+                nrspin_unlock(&d->page_alloc_lock);
 
                 if ( drop_dom_ref )
                     put_domain(d);
diff --git a/xen/common/numa.c b/xen/common/numa.c
index f454c4d894..47b1d0b5a8 100644
--- a/xen/common/numa.c
+++ b/xen/common/numa.c
@@ -718,13 +718,13 @@ static void cf_check dump_numa(unsigned char key)
 
         memset(page_num_node, 0, sizeof(page_num_node));
 
-        spin_lock(&d->page_alloc_lock);
+        nrspin_lock(&d->page_alloc_lock);
         page_list_for_each ( page, &d->page_list )
         {
             i = page_to_nid(page);
             page_num_node[i]++;
         }
-        spin_unlock(&d->page_alloc_lock);
+        nrspin_unlock(&d->page_alloc_lock);
 
         for_each_online_node ( i )
             printk("    Node %u: %u\n", i, page_num_node[i]);
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 8c6a3d9274..a25c00a7d4 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -515,7 +515,7 @@ int domain_set_outstanding_pages(struct domain *d, unsigned long pages)
      * must always take the global heap_lock rather than only in the much
      * rarer case that d->outstanding_pages is non-zero
      */
-    spin_lock(&d->page_alloc_lock);
+    nrspin_lock(&d->page_alloc_lock);
     spin_lock(&heap_lock);
 
     /* pages==0 means "unset" the claim. */
@@ -561,7 +561,7 @@ int domain_set_outstanding_pages(struct domain *d, unsigned long pages)
 
 out:
     spin_unlock(&heap_lock);
-    spin_unlock(&d->page_alloc_lock);
+    nrspin_unlock(&d->page_alloc_lock);
     return ret;
 }
 
@@ -2343,7 +2343,7 @@ int assign_pages(
     int rc = 0;
     unsigned int i;
 
-    spin_lock(&d->page_alloc_lock);
+    nrspin_lock(&d->page_alloc_lock);
 
     if ( unlikely(d->is_dying) )
     {
@@ -2425,7 +2425,7 @@ int assign_pages(
     }
 
  out:
-    spin_unlock(&d->page_alloc_lock);
+    nrspin_unlock(&d->page_alloc_lock);
     return rc;
 }
 
@@ -2906,9 +2906,9 @@ mfn_t acquire_reserved_page(struct domain *d, unsigned int memflags)
     ASSERT_ALLOC_CONTEXT();
 
     /* Acquire a page from reserved page list(resv_page_list). */
-    spin_lock(&d->page_alloc_lock);
+    nrspin_lock(&d->page_alloc_lock);
     page = page_list_remove_head(&d->resv_page_list);
-    spin_unlock(&d->page_alloc_lock);
+    nrspin_unlock(&d->page_alloc_lock);
     if ( unlikely(!page) )
         return INVALID_MFN;
 
@@ -2927,9 +2927,9 @@ mfn_t acquire_reserved_page(struct domain *d, unsigned int memflags)
      */
     unprepare_staticmem_pages(page, 1, false);
  fail:
-    spin_lock(&d->page_alloc_lock);
+    nrspin_lock(&d->page_alloc_lock);
     page_list_add_tail(page, &d->resv_page_list);
-    spin_unlock(&d->page_alloc_lock);
+    nrspin_unlock(&d->page_alloc_lock);
     return INVALID_MFN;
 }
 #endif
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index 1db2bbdb6a..8d05c57f69 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -369,9 +369,9 @@ long read_console_ring(struct xen_sysctl_readconsole *op)
 
     if ( op->clear )
     {
-        spin_lock_irq(&console_lock);
+        nrspin_lock_irq(&console_lock);
         conringc = p - c > conring_size ? p - conring_size : c;
-        spin_unlock_irq(&console_lock);
+        nrspin_unlock_irq(&console_lock);
     }
 
     op->count = sofar;
@@ -639,7 +639,7 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer,
         if ( is_hardware_domain(cd) )
         {
             /* Use direct console output as it could be interactive */
-            spin_lock_irq(&console_lock);
+            nrspin_lock_irq(&console_lock);
 
             console_serial_puts(kbuf, kcount);
             video_puts(kbuf, kcount);
@@ -660,7 +660,7 @@ static long guest_console_write(XEN_GUEST_HANDLE_PARAM(char) buffer,
                 tasklet_schedule(&notify_dom0_con_ring_tasklet);
             }
 
-            spin_unlock_irq(&console_lock);
+            nrspin_unlock_irq(&console_lock);
         }
         else
         {
@@ -1027,9 +1027,9 @@ void __init console_init_preirq(void)
     pv_console_set_rx_handler(serial_rx);
 
     /* HELLO WORLD --- start-of-day banner text. */
-    spin_lock(&console_lock);
+    nrspin_lock(&console_lock);
     __putstr(xen_banner());
-    spin_unlock(&console_lock);
+    nrspin_unlock(&console_lock);
     printk("Xen version %d.%d%s (%s@%s) (%s) %s %s\n",
            xen_major_version(), xen_minor_version(), xen_extra_version(),
            xen_compile_by(), xen_compile_domain(), xen_compiler(),
@@ -1066,13 +1066,13 @@ void __init console_init_ring(void)
     }
     opt_conring_size = PAGE_SIZE << order;
 
-    spin_lock_irqsave(&console_lock, flags);
+    nrspin_lock_irqsave(&console_lock, flags);
     for ( i = conringc ; i != conringp; i++ )
         ring[i & (opt_conring_size - 1)] = conring[i & (conring_size - 1)];
     conring = ring;
     smp_wmb(); /* Allow users of console_force_unlock() to see larger buffer. */
     conring_size = opt_conring_size;
-    spin_unlock_irqrestore(&console_lock, flags);
+    nrspin_unlock_irqrestore(&console_lock, flags);
 
     printk("Allocated console ring of %u KiB.\n", opt_conring_size >> 10);
 }
diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index ac3bef267a..82ef99d3b6 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -101,6 +101,8 @@ struct lock_profile_qhead {
 };
 
 #define _LOCK_PROFILE(lockname) { .name = #lockname, .lock = &lockname, }
+#define _RLOCK_PROFILE(lockname) { .name = #lockname, .rlock = &lockname,     \
+    .is_rlock = 1, }
 #define _LOCK_PROFILE_PTR(name)                                               \
     static struct lock_profile * const __lock_profile_##name                  \
     __used_section(".lockprofile.data") =                                     \
@@ -117,10 +119,10 @@ struct lock_profile_qhead {
     _LOCK_PROFILE_PTR(l)
 #define DEFINE_RSPINLOCK(l)                                                   \
     rspinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                \
-    static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
+    static struct lock_profile __lock_profile_data_##l = _RLOCK_PROFILE(l);   \
     _LOCK_PROFILE_PTR(l)
 
-#define __spin_lock_init_prof(s, l, locktype)                                 \
+#define __spin_lock_init_prof(s, l, lockptr, locktype, isr)                   \
     do {                                                                      \
         struct lock_profile *prof;                                            \
         prof = xzalloc(struct lock_profile);                                  \
@@ -133,13 +135,16 @@ struct lock_profile_qhead {
             break;                                                            \
         }                                                                     \
         prof->name = #l;                                                      \
-        prof->lock = &(s)->l;                                                 \
+        prof->lockptr = &(s)->l;                                              \
+        prof->is_rlock = isr;                                                 \
         prof->next = (s)->profile_head.elem_q;                                \
         (s)->profile_head.elem_q = prof;                                      \
     } while( 0 )
 
-#define spin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, spinlock_t)
-#define rspin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, rspinlock_t)
+#define spin_lock_init_prof(s, l)                                             \
+    __spin_lock_init_prof(s, l, lock, spinlock_t, 0)
+#define rspin_lock_init_prof(s, l)                                            \
+    __spin_lock_init_prof(s, l, rlock, rspinlock_t, 1)
 
 void _lock_profile_register_struct(
     int32_t type, struct lock_profile_qhead *qhead, int32_t idx);
@@ -174,6 +179,7 @@ struct lock_profile_qhead { };
 
 #endif
 
+
 typedef union {
     uint32_t head_tail;
     struct {
@@ -261,4 +267,12 @@ void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags);
 /* Ensure a lock is quiescent between two critical operations. */
 #define spin_barrier(l)               _spin_barrier(l)
 
+#define nrspin_trylock(l)    spin_trylock(l)
+#define nrspin_lock(l)       spin_lock(l)
+#define nrspin_unlock(l)     spin_unlock(l)
+#define nrspin_lock_irq(l)   spin_lock_irq(l)
+#define nrspin_unlock_irq(l) spin_unlock_irq(l)
+#define nrspin_lock_irqsave(l, f)      spin_lock_irqsave(l, f)
+#define nrspin_unlock_irqrestore(l, f) spin_unlock_irqrestore(l, f)
+
 #endif /* __SPINLOCK_H__ */
-- 
2.35.3



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

* [PATCH v4 08/12] xen/spinlock: add another function level
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
                   ` (6 preceding siblings ...)
  2023-12-12  9:47 ` [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2023-12-12 19:10   ` Julien Grall
  2024-02-29 13:59   ` Jan Beulich
  2023-12-12  9:47 ` [PATCH v4 09/12] xen/spinlock: add missing rspin_is_locked() and rspin_barrier() Juergen Gross
                   ` (3 subsequent siblings)
  11 siblings, 2 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Andrew Cooper, George Dunlap, Jan Beulich,
	Julien Grall, Stefano Stabellini, Wei Liu

Add another function level in spinlock.c hiding the spinlock_t layout
from the low level locking code.

This is done in preparation of introducing rspinlock_t for recursive
locks without having to duplicate all of the locking code.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- new patch
---
 xen/common/spinlock.c      | 104 +++++++++++++++++++++++--------------
 xen/include/xen/spinlock.h |   1 +
 2 files changed, 65 insertions(+), 40 deletions(-)

diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
index 7d611d3d7d..31d12b1006 100644
--- a/xen/common/spinlock.c
+++ b/xen/common/spinlock.c
@@ -261,29 +261,31 @@ void spin_debug_disable(void)
 
 #ifdef CONFIG_DEBUG_LOCK_PROFILE
 
+#define LOCK_PROFILE_PAR lock->profile
 #define LOCK_PROFILE_REL                                                     \
-    if ( lock->profile )                                                     \
+    if ( profile )                                                           \
     {                                                                        \
-        lock->profile->time_hold += NOW() - lock->profile->time_locked;      \
-        lock->profile->lock_cnt++;                                           \
+        profile->time_hold += NOW() - profile->time_locked;                  \
+        profile->lock_cnt++;                                                 \
     }
 #define LOCK_PROFILE_VAR(var, val)    s_time_t var = (val)
 #define LOCK_PROFILE_BLOCK(var)       var = var ? : NOW()
 #define LOCK_PROFILE_BLKACC(tst, val)                                        \
     if ( tst )                                                               \
     {                                                                        \
-        lock->profile->time_block += lock->profile->time_locked - (val);     \
-        lock->profile->block_cnt++;                                          \
+        profile->time_block += profile->time_locked - (val);                 \
+        profile->block_cnt++;                                                \
     }
 #define LOCK_PROFILE_GOT(val)                                                \
-    if ( lock->profile )                                                     \
+    if ( profile )                                                           \
     {                                                                        \
-        lock->profile->time_locked = NOW();                                  \
+        profile->time_locked = NOW();                                        \
         LOCK_PROFILE_BLKACC(val, val);                                       \
     }
 
 #else
 
+#define LOCK_PROFILE_PAR NULL
 #define LOCK_PROFILE_REL
 #define LOCK_PROFILE_VAR(var, val)
 #define LOCK_PROFILE_BLOCK(var)
@@ -307,17 +309,18 @@ static always_inline uint16_t observe_head(const spinlock_tickets_t *t)
     return read_atomic(&t->head);
 }
 
-static void always_inline spin_lock_common(spinlock_t *lock,
+static void always_inline spin_lock_common(spinlock_tickets_t *t,
+                                           union lock_debug *debug,
+                                           struct lock_profile *profile,
                                            void (*cb)(void *data), void *data)
 {
     spinlock_tickets_t tickets = SPINLOCK_TICKET_INC;
     LOCK_PROFILE_VAR(block, 0);
 
-    check_lock(&lock->debug, false);
+    check_lock(debug, false);
     preempt_disable();
-    tickets.head_tail = arch_fetch_and_add(&lock->tickets.head_tail,
-                                           tickets.head_tail);
-    while ( tickets.tail != observe_head(&lock->tickets) )
+    tickets.head_tail = arch_fetch_and_add(&t->head_tail, tickets.head_tail);
+    while ( tickets.tail != observe_head(t) )
     {
         LOCK_PROFILE_BLOCK(block);
         if ( cb )
@@ -325,18 +328,19 @@ static void always_inline spin_lock_common(spinlock_t *lock,
         arch_lock_relax();
     }
     arch_lock_acquire_barrier();
-    got_lock(&lock->debug);
+    got_lock(debug);
     LOCK_PROFILE_GOT(block);
 }
 
 void _spin_lock(spinlock_t *lock)
 {
-    spin_lock_common(lock, NULL, NULL);
+    spin_lock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR, NULL,
+                     NULL);
 }
 
 void _spin_lock_cb(spinlock_t *lock, void (*cb)(void *data), void *data)
 {
-    spin_lock_common(lock, cb, data);
+    spin_lock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR, cb, data);
 }
 
 void _spin_lock_irq(spinlock_t *lock)
@@ -355,16 +359,23 @@ unsigned long _spin_lock_irqsave(spinlock_t *lock)
     return flags;
 }
 
-void _spin_unlock(spinlock_t *lock)
+static void always_inline spin_unlock_common(spinlock_tickets_t *t,
+                                             union lock_debug *debug,
+                                             struct lock_profile *profile)
 {
     LOCK_PROFILE_REL;
-    rel_lock(&lock->debug);
+    rel_lock(debug);
     arch_lock_release_barrier();
-    add_sized(&lock->tickets.head, 1);
+    add_sized(&t->head, 1);
     arch_lock_signal();
     preempt_enable();
 }
 
+void _spin_unlock(spinlock_t *lock)
+{
+    spin_unlock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
+}
+
 void _spin_unlock_irq(spinlock_t *lock)
 {
     _spin_unlock(lock);
@@ -377,25 +388,25 @@ void _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
     local_irq_restore(flags);
 }
 
+static int always_inline spin_is_locked_common(const spinlock_tickets_t *t)
+{
+    return t->head != t->tail;
+}
+
 int _spin_is_locked(const spinlock_t *lock)
 {
-    /*
-     * Recursive locks may be locked by another CPU, yet we return
-     * "false" here, making this function suitable only for use in
-     * ASSERT()s and alike.
-     */
-    return lock->recurse_cpu == SPINLOCK_NO_CPU
-           ? lock->tickets.head != lock->tickets.tail
-           : lock->recurse_cpu == smp_processor_id();
+    return spin_is_locked_common(&lock->tickets);
 }
 
-int _spin_trylock(spinlock_t *lock)
+static int always_inline spin_trylock_common(spinlock_tickets_t *t,
+                                             union lock_debug *debug,
+                                             struct lock_profile *profile)
 {
     spinlock_tickets_t old, new;
 
     preempt_disable();
-    check_lock(&lock->debug, true);
-    old = observe_lock(&lock->tickets);
+    check_lock(debug, true);
+    old = observe_lock(t);
     if ( old.head != old.tail )
     {
         preempt_enable();
@@ -403,8 +414,7 @@ int _spin_trylock(spinlock_t *lock)
     }
     new = old;
     new.tail++;
-    if ( cmpxchg(&lock->tickets.head_tail,
-                 old.head_tail, new.head_tail) != old.head_tail )
+    if ( cmpxchg(&t->head_tail, old.head_tail, new.head_tail) != old.head_tail )
     {
         preempt_enable();
         return 0;
@@ -413,29 +423,41 @@ int _spin_trylock(spinlock_t *lock)
      * cmpxchg() is a full barrier so no need for an
      * arch_lock_acquire_barrier().
      */
-    got_lock(&lock->debug);
+    got_lock(debug);
     LOCK_PROFILE_GOT(0);
 
     return 1;
 }
 
-void _spin_barrier(spinlock_t *lock)
+int _spin_trylock(spinlock_t *lock)
+{
+    return spin_trylock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
+}
+
+static void always_inline spin_barrier_common(spinlock_tickets_t *t,
+                                              union lock_debug *debug,
+                                              struct lock_profile *profile)
 {
     spinlock_tickets_t sample;
     LOCK_PROFILE_VAR(block, NOW());
 
-    check_barrier(&lock->debug);
+    check_barrier(debug);
     smp_mb();
-    sample = observe_lock(&lock->tickets);
+    sample = observe_lock(t);
     if ( sample.head != sample.tail )
     {
-        while ( observe_head(&lock->tickets) == sample.head )
+        while ( observe_head(t) == sample.head )
             arch_lock_relax();
-        LOCK_PROFILE_BLKACC(lock->profile, block);
+        LOCK_PROFILE_BLKACC(profile, block);
     }
     smp_mb();
 }
 
+void _spin_barrier(spinlock_t *lock)
+{
+    spin_barrier_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
+}
+
 int rspin_trylock(rspinlock_t *lock)
 {
     unsigned int cpu = smp_processor_id();
@@ -448,7 +470,8 @@ int rspin_trylock(rspinlock_t *lock)
 
     if ( likely(lock->recurse_cpu != cpu) )
     {
-        if ( !spin_trylock(lock) )
+        if ( !spin_trylock_common(&lock->tickets, &lock->debug,
+                                  LOCK_PROFILE_PAR) )
             return 0;
         lock->recurse_cpu = cpu;
     }
@@ -466,7 +489,8 @@ void rspin_lock(rspinlock_t *lock)
 
     if ( likely(lock->recurse_cpu != cpu) )
     {
-        _spin_lock(lock);
+        spin_lock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR, NULL,
+                         NULL);
         lock->recurse_cpu = cpu;
     }
 
@@ -490,7 +514,7 @@ void rspin_unlock(rspinlock_t *lock)
     if ( likely(--lock->recurse_cnt == 0) )
     {
         lock->recurse_cpu = SPINLOCK_NO_CPU;
-        spin_unlock(lock);
+        spin_unlock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
     }
 }
 
diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index 82ef99d3b6..d6f4b66613 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -163,6 +163,7 @@ extern void cf_check spinlock_profile_reset(unsigned char key);
 #else
 
 struct lock_profile_qhead { };
+struct lock_profile { };
 
 #define SPIN_LOCK_UNLOCKED {                                                  \
     .recurse_cpu = SPINLOCK_NO_CPU,                                           \
-- 
2.35.3



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

* [PATCH v4 09/12] xen/spinlock: add missing rspin_is_locked() and rspin_barrier()
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
                   ` (7 preceding siblings ...)
  2023-12-12  9:47 ` [PATCH v4 08/12] xen/spinlock: add another function level Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2024-02-29 14:14   ` Jan Beulich
  2023-12-12  9:47 ` [PATCH v4 10/12] xen/spinlock: split recursive spinlocks from normal ones Juergen Gross
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Jan Beulich, Andrew Cooper, George Dunlap,
	Roger Pau Monné,
	Wei Liu, Julien Grall, Stefano Stabellini, Paul Durrant

Add rspin_is_locked() and rspin_barrier() in order to prepare differing
spinlock_t and rspinlock_t types.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- partially carved out from V1 patch, partially new
---
 xen/arch/x86/mm/p2m-pod.c     |  2 +-
 xen/common/domain.c           |  2 +-
 xen/common/page_alloc.c       |  2 +-
 xen/common/spinlock.c         | 17 +++++++++++++++++
 xen/drivers/char/console.c    |  4 ++--
 xen/drivers/passthrough/pci.c |  2 +-
 xen/include/xen/spinlock.h    |  2 ++
 7 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/xen/arch/x86/mm/p2m-pod.c b/xen/arch/x86/mm/p2m-pod.c
index 61a91f5a94..40d3b25d25 100644
--- a/xen/arch/x86/mm/p2m-pod.c
+++ b/xen/arch/x86/mm/p2m-pod.c
@@ -385,7 +385,7 @@ int p2m_pod_empty_cache(struct domain *d)
 
     /* After this barrier no new PoD activities can happen. */
     BUG_ON(!d->is_dying);
-    spin_barrier(&p2m->pod.lock.lock);
+    rspin_barrier(&p2m->pod.lock.lock);
 
     lock_page_alloc(p2m);
 
diff --git a/xen/common/domain.c b/xen/common/domain.c
index dc97755391..198cb36878 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -982,7 +982,7 @@ int domain_kill(struct domain *d)
     case DOMDYING_alive:
         domain_pause(d);
         d->is_dying = DOMDYING_dying;
-        spin_barrier(&d->domain_lock);
+        rspin_barrier(&d->domain_lock);
         argo_destroy(d);
         vnuma_destroy(d->vnuma);
         domain_set_outstanding_pages(d, 0);
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index a25c00a7d4..14010b6fa5 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -476,7 +476,7 @@ unsigned long domain_adjust_tot_pages(struct domain *d, long pages)
 {
     long dom_before, dom_after, dom_claimed, sys_before, sys_after;
 
-    ASSERT(spin_is_locked(&d->page_alloc_lock));
+    ASSERT(rspin_is_locked(&d->page_alloc_lock));
     d->tot_pages += pages;
 
     /*
diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
index 31d12b1006..91e325f3fe 100644
--- a/xen/common/spinlock.c
+++ b/xen/common/spinlock.c
@@ -458,6 +458,23 @@ void _spin_barrier(spinlock_t *lock)
     spin_barrier_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
 }
 
+int rspin_is_locked(const rspinlock_t *lock)
+{
+    /*
+     * Recursive locks may be locked by another CPU, yet we return
+     * "false" here, making this function suitable only for use in
+     * ASSERT()s and alike.
+     */
+    return lock->recurse_cpu == SPINLOCK_NO_CPU
+           ? spin_is_locked_common(&lock->tickets)
+           : lock->recurse_cpu == smp_processor_id();
+}
+
+void rspin_barrier(rspinlock_t *lock)
+{
+    spin_barrier_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
+}
+
 int rspin_trylock(rspinlock_t *lock)
 {
     unsigned int cpu = smp_processor_id();
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index 8d05c57f69..e6502641eb 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -328,7 +328,7 @@ static void cf_check do_dec_thresh(unsigned char key, struct cpu_user_regs *regs
 
 static void conring_puts(const char *str, size_t len)
 {
-    ASSERT(spin_is_locked(&console_lock));
+    ASSERT(rspin_is_locked(&console_lock));
 
     while ( len-- )
         conring[CONRING_IDX_MASK(conringp++)] = *str++;
@@ -766,7 +766,7 @@ static void __putstr(const char *str)
 {
     size_t len = strlen(str);
 
-    ASSERT(spin_is_locked(&console_lock));
+    ASSERT(rspin_is_locked(&console_lock));
 
     console_serial_puts(str, len);
     video_puts(str, len);
diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index 41444f8e2e..94f52b7acc 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -64,7 +64,7 @@ void pcidevs_unlock(void)
 
 bool pcidevs_locked(void)
 {
-    return !!spin_is_locked(&_pcidevs_lock);
+    return rspin_is_locked(&_pcidevs_lock);
 }
 
 static struct radix_tree_root pci_segments;
diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index d6f4b66613..e63db4eb4c 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -239,6 +239,8 @@ void rspin_lock(rspinlock_t *lock);
 unsigned long __rspin_lock_irqsave(rspinlock_t *lock);
 void rspin_unlock(rspinlock_t *lock);
 void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags);
+int rspin_is_locked(const rspinlock_t *lock);
+void rspin_barrier(rspinlock_t *lock);
 
 #define spin_lock(l)                  _spin_lock(l)
 #define spin_lock_cb(l, c, d)         _spin_lock_cb(l, c, d)
-- 
2.35.3



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

* [PATCH v4 10/12] xen/spinlock: split recursive spinlocks from normal ones
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
                   ` (8 preceding siblings ...)
  2023-12-12  9:47 ` [PATCH v4 09/12] xen/spinlock: add missing rspin_is_locked() and rspin_barrier() Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2024-02-29 15:32   ` Jan Beulich
  2023-12-12  9:47 ` [PATCH v4 11/12] xen/spinlock: remove indirection through macros for spin_*() functions Juergen Gross
  2023-12-12  9:47 ` [PATCH v4 12/12] xen/spinlock: support higher number of cpus Juergen Gross
  11 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Andrew Cooper, George Dunlap, Jan Beulich,
	Julien Grall, Stefano Stabellini, Wei Liu

Recursive and normal spinlocks are sharing the same data structure for
representation of the lock. This has two major disadvantages:

- it is not clear from the definition of a lock, whether it is intended
  to be used recursive or not, while a mixture of both usage variants
  needs to be

- in production builds (builds without CONFIG_DEBUG_LOCKS) the needed
  data size of an ordinary spinlock is 8 bytes instead of 4, due to the
  additional recursion data needed (associated with that the rwlock
  data is using 12 instead of only 8 bytes)

Fix that by introducing a struct spinlock_recursive for recursive
spinlocks only, and switch recursive spinlock functions to require
pointers to this new struct.

This allows to check the correct usage at build time.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- use shorter names (Jan Beulich)
- don't embed spinlock_t in rspinlock_t (Jan Beulich)
---
 xen/common/spinlock.c      | 49 ++++++++++++++++++++++++++++++++
 xen/include/xen/spinlock.h | 58 +++++++++++++++++++++++++-------------
 2 files changed, 88 insertions(+), 19 deletions(-)

diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
index 91e325f3fe..d0f8393504 100644
--- a/xen/common/spinlock.c
+++ b/xen/common/spinlock.c
@@ -541,6 +541,55 @@ void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags)
     local_irq_restore(flags);
 }
 
+int nrspin_trylock(rspinlock_t *lock)
+{
+    check_lock(&lock->debug, true);
+
+    if ( unlikely(lock->recurse_cpu != SPINLOCK_NO_CPU) )
+        return 0;
+
+    return spin_trylock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
+}
+
+void nrspin_lock(rspinlock_t *lock)
+{
+    spin_lock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR, NULL,
+                     NULL);
+}
+
+void nrspin_unlock(rspinlock_t *lock)
+{
+    spin_unlock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
+}
+
+void nrspin_lock_irq(rspinlock_t *lock)
+{
+    ASSERT(local_irq_is_enabled());
+    local_irq_disable();
+    nrspin_lock(lock);
+}
+
+void nrspin_unlock_irq(rspinlock_t *lock)
+{
+    nrspin_unlock(lock);
+    local_irq_enable();
+}
+
+unsigned long __nrspin_lock_irqsave(rspinlock_t *lock)
+{
+    unsigned long flags;
+
+    local_irq_save(flags);
+    nrspin_lock(lock);
+    return flags;
+}
+
+void nrspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags)
+{
+    nrspin_unlock(lock);
+    local_irq_restore(flags);
+}
+
 #ifdef CONFIG_DEBUG_LOCK_PROFILE
 
 struct lock_profile_anc {
diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index e63db4eb4c..ca18b9250a 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -76,8 +76,6 @@ union lock_debug { };
 */
 
 struct spinlock;
-/* Temporary hack until a dedicated struct rspinlock is existing. */
-#define rspinlock spinlock
 
 struct lock_profile {
     struct lock_profile *next;       /* forward link */
@@ -108,6 +106,10 @@ struct lock_profile_qhead {
     __used_section(".lockprofile.data") =                                     \
     &__lock_profile_data_##name
 #define _SPIN_LOCK_UNLOCKED(x) {                                              \
+    .debug =_LOCK_DEBUG,                                                      \
+    .profile = x,                                                             \
+}
+#define _RSPIN_LOCK_UNLOCKED(x) {                                             \
     .recurse_cpu = SPINLOCK_NO_CPU,                                           \
     .debug =_LOCK_DEBUG,                                                      \
     .profile = x,                                                             \
@@ -117,8 +119,9 @@ struct lock_profile_qhead {
     spinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                 \
     static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
     _LOCK_PROFILE_PTR(l)
+#define RSPIN_LOCK_UNLOCKED _RSPIN_LOCK_UNLOCKED(NULL)
 #define DEFINE_RSPINLOCK(l)                                                   \
-    rspinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                \
+    rspinlock_t l = _RSPIN_LOCK_UNLOCKED(NULL);                               \
     static struct lock_profile __lock_profile_data_##l = _RLOCK_PROFILE(l);   \
     _LOCK_PROFILE_PTR(l)
 
@@ -143,8 +146,11 @@ struct lock_profile_qhead {
 
 #define spin_lock_init_prof(s, l)                                             \
     __spin_lock_init_prof(s, l, lock, spinlock_t, 0)
-#define rspin_lock_init_prof(s, l)                                            \
-    __spin_lock_init_prof(s, l, rlock, rspinlock_t, 1)
+#define rspin_lock_init_prof(s, l) do {                                       \
+        __spin_lock_init_prof(s, l, rlock, rspinlock_t, 1);                   \
+        (s)->l.recurse_cpu = SPINLOCK_NO_CPU;                                 \
+        (s)->l.recurse_cnt = 0;                                               \
+    } while (0)
 
 void _lock_profile_register_struct(
     int32_t type, struct lock_profile_qhead *qhead, int32_t idx);
@@ -166,11 +172,15 @@ struct lock_profile_qhead { };
 struct lock_profile { };
 
 #define SPIN_LOCK_UNLOCKED {                                                  \
+    .debug =_LOCK_DEBUG,                                                      \
+}
+#define RSPIN_LOCK_UNLOCKED {                                                 \
+    .debug =_LOCK_DEBUG,                                                      \
     .recurse_cpu = SPINLOCK_NO_CPU,                                           \
     .debug =_LOCK_DEBUG,                                                      \
 }
 #define DEFINE_SPINLOCK(l) spinlock_t l = SPIN_LOCK_UNLOCKED
-#define DEFINE_RSPINLOCK(l) rspinlock_t l = SPIN_LOCK_UNLOCKED
+#define DEFINE_RSPINLOCK(l) rspinlock_t l = RSPIN_LOCK_UNLOCKED
 
 #define spin_lock_init_prof(s, l) spin_lock_init(&((s)->l))
 #define rspin_lock_init_prof(s, l) rspin_lock_init(&((s)->l))
@@ -180,7 +190,6 @@ struct lock_profile { };
 
 #endif
 
-
 typedef union {
     uint32_t head_tail;
     struct {
@@ -192,6 +201,14 @@ typedef union {
 #define SPINLOCK_TICKET_INC { .head_tail = 0x10000, }
 
 typedef struct spinlock {
+    spinlock_tickets_t tickets;
+    union lock_debug debug;
+#ifdef CONFIG_DEBUG_LOCK_PROFILE
+    struct lock_profile *profile;
+#endif
+} spinlock_t;
+
+typedef struct rspinlock {
     spinlock_tickets_t tickets;
     uint16_t recurse_cpu:SPINLOCK_CPU_BITS;
 #define SPINLOCK_NO_CPU        ((1u << SPINLOCK_CPU_BITS) - 1)
@@ -202,12 +219,10 @@ typedef struct spinlock {
 #ifdef CONFIG_DEBUG_LOCK_PROFILE
     struct lock_profile *profile;
 #endif
-} spinlock_t;
-
-typedef spinlock_t rspinlock_t;
+} rspinlock_t;
 
 #define spin_lock_init(l) (*(l) = (spinlock_t)SPIN_LOCK_UNLOCKED)
-#define rspin_lock_init(l) (*(l) = (rspinlock_t)SPIN_LOCK_UNLOCKED)
+#define rspin_lock_init(l) (*(l) = (rspinlock_t)RSPIN_LOCK_UNLOCKED)
 
 void _spin_lock(spinlock_t *lock);
 void _spin_lock_cb(spinlock_t *lock, void (*cb)(void *data), void *data);
@@ -242,6 +257,19 @@ void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags);
 int rspin_is_locked(const rspinlock_t *lock);
 void rspin_barrier(rspinlock_t *lock);
 
+int nrspin_trylock(rspinlock_t *lock);
+void nrspin_lock(rspinlock_t *lock);
+void nrspin_unlock(rspinlock_t *lock);
+void nrspin_lock_irq(rspinlock_t *lock);
+void nrspin_unlock_irq(rspinlock_t *lock);
+#define nrspin_lock_irqsave(l, f)                               \
+    ({                                                          \
+        BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long));       \
+        ((f) = __nrspin_lock_irqsave(l));                       \
+    })
+unsigned long __nrspin_lock_irqsave(rspinlock_t *lock);
+void nrspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags);
+
 #define spin_lock(l)                  _spin_lock(l)
 #define spin_lock_cb(l, c, d)         _spin_lock_cb(l, c, d)
 #define spin_lock_irq(l)              _spin_lock_irq(l)
@@ -270,12 +298,4 @@ void rspin_barrier(rspinlock_t *lock);
 /* Ensure a lock is quiescent between two critical operations. */
 #define spin_barrier(l)               _spin_barrier(l)
 
-#define nrspin_trylock(l)    spin_trylock(l)
-#define nrspin_lock(l)       spin_lock(l)
-#define nrspin_unlock(l)     spin_unlock(l)
-#define nrspin_lock_irq(l)   spin_lock_irq(l)
-#define nrspin_unlock_irq(l) spin_unlock_irq(l)
-#define nrspin_lock_irqsave(l, f)      spin_lock_irqsave(l, f)
-#define nrspin_unlock_irqrestore(l, f) spin_unlock_irqrestore(l, f)
-
 #endif /* __SPINLOCK_H__ */
-- 
2.35.3



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

* [PATCH v4 11/12] xen/spinlock: remove indirection through macros for spin_*() functions
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
                   ` (9 preceding siblings ...)
  2023-12-12  9:47 ` [PATCH v4 10/12] xen/spinlock: split recursive spinlocks from normal ones Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2024-02-29 15:35   ` Jan Beulich
  2023-12-12  9:47 ` [PATCH v4 12/12] xen/spinlock: support higher number of cpus Juergen Gross
  11 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Andrew Cooper, George Dunlap, Jan Beulich,
	Julien Grall, Stefano Stabellini, Wei Liu

In reality all spin_*() functions are macros which are defined to just
call a related real function.

Remove this macro layer, as it is adding complexity without any gain.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
V2:
- new patch
---
 xen/common/spinlock.c      | 28 +++++++++---------
 xen/include/xen/spinlock.h | 58 +++++++++++++++-----------------------
 2 files changed, 36 insertions(+), 50 deletions(-)

diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
index d0f8393504..296bcf33e6 100644
--- a/xen/common/spinlock.c
+++ b/xen/common/spinlock.c
@@ -332,30 +332,30 @@ static void always_inline spin_lock_common(spinlock_tickets_t *t,
     LOCK_PROFILE_GOT(block);
 }
 
-void _spin_lock(spinlock_t *lock)
+void spin_lock(spinlock_t *lock)
 {
     spin_lock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR, NULL,
                      NULL);
 }
 
-void _spin_lock_cb(spinlock_t *lock, void (*cb)(void *data), void *data)
+void spin_lock_cb(spinlock_t *lock, void (*cb)(void *data), void *data)
 {
     spin_lock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR, cb, data);
 }
 
-void _spin_lock_irq(spinlock_t *lock)
+void spin_lock_irq(spinlock_t *lock)
 {
     ASSERT(local_irq_is_enabled());
     local_irq_disable();
-    _spin_lock(lock);
+    spin_lock(lock);
 }
 
-unsigned long _spin_lock_irqsave(spinlock_t *lock)
+unsigned long __spin_lock_irqsave(spinlock_t *lock)
 {
     unsigned long flags;
 
     local_irq_save(flags);
-    _spin_lock(lock);
+    spin_lock(lock);
     return flags;
 }
 
@@ -371,20 +371,20 @@ static void always_inline spin_unlock_common(spinlock_tickets_t *t,
     preempt_enable();
 }
 
-void _spin_unlock(spinlock_t *lock)
+void spin_unlock(spinlock_t *lock)
 {
     spin_unlock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
 }
 
-void _spin_unlock_irq(spinlock_t *lock)
+void spin_unlock_irq(spinlock_t *lock)
 {
-    _spin_unlock(lock);
+    spin_unlock(lock);
     local_irq_enable();
 }
 
-void _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
+void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
 {
-    _spin_unlock(lock);
+    spin_unlock(lock);
     local_irq_restore(flags);
 }
 
@@ -393,7 +393,7 @@ static int always_inline spin_is_locked_common(const spinlock_tickets_t *t)
     return t->head != t->tail;
 }
 
-int _spin_is_locked(const spinlock_t *lock)
+int spin_is_locked(const spinlock_t *lock)
 {
     return spin_is_locked_common(&lock->tickets);
 }
@@ -429,7 +429,7 @@ static int always_inline spin_trylock_common(spinlock_tickets_t *t,
     return 1;
 }
 
-int _spin_trylock(spinlock_t *lock)
+int spin_trylock(spinlock_t *lock)
 {
     return spin_trylock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
 }
@@ -453,7 +453,7 @@ static void always_inline spin_barrier_common(spinlock_tickets_t *t,
     smp_mb();
 }
 
-void _spin_barrier(spinlock_t *lock)
+void spin_barrier(spinlock_t *lock)
 {
     spin_barrier_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
 }
diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
index ca18b9250a..87946965b2 100644
--- a/xen/include/xen/spinlock.h
+++ b/xen/include/xen/spinlock.h
@@ -224,18 +224,30 @@ typedef struct rspinlock {
 #define spin_lock_init(l) (*(l) = (spinlock_t)SPIN_LOCK_UNLOCKED)
 #define rspin_lock_init(l) (*(l) = (rspinlock_t)RSPIN_LOCK_UNLOCKED)
 
-void _spin_lock(spinlock_t *lock);
-void _spin_lock_cb(spinlock_t *lock, void (*cb)(void *data), void *data);
-void _spin_lock_irq(spinlock_t *lock);
-unsigned long _spin_lock_irqsave(spinlock_t *lock);
+void spin_lock(spinlock_t *lock);
+void spin_lock_cb(spinlock_t *lock, void (*cb)(void *data), void *data);
+void spin_lock_irq(spinlock_t *lock);
+#define spin_lock_irqsave(l, f)                                 \
+    ({                                                          \
+        BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long));       \
+        ((f) = __spin_lock_irqsave(l));                         \
+    })
+unsigned long __spin_lock_irqsave(spinlock_t *lock);
 
-void _spin_unlock(spinlock_t *lock);
-void _spin_unlock_irq(spinlock_t *lock);
-void _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
+void spin_unlock(spinlock_t *lock);
+void spin_unlock_irq(spinlock_t *lock);
+void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
 
-int _spin_is_locked(const spinlock_t *lock);
-int _spin_trylock(spinlock_t *lock);
-void _spin_barrier(spinlock_t *lock);
+int spin_is_locked(const spinlock_t *lock);
+int spin_trylock(spinlock_t *lock);
+#define spin_trylock_irqsave(lock, flags)       \
+({                                              \
+    local_irq_save(flags);                      \
+    spin_trylock(lock) ?                        \
+    1 : ({ local_irq_restore(flags); 0; });     \
+})
+/* Ensure a lock is quiescent between two critical operations. */
+void spin_barrier(spinlock_t *lock);
 
 /*
  * rspin_[un]lock(): Use these forms when the lock can (safely!) be
@@ -270,32 +282,6 @@ void nrspin_unlock_irq(rspinlock_t *lock);
 unsigned long __nrspin_lock_irqsave(rspinlock_t *lock);
 void nrspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags);
 
-#define spin_lock(l)                  _spin_lock(l)
-#define spin_lock_cb(l, c, d)         _spin_lock_cb(l, c, d)
-#define spin_lock_irq(l)              _spin_lock_irq(l)
-#define spin_lock_irqsave(l, f)                                 \
-    ({                                                          \
-        BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long));       \
-        ((f) = _spin_lock_irqsave(l));                          \
-    })
-
-#define spin_unlock(l)                _spin_unlock(l)
-#define spin_unlock_irq(l)            _spin_unlock_irq(l)
-#define spin_unlock_irqrestore(l, f)  _spin_unlock_irqrestore(l, f)
-
-#define spin_is_locked(l)             _spin_is_locked(l)
-#define spin_trylock(l)               _spin_trylock(l)
-
-#define spin_trylock_irqsave(lock, flags)       \
-({                                              \
-    local_irq_save(flags);                      \
-    spin_trylock(lock) ?                        \
-    1 : ({ local_irq_restore(flags); 0; });     \
-})
-
 #define spin_lock_kick(l)             arch_lock_signal_wmb()
 
-/* Ensure a lock is quiescent between two critical operations. */
-#define spin_barrier(l)               _spin_barrier(l)
-
 #endif /* __SPINLOCK_H__ */
-- 
2.35.3



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

* [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
                   ` (10 preceding siblings ...)
  2023-12-12  9:47 ` [PATCH v4 11/12] xen/spinlock: remove indirection through macros for spin_*() functions Juergen Gross
@ 2023-12-12  9:47 ` Juergen Gross
  2023-12-12 10:10   ` Julien Grall
                     ` (2 more replies)
  11 siblings, 3 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-12  9:47 UTC (permalink / raw)
  To: xen-devel
  Cc: Juergen Gross, Andrew Cooper, George Dunlap, Jan Beulich,
	Julien Grall, Stefano Stabellini, Wei Liu

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;
 #define SPINLOCK_MAX_RECURSE   ((1u << SPINLOCK_RECURSE_BITS) - 1)
     union lock_debug debug;
 #ifdef CONFIG_DEBUG_LOCK_PROFILE
-- 
2.35.3



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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2023-12-12  9:47 ` [PATCH v4 12/12] xen/spinlock: support higher number of cpus Juergen Gross
@ 2023-12-12 10:10   ` Julien Grall
  2023-12-12 11:09     ` Juergen Gross
  2023-12-12 12:39   ` Julien Grall
  2024-02-29 15:46   ` Jan Beulich
  2 siblings, 1 reply; 73+ messages in thread
From: Julien Grall @ 2023-12-12 10:10 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini, Wei Liu

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

-- 
Julien Grall


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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2023-12-12 10:10   ` Julien Grall
@ 2023-12-12 11:09     ` Juergen Gross
  2023-12-12 11:40       ` Julien Grall
  0 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-12 11:09 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini,
	Wei Liu, javi.merino


[-- Attachment #1.1.1: Type: text/plain, Size: 1135 bytes --]

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


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2023-12-12 11:09     ` Juergen Gross
@ 2023-12-12 11:40       ` Julien Grall
  2023-12-12 12:11         ` Juergen Gross
  0 siblings, 1 reply; 73+ messages in thread
From: Julien Grall @ 2023-12-12 11:40 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini,
	Wei Liu, javi.merino

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,

-- 
Julien Grall


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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2023-12-12 11:40       ` Julien Grall
@ 2023-12-12 12:11         ` Juergen Gross
  2023-12-12 12:22           ` Julien Grall
  0 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-12 12:11 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini,
	Wei Liu, javi.merino


[-- Attachment #1.1.1: Type: text/plain, Size: 1485 bytes --]

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

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2023-12-12 12:11         ` Juergen Gross
@ 2023-12-12 12:22           ` Julien Grall
  0 siblings, 0 replies; 73+ messages in thread
From: Julien Grall @ 2023-12-12 12:22 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini,
	Wei Liu, javi.merino

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


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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2023-12-12  9:47 ` [PATCH v4 12/12] xen/spinlock: support higher number of cpus Juergen Gross
  2023-12-12 10:10   ` Julien Grall
@ 2023-12-12 12:39   ` Julien Grall
  2023-12-12 13:08     ` Juergen Gross
  2024-02-29 15:46   ` Jan Beulich
  2 siblings, 1 reply; 73+ messages in thread
From: Julien Grall @ 2023-12-12 12:39 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini, Wei Liu

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,

-- 
Julien Grall


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

* Re: [PATCH v4 01/12] xen/spinlock: reduce lock profile ifdefs
  2023-12-12  9:47 ` [PATCH v4 01/12] xen/spinlock: reduce lock profile ifdefs Juergen Gross
@ 2023-12-12 12:44   ` Julien Grall
  0 siblings, 0 replies; 73+ messages in thread
From: Julien Grall @ 2023-12-12 12:44 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini,
	Wei Liu, Alejandro Vallejo

Hi Juergen,

On 12/12/2023 09:47, Juergen Gross wrote:
> With some small adjustments to the LOCK_PROFILE_* macros some #ifdefs
> can be dropped from spinlock.c.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>
> Reviewed-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>

Acked-by: Julien Grall <jgrall@amazon.com>

Cheers,

-- 
Julien Grall


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

* Re: [PATCH v4 03/12] xen/spinlock: introduce new type for recursive spinlocks
  2023-12-12  9:47 ` [PATCH v4 03/12] xen/spinlock: introduce new type for recursive spinlocks Juergen Gross
@ 2023-12-12 12:57   ` Julien Grall
  2023-12-12 13:04     ` Juergen Gross
  2023-12-21 10:34     ` Jan Beulich
  0 siblings, 2 replies; 73+ messages in thread
From: Julien Grall @ 2023-12-12 12:57 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Jan Beulich, Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Stefano Stabellini, Paul Durrant

Hi Juergen,

On 12/12/2023 09:47, Juergen Gross wrote:
> diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
> index 1cd9120eac..20d15f34dd 100644
> --- a/xen/include/xen/spinlock.h
> +++ b/xen/include/xen/spinlock.h
> @@ -45,7 +45,7 @@ union lock_debug { };
>       lock profiling on:
>   
>       Global locks which should be subject to profiling must be declared via
> -    DEFINE_SPINLOCK.
> +    DEFINE_[R]SPINLOCK.
>   
>       For locks in structures further measures are necessary:
>       - the structure definition must include a profile_head with exactly this
> @@ -56,7 +56,7 @@ union lock_debug { };
>       - the single locks which are subject to profiling have to be initialized
>         via
>   
> -      spin_lock_init_prof(ptr, lock);
> +      [r]spin_lock_init_prof(ptr, lock);
>   
>         with ptr being the main structure pointer and lock the spinlock field
>   
> @@ -109,12 +109,16 @@ struct lock_profile_qhead {
>       spinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                 \
>       static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
>       _LOCK_PROFILE_PTR(l)
> +#define DEFINE_RSPINLOCK(l)                                                   \
> +    rspinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                \
> +    static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
> +    _LOCK_PROFILE_PTR(l)
>   
> -#define spin_lock_init_prof(s, l)                                             \
> +#define __spin_lock_init_prof(s, l, locktype)                                 \

If I am not mistaken the double-underscore prefix is a violation in 
MISRA. So can this be renamed to:

spin_lock_init_prof__()?

The rest of the code looks fine. I have checked the lock you are 
modifying in common/drivers and they all are meant to be recursive lock:

Acked-by: Julien Grall <jgrall@amazon.com>

Cheers,

-- 
Julien Grall


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

* Re: [PATCH v4 04/12] xen/spinlock: rename recursive lock functions
  2023-12-12  9:47 ` [PATCH v4 04/12] xen/spinlock: rename recursive lock functions Juergen Gross
@ 2023-12-12 12:59   ` Julien Grall
  2024-02-28 14:59   ` Jan Beulich
  1 sibling, 0 replies; 73+ messages in thread
From: Julien Grall @ 2023-12-12 12:59 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Stefano Stabellini, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Jan Beulich,
	Wei Liu, Roger Pau Monné,
	Tamas K Lengyel, Paul Durrant

Hi Juergen,

On 12/12/2023 09:47, Juergen Gross wrote:
> Rename the recursive spin_lock() functions by replacing the trailing
> "_recursive" with a leading "r".
> 
> Switch the parameter to be a pointer to rspinlock_t.
> 
> Remove the indirection through a macro, as it is adding only complexity
> without any gain.
> 
> Suggested-by: Jan Beulich <jbeulich@suse.com>
> Signed-off-by: Juergen Gross <jgross@suse.com>

Acked-by: Julien Grall <jgrall@amazon.com>

Cheers,

-- 
Julien Grall


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

* Re: [PATCH v4 05/12] xen/spinlock: add rspin_[un]lock_irq[save|restore]()
  2023-12-12  9:47 ` [PATCH v4 05/12] xen/spinlock: add rspin_[un]lock_irq[save|restore]() Juergen Gross
@ 2023-12-12 13:03   ` Julien Grall
  2023-12-12 14:16     ` Juergen Gross
  2024-02-28 15:09   ` Jan Beulich
  1 sibling, 1 reply; 73+ messages in thread
From: Julien Grall @ 2023-12-12 13:03 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Jan Beulich, Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Stefano Stabellini

Hi Juergen,

On 12/12/2023 09:47, Juergen Gross wrote:
> Instead of special casing rspin_lock_irqsave() and
> rspin_unlock_irqrestore() for the console lock, add those functions
> to spinlock handling and use them where needed.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>
> ---
> V2:
> - new patch
> ---
>   xen/arch/x86/traps.c       | 14 ++++++++------
>   xen/common/spinlock.c      | 16 ++++++++++++++++
>   xen/drivers/char/console.c | 18 +-----------------
>   xen/include/xen/console.h  |  5 +++--
>   xen/include/xen/spinlock.h |  7 +++++++
>   5 files changed, 35 insertions(+), 25 deletions(-)
> 
> diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
> index 7724306116..21227877b3 100644
> --- a/xen/arch/x86/traps.c
> +++ b/xen/arch/x86/traps.c
> @@ -647,13 +647,15 @@ void show_stack_overflow(unsigned int cpu, const struct cpu_user_regs *regs)
>   void show_execution_state(const struct cpu_user_regs *regs)
>   {
>       /* Prevent interleaving of output. */
> -    unsigned long flags = console_lock_recursive_irqsave();
> +    unsigned long flags;
> +
> +    rspin_lock_irqsave(&console_lock, flags);
>   
>       show_registers(regs);
>       show_code(regs);
>       show_stack(regs);
>   
> -    console_unlock_recursive_irqrestore(flags);
> +    rspin_unlock_irqrestore(&console_lock, flags);
>   }
>   
>   void cf_check show_execution_state_nonconst(struct cpu_user_regs *regs)
> @@ -663,7 +665,7 @@ void cf_check show_execution_state_nonconst(struct cpu_user_regs *regs)
>   
>   void vcpu_show_execution_state(struct vcpu *v)
>   {
> -    unsigned long flags = 0;
> +    unsigned long flags;
>   
>       if ( test_bit(_VPF_down, &v->pause_flags) )
>       {
> @@ -698,7 +700,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>   #endif
>   
>       /* Prevent interleaving of output. */
> -    flags = console_lock_recursive_irqsave();
> +    rspin_lock_irqsave(&console_lock, flags);
>   
>       vcpu_show_registers(v);
>   
> @@ -708,7 +710,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>            * Stop interleaving prevention: The necessary P2M lookups involve
>            * locking, which has to occur with IRQs enabled.
>            */
> -        console_unlock_recursive_irqrestore(flags);
> +        rspin_unlock_irqrestore(&console_lock, flags);
>   
>           show_hvm_stack(v, &v->arch.user_regs);
>       }
> @@ -717,7 +719,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>           if ( guest_kernel_mode(v, &v->arch.user_regs) )
>               show_guest_stack(v, &v->arch.user_regs);
>   
> -        console_unlock_recursive_irqrestore(flags);
> +        rspin_unlock_irqrestore(&console_lock, flags);
>       }
>   
>   #ifdef CONFIG_HVM
> diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
> index 422a7fb1db..c1a9ba1304 100644
> --- a/xen/common/spinlock.c
> +++ b/xen/common/spinlock.c
> @@ -475,6 +475,16 @@ void rspin_lock(rspinlock_t *lock)
>       lock->recurse_cnt++;
>   }
>   
> +unsigned long __rspin_lock_irqsave(rspinlock_t *lock)

This is going to be a problem with MISRA (see Rule 21.1). Can you move 
the double underscore to the end? Alternatively, I am not sure I see the 
benefits of the function here. So maybe we can fold the code in the 
macro below?

Other than that, the rest of the patch LGTM.

Cheers,

-- 
Julien Grall


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

* Re: [PATCH v4 03/12] xen/spinlock: introduce new type for recursive spinlocks
  2023-12-12 12:57   ` Julien Grall
@ 2023-12-12 13:04     ` Juergen Gross
  2023-12-12 13:07       ` Julien Grall
  2023-12-21 10:34     ` Jan Beulich
  1 sibling, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-12 13:04 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Jan Beulich, Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Stefano Stabellini, Paul Durrant


[-- Attachment #1.1.1: Type: text/plain, Size: 2529 bytes --]

On 12.12.23 13:57, Julien Grall wrote:
> Hi Juergen,
> 
> On 12/12/2023 09:47, Juergen Gross wrote:
>> diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
>> index 1cd9120eac..20d15f34dd 100644
>> --- a/xen/include/xen/spinlock.h
>> +++ b/xen/include/xen/spinlock.h
>> @@ -45,7 +45,7 @@ union lock_debug { };
>>       lock profiling on:
>>       Global locks which should be subject to profiling must be declared via
>> -    DEFINE_SPINLOCK.
>> +    DEFINE_[R]SPINLOCK.
>>       For locks in structures further measures are necessary:
>>       - the structure definition must include a profile_head with exactly this
>> @@ -56,7 +56,7 @@ union lock_debug { };
>>       - the single locks which are subject to profiling have to be initialized
>>         via
>> -      spin_lock_init_prof(ptr, lock);
>> +      [r]spin_lock_init_prof(ptr, lock);
>>         with ptr being the main structure pointer and lock the spinlock field
>> @@ -109,12 +109,16 @@ struct lock_profile_qhead {
>>       spinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                 \
>>       static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
>>       _LOCK_PROFILE_PTR(l)
>> +#define DEFINE_RSPINLOCK(l)                                                   \
>> +    rspinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                \
>> +    static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
>> +    _LOCK_PROFILE_PTR(l)
>> -#define spin_lock_init_prof(s, l)                                             \
>> +#define __spin_lock_init_prof(s, l, locktype)                                 \
> 
> If I am not mistaken the double-underscore prefix is a violation in MISRA. So 
> can this be renamed to:
> 
> spin_lock_init_prof__()?

Fine with me.

Note that __lock_profile_data_##l and __lock_profile_##name seem to violate
MISRA, too. Probably a good idea to change them as well? This should probably
be done as a prereq patch then?

> 
> The rest of the code looks fine. I have checked the lock you are modifying in 
> common/drivers and they all are meant to be recursive lock:
> 
> Acked-by: Julien Grall <jgrall@amazon.com>

Thanks,


Juergen


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 03/12] xen/spinlock: introduce new type for recursive spinlocks
  2023-12-12 13:04     ` Juergen Gross
@ 2023-12-12 13:07       ` Julien Grall
  0 siblings, 0 replies; 73+ messages in thread
From: Julien Grall @ 2023-12-12 13:07 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Jan Beulich, Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Stefano Stabellini, Paul Durrant

Hi Juergen,

On 12/12/2023 13:04, Juergen Gross wrote:
> On 12.12.23 13:57, Julien Grall wrote:
>> Hi Juergen,
>>
>> On 12/12/2023 09:47, Juergen Gross wrote:
>>> diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
>>> index 1cd9120eac..20d15f34dd 100644
>>> --- a/xen/include/xen/spinlock.h
>>> +++ b/xen/include/xen/spinlock.h
>>> @@ -45,7 +45,7 @@ union lock_debug { };
>>>       lock profiling on:
>>>       Global locks which should be subject to profiling must be 
>>> declared via
>>> -    DEFINE_SPINLOCK.
>>> +    DEFINE_[R]SPINLOCK.
>>>       For locks in structures further measures are necessary:
>>>       - the structure definition must include a profile_head with 
>>> exactly this
>>> @@ -56,7 +56,7 @@ union lock_debug { };
>>>       - the single locks which are subject to profiling have to be 
>>> initialized
>>>         via
>>> -      spin_lock_init_prof(ptr, lock);
>>> +      [r]spin_lock_init_prof(ptr, lock);
>>>         with ptr being the main structure pointer and lock the 
>>> spinlock field
>>> @@ -109,12 +109,16 @@ struct lock_profile_qhead {
>>>       spinlock_t l = 
>>> _SPIN_LOCK_UNLOCKED(NULL);                                 \
>>>       static struct lock_profile __lock_profile_data_##l = 
>>> _LOCK_PROFILE(l);    \
>>>       _LOCK_PROFILE_PTR(l)
>>> +#define 
>>> DEFINE_RSPINLOCK(l)                                                   \
>>> +    rspinlock_t l = 
>>> _SPIN_LOCK_UNLOCKED(NULL);                                \
>>> +    static struct lock_profile __lock_profile_data_##l = 
>>> _LOCK_PROFILE(l);    \
>>> +    _LOCK_PROFILE_PTR(l)
>>> -#define spin_lock_init_prof(s, 
>>> l)                                             \
>>> +#define __spin_lock_init_prof(s, l, 
>>> locktype)                                 \
>>
>> If I am not mistaken the double-underscore prefix is a violation in 
>> MISRA. So can this be renamed to:
>>
>> spin_lock_init_prof__()?
> 
> Fine with me.
> 
> Note that __lock_profile_data_##l and __lock_profile_##name seem to violate
> MISRA, too. Probably a good idea to change them as well? This should 
> probably
> be done as a prereq patch then?

It would be preferable if this is done in a separate patch. But I don't 
mind if this is not part of this series or if you don't want to do it. 
They are existing violations and not the only ones in the codebase.

But we should try to avoid adding new ones.

Cheers,

-- 
Julien Grall


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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2023-12-12 12:39   ` Julien Grall
@ 2023-12-12 13:08     ` Juergen Gross
  2023-12-12 14:04       ` Julien Grall
  0 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-12 13:08 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini, Wei Liu


[-- Attachment #1.1.1: Type: text/plain, Size: 3295 bytes --]

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

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2023-12-12 13:08     ` Juergen Gross
@ 2023-12-12 14:04       ` Julien Grall
  0 siblings, 0 replies; 73+ messages in thread
From: Julien Grall @ 2023-12-12 14:04 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini, Wei Liu



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,

-- 
Julien Grall


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

* Re: [PATCH v4 05/12] xen/spinlock: add rspin_[un]lock_irq[save|restore]()
  2023-12-12 13:03   ` Julien Grall
@ 2023-12-12 14:16     ` Juergen Gross
  0 siblings, 0 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-12 14:16 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Jan Beulich, Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Stefano Stabellini


[-- Attachment #1.1.1: Type: text/plain, Size: 3708 bytes --]

On 12.12.23 14:03, Julien Grall wrote:
> Hi Juergen,
> 
> On 12/12/2023 09:47, Juergen Gross wrote:
>> Instead of special casing rspin_lock_irqsave() and
>> rspin_unlock_irqrestore() for the console lock, add those functions
>> to spinlock handling and use them where needed.
>>
>> Signed-off-by: Juergen Gross <jgross@suse.com>
>> ---
>> V2:
>> - new patch
>> ---
>>   xen/arch/x86/traps.c       | 14 ++++++++------
>>   xen/common/spinlock.c      | 16 ++++++++++++++++
>>   xen/drivers/char/console.c | 18 +-----------------
>>   xen/include/xen/console.h  |  5 +++--
>>   xen/include/xen/spinlock.h |  7 +++++++
>>   5 files changed, 35 insertions(+), 25 deletions(-)
>>
>> diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
>> index 7724306116..21227877b3 100644
>> --- a/xen/arch/x86/traps.c
>> +++ b/xen/arch/x86/traps.c
>> @@ -647,13 +647,15 @@ void show_stack_overflow(unsigned int cpu, const struct 
>> cpu_user_regs *regs)
>>   void show_execution_state(const struct cpu_user_regs *regs)
>>   {
>>       /* Prevent interleaving of output. */
>> -    unsigned long flags = console_lock_recursive_irqsave();
>> +    unsigned long flags;
>> +
>> +    rspin_lock_irqsave(&console_lock, flags);
>>       show_registers(regs);
>>       show_code(regs);
>>       show_stack(regs);
>> -    console_unlock_recursive_irqrestore(flags);
>> +    rspin_unlock_irqrestore(&console_lock, flags);
>>   }
>>   void cf_check show_execution_state_nonconst(struct cpu_user_regs *regs)
>> @@ -663,7 +665,7 @@ void cf_check show_execution_state_nonconst(struct 
>> cpu_user_regs *regs)
>>   void vcpu_show_execution_state(struct vcpu *v)
>>   {
>> -    unsigned long flags = 0;
>> +    unsigned long flags;
>>       if ( test_bit(_VPF_down, &v->pause_flags) )
>>       {
>> @@ -698,7 +700,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>>   #endif
>>       /* Prevent interleaving of output. */
>> -    flags = console_lock_recursive_irqsave();
>> +    rspin_lock_irqsave(&console_lock, flags);
>>       vcpu_show_registers(v);
>> @@ -708,7 +710,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>>            * Stop interleaving prevention: The necessary P2M lookups involve
>>            * locking, which has to occur with IRQs enabled.
>>            */
>> -        console_unlock_recursive_irqrestore(flags);
>> +        rspin_unlock_irqrestore(&console_lock, flags);
>>           show_hvm_stack(v, &v->arch.user_regs);
>>       }
>> @@ -717,7 +719,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>>           if ( guest_kernel_mode(v, &v->arch.user_regs) )
>>               show_guest_stack(v, &v->arch.user_regs);
>> -        console_unlock_recursive_irqrestore(flags);
>> +        rspin_unlock_irqrestore(&console_lock, flags);
>>       }
>>   #ifdef CONFIG_HVM
>> diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
>> index 422a7fb1db..c1a9ba1304 100644
>> --- a/xen/common/spinlock.c
>> +++ b/xen/common/spinlock.c
>> @@ -475,6 +475,16 @@ void rspin_lock(rspinlock_t *lock)
>>       lock->recurse_cnt++;
>>   }
>> +unsigned long __rspin_lock_irqsave(rspinlock_t *lock)
> 
> This is going to be a problem with MISRA (see Rule 21.1). Can you move the 
> double underscore to the end? Alternatively, I am not sure I see the benefits of 
> the function here. So maybe we can fold the code in the macro below?

I think I'll follow the common pattern and just rename the function as you
suggest.


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware
  2023-12-12  9:47 ` [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware Juergen Gross
@ 2023-12-12 18:42   ` Julien Grall
  2023-12-13  6:05     ` Juergen Gross
  2024-02-28 15:19   ` Jan Beulich
  1 sibling, 1 reply; 73+ messages in thread
From: Julien Grall @ 2023-12-12 18:42 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini,
	Wei Liu, Alejandro Vallejo

Hi,

On 12/12/2023 09:47, Juergen Gross wrote:
> Struct lock_profile contains a pointer to the spinlock it is associated
> with. Prepare support of differing spinlock_t and rspinlock_t types by
> adding a type indicator of the pointer. Use the highest bit of the
> block_cnt member for this indicator in order to not grow the struct
> while hurting only the slow path with slightly less performant code.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>
> Acked-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
> ---
> V2:
> - new patch
> ---
>   xen/common/spinlock.c      | 26 +++++++++++++++++++-------
>   xen/include/xen/spinlock.h | 10 ++++++++--
>   2 files changed, 27 insertions(+), 9 deletions(-)
> 
> diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
> index c1a9ba1304..7d611d3d7d 100644
> --- a/xen/common/spinlock.c
> +++ b/xen/common/spinlock.c
> @@ -538,19 +538,31 @@ static void spinlock_profile_iterate(lock_profile_subfunc *sub, void *par)
>   static void cf_check spinlock_profile_print_elem(struct lock_profile *data,
>       int32_t type, int32_t idx, void *par)
>   {
> -    struct spinlock *lock = data->lock;
> +    unsigned int cpu;
> +    uint32_t lockval;
> +
> +    if ( data->is_rlock )
> +    {
> +        cpu = data->rlock->debug.cpu;
> +        lockval = data->rlock->tickets.head_tail;
> +    }
> +    else
> +    {
> +        cpu = data->lock->debug.cpu;
> +        lockval = data->lock->tickets.head_tail;
> +    }
>   
>       printk("%s ", lock_profile_ancs[type].name);
>       if ( type != LOCKPROF_TYPE_GLOBAL )
>           printk("%d ", idx);
> -    printk("%s: addr=%p, lockval=%08x, ", data->name, lock,
> -           lock->tickets.head_tail);
> -    if ( lock->debug.cpu == SPINLOCK_NO_CPU )
> +    printk("%s: addr=%p, lockval=%08x, ", data->name, data->lock, lockval);
> +    if ( cpu == SPINLOCK_NO_CPU )
>           printk("not locked\n");
>       else
> -        printk("cpu=%d\n", lock->debug.cpu);
> -    printk("  lock:%" PRId64 "(%" PRI_stime "), block:%" PRId64 "(%" PRI_stime ")\n",
> -           data->lock_cnt, data->time_hold, data->block_cnt, data->time_block);
> +        printk("cpu=%u\n", cpu);
> +    printk("  lock:%" PRIu64 "(%" PRI_stime "), block:%" PRIu64 "(%" PRI_stime ")\n",
> +           data->lock_cnt, data->time_hold, (uint64_t)data->block_cnt,
> +           data->time_block);
>   }
>   
>   void cf_check spinlock_profile_printall(unsigned char key)
> diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
> index 05b97c1e03..ac3bef267a 100644
> --- a/xen/include/xen/spinlock.h
> +++ b/xen/include/xen/spinlock.h
> @@ -76,13 +76,19 @@ union lock_debug { };
>   */
>   
>   struct spinlock;
> +/* Temporary hack until a dedicated struct rspinlock is existing. */
> +#define rspinlock spinlock
>   
>   struct lock_profile {
>       struct lock_profile *next;       /* forward link */
>       const char          *name;       /* lock name */
> -    struct spinlock     *lock;       /* the lock itself */
> +    union {
> +        struct spinlock *lock;       /* the lock itself */
> +        struct rspinlock *rlock;     /* the recursive lock itself */
> +    };
>       uint64_t            lock_cnt;    /* # of complete locking ops */
> -    uint64_t            block_cnt;   /* # of complete wait for lock */
> +    uint64_t            block_cnt:63; /* # of complete wait for lock */
> +    uint64_t            is_rlock:1;  /* use rlock pointer */

This is meant to act like a bool. So I would prefer if we use:

bool is_rwlock:1;

And then use true/false when set.

Acked-by: Julien Grall <jgrall@amazon.com>

>       s_time_t            time_hold;   /* cumulated lock time */
>       s_time_t            time_block;  /* cumulated wait time */
>       s_time_t            time_locked; /* system time of last locking */

Cheers,

-- 
Julien Grall


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

* Re: [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions
  2023-12-12  9:47 ` [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions Juergen Gross
@ 2023-12-12 18:49   ` Julien Grall
  2023-12-13  6:17     ` Juergen Gross
  2024-02-29 13:49   ` Jan Beulich
  1 sibling, 1 reply; 73+ messages in thread
From: Julien Grall @ 2023-12-12 18:49 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Stefano Stabellini, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Jan Beulich,
	Wei Liu, Roger Pau Monné,
	Tamas K Lengyel, Lukasz Hawrylko, Daniel P. Smith,
	Mateusz Mówka

Hi Juergen,

On 12/12/2023 09:47, Juergen Gross wrote:
> -#define spin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, spinlock_t)
> -#define rspin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, rspinlock_t)
> +#define spin_lock_init_prof(s, l)                                             \
> +    __spin_lock_init_prof(s, l, lock, spinlock_t, 0)
> +#define rspin_lock_init_prof(s, l)                                            \
> +    __spin_lock_init_prof(s, l, rlock, rspinlock_t, 1)
>   
>   void _lock_profile_register_struct(
>       int32_t type, struct lock_profile_qhead *qhead, int32_t idx);
> @@ -174,6 +179,7 @@ struct lock_profile_qhead { };
>   
>   #endif
>   
> +

Spurious change?

>   typedef union {
>       uint32_t head_tail;
>       struct {
> @@ -261,4 +267,12 @@ void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags);
>   /* Ensure a lock is quiescent between two critical operations. */
>   #define spin_barrier(l)               _spin_barrier(l)
>   
> +#define nrspin_trylock(l)    spin_trylock(l)
> +#define nrspin_lock(l)       spin_lock(l)
> +#define nrspin_unlock(l)     spin_unlock(l)
> +#define nrspin_lock_irq(l)   spin_lock_irq(l)
> +#define nrspin_unlock_irq(l) spin_unlock_irq(l)
> +#define nrspin_lock_irqsave(l, f)      spin_lock_irqsave(l, f)
> +#define nrspin_unlock_irqrestore(l, f) spin_unlock_irqrestore(l, f)

There is a comment describing [r]spinlock but not this new variant. Can 
you add one?

That said, I know this is existing code, but I have to admit this is a 
bit unclear why we are allowing an recursive spinlock to be 
non-recursive. To me it sounds like we are making the typesafe not very 
safe because it doesn't guarantee that we are not mixing the call 
nrspin_* with rspin_*.

Cheers,

-- 
Julien Grall


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

* Re: [PATCH v4 08/12] xen/spinlock: add another function level
  2023-12-12  9:47 ` [PATCH v4 08/12] xen/spinlock: add another function level Juergen Gross
@ 2023-12-12 19:10   ` Julien Grall
  2023-12-13  6:23     ` Juergen Gross
  2024-02-29 13:59   ` Jan Beulich
  1 sibling, 1 reply; 73+ messages in thread
From: Julien Grall @ 2023-12-12 19:10 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini, Wei Liu

Hi Juergen,

On 12/12/2023 09:47, Juergen Gross wrote:
> Add another function level in spinlock.c hiding the spinlock_t layout
> from the low level locking code.
> 
> This is done in preparation of introducing rspinlock_t for recursive
> locks without having to duplicate all of the locking code.

So all the fields you pass are the one from spinlock.

Looking at pahole after this series is applid, we have:

==== Debug + Lock profile ====

struct spinlock {
         spinlock_tickets_t         tickets;              /*     0     4 */
         union lock_debug           debug;                /*     4     4 */
         struct lock_profile *      profile;              /*     8     8 */

         /* size: 16, cachelines: 1, members: 3 */
         /* last cacheline: 16 bytes */
};
struct rspinlock {
         spinlock_tickets_t         tickets;              /*     0     4 */
         uint16_t                   recurse_cpu;          /*     4     2 */
         uint8_t                    recurse_cnt;          /*     6     1 */

         /* XXX 1 byte hole, try to pack */

         union lock_debug           debug;                /*     8     4 */

         /* XXX 4 bytes hole, try to pack */

         struct lock_profile *      profile;              /*    16     8 */

         /* size: 24, cachelines: 1, members: 5 */
         /* sum members: 19, holes: 2, sum holes: 5 */
         /* last cacheline: 24 bytes */
};


==== Debug ====

struct spinlock {
         spinlock_tickets_t         tickets;              /*     0     4 */
         union lock_debug           debug;                /*     4     4 */

         /* size: 8, cachelines: 1, members: 2 */
         /* last cacheline: 8 bytes */
};
struct rspinlock {
         spinlock_tickets_t         tickets;              /*     0     4 */
         uint16_t                   recurse_cpu;          /*     4     2 */
         uint8_t                    recurse_cnt;          /*     6     1 */

         /* XXX 1 byte hole, try to pack */

         union lock_debug           debug;                /*     8     4 */

         /* size: 12, cachelines: 1, members: 4 */
         /* sum members: 11, holes: 1, sum holes: 1 */
         /* last cacheline: 12 bytes */
};

==== Prod ====

struct spinlock {
         spinlock_tickets_t         tickets;              /*     0     4 */
         union lock_debug           debug;                /*     4     0 */

         /* size: 4, cachelines: 1, members: 2 */
         /* last cacheline: 4 bytes */
};
struct rspinlock {
         spinlock_tickets_t         tickets;              /*     0     4 */
         uint16_t                   recurse_cpu;          /*     4     2 */
         uint8_t                    recurse_cnt;          /*     6     1 */
         union lock_debug           debug;                /*     7     0 */

         /* size: 8, cachelines: 1, members: 4 */
         /* padding: 1 */
         /* last cacheline: 8 bytes */
};


I think we could embed spinlock_t in rspinlock_t without increasing 
rspinlock_t. Have you considered it? This could reduce the number of 
function level introduced in this series.

Cheers,

-- 
Julien Grall


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

* Re: [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware
  2023-12-12 18:42   ` Julien Grall
@ 2023-12-13  6:05     ` Juergen Gross
  2023-12-13  8:32       ` Julien Grall
  2023-12-13  8:36       ` Jan Beulich
  0 siblings, 2 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-13  6:05 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini,
	Wei Liu, Alejandro Vallejo


[-- Attachment #1.1.1: Type: text/plain, Size: 4345 bytes --]

On 12.12.23 19:42, Julien Grall wrote:
> Hi,
> 
> On 12/12/2023 09:47, Juergen Gross wrote:
>> Struct lock_profile contains a pointer to the spinlock it is associated
>> with. Prepare support of differing spinlock_t and rspinlock_t types by
>> adding a type indicator of the pointer. Use the highest bit of the
>> block_cnt member for this indicator in order to not grow the struct
>> while hurting only the slow path with slightly less performant code.
>>
>> Signed-off-by: Juergen Gross <jgross@suse.com>
>> Acked-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
>> ---
>> V2:
>> - new patch
>> ---
>>   xen/common/spinlock.c      | 26 +++++++++++++++++++-------
>>   xen/include/xen/spinlock.h | 10 ++++++++--
>>   2 files changed, 27 insertions(+), 9 deletions(-)
>>
>> diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
>> index c1a9ba1304..7d611d3d7d 100644
>> --- a/xen/common/spinlock.c
>> +++ b/xen/common/spinlock.c
>> @@ -538,19 +538,31 @@ static void 
>> spinlock_profile_iterate(lock_profile_subfunc *sub, void *par)
>>   static void cf_check spinlock_profile_print_elem(struct lock_profile *data,
>>       int32_t type, int32_t idx, void *par)
>>   {
>> -    struct spinlock *lock = data->lock;
>> +    unsigned int cpu;
>> +    uint32_t lockval;
>> +
>> +    if ( data->is_rlock )
>> +    {
>> +        cpu = data->rlock->debug.cpu;
>> +        lockval = data->rlock->tickets.head_tail;
>> +    }
>> +    else
>> +    {
>> +        cpu = data->lock->debug.cpu;
>> +        lockval = data->lock->tickets.head_tail;
>> +    }
>>       printk("%s ", lock_profile_ancs[type].name);
>>       if ( type != LOCKPROF_TYPE_GLOBAL )
>>           printk("%d ", idx);
>> -    printk("%s: addr=%p, lockval=%08x, ", data->name, lock,
>> -           lock->tickets.head_tail);
>> -    if ( lock->debug.cpu == SPINLOCK_NO_CPU )
>> +    printk("%s: addr=%p, lockval=%08x, ", data->name, data->lock, lockval);
>> +    if ( cpu == SPINLOCK_NO_CPU )
>>           printk("not locked\n");
>>       else
>> -        printk("cpu=%d\n", lock->debug.cpu);
>> -    printk("  lock:%" PRId64 "(%" PRI_stime "), block:%" PRId64 "(%" 
>> PRI_stime ")\n",
>> -           data->lock_cnt, data->time_hold, data->block_cnt, data->time_block);
>> +        printk("cpu=%u\n", cpu);
>> +    printk("  lock:%" PRIu64 "(%" PRI_stime "), block:%" PRIu64 "(%" 
>> PRI_stime ")\n",
>> +           data->lock_cnt, data->time_hold, (uint64_t)data->block_cnt,
>> +           data->time_block);
>>   }
>>   void cf_check spinlock_profile_printall(unsigned char key)
>> diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
>> index 05b97c1e03..ac3bef267a 100644
>> --- a/xen/include/xen/spinlock.h
>> +++ b/xen/include/xen/spinlock.h
>> @@ -76,13 +76,19 @@ union lock_debug { };
>>   */
>>   struct spinlock;
>> +/* Temporary hack until a dedicated struct rspinlock is existing. */
>> +#define rspinlock spinlock
>>   struct lock_profile {
>>       struct lock_profile *next;       /* forward link */
>>       const char          *name;       /* lock name */
>> -    struct spinlock     *lock;       /* the lock itself */
>> +    union {
>> +        struct spinlock *lock;       /* the lock itself */
>> +        struct rspinlock *rlock;     /* the recursive lock itself */
>> +    };
>>       uint64_t            lock_cnt;    /* # of complete locking ops */
>> -    uint64_t            block_cnt;   /* # of complete wait for lock */
>> +    uint64_t            block_cnt:63; /* # of complete wait for lock */
>> +    uint64_t            is_rlock:1;  /* use rlock pointer */
> 
> This is meant to act like a bool. So I would prefer if we use:
> 
> bool is_rwlock:1;
> 
> And then use true/false when set.

Do we want to do that? AFAIK it would depend on the compiler what the size of
the struct is when mixing types in bitfields (in this case: bool and uint64_t).

> Acked-by: Julien Grall <jgrall@amazon.com>

Thanks,


Juergen


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions
  2023-12-12 18:49   ` Julien Grall
@ 2023-12-13  6:17     ` Juergen Gross
  2023-12-13  8:36       ` Julien Grall
  0 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-13  6:17 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Stefano Stabellini, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Jan Beulich,
	Wei Liu, Roger Pau Monné,
	Tamas K Lengyel, Lukasz Hawrylko, Daniel P. Smith,
	Mateusz Mówka


[-- Attachment #1.1.1: Type: text/plain, Size: 2485 bytes --]

On 12.12.23 19:49, Julien Grall wrote:
> Hi Juergen,
> 
> On 12/12/2023 09:47, Juergen Gross wrote:
>> -#define spin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, spinlock_t)
>> -#define rspin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, rspinlock_t)
>> +#define spin_lock_init_prof(s, l)                                             \
>> +    __spin_lock_init_prof(s, l, lock, spinlock_t, 0)
>> +#define rspin_lock_init_prof(s, l)                                            \
>> +    __spin_lock_init_prof(s, l, rlock, rspinlock_t, 1)
>>   void _lock_profile_register_struct(
>>       int32_t type, struct lock_profile_qhead *qhead, int32_t idx);
>> @@ -174,6 +179,7 @@ struct lock_profile_qhead { };
>>   #endif
>> +
> 
> Spurious change?

Indeed, will remove it.

> 
>>   typedef union {
>>       uint32_t head_tail;
>>       struct {
>> @@ -261,4 +267,12 @@ void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned 
>> long flags);
>>   /* Ensure a lock is quiescent between two critical operations. */
>>   #define spin_barrier(l)               _spin_barrier(l)
>> +#define nrspin_trylock(l)    spin_trylock(l)
>> +#define nrspin_lock(l)       spin_lock(l)
>> +#define nrspin_unlock(l)     spin_unlock(l)
>> +#define nrspin_lock_irq(l)   spin_lock_irq(l)
>> +#define nrspin_unlock_irq(l) spin_unlock_irq(l)
>> +#define nrspin_lock_irqsave(l, f)      spin_lock_irqsave(l, f)
>> +#define nrspin_unlock_irqrestore(l, f) spin_unlock_irqrestore(l, f)
> 
> There is a comment describing [r]spinlock but not this new variant. Can you add 
> one?

Okay.

> That said, I know this is existing code, but I have to admit this is a bit 
> unclear why we are allowing an recursive spinlock to be non-recursive. To me it 
> sounds like we are making the typesafe not very safe because it doesn't 
> guarantee that we are not mixing the call nrspin_* with rspin_*.

This is the current API.

If you have locked with nrspin_*, any rspin_* attempt on the same lock will
spin until rspin_unlock (nrspin_* will not set recurse_cpu, but take the
lock).

If you have locked with rspin_*, any nrspin_* attempt on the same lock will
spin, too.

So I don't see any major problem regarding accidental misuse, which wouldn't
be visible by deadlocks (there is no silent misbehavior).


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 08/12] xen/spinlock: add another function level
  2023-12-12 19:10   ` Julien Grall
@ 2023-12-13  6:23     ` Juergen Gross
  2023-12-13  8:43       ` Julien Grall
  0 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-13  6:23 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini, Wei Liu


[-- Attachment #1.1.1: Type: text/plain, Size: 4538 bytes --]

On 12.12.23 20:10, Julien Grall wrote:
> Hi Juergen,
> 
> On 12/12/2023 09:47, Juergen Gross wrote:
>> Add another function level in spinlock.c hiding the spinlock_t layout
>> from the low level locking code.
>>
>> This is done in preparation of introducing rspinlock_t for recursive
>> locks without having to duplicate all of the locking code.
> 
> So all the fields you pass are the one from spinlock.
> 
> Looking at pahole after this series is applid, we have:
> 
> ==== Debug + Lock profile ====
> 
> struct spinlock {
>          spinlock_tickets_t         tickets;              /*     0     4 */
>          union lock_debug           debug;                /*     4     4 */
>          struct lock_profile *      profile;              /*     8     8 */
> 
>          /* size: 16, cachelines: 1, members: 3 */
>          /* last cacheline: 16 bytes */
> };
> struct rspinlock {
>          spinlock_tickets_t         tickets;              /*     0     4 */
>          uint16_t                   recurse_cpu;          /*     4     2 */
>          uint8_t                    recurse_cnt;          /*     6     1 */
> 
>          /* XXX 1 byte hole, try to pack */
> 
>          union lock_debug           debug;                /*     8     4 */
> 
>          /* XXX 4 bytes hole, try to pack */
> 
>          struct lock_profile *      profile;              /*    16     8 */
> 
>          /* size: 24, cachelines: 1, members: 5 */
>          /* sum members: 19, holes: 2, sum holes: 5 */
>          /* last cacheline: 24 bytes */
> };
> 
> 
> ==== Debug ====
> 
> struct spinlock {
>          spinlock_tickets_t         tickets;              /*     0     4 */
>          union lock_debug           debug;                /*     4     4 */
> 
>          /* size: 8, cachelines: 1, members: 2 */
>          /* last cacheline: 8 bytes */
> };
> struct rspinlock {
>          spinlock_tickets_t         tickets;              /*     0     4 */
>          uint16_t                   recurse_cpu;          /*     4     2 */
>          uint8_t                    recurse_cnt;          /*     6     1 */
> 
>          /* XXX 1 byte hole, try to pack */
> 
>          union lock_debug           debug;                /*     8     4 */
> 
>          /* size: 12, cachelines: 1, members: 4 */
>          /* sum members: 11, holes: 1, sum holes: 1 */
>          /* last cacheline: 12 bytes */
> };
> 
> ==== Prod ====
> 
> struct spinlock {
>          spinlock_tickets_t         tickets;              /*     0     4 */
>          union lock_debug           debug;                /*     4     0 */
> 
>          /* size: 4, cachelines: 1, members: 2 */
>          /* last cacheline: 4 bytes */
> };
> struct rspinlock {
>          spinlock_tickets_t         tickets;              /*     0     4 */
>          uint16_t                   recurse_cpu;          /*     4     2 */
>          uint8_t                    recurse_cnt;          /*     6     1 */
>          union lock_debug           debug;                /*     7     0 */
> 
>          /* size: 8, cachelines: 1, members: 4 */
>          /* padding: 1 */
>          /* last cacheline: 8 bytes */
> };
> 
> 
> I think we could embed spinlock_t in rspinlock_t without increasing rspinlock_t. 
> Have you considered it? This could reduce the number of function level 
> introduced in this series.

That was the layout in the first version of this series. Jan requested to change
it to the current layout [1].


Juergen

[1]: https://lists.xen.org/archives/html/xen-devel/2022-12/msg01054.html

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware
  2023-12-13  6:05     ` Juergen Gross
@ 2023-12-13  8:32       ` Julien Grall
  2023-12-13  8:36       ` Jan Beulich
  1 sibling, 0 replies; 73+ messages in thread
From: Julien Grall @ 2023-12-13  8:32 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini,
	Wei Liu, Alejandro Vallejo

Hi Juergen,

On 13/12/2023 06:05, Juergen Gross wrote:
> On 12.12.23 19:42, Julien Grall wrote:
>> Hi,
>>
>> On 12/12/2023 09:47, Juergen Gross wrote:
>>> Struct lock_profile contains a pointer to the spinlock it is associated
>>> with. Prepare support of differing spinlock_t and rspinlock_t types by
>>> adding a type indicator of the pointer. Use the highest bit of the
>>> block_cnt member for this indicator in order to not grow the struct
>>> while hurting only the slow path with slightly less performant code.
>>>
>>> Signed-off-by: Juergen Gross <jgross@suse.com>
>>> Acked-by: Alejandro Vallejo <alejandro.vallejo@cloud.com>
>>> ---
>>> V2:
>>> - new patch
>>> ---
>>>   xen/common/spinlock.c      | 26 +++++++++++++++++++-------
>>>   xen/include/xen/spinlock.h | 10 ++++++++--
>>>   2 files changed, 27 insertions(+), 9 deletions(-)
>>>
>>> diff --git a/xen/common/spinlock.c b/xen/common/spinlock.c
>>> index c1a9ba1304..7d611d3d7d 100644
>>> --- a/xen/common/spinlock.c
>>> +++ b/xen/common/spinlock.c
>>> @@ -538,19 +538,31 @@ static void 
>>> spinlock_profile_iterate(lock_profile_subfunc *sub, void *par)
>>>   static void cf_check spinlock_profile_print_elem(struct 
>>> lock_profile *data,
>>>       int32_t type, int32_t idx, void *par)
>>>   {
>>> -    struct spinlock *lock = data->lock;
>>> +    unsigned int cpu;
>>> +    uint32_t lockval;
>>> +
>>> +    if ( data->is_rlock )
>>> +    {
>>> +        cpu = data->rlock->debug.cpu;
>>> +        lockval = data->rlock->tickets.head_tail;
>>> +    }
>>> +    else
>>> +    {
>>> +        cpu = data->lock->debug.cpu;
>>> +        lockval = data->lock->tickets.head_tail;
>>> +    }
>>>       printk("%s ", lock_profile_ancs[type].name);
>>>       if ( type != LOCKPROF_TYPE_GLOBAL )
>>>           printk("%d ", idx);
>>> -    printk("%s: addr=%p, lockval=%08x, ", data->name, lock,
>>> -           lock->tickets.head_tail);
>>> -    if ( lock->debug.cpu == SPINLOCK_NO_CPU )
>>> +    printk("%s: addr=%p, lockval=%08x, ", data->name, data->lock, 
>>> lockval);
>>> +    if ( cpu == SPINLOCK_NO_CPU )
>>>           printk("not locked\n");
>>>       else
>>> -        printk("cpu=%d\n", lock->debug.cpu);
>>> -    printk("  lock:%" PRId64 "(%" PRI_stime "), block:%" PRId64 "(%" 
>>> PRI_stime ")\n",
>>> -           data->lock_cnt, data->time_hold, data->block_cnt, 
>>> data->time_block);
>>> +        printk("cpu=%u\n", cpu);
>>> +    printk("  lock:%" PRIu64 "(%" PRI_stime "), block:%" PRIu64 "(%" 
>>> PRI_stime ")\n",
>>> +           data->lock_cnt, data->time_hold, (uint64_t)data->block_cnt,
>>> +           data->time_block);
>>>   }
>>>   void cf_check spinlock_profile_printall(unsigned char key)
>>> diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h
>>> index 05b97c1e03..ac3bef267a 100644
>>> --- a/xen/include/xen/spinlock.h
>>> +++ b/xen/include/xen/spinlock.h
>>> @@ -76,13 +76,19 @@ union lock_debug { };
>>>   */
>>>   struct spinlock;
>>> +/* Temporary hack until a dedicated struct rspinlock is existing. */
>>> +#define rspinlock spinlock
>>>   struct lock_profile {
>>>       struct lock_profile *next;       /* forward link */
>>>       const char          *name;       /* lock name */
>>> -    struct spinlock     *lock;       /* the lock itself */
>>> +    union {
>>> +        struct spinlock *lock;       /* the lock itself */
>>> +        struct rspinlock *rlock;     /* the recursive lock itself */
>>> +    };
>>>       uint64_t            lock_cnt;    /* # of complete locking ops */
>>> -    uint64_t            block_cnt;   /* # of complete wait for lock */
>>> +    uint64_t            block_cnt:63; /* # of complete wait for lock */
>>> +    uint64_t            is_rlock:1;  /* use rlock pointer */
>>
>> This is meant to act like a bool. So I would prefer if we use:
>>
>> bool is_rwlock:1;
>>
>> And then use true/false when set.
> 
> Do we want to do that? AFAIK it would depend on the compiler what the 
> size of
> the struct is when mixing types in bitfields (in this case: bool and 
> uint64_t).

I looked through our codebase and I could already find some use. Such as:

typedef union
{
     struct
     {
         uint8_t  vector;
         uint8_t  type:3;
         bool     ev:1;
         uint32_t resvd1:19;
         bool     v:1;
         uint32_t ec;
     };
     uint64_t raw;
} intinfo_t;

So I would assume that a mix is possible or we would have problem in 
other places.

Anyway, this is not a critical comment. It is just a preference of using 
true/false when a field can only be 0 or 1.

Cheers,

-- 
Julien Grall


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

* Re: [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware
  2023-12-13  6:05     ` Juergen Gross
  2023-12-13  8:32       ` Julien Grall
@ 2023-12-13  8:36       ` Jan Beulich
  2023-12-13  9:07         ` Juergen Gross
  1 sibling, 1 reply; 73+ messages in thread
From: Jan Beulich @ 2023-12-13  8:36 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Stefano Stabellini, Wei Liu,
	Alejandro Vallejo, Julien Grall, xen-devel

On 13.12.2023 07:05, Juergen Gross wrote:
> On 12.12.23 19:42, Julien Grall wrote:
>> On 12/12/2023 09:47, Juergen Gross wrote:
>>> --- a/xen/include/xen/spinlock.h
>>> +++ b/xen/include/xen/spinlock.h
>>> @@ -76,13 +76,19 @@ union lock_debug { };
>>>   */
>>>   struct spinlock;
>>> +/* Temporary hack until a dedicated struct rspinlock is existing. */
>>> +#define rspinlock spinlock
>>>   struct lock_profile {
>>>       struct lock_profile *next;       /* forward link */
>>>       const char          *name;       /* lock name */
>>> -    struct spinlock     *lock;       /* the lock itself */
>>> +    union {
>>> +        struct spinlock *lock;       /* the lock itself */
>>> +        struct rspinlock *rlock;     /* the recursive lock itself */
>>> +    };
>>>       uint64_t            lock_cnt;    /* # of complete locking ops */
>>> -    uint64_t            block_cnt;   /* # of complete wait for lock */
>>> +    uint64_t            block_cnt:63; /* # of complete wait for lock */
>>> +    uint64_t            is_rlock:1;  /* use rlock pointer */
>>
>> This is meant to act like a bool. So I would prefer if we use:
>>
>> bool is_rwlock:1;
>>
>> And then use true/false when set.
> 
> Do we want to do that? AFAIK it would depend on the compiler what the size of
> the struct is when mixing types in bitfields (in this case: bool and uint64_t).

I thought in a similar way as you did when Andrew introduced similar
patterns (see Julien's reply for an example), and was then convinced
that the compiler really is supposed to be doing what we want here.
So yes, I second Julien's desire to have bool used when boolean is
meant.

Jan


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

* Re: [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions
  2023-12-13  6:17     ` Juergen Gross
@ 2023-12-13  8:36       ` Julien Grall
  2023-12-13  9:11         ` Juergen Gross
  0 siblings, 1 reply; 73+ messages in thread
From: Julien Grall @ 2023-12-13  8:36 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Stefano Stabellini, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Jan Beulich,
	Wei Liu, Roger Pau Monné,
	Tamas K Lengyel, Lukasz Hawrylko, Daniel P. Smith,
	Mateusz Mówka



On 13/12/2023 06:17, Juergen Gross wrote:
> On 12.12.23 19:49, Julien Grall wrote:
>> Hi Juergen,
>>
>> On 12/12/2023 09:47, Juergen Gross wrote:
>>> -#define spin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, 
>>> spinlock_t)
>>> -#define rspin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, 
>>> rspinlock_t)
>>> +#define spin_lock_init_prof(s, 
>>> l)                                             \
>>> +    __spin_lock_init_prof(s, l, lock, spinlock_t, 0)
>>> +#define rspin_lock_init_prof(s, 
>>> l)                                            \
>>> +    __spin_lock_init_prof(s, l, rlock, rspinlock_t, 1)
>>>   void _lock_profile_register_struct(
>>>       int32_t type, struct lock_profile_qhead *qhead, int32_t idx);
>>> @@ -174,6 +179,7 @@ struct lock_profile_qhead { };
>>>   #endif
>>> +
>>
>> Spurious change?
> 
> Indeed, will remove it.
> 
>>
>>>   typedef union {
>>>       uint32_t head_tail;
>>>       struct {
>>> @@ -261,4 +267,12 @@ void rspin_unlock_irqrestore(rspinlock_t *lock, 
>>> unsigned long flags);
>>>   /* Ensure a lock is quiescent between two critical operations. */
>>>   #define spin_barrier(l)               _spin_barrier(l)
>>> +#define nrspin_trylock(l)    spin_trylock(l)
>>> +#define nrspin_lock(l)       spin_lock(l)
>>> +#define nrspin_unlock(l)     spin_unlock(l)
>>> +#define nrspin_lock_irq(l)   spin_lock_irq(l)
>>> +#define nrspin_unlock_irq(l) spin_unlock_irq(l)
>>> +#define nrspin_lock_irqsave(l, f)      spin_lock_irqsave(l, f)
>>> +#define nrspin_unlock_irqrestore(l, f) spin_unlock_irqrestore(l, f)
>>
>> There is a comment describing [r]spinlock but not this new variant. 
>> Can you add one?
> 
> Okay.
> 
>> That said, I know this is existing code, but I have to admit this is a 
>> bit unclear why we are allowing an recursive spinlock to be 
>> non-recursive. To me it sounds like we are making the typesafe not 
>> very safe because it doesn't guarantee that we are not mixing the call 
>> nrspin_* with rspin_*.
> 
> This is the current API.

I know. This is why I wrote "I know this is existing code".

> 
> If you have locked with nrspin_*, any rspin_* attempt on the same lock will
> spin until rspin_unlock (nrspin_* will not set recurse_cpu, but take the
> lock).
> 
> If you have locked with rspin_*, any nrspin_* attempt on the same lock will
> spin, too.
> 
> So I don't see any major problem regarding accidental misuse, which 
> wouldn't
> be visible by deadlocks (there is no silent misbehavior).

Right, so this will lead to a deadlock, which is my concern. If we were 
using rspinlock_* everywhere then the deadlock (at least in the case 
when you recurse) would in theory not be possible (unless you recurse 
too much).

My point here is to simplify the interface rather than providing because 
I don't really see the benefits of providing a non-recursive version for 
recursive spinlock.

Anyway as I said this is nothing new.

Cheers,

-- 
Julien Grall


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

* Re: [PATCH v4 08/12] xen/spinlock: add another function level
  2023-12-13  6:23     ` Juergen Gross
@ 2023-12-13  8:43       ` Julien Grall
  2023-12-13  9:17         ` Juergen Gross
  0 siblings, 1 reply; 73+ messages in thread
From: Julien Grall @ 2023-12-13  8:43 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini, Wei Liu

Hi Juergen,

On 13/12/2023 06:23, Juergen Gross wrote:
> On 12.12.23 20:10, Julien Grall wrote:
>> Hi Juergen,
>>
>> On 12/12/2023 09:47, Juergen Gross wrote:
>>> Add another function level in spinlock.c hiding the spinlock_t layout
>>> from the low level locking code.
>>>
>>> This is done in preparation of introducing rspinlock_t for recursive
>>> locks without having to duplicate all of the locking code.
>>
>> So all the fields you pass are the one from spinlock.
>>
>> Looking at pahole after this series is applid, we have:
>>
>> ==== Debug + Lock profile ====
>>
>> struct spinlock {
>>          spinlock_tickets_t         tickets;              /*     0     
>> 4 */
>>          union lock_debug           debug;                /*     4     
>> 4 */
>>          struct lock_profile *      profile;              /*     8     
>> 8 */
>>
>>          /* size: 16, cachelines: 1, members: 3 */
>>          /* last cacheline: 16 bytes */
>> };
>> struct rspinlock {
>>          spinlock_tickets_t         tickets;              /*     0     
>> 4 */
>>          uint16_t                   recurse_cpu;          /*     4     
>> 2 */
>>          uint8_t                    recurse_cnt;          /*     6     
>> 1 */
>>
>>          /* XXX 1 byte hole, try to pack */
>>
>>          union lock_debug           debug;                /*     8     
>> 4 */
>>
>>          /* XXX 4 bytes hole, try to pack */
>>
>>          struct lock_profile *      profile;              /*    16     
>> 8 */
>>
>>          /* size: 24, cachelines: 1, members: 5 */
>>          /* sum members: 19, holes: 2, sum holes: 5 */
>>          /* last cacheline: 24 bytes */
>> };
>>
>>
>> ==== Debug ====
>>
>> struct spinlock {
>>          spinlock_tickets_t         tickets;              /*     0     
>> 4 */
>>          union lock_debug           debug;                /*     4     
>> 4 */
>>
>>          /* size: 8, cachelines: 1, members: 2 */
>>          /* last cacheline: 8 bytes */
>> };
>> struct rspinlock {
>>          spinlock_tickets_t         tickets;              /*     0     
>> 4 */
>>          uint16_t                   recurse_cpu;          /*     4     
>> 2 */
>>          uint8_t                    recurse_cnt;          /*     6     
>> 1 */
>>
>>          /* XXX 1 byte hole, try to pack */
>>
>>          union lock_debug           debug;                /*     8     
>> 4 */
>>
>>          /* size: 12, cachelines: 1, members: 4 */
>>          /* sum members: 11, holes: 1, sum holes: 1 */
>>          /* last cacheline: 12 bytes */
>> };
>>
>> ==== Prod ====
>>
>> struct spinlock {
>>          spinlock_tickets_t         tickets;              /*     0     
>> 4 */
>>          union lock_debug           debug;                /*     4     
>> 0 */
>>
>>          /* size: 4, cachelines: 1, members: 2 */
>>          /* last cacheline: 4 bytes */
>> };
>> struct rspinlock {
>>          spinlock_tickets_t         tickets;              /*     0     
>> 4 */
>>          uint16_t                   recurse_cpu;          /*     4     
>> 2 */
>>          uint8_t                    recurse_cnt;          /*     6     
>> 1 */
>>          union lock_debug           debug;                /*     7     
>> 0 */
>>
>>          /* size: 8, cachelines: 1, members: 4 */
>>          /* padding: 1 */
>>          /* last cacheline: 8 bytes */
>> };
>>
>>
>> I think we could embed spinlock_t in rspinlock_t without increasing 
>> rspinlock_t. Have you considered it? This could reduce the number of 
>> function level introduced in this series.
> 
> That was the layout in the first version of this series. Jan requested 
> to change
> it to the current layout [1].

Ah... Looking through the reasoning, I have to disagree with Jan 
argumentations. At least with the full series applied, there is no 
increase of rspinlock_t in debug build (if we compare to the version you 
provided in this series).

Furthermore, this is going to remove at least patch #6 and #8. We would 
still need nrspinlock_* because they can just be wrapper to
spin_barrier(&lock->lock).

This should also solve his concern of unwieldy code:

 > +    spin_barrier(&p2m->pod.lock.lock.lock);

Cheers,

-- 
Julien Grall


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

* Re: [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware
  2023-12-13  8:36       ` Jan Beulich
@ 2023-12-13  9:07         ` Juergen Gross
  0 siblings, 0 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-13  9:07 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Stefano Stabellini, Wei Liu,
	Alejandro Vallejo, Julien Grall, xen-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 1941 bytes --]

On 13.12.23 09:36, Jan Beulich wrote:
> On 13.12.2023 07:05, Juergen Gross wrote:
>> On 12.12.23 19:42, Julien Grall wrote:
>>> On 12/12/2023 09:47, Juergen Gross wrote:
>>>> --- a/xen/include/xen/spinlock.h
>>>> +++ b/xen/include/xen/spinlock.h
>>>> @@ -76,13 +76,19 @@ union lock_debug { };
>>>>    */
>>>>    struct spinlock;
>>>> +/* Temporary hack until a dedicated struct rspinlock is existing. */
>>>> +#define rspinlock spinlock
>>>>    struct lock_profile {
>>>>        struct lock_profile *next;       /* forward link */
>>>>        const char          *name;       /* lock name */
>>>> -    struct spinlock     *lock;       /* the lock itself */
>>>> +    union {
>>>> +        struct spinlock *lock;       /* the lock itself */
>>>> +        struct rspinlock *rlock;     /* the recursive lock itself */
>>>> +    };
>>>>        uint64_t            lock_cnt;    /* # of complete locking ops */
>>>> -    uint64_t            block_cnt;   /* # of complete wait for lock */
>>>> +    uint64_t            block_cnt:63; /* # of complete wait for lock */
>>>> +    uint64_t            is_rlock:1;  /* use rlock pointer */
>>>
>>> This is meant to act like a bool. So I would prefer if we use:
>>>
>>> bool is_rwlock:1;
>>>
>>> And then use true/false when set.
>>
>> Do we want to do that? AFAIK it would depend on the compiler what the size of
>> the struct is when mixing types in bitfields (in this case: bool and uint64_t).
> 
> I thought in a similar way as you did when Andrew introduced similar
> patterns (see Julien's reply for an example), and was then convinced
> that the compiler really is supposed to be doing what we want here.
> So yes, I second Julien's desire to have bool used when boolean is
> meant.

Okay, fine with me.


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions
  2023-12-13  8:36       ` Julien Grall
@ 2023-12-13  9:11         ` Juergen Gross
  0 siblings, 0 replies; 73+ messages in thread
From: Juergen Gross @ 2023-12-13  9:11 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Stefano Stabellini, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Jan Beulich,
	Wei Liu, Roger Pau Monné,
	Tamas K Lengyel, Lukasz Hawrylko, Daniel P. Smith,
	Mateusz Mówka


[-- Attachment #1.1.1: Type: text/plain, Size: 3695 bytes --]

On 13.12.23 09:36, Julien Grall wrote:
> 
> 
> On 13/12/2023 06:17, Juergen Gross wrote:
>> On 12.12.23 19:49, Julien Grall wrote:
>>> Hi Juergen,
>>>
>>> On 12/12/2023 09:47, Juergen Gross wrote:
>>>> -#define spin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, spinlock_t)
>>>> -#define rspin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, rspinlock_t)
>>>> +#define spin_lock_init_prof(s, 
>>>> l)                                             \
>>>> +    __spin_lock_init_prof(s, l, lock, spinlock_t, 0)
>>>> +#define rspin_lock_init_prof(s, 
>>>> l)                                            \
>>>> +    __spin_lock_init_prof(s, l, rlock, rspinlock_t, 1)
>>>>   void _lock_profile_register_struct(
>>>>       int32_t type, struct lock_profile_qhead *qhead, int32_t idx);
>>>> @@ -174,6 +179,7 @@ struct lock_profile_qhead { };
>>>>   #endif
>>>> +
>>>
>>> Spurious change?
>>
>> Indeed, will remove it.
>>
>>>
>>>>   typedef union {
>>>>       uint32_t head_tail;
>>>>       struct {
>>>> @@ -261,4 +267,12 @@ void rspin_unlock_irqrestore(rspinlock_t *lock, 
>>>> unsigned long flags);
>>>>   /* Ensure a lock is quiescent between two critical operations. */
>>>>   #define spin_barrier(l)               _spin_barrier(l)
>>>> +#define nrspin_trylock(l)    spin_trylock(l)
>>>> +#define nrspin_lock(l)       spin_lock(l)
>>>> +#define nrspin_unlock(l)     spin_unlock(l)
>>>> +#define nrspin_lock_irq(l)   spin_lock_irq(l)
>>>> +#define nrspin_unlock_irq(l) spin_unlock_irq(l)
>>>> +#define nrspin_lock_irqsave(l, f)      spin_lock_irqsave(l, f)
>>>> +#define nrspin_unlock_irqrestore(l, f) spin_unlock_irqrestore(l, f)
>>>
>>> There is a comment describing [r]spinlock but not this new variant. Can you 
>>> add one?
>>
>> Okay.
>>
>>> That said, I know this is existing code, but I have to admit this is a bit 
>>> unclear why we are allowing an recursive spinlock to be non-recursive. To me 
>>> it sounds like we are making the typesafe not very safe because it doesn't 
>>> guarantee that we are not mixing the call nrspin_* with rspin_*.
>>
>> This is the current API.
> 
> I know. This is why I wrote "I know this is existing code".
> 
>>
>> If you have locked with nrspin_*, any rspin_* attempt on the same lock will
>> spin until rspin_unlock (nrspin_* will not set recurse_cpu, but take the
>> lock).
>>
>> If you have locked with rspin_*, any nrspin_* attempt on the same lock will
>> spin, too.
>>
>> So I don't see any major problem regarding accidental misuse, which wouldn't
>> be visible by deadlocks (there is no silent misbehavior).
> 
> Right, so this will lead to a deadlock, which is my concern. If we were using 
> rspinlock_* everywhere then the deadlock (at least in the case when you recurse) 
> would in theory not be possible (unless you recurse too much).

A programming error can lead to a deadlock, yes.

My understanding is that there are deliberate use cases of non-recursive locking
as paths using recursive locking of the same lock are not allowed in those
cases.

Just using rspinlock_* instead of nrspinlock_* would silently ignore such cases,
which is far worse than a deadlock, as those cases might introduce e.g. security
holes.

> My point here is to simplify the interface rather than providing because I don't 
> really see the benefits of providing a non-recursive version for recursive 
> spinlock.
> 
> Anyway as I said this is nothing new.

Correct. Nothing I'd like to address in this series.


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 08/12] xen/spinlock: add another function level
  2023-12-13  8:43       ` Julien Grall
@ 2023-12-13  9:17         ` Juergen Gross
  2023-12-13  9:48           ` Julien Grall
  0 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-13  9:17 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini, Wei Liu


[-- Attachment #1.1.1: Type: text/plain, Size: 5536 bytes --]

On 13.12.23 09:43, Julien Grall wrote:
> Hi Juergen,
> 
> On 13/12/2023 06:23, Juergen Gross wrote:
>> On 12.12.23 20:10, Julien Grall wrote:
>>> Hi Juergen,
>>>
>>> On 12/12/2023 09:47, Juergen Gross wrote:
>>>> Add another function level in spinlock.c hiding the spinlock_t layout
>>>> from the low level locking code.
>>>>
>>>> This is done in preparation of introducing rspinlock_t for recursive
>>>> locks without having to duplicate all of the locking code.
>>>
>>> So all the fields you pass are the one from spinlock.
>>>
>>> Looking at pahole after this series is applid, we have:
>>>
>>> ==== Debug + Lock profile ====
>>>
>>> struct spinlock {
>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>          union lock_debug           debug;                /*     4 4 */
>>>          struct lock_profile *      profile;              /*     8 8 */
>>>
>>>          /* size: 16, cachelines: 1, members: 3 */
>>>          /* last cacheline: 16 bytes */
>>> };
>>> struct rspinlock {
>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>
>>>          /* XXX 1 byte hole, try to pack */
>>>
>>>          union lock_debug           debug;                /*     8 4 */
>>>
>>>          /* XXX 4 bytes hole, try to pack */
>>>
>>>          struct lock_profile *      profile;              /*    16 8 */
>>>
>>>          /* size: 24, cachelines: 1, members: 5 */
>>>          /* sum members: 19, holes: 2, sum holes: 5 */
>>>          /* last cacheline: 24 bytes */
>>> };
>>>
>>>
>>> ==== Debug ====
>>>
>>> struct spinlock {
>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>          union lock_debug           debug;                /*     4 4 */
>>>
>>>          /* size: 8, cachelines: 1, members: 2 */
>>>          /* last cacheline: 8 bytes */
>>> };
>>> struct rspinlock {
>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>
>>>          /* XXX 1 byte hole, try to pack */
>>>
>>>          union lock_debug           debug;                /*     8 4 */
>>>
>>>          /* size: 12, cachelines: 1, members: 4 */
>>>          /* sum members: 11, holes: 1, sum holes: 1 */
>>>          /* last cacheline: 12 bytes */
>>> };
>>>
>>> ==== Prod ====
>>>
>>> struct spinlock {
>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>          union lock_debug           debug;                /*     4 0 */
>>>
>>>          /* size: 4, cachelines: 1, members: 2 */
>>>          /* last cacheline: 4 bytes */
>>> };
>>> struct rspinlock {
>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>          union lock_debug           debug;                /*     7 0 */
>>>
>>>          /* size: 8, cachelines: 1, members: 4 */
>>>          /* padding: 1 */
>>>          /* last cacheline: 8 bytes */
>>> };
>>>
>>>
>>> I think we could embed spinlock_t in rspinlock_t without increasing 
>>> rspinlock_t. Have you considered it? This could reduce the number of function 
>>> level introduced in this series.
>>
>> That was the layout in the first version of this series. Jan requested to change
>> it to the current layout [1].
> 
> Ah... Looking through the reasoning, I have to disagree with Jan argumentations.

I would _really_ have liked you to mention this disagreement back then (you've
been on Cc: in the thread, too).

Letting me do a major rework and then after 2 more iterations of the series
requesting to undo most of the work isn't great.

> At least with the full series applied, there is no increase of rspinlock_t in 
> debug build (if we compare to the version you provided in this series).

That wasn't his sole reasoning, right?

> Furthermore, this is going to remove at least patch #6 and #8. We would still 
> need nrspinlock_* because they can just be wrapper to
> spin_barrier(&lock->lock).
> 
> This should also solve his concern of unwieldy code:
> 
>  > +    spin_barrier(&p2m->pod.lock.lock.lock);

Yes, but the demand to have optional fields at the end of the struct isn't
covered by your request.


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 08/12] xen/spinlock: add another function level
  2023-12-13  9:17         ` Juergen Gross
@ 2023-12-13  9:48           ` Julien Grall
  2023-12-13  9:55             ` Juergen Gross
  2023-12-13 10:04             ` Jan Beulich
  0 siblings, 2 replies; 73+ messages in thread
From: Julien Grall @ 2023-12-13  9:48 UTC (permalink / raw)
  To: Juergen Gross, xen-devel
  Cc: Andrew Cooper, George Dunlap, Jan Beulich, Stefano Stabellini, Wei Liu



On 13/12/2023 09:17, Juergen Gross wrote:
> On 13.12.23 09:43, Julien Grall wrote:
>> Hi Juergen,
>>
>> On 13/12/2023 06:23, Juergen Gross wrote:
>>> On 12.12.23 20:10, Julien Grall wrote:
>>>> Hi Juergen,
>>>>
>>>> On 12/12/2023 09:47, Juergen Gross wrote:
>>>>> Add another function level in spinlock.c hiding the spinlock_t layout
>>>>> from the low level locking code.
>>>>>
>>>>> This is done in preparation of introducing rspinlock_t for recursive
>>>>> locks without having to duplicate all of the locking code.
>>>>
>>>> So all the fields you pass are the one from spinlock.
>>>>
>>>> Looking at pahole after this series is applid, we have:
>>>>
>>>> ==== Debug + Lock profile ====
>>>>
>>>> struct spinlock {
>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>          union lock_debug           debug;                /*     4 4 */
>>>>          struct lock_profile *      profile;              /*     8 8 */
>>>>
>>>>          /* size: 16, cachelines: 1, members: 3 */
>>>>          /* last cacheline: 16 bytes */
>>>> };
>>>> struct rspinlock {
>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>>
>>>>          /* XXX 1 byte hole, try to pack */
>>>>
>>>>          union lock_debug           debug;                /*     8 4 */
>>>>
>>>>          /* XXX 4 bytes hole, try to pack */
>>>>
>>>>          struct lock_profile *      profile;              /*    16 8 */
>>>>
>>>>          /* size: 24, cachelines: 1, members: 5 */
>>>>          /* sum members: 19, holes: 2, sum holes: 5 */
>>>>          /* last cacheline: 24 bytes */
>>>> };
>>>>
>>>>
>>>> ==== Debug ====
>>>>
>>>> struct spinlock {
>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>          union lock_debug           debug;                /*     4 4 */
>>>>
>>>>          /* size: 8, cachelines: 1, members: 2 */
>>>>          /* last cacheline: 8 bytes */
>>>> };
>>>> struct rspinlock {
>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>>
>>>>          /* XXX 1 byte hole, try to pack */
>>>>
>>>>          union lock_debug           debug;                /*     8 4 */
>>>>
>>>>          /* size: 12, cachelines: 1, members: 4 */
>>>>          /* sum members: 11, holes: 1, sum holes: 1 */
>>>>          /* last cacheline: 12 bytes */
>>>> };
>>>>
>>>> ==== Prod ====
>>>>
>>>> struct spinlock {
>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>          union lock_debug           debug;                /*     4 0 */
>>>>
>>>>          /* size: 4, cachelines: 1, members: 2 */
>>>>          /* last cacheline: 4 bytes */
>>>> };
>>>> struct rspinlock {
>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>>          union lock_debug           debug;                /*     7 0 */
>>>>
>>>>          /* size: 8, cachelines: 1, members: 4 */
>>>>          /* padding: 1 */
>>>>          /* last cacheline: 8 bytes */
>>>> };
>>>>
>>>>
>>>> I think we could embed spinlock_t in rspinlock_t without increasing 
>>>> rspinlock_t. Have you considered it? This could reduce the number of 
>>>> function level introduced in this series.
>>>
>>> That was the layout in the first version of this series. Jan 
>>> requested to change
>>> it to the current layout [1].
>>
>> Ah... Looking through the reasoning, I have to disagree with Jan 
>> argumentations.
> 
> I would _really_ have liked you to mention this disagreement back then 
> (you've
> been on Cc: in the thread, too).

Sorry for that. My e-mails backlog is quite large and I can't keep up 
with all the series.

> Letting me do a major rework and then after 2 more iterations of the series
> requesting to undo most of the work isn't great.

Indeed. But I note you continued without any additional feedback [1]. If 
you were not sure about the approach suggested by Jan, then why did you 
post two new versions? Shouldn't you have pinged the maintainers to make 
sure there is a consensus?

> 
>> At least with the full series applied, there is no increase of 
>> rspinlock_t in debug build (if we compare to the version you provided 
>> in this series).
> 
> That wasn't his sole reasoning, right?

I guess you mean the non-optional fields should always be at the same 
position?

> 
>> Furthermore, this is going to remove at least patch #6 and #8. We 
>> would still need nrspinlock_* because they can just be wrapper to
>> spin_barrier(&lock->lock).
>>
>> This should also solve his concern of unwieldy code:
>>
>>  > +    spin_barrier(&p2m->pod.lock.lock.lock);
> 
> Yes, but the demand to have optional fields at the end of the struct isn't
> covered by your request.

I note this was a preference and weight against code duplication. It is 
not clear to me whether Jan agrees with this extra work now.

Anyway, I am not against this approach and if this is what Jan much 
prefers then so be it. But I thought I would point out the additional 
complexity which doesn't seem to be worth it.

Cheers,

[1] https://lists.xen.org/archives/html/xen-devel/2022-12/msg01065.html

-- 
Julien Grall


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

* Re: [PATCH v4 08/12] xen/spinlock: add another function level
  2023-12-13  9:48           ` Julien Grall
@ 2023-12-13  9:55             ` Juergen Gross
  2023-12-13 10:06               ` Jan Beulich
  2023-12-13 10:04             ` Jan Beulich
  1 sibling, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-13  9:55 UTC (permalink / raw)
  To: Julien Grall, xen-devel, Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Stefano Stabellini, Wei Liu


[-- Attachment #1.1.1: Type: text/plain, Size: 6811 bytes --]

On 13.12.23 10:48, Julien Grall wrote:
> 
> 
> On 13/12/2023 09:17, Juergen Gross wrote:
>> On 13.12.23 09:43, Julien Grall wrote:
>>> Hi Juergen,
>>>
>>> On 13/12/2023 06:23, Juergen Gross wrote:
>>>> On 12.12.23 20:10, Julien Grall wrote:
>>>>> Hi Juergen,
>>>>>
>>>>> On 12/12/2023 09:47, Juergen Gross wrote:
>>>>>> Add another function level in spinlock.c hiding the spinlock_t layout
>>>>>> from the low level locking code.
>>>>>>
>>>>>> This is done in preparation of introducing rspinlock_t for recursive
>>>>>> locks without having to duplicate all of the locking code.
>>>>>
>>>>> So all the fields you pass are the one from spinlock.
>>>>>
>>>>> Looking at pahole after this series is applid, we have:
>>>>>
>>>>> ==== Debug + Lock profile ====
>>>>>
>>>>> struct spinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          union lock_debug           debug;                /*     4 4 */
>>>>>          struct lock_profile *      profile;              /*     8 8 */
>>>>>
>>>>>          /* size: 16, cachelines: 1, members: 3 */
>>>>>          /* last cacheline: 16 bytes */
>>>>> };
>>>>> struct rspinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>>>
>>>>>          /* XXX 1 byte hole, try to pack */
>>>>>
>>>>>          union lock_debug           debug;                /*     8 4 */
>>>>>
>>>>>          /* XXX 4 bytes hole, try to pack */
>>>>>
>>>>>          struct lock_profile *      profile;              /*    16 8 */
>>>>>
>>>>>          /* size: 24, cachelines: 1, members: 5 */
>>>>>          /* sum members: 19, holes: 2, sum holes: 5 */
>>>>>          /* last cacheline: 24 bytes */
>>>>> };
>>>>>
>>>>>
>>>>> ==== Debug ====
>>>>>
>>>>> struct spinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          union lock_debug           debug;                /*     4 4 */
>>>>>
>>>>>          /* size: 8, cachelines: 1, members: 2 */
>>>>>          /* last cacheline: 8 bytes */
>>>>> };
>>>>> struct rspinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>>>
>>>>>          /* XXX 1 byte hole, try to pack */
>>>>>
>>>>>          union lock_debug           debug;                /*     8 4 */
>>>>>
>>>>>          /* size: 12, cachelines: 1, members: 4 */
>>>>>          /* sum members: 11, holes: 1, sum holes: 1 */
>>>>>          /* last cacheline: 12 bytes */
>>>>> };
>>>>>
>>>>> ==== Prod ====
>>>>>
>>>>> struct spinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          union lock_debug           debug;                /*     4 0 */
>>>>>
>>>>>          /* size: 4, cachelines: 1, members: 2 */
>>>>>          /* last cacheline: 4 bytes */
>>>>> };
>>>>> struct rspinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>>>          union lock_debug           debug;                /*     7 0 */
>>>>>
>>>>>          /* size: 8, cachelines: 1, members: 4 */
>>>>>          /* padding: 1 */
>>>>>          /* last cacheline: 8 bytes */
>>>>> };
>>>>>
>>>>>
>>>>> I think we could embed spinlock_t in rspinlock_t without increasing 
>>>>> rspinlock_t. Have you considered it? This could reduce the number of 
>>>>> function level introduced in this series.
>>>>
>>>> That was the layout in the first version of this series. Jan requested to 
>>>> change
>>>> it to the current layout [1].
>>>
>>> Ah... Looking through the reasoning, I have to disagree with Jan argumentations.
>>
>> I would _really_ have liked you to mention this disagreement back then (you've
>> been on Cc: in the thread, too).
> 
> Sorry for that. My e-mails backlog is quite large and I can't keep up with all 
> the series.
> 
>> Letting me do a major rework and then after 2 more iterations of the series
>> requesting to undo most of the work isn't great.
> 
> Indeed. But I note you continued without any additional feedback [1]. If you 
> were not sure about the approach suggested by Jan, then why did you post two new 
> versions? Shouldn't you have pinged the maintainers to make sure there is a 
> consensus?

https://lists.xen.org/archives/html/xen-devel/2023-10/msg01221.html

> 
>>
>>> At least with the full series applied, there is no increase of rspinlock_t in 
>>> debug build (if we compare to the version you provided in this series).
>>
>> That wasn't his sole reasoning, right?
> 
> I guess you mean the non-optional fields should always be at the same position?

Yes.

> 
>>
>>> Furthermore, this is going to remove at least patch #6 and #8. We would still 
>>> need nrspinlock_* because they can just be wrapper to
>>> spin_barrier(&lock->lock).
>>>
>>> This should also solve his concern of unwieldy code:
>>>
>>>  > +    spin_barrier(&p2m->pod.lock.lock.lock);
>>
>> Yes, but the demand to have optional fields at the end of the struct isn't
>> covered by your request.
> 
> I note this was a preference and weight against code duplication. It is not 
> clear to me whether Jan agrees with this extra work now.
> 
> Anyway, I am not against this approach and if this is what Jan much prefers then 
> so be it. But I thought I would point out the additional complexity which 
> doesn't seem to be worth it.

Thanks for the clarification.

Jan?


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 08/12] xen/spinlock: add another function level
  2023-12-13  9:48           ` Julien Grall
  2023-12-13  9:55             ` Juergen Gross
@ 2023-12-13 10:04             ` Jan Beulich
  1 sibling, 0 replies; 73+ messages in thread
From: Jan Beulich @ 2023-12-13 10:04 UTC (permalink / raw)
  To: Julien Grall
  Cc: Andrew Cooper, George Dunlap, Stefano Stabellini, Wei Liu,
	Juergen Gross, xen-devel

On 13.12.2023 10:48, Julien Grall wrote:
> On 13/12/2023 09:17, Juergen Gross wrote:
>> On 13.12.23 09:43, Julien Grall wrote:
>>> On 13/12/2023 06:23, Juergen Gross wrote:
>>>> On 12.12.23 20:10, Julien Grall wrote:
>>>>> On 12/12/2023 09:47, Juergen Gross wrote:
>>>>>> Add another function level in spinlock.c hiding the spinlock_t layout
>>>>>> from the low level locking code.
>>>>>>
>>>>>> This is done in preparation of introducing rspinlock_t for recursive
>>>>>> locks without having to duplicate all of the locking code.
>>>>>
>>>>> So all the fields you pass are the one from spinlock.
>>>>>
>>>>> Looking at pahole after this series is applid, we have:
>>>>>
>>>>> ==== Debug + Lock profile ====
>>>>>
>>>>> struct spinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          union lock_debug           debug;                /*     4 4 */
>>>>>          struct lock_profile *      profile;              /*     8 8 */
>>>>>
>>>>>          /* size: 16, cachelines: 1, members: 3 */
>>>>>          /* last cacheline: 16 bytes */
>>>>> };
>>>>> struct rspinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>>>
>>>>>          /* XXX 1 byte hole, try to pack */
>>>>>
>>>>>          union lock_debug           debug;                /*     8 4 */
>>>>>
>>>>>          /* XXX 4 bytes hole, try to pack */
>>>>>
>>>>>          struct lock_profile *      profile;              /*    16 8 */
>>>>>
>>>>>          /* size: 24, cachelines: 1, members: 5 */
>>>>>          /* sum members: 19, holes: 2, sum holes: 5 */
>>>>>          /* last cacheline: 24 bytes */
>>>>> };
>>>>>
>>>>>
>>>>> ==== Debug ====
>>>>>
>>>>> struct spinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          union lock_debug           debug;                /*     4 4 */
>>>>>
>>>>>          /* size: 8, cachelines: 1, members: 2 */
>>>>>          /* last cacheline: 8 bytes */
>>>>> };
>>>>> struct rspinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>>>
>>>>>          /* XXX 1 byte hole, try to pack */
>>>>>
>>>>>          union lock_debug           debug;                /*     8 4 */
>>>>>
>>>>>          /* size: 12, cachelines: 1, members: 4 */
>>>>>          /* sum members: 11, holes: 1, sum holes: 1 */
>>>>>          /* last cacheline: 12 bytes */
>>>>> };
>>>>>
>>>>> ==== Prod ====
>>>>>
>>>>> struct spinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          union lock_debug           debug;                /*     4 0 */
>>>>>
>>>>>          /* size: 4, cachelines: 1, members: 2 */
>>>>>          /* last cacheline: 4 bytes */
>>>>> };
>>>>> struct rspinlock {
>>>>>          spinlock_tickets_t         tickets;              /*     0 4 */
>>>>>          uint16_t                   recurse_cpu;          /*     4 2 */
>>>>>          uint8_t                    recurse_cnt;          /*     6 1 */
>>>>>          union lock_debug           debug;                /*     7 0 */
>>>>>
>>>>>          /* size: 8, cachelines: 1, members: 4 */
>>>>>          /* padding: 1 */
>>>>>          /* last cacheline: 8 bytes */
>>>>> };
>>>>>
>>>>>
>>>>> I think we could embed spinlock_t in rspinlock_t without increasing 
>>>>> rspinlock_t. Have you considered it? This could reduce the number of 
>>>>> function level introduced in this series.
>>>>
>>>> That was the layout in the first version of this series. Jan 
>>>> requested to change
>>>> it to the current layout [1].
>>>
>>> Ah... Looking through the reasoning, I have to disagree with Jan 
>>> argumentations.
>>
>> I would _really_ have liked you to mention this disagreement back then 
>> (you've
>> been on Cc: in the thread, too).
> 
> Sorry for that. My e-mails backlog is quite large and I can't keep up 
> with all the series.
> 
>> Letting me do a major rework and then after 2 more iterations of the series
>> requesting to undo most of the work isn't great.
> 
> Indeed. But I note you continued without any additional feedback [1]. If 
> you were not sure about the approach suggested by Jan, then why did you 
> post two new versions? Shouldn't you have pinged the maintainers to make 
> sure there is a consensus?

I think this is unfair to Jürgen. We use the lazy consensus model generally,
and hence no replies generally mean consensus. Also note that it has been
very close to a fully year between my review comments back then and now. It
has been well over a year from the original posting of the RFC.

That said, I also understand that in particular RFCs receive less attention,
no matter that this is entirely contrary to their purpose. That's all the
same for me - I hardly ever look at RFCs as long as there are still non-RFC
patches pending review. Which in reality means it is close to impossible to
ever look at RFCs.

>>> At least with the full series applied, there is no increase of 
>>> rspinlock_t in debug build (if we compare to the version you provided 
>>> in this series).
>>
>> That wasn't his sole reasoning, right?
> 
> I guess you mean the non-optional fields should always be at the same 
> position?

I consider this at least desirable, yes.

>>> Furthermore, this is going to remove at least patch #6 and #8. We 
>>> would still need nrspinlock_* because they can just be wrapper to
>>> spin_barrier(&lock->lock).
>>>
>>> This should also solve his concern of unwieldy code:
>>>
>>>  > +    spin_barrier(&p2m->pod.lock.lock.lock);
>>
>> Yes, but the demand to have optional fields at the end of the struct isn't
>> covered by your request.
> 
> I note this was a preference and weight against code duplication. It is 
> not clear to me whether Jan agrees with this extra work now.

Well, at the time I said I think "that's a reasonable price to pay", to
further state "with some de-duplication potential".

> Anyway, I am not against this approach and if this is what Jan much 
> prefers then so be it. But I thought I would point out the additional 
> complexity which doesn't seem to be worth it.

It's not "much", I would say, but some of the earlier oddities (like also
the .lock.lock.lock) would be really nice if they went away.

Jan


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

* Re: [PATCH v4 08/12] xen/spinlock: add another function level
  2023-12-13  9:55             ` Juergen Gross
@ 2023-12-13 10:06               ` Jan Beulich
  0 siblings, 0 replies; 73+ messages in thread
From: Jan Beulich @ 2023-12-13 10:06 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Stefano Stabellini, Wei Liu,
	Julien Grall, xen-devel

On 13.12.2023 10:55, Juergen Gross wrote:
> On 13.12.23 10:48, Julien Grall wrote:
>> I note this was a preference and weight against code duplication. It is not 
>> clear to me whether Jan agrees with this extra work now.
>>
>> Anyway, I am not against this approach and if this is what Jan much prefers then 
>> so be it. But I thought I would point out the additional complexity which 
>> doesn't seem to be worth it.
> 
> Thanks for the clarification.
> 
> Jan?

Just to clarify: While I have replied to Julien's mail just a minute ago,
I didn't get around yet to look at the actual patch. That reply of mine
was purely based on what I said earlier on.

Jan


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

* Re: [PATCH v4 03/12] xen/spinlock: introduce new type for recursive spinlocks
  2023-12-12 12:57   ` Julien Grall
  2023-12-12 13:04     ` Juergen Gross
@ 2023-12-21 10:34     ` Jan Beulich
  2023-12-21 11:06       ` Juergen Gross
  1 sibling, 1 reply; 73+ messages in thread
From: Jan Beulich @ 2023-12-21 10:34 UTC (permalink / raw)
  To: Julien Grall, Juergen Gross, xen-devel
  Cc: Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Stefano Stabellini, Paul Durrant

On 12.12.2023 13:57, Julien Grall wrote:
> On 12/12/2023 09:47, Juergen Gross wrote:
>> @@ -109,12 +109,16 @@ struct lock_profile_qhead {
>>       spinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                 \
>>       static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
>>       _LOCK_PROFILE_PTR(l)
>> +#define DEFINE_RSPINLOCK(l)                                                   \
>> +    rspinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                \
>> +    static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
>> +    _LOCK_PROFILE_PTR(l)
>>   
>> -#define spin_lock_init_prof(s, l)                                             \
>> +#define __spin_lock_init_prof(s, l, locktype)                                 \
> 
> If I am not mistaken the double-underscore prefix is a violation in 
> MISRA. So can this be renamed to:
> 
> spin_lock_init_prof__()?

Is the new parameter needed at all? Can't we use typeof((s)->l) in place of
passing the type explicitly?

Jan


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

* Re: [PATCH v4 03/12] xen/spinlock: introduce new type for recursive spinlocks
  2023-12-21 10:34     ` Jan Beulich
@ 2023-12-21 11:06       ` Juergen Gross
  2023-12-21 11:07         ` Jan Beulich
  0 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2023-12-21 11:06 UTC (permalink / raw)
  To: Jan Beulich, Julien Grall, xen-devel
  Cc: Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Stefano Stabellini, Paul Durrant


[-- Attachment #1.1.1: Type: text/plain, Size: 1320 bytes --]

On 21.12.23 11:34, Jan Beulich wrote:
> On 12.12.2023 13:57, Julien Grall wrote:
>> On 12/12/2023 09:47, Juergen Gross wrote:
>>> @@ -109,12 +109,16 @@ struct lock_profile_qhead {
>>>        spinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                 \
>>>        static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
>>>        _LOCK_PROFILE_PTR(l)
>>> +#define DEFINE_RSPINLOCK(l)                                                   \
>>> +    rspinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                \
>>> +    static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
>>> +    _LOCK_PROFILE_PTR(l)
>>>    
>>> -#define spin_lock_init_prof(s, l)                                             \
>>> +#define __spin_lock_init_prof(s, l, locktype)                                 \
>>
>> If I am not mistaken the double-underscore prefix is a violation in
>> MISRA. So can this be renamed to:
>>
>> spin_lock_init_prof__()?
> 
> Is the new parameter needed at all? Can't we use typeof((s)->l) in place of
> passing the type explicitly?

IMO spin_lock_init_prof() should be usable for spinlock_t only, and
rspin_lock_init_prof() for rspinlock_t only. Using typeof() would make
either of them usable for both types.


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 03/12] xen/spinlock: introduce new type for recursive spinlocks
  2023-12-21 11:06       ` Juergen Gross
@ 2023-12-21 11:07         ` Jan Beulich
  0 siblings, 0 replies; 73+ messages in thread
From: Jan Beulich @ 2023-12-21 11:07 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Stefano Stabellini, Paul Durrant,
	Julien Grall, xen-devel

On 21.12.2023 12:06, Juergen Gross wrote:
> On 21.12.23 11:34, Jan Beulich wrote:
>> On 12.12.2023 13:57, Julien Grall wrote:
>>> On 12/12/2023 09:47, Juergen Gross wrote:
>>>> @@ -109,12 +109,16 @@ struct lock_profile_qhead {
>>>>        spinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                 \
>>>>        static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
>>>>        _LOCK_PROFILE_PTR(l)
>>>> +#define DEFINE_RSPINLOCK(l)                                                   \
>>>> +    rspinlock_t l = _SPIN_LOCK_UNLOCKED(NULL);                                \
>>>> +    static struct lock_profile __lock_profile_data_##l = _LOCK_PROFILE(l);    \
>>>> +    _LOCK_PROFILE_PTR(l)
>>>>    
>>>> -#define spin_lock_init_prof(s, l)                                             \
>>>> +#define __spin_lock_init_prof(s, l, locktype)                                 \
>>>
>>> If I am not mistaken the double-underscore prefix is a violation in
>>> MISRA. So can this be renamed to:
>>>
>>> spin_lock_init_prof__()?
>>
>> Is the new parameter needed at all? Can't we use typeof((s)->l) in place of
>> passing the type explicitly?
> 
> IMO spin_lock_init_prof() should be usable for spinlock_t only, and
> rspin_lock_init_prof() for rspinlock_t only. Using typeof() would make
> either of them usable for both types.

Fair point.

Jan


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

* Re: [PATCH v4 04/12] xen/spinlock: rename recursive lock functions
  2023-12-12  9:47 ` [PATCH v4 04/12] xen/spinlock: rename recursive lock functions Juergen Gross
  2023-12-12 12:59   ` Julien Grall
@ 2024-02-28 14:59   ` Jan Beulich
  1 sibling, 0 replies; 73+ messages in thread
From: Jan Beulich @ 2024-02-28 14:59 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Stefano Stabellini, Julien Grall, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Wei Liu,
	Roger Pau Monné,
	Tamas K Lengyel, Paul Durrant, xen-devel

On 12.12.2023 10:47, Juergen Gross wrote:
> Rename the recursive spin_lock() functions by replacing the trailing
> "_recursive" with a leading "r".
> 
> Switch the parameter to be a pointer to rspinlock_t.
> 
> Remove the indirection through a macro, as it is adding only complexity
> without any gain.

Considering we aren't aware of any leveraging of this, doing so is
probably okay. Still I think it was done that way for a reason. Plus
of course if we undo the indirection here, sooner or later we should
also undo similar indirection elsewhere.

> Suggested-by: Jan Beulich <jbeulich@suse.com>
> Signed-off-by: Juergen Gross <jgross@suse.com>

Acked-by: Jan Beulich <jbeulich@suse.com>

Jan



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

* Re: [PATCH v4 05/12] xen/spinlock: add rspin_[un]lock_irq[save|restore]()
  2023-12-12  9:47 ` [PATCH v4 05/12] xen/spinlock: add rspin_[un]lock_irq[save|restore]() Juergen Gross
  2023-12-12 13:03   ` Julien Grall
@ 2024-02-28 15:09   ` Jan Beulich
  2024-02-28 15:21     ` Jürgen Groß
  1 sibling, 1 reply; 73+ messages in thread
From: Jan Beulich @ 2024-02-28 15:09 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Julien Grall, Stefano Stabellini,
	xen-devel

On 12.12.2023 10:47, Juergen Gross wrote:
> Instead of special casing rspin_lock_irqsave() and
> rspin_unlock_irqrestore() for the console lock, add those functions
> to spinlock handling and use them where needed.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>
> ---
> V2:
> - new patch

In how far is this a necessary part of the series?

> --- a/xen/arch/x86/traps.c
> +++ b/xen/arch/x86/traps.c
> @@ -647,13 +647,15 @@ void show_stack_overflow(unsigned int cpu, const struct cpu_user_regs *regs)
>  void show_execution_state(const struct cpu_user_regs *regs)
>  {
>      /* Prevent interleaving of output. */
> -    unsigned long flags = console_lock_recursive_irqsave();
> +    unsigned long flags;
> +
> +    rspin_lock_irqsave(&console_lock, flags);
>  
>      show_registers(regs);
>      show_code(regs);
>      show_stack(regs);
>  
> -    console_unlock_recursive_irqrestore(flags);
> +    rspin_unlock_irqrestore(&console_lock, flags);
>  }
>  
>  void cf_check show_execution_state_nonconst(struct cpu_user_regs *regs)
> @@ -663,7 +665,7 @@ void cf_check show_execution_state_nonconst(struct cpu_user_regs *regs)
>  
>  void vcpu_show_execution_state(struct vcpu *v)
>  {
> -    unsigned long flags = 0;
> +    unsigned long flags;
>  
>      if ( test_bit(_VPF_down, &v->pause_flags) )
>      {
> @@ -698,7 +700,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>  #endif
>  
>      /* Prevent interleaving of output. */
> -    flags = console_lock_recursive_irqsave();
> +    rspin_lock_irqsave(&console_lock, flags);
>  
>      vcpu_show_registers(v);
>  
> @@ -708,7 +710,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>           * Stop interleaving prevention: The necessary P2M lookups involve
>           * locking, which has to occur with IRQs enabled.
>           */
> -        console_unlock_recursive_irqrestore(flags);
> +        rspin_unlock_irqrestore(&console_lock, flags);
>  
>          show_hvm_stack(v, &v->arch.user_regs);
>      }
> @@ -717,7 +719,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>          if ( guest_kernel_mode(v, &v->arch.user_regs) )
>              show_guest_stack(v, &v->arch.user_regs);
>  
> -        console_unlock_recursive_irqrestore(flags);
> +        rspin_unlock_irqrestore(&console_lock, flags);
>      }
>  

I view these as layering violations; ...

> --- a/xen/drivers/char/console.c
> +++ b/xen/drivers/char/console.c
> @@ -120,7 +120,7 @@ static int __read_mostly sercon_handle = -1;
>  int8_t __read_mostly opt_console_xen; /* console=xen */
>  #endif
>  
> -static DEFINE_RSPINLOCK(console_lock);
> +DEFINE_RSPINLOCK(console_lock);

... this should remain static. The question therefore just is whether
to omit this patch or ...

> @@ -1158,22 +1158,6 @@ void console_end_log_everything(void)
>      atomic_dec(&print_everything);
>  }
>  
> -unsigned long console_lock_recursive_irqsave(void)
> -{
> -    unsigned long flags;
> -
> -    local_irq_save(flags);
> -    rspin_lock(&console_lock);
> -
> -    return flags;
> -}
> -
> -void console_unlock_recursive_irqrestore(unsigned long flags)
> -{
> -    rspin_unlock(&console_lock);
> -    local_irq_restore(flags);
> -}

... whether to retain these two functions as thin wrappers around the
new, more generic construct.

Jan


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

* Re: [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware
  2023-12-12  9:47 ` [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware Juergen Gross
  2023-12-12 18:42   ` Julien Grall
@ 2024-02-28 15:19   ` Jan Beulich
  2024-02-28 15:43     ` Jürgen Groß
  1 sibling, 1 reply; 73+ messages in thread
From: Jan Beulich @ 2024-02-28 15:19 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, Alejandro Vallejo, xen-devel

On 12.12.2023 10:47, Juergen Gross wrote:
> --- a/xen/common/spinlock.c
> +++ b/xen/common/spinlock.c
> @@ -538,19 +538,31 @@ static void spinlock_profile_iterate(lock_profile_subfunc *sub, void *par)
>  static void cf_check spinlock_profile_print_elem(struct lock_profile *data,
>      int32_t type, int32_t idx, void *par)
>  {
> -    struct spinlock *lock = data->lock;
> +    unsigned int cpu;
> +    uint32_t lockval;

Any reason for this not being unsigned int as well? The more that ...

> +    if ( data->is_rlock )
> +    {
> +        cpu = data->rlock->debug.cpu;
> +        lockval = data->rlock->tickets.head_tail;
> +    }
> +    else
> +    {
> +        cpu = data->lock->debug.cpu;
> +        lockval = data->lock->tickets.head_tail;
> +    }
>  
>      printk("%s ", lock_profile_ancs[type].name);
>      if ( type != LOCKPROF_TYPE_GLOBAL )
>          printk("%d ", idx);
> -    printk("%s: addr=%p, lockval=%08x, ", data->name, lock,
> -           lock->tickets.head_tail);
> -    if ( lock->debug.cpu == SPINLOCK_NO_CPU )
> +    printk("%s: addr=%p, lockval=%08x, ", data->name, data->lock, lockval);

... it's then printed with plain x as the format char.

> +    if ( cpu == SPINLOCK_NO_CPU )
>          printk("not locked\n");
>      else
> -        printk("cpu=%d\n", lock->debug.cpu);
> -    printk("  lock:%" PRId64 "(%" PRI_stime "), block:%" PRId64 "(%" PRI_stime ")\n",
> -           data->lock_cnt, data->time_hold, data->block_cnt, data->time_block);
> +        printk("cpu=%u\n", cpu);
> +    printk("  lock:%" PRIu64 "(%" PRI_stime "), block:%" PRIu64 "(%" PRI_stime ")\n",
> +           data->lock_cnt, data->time_hold, (uint64_t)data->block_cnt,

I think I know why the cast is suddenly / unexpectedly needed, but imo
such wants stating in the description, when generally we aim at avoiding
casts where possible.

> --- a/xen/include/xen/spinlock.h
> +++ b/xen/include/xen/spinlock.h
> @@ -76,13 +76,19 @@ union lock_debug { };
>  */
>  
>  struct spinlock;
> +/* Temporary hack until a dedicated struct rspinlock is existing. */
> +#define rspinlock spinlock
>  
>  struct lock_profile {
>      struct lock_profile *next;       /* forward link */
>      const char          *name;       /* lock name */
> -    struct spinlock     *lock;       /* the lock itself */
> +    union {
> +        struct spinlock *lock;       /* the lock itself */
> +        struct rspinlock *rlock;     /* the recursive lock itself */
> +    };

_LOCK_PROFILE() wants to initialize this field, unconditionally using
.lock. While I expect that problem to be taken care of in one of the
later patches, use of the macro won't work anymore with this union in
use with very old gcc that formally we still support. While a road to
generally raising the baseline requirements is still pretty unclear to
me, an option might be to require (and document) that to enable
DEBUG_LOCK_PROFILE somewhat newer gcc needs using.

>      uint64_t            lock_cnt;    /* # of complete locking ops */
> -    uint64_t            block_cnt;   /* # of complete wait for lock */
> +    uint64_t            block_cnt:63; /* # of complete wait for lock */
> +    uint64_t            is_rlock:1;  /* use rlock pointer */

bool?

Jan


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

* Re: [PATCH v4 05/12] xen/spinlock: add rspin_[un]lock_irq[save|restore]()
  2024-02-28 15:09   ` Jan Beulich
@ 2024-02-28 15:21     ` Jürgen Groß
  0 siblings, 0 replies; 73+ messages in thread
From: Jürgen Groß @ 2024-02-28 15:21 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, Roger Pau Monné,
	Wei Liu, George Dunlap, Julien Grall, Stefano Stabellini,
	xen-devel

On 28.02.24 16:09, Jan Beulich wrote:
> On 12.12.2023 10:47, Juergen Gross wrote:
>> Instead of special casing rspin_lock_irqsave() and
>> rspin_unlock_irqrestore() for the console lock, add those functions
>> to spinlock handling and use them where needed.
>>
>> Signed-off-by: Juergen Gross <jgross@suse.com>
>> ---
>> V2:
>> - new patch
> 
> In how far is this a necessary part of the series?

Not really necessary. It just seemed wrong to have an open coded
variant of rspin_lock_irqsave() and rspin_unlock_irqrestore().

> 
>> --- a/xen/arch/x86/traps.c
>> +++ b/xen/arch/x86/traps.c
>> @@ -647,13 +647,15 @@ void show_stack_overflow(unsigned int cpu, const struct cpu_user_regs *regs)
>>   void show_execution_state(const struct cpu_user_regs *regs)
>>   {
>>       /* Prevent interleaving of output. */
>> -    unsigned long flags = console_lock_recursive_irqsave();
>> +    unsigned long flags;
>> +
>> +    rspin_lock_irqsave(&console_lock, flags);
>>   
>>       show_registers(regs);
>>       show_code(regs);
>>       show_stack(regs);
>>   
>> -    console_unlock_recursive_irqrestore(flags);
>> +    rspin_unlock_irqrestore(&console_lock, flags);
>>   }
>>   
>>   void cf_check show_execution_state_nonconst(struct cpu_user_regs *regs)
>> @@ -663,7 +665,7 @@ void cf_check show_execution_state_nonconst(struct cpu_user_regs *regs)
>>   
>>   void vcpu_show_execution_state(struct vcpu *v)
>>   {
>> -    unsigned long flags = 0;
>> +    unsigned long flags;
>>   
>>       if ( test_bit(_VPF_down, &v->pause_flags) )
>>       {
>> @@ -698,7 +700,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>>   #endif
>>   
>>       /* Prevent interleaving of output. */
>> -    flags = console_lock_recursive_irqsave();
>> +    rspin_lock_irqsave(&console_lock, flags);
>>   
>>       vcpu_show_registers(v);
>>   
>> @@ -708,7 +710,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>>            * Stop interleaving prevention: The necessary P2M lookups involve
>>            * locking, which has to occur with IRQs enabled.
>>            */
>> -        console_unlock_recursive_irqrestore(flags);
>> +        rspin_unlock_irqrestore(&console_lock, flags);
>>   
>>           show_hvm_stack(v, &v->arch.user_regs);
>>       }
>> @@ -717,7 +719,7 @@ void vcpu_show_execution_state(struct vcpu *v)
>>           if ( guest_kernel_mode(v, &v->arch.user_regs) )
>>               show_guest_stack(v, &v->arch.user_regs);
>>   
>> -        console_unlock_recursive_irqrestore(flags);
>> +        rspin_unlock_irqrestore(&console_lock, flags);
>>       }
>>   
> 
> I view these as layering violations; ...
> 
>> --- a/xen/drivers/char/console.c
>> +++ b/xen/drivers/char/console.c
>> @@ -120,7 +120,7 @@ static int __read_mostly sercon_handle = -1;
>>   int8_t __read_mostly opt_console_xen; /* console=xen */
>>   #endif
>>   
>> -static DEFINE_RSPINLOCK(console_lock);
>> +DEFINE_RSPINLOCK(console_lock);
> 
> ... this should remain static. The question therefore just is whether
> to omit this patch or ...
> 
>> @@ -1158,22 +1158,6 @@ void console_end_log_everything(void)
>>       atomic_dec(&print_everything);
>>   }
>>   
>> -unsigned long console_lock_recursive_irqsave(void)
>> -{
>> -    unsigned long flags;
>> -
>> -    local_irq_save(flags);
>> -    rspin_lock(&console_lock);
>> -
>> -    return flags;
>> -}
>> -
>> -void console_unlock_recursive_irqrestore(unsigned long flags)
>> -{
>> -    rspin_unlock(&console_lock);
>> -    local_irq_restore(flags);
>> -}
> 
> ... whether to retain these two functions as thin wrappers around the
> new, more generic construct.

I'd vote for the latter.


Juergen


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

* Re: [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware
  2024-02-28 15:19   ` Jan Beulich
@ 2024-02-28 15:43     ` Jürgen Groß
  2024-02-28 16:02       ` Jan Beulich
  0 siblings, 1 reply; 73+ messages in thread
From: Jürgen Groß @ 2024-02-28 15:43 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, Alejandro Vallejo, xen-devel

On 28.02.24 16:19, Jan Beulich wrote:
> On 12.12.2023 10:47, Juergen Gross wrote:
>> --- a/xen/common/spinlock.c
>> +++ b/xen/common/spinlock.c
>> @@ -538,19 +538,31 @@ static void spinlock_profile_iterate(lock_profile_subfunc *sub, void *par)
>>   static void cf_check spinlock_profile_print_elem(struct lock_profile *data,
>>       int32_t type, int32_t idx, void *par)
>>   {
>> -    struct spinlock *lock = data->lock;
>> +    unsigned int cpu;
>> +    uint32_t lockval;
> 
> Any reason for this not being unsigned int as well? The more that ...
> 
>> +    if ( data->is_rlock )
>> +    {
>> +        cpu = data->rlock->debug.cpu;
>> +        lockval = data->rlock->tickets.head_tail;
>> +    }
>> +    else
>> +    {
>> +        cpu = data->lock->debug.cpu;
>> +        lockval = data->lock->tickets.head_tail;
>> +    }

I've used the same type as tickets.head_tail.

>>   
>>       printk("%s ", lock_profile_ancs[type].name);
>>       if ( type != LOCKPROF_TYPE_GLOBAL )
>>           printk("%d ", idx);
>> -    printk("%s: addr=%p, lockval=%08x, ", data->name, lock,
>> -           lock->tickets.head_tail);
>> -    if ( lock->debug.cpu == SPINLOCK_NO_CPU )
>> +    printk("%s: addr=%p, lockval=%08x, ", data->name, data->lock, lockval);
> 
> ... it's then printed with plain x as the format char.

Which hasn't been changed by the patch. I can change it to PRIx32 if you want.

> 
>> +    if ( cpu == SPINLOCK_NO_CPU )
>>           printk("not locked\n");
>>       else
>> -        printk("cpu=%d\n", lock->debug.cpu);
>> -    printk("  lock:%" PRId64 "(%" PRI_stime "), block:%" PRId64 "(%" PRI_stime ")\n",
>> -           data->lock_cnt, data->time_hold, data->block_cnt, data->time_block);
>> +        printk("cpu=%u\n", cpu);
>> +    printk("  lock:%" PRIu64 "(%" PRI_stime "), block:%" PRIu64 "(%" PRI_stime ")\n",
>> +           data->lock_cnt, data->time_hold, (uint64_t)data->block_cnt,
> 
> I think I know why the cast is suddenly / unexpectedly needed, but imo
> such wants stating in the description, when generally we aim at avoiding
> casts where possible.

Okay, will add a sentence.

> 
>> --- a/xen/include/xen/spinlock.h
>> +++ b/xen/include/xen/spinlock.h
>> @@ -76,13 +76,19 @@ union lock_debug { };
>>   */
>>   
>>   struct spinlock;
>> +/* Temporary hack until a dedicated struct rspinlock is existing. */
>> +#define rspinlock spinlock
>>   
>>   struct lock_profile {
>>       struct lock_profile *next;       /* forward link */
>>       const char          *name;       /* lock name */
>> -    struct spinlock     *lock;       /* the lock itself */
>> +    union {
>> +        struct spinlock *lock;       /* the lock itself */
>> +        struct rspinlock *rlock;     /* the recursive lock itself */
>> +    };
> 
> _LOCK_PROFILE() wants to initialize this field, unconditionally using
> .lock. While I expect that problem to be taken care of in one of the
> later patches, use of the macro won't work anymore with this union in
> use with very old gcc that formally we still support. While a road to
> generally raising the baseline requirements is still pretty unclear to
> me, an option might be to require (and document) that to enable
> DEBUG_LOCK_PROFILE somewhat newer gcc needs using.

Patch 8 is using either .lock or .rlock depending on the lock type.

What is the problem with the old gcc version? Static initializers of
anonymous union members?

> 
>>       uint64_t            lock_cnt;    /* # of complete locking ops */
>> -    uint64_t            block_cnt;   /* # of complete wait for lock */
>> +    uint64_t            block_cnt:63; /* # of complete wait for lock */
>> +    uint64_t            is_rlock:1;  /* use rlock pointer */
> 
> bool?

Yes.


Juergen


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

* Re: [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware
  2024-02-28 15:43     ` Jürgen Groß
@ 2024-02-28 16:02       ` Jan Beulich
  2024-02-28 16:22         ` Jürgen Groß
  0 siblings, 1 reply; 73+ messages in thread
From: Jan Beulich @ 2024-02-28 16:02 UTC (permalink / raw)
  To: Jürgen Groß
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, Alejandro Vallejo, xen-devel

On 28.02.2024 16:43, Jürgen Groß wrote:
> On 28.02.24 16:19, Jan Beulich wrote:
>> On 12.12.2023 10:47, Juergen Gross wrote:
>>> --- a/xen/common/spinlock.c
>>> +++ b/xen/common/spinlock.c
>>> @@ -538,19 +538,31 @@ static void spinlock_profile_iterate(lock_profile_subfunc *sub, void *par)
>>>   static void cf_check spinlock_profile_print_elem(struct lock_profile *data,
>>>       int32_t type, int32_t idx, void *par)
>>>   {
>>> -    struct spinlock *lock = data->lock;
>>> +    unsigned int cpu;
>>> +    uint32_t lockval;
>>
>> Any reason for this not being unsigned int as well? The more that ...
>>
>>> +    if ( data->is_rlock )
>>> +    {
>>> +        cpu = data->rlock->debug.cpu;
>>> +        lockval = data->rlock->tickets.head_tail;
>>> +    }
>>> +    else
>>> +    {
>>> +        cpu = data->lock->debug.cpu;
>>> +        lockval = data->lock->tickets.head_tail;
>>> +    }
> 
> I've used the same type as tickets.head_tail.
> 
>>>   
>>>       printk("%s ", lock_profile_ancs[type].name);
>>>       if ( type != LOCKPROF_TYPE_GLOBAL )
>>>           printk("%d ", idx);
>>> -    printk("%s: addr=%p, lockval=%08x, ", data->name, lock,
>>> -           lock->tickets.head_tail);
>>> -    if ( lock->debug.cpu == SPINLOCK_NO_CPU )
>>> +    printk("%s: addr=%p, lockval=%08x, ", data->name, data->lock, lockval);
>>
>> ... it's then printed with plain x as the format char.
> 
> Which hasn't been changed by the patch. I can change it to PRIx32 if you want.

As per ./CODING_STYLE unsigned int is preferred.

>>> --- a/xen/include/xen/spinlock.h
>>> +++ b/xen/include/xen/spinlock.h
>>> @@ -76,13 +76,19 @@ union lock_debug { };
>>>   */
>>>   
>>>   struct spinlock;
>>> +/* Temporary hack until a dedicated struct rspinlock is existing. */
>>> +#define rspinlock spinlock
>>>   
>>>   struct lock_profile {
>>>       struct lock_profile *next;       /* forward link */
>>>       const char          *name;       /* lock name */
>>> -    struct spinlock     *lock;       /* the lock itself */
>>> +    union {
>>> +        struct spinlock *lock;       /* the lock itself */
>>> +        struct rspinlock *rlock;     /* the recursive lock itself */
>>> +    };
>>
>> _LOCK_PROFILE() wants to initialize this field, unconditionally using
>> .lock. While I expect that problem to be taken care of in one of the
>> later patches, use of the macro won't work anymore with this union in
>> use with very old gcc that formally we still support. While a road to
>> generally raising the baseline requirements is still pretty unclear to
>> me, an option might be to require (and document) that to enable
>> DEBUG_LOCK_PROFILE somewhat newer gcc needs using.
> 
> Patch 8 is using either .lock or .rlock depending on the lock type.
> 
> What is the problem with the old gcc version? Static initializers of
> anonymous union members?

Yes.

Jan


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

* Re: [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware
  2024-02-28 16:02       ` Jan Beulich
@ 2024-02-28 16:22         ` Jürgen Groß
  0 siblings, 0 replies; 73+ messages in thread
From: Jürgen Groß @ 2024-02-28 16:22 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, Alejandro Vallejo, xen-devel

On 28.02.24 17:02, Jan Beulich wrote:
> On 28.02.2024 16:43, Jürgen Groß wrote:
>> On 28.02.24 16:19, Jan Beulich wrote:
>>> On 12.12.2023 10:47, Juergen Gross wrote:
>>>> --- a/xen/common/spinlock.c
>>>> +++ b/xen/common/spinlock.c
>>>> @@ -538,19 +538,31 @@ static void spinlock_profile_iterate(lock_profile_subfunc *sub, void *par)
>>>>    static void cf_check spinlock_profile_print_elem(struct lock_profile *data,
>>>>        int32_t type, int32_t idx, void *par)
>>>>    {
>>>> -    struct spinlock *lock = data->lock;
>>>> +    unsigned int cpu;
>>>> +    uint32_t lockval;
>>>
>>> Any reason for this not being unsigned int as well? The more that ...
>>>
>>>> +    if ( data->is_rlock )
>>>> +    {
>>>> +        cpu = data->rlock->debug.cpu;
>>>> +        lockval = data->rlock->tickets.head_tail;
>>>> +    }
>>>> +    else
>>>> +    {
>>>> +        cpu = data->lock->debug.cpu;
>>>> +        lockval = data->lock->tickets.head_tail;
>>>> +    }
>>
>> I've used the same type as tickets.head_tail.
>>
>>>>    
>>>>        printk("%s ", lock_profile_ancs[type].name);
>>>>        if ( type != LOCKPROF_TYPE_GLOBAL )
>>>>            printk("%d ", idx);
>>>> -    printk("%s: addr=%p, lockval=%08x, ", data->name, lock,
>>>> -           lock->tickets.head_tail);
>>>> -    if ( lock->debug.cpu == SPINLOCK_NO_CPU )
>>>> +    printk("%s: addr=%p, lockval=%08x, ", data->name, data->lock, lockval);
>>>
>>> ... it's then printed with plain x as the format char.
>>
>> Which hasn't been changed by the patch. I can change it to PRIx32 if you want.
> 
> As per ./CODING_STYLE unsigned int is preferred.

Okay, I'll switch to unsigned int then.

> 
>>>> --- a/xen/include/xen/spinlock.h
>>>> +++ b/xen/include/xen/spinlock.h
>>>> @@ -76,13 +76,19 @@ union lock_debug { };
>>>>    */
>>>>    
>>>>    struct spinlock;
>>>> +/* Temporary hack until a dedicated struct rspinlock is existing. */
>>>> +#define rspinlock spinlock
>>>>    
>>>>    struct lock_profile {
>>>>        struct lock_profile *next;       /* forward link */
>>>>        const char          *name;       /* lock name */
>>>> -    struct spinlock     *lock;       /* the lock itself */
>>>> +    union {
>>>> +        struct spinlock *lock;       /* the lock itself */
>>>> +        struct rspinlock *rlock;     /* the recursive lock itself */
>>>> +    };
>>>
>>> _LOCK_PROFILE() wants to initialize this field, unconditionally using
>>> .lock. While I expect that problem to be taken care of in one of the
>>> later patches, use of the macro won't work anymore with this union in
>>> use with very old gcc that formally we still support. While a road to
>>> generally raising the baseline requirements is still pretty unclear to
>>> me, an option might be to require (and document) that to enable
>>> DEBUG_LOCK_PROFILE somewhat newer gcc needs using.
>>
>> Patch 8 is using either .lock or .rlock depending on the lock type.
>>
>> What is the problem with the old gcc version? Static initializers of
>> anonymous union members?
> 
> Yes.

The easiest solution might then be to give the union a name.


Juergen



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

* Re: [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions
  2023-12-12  9:47 ` [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions Juergen Gross
  2023-12-12 18:49   ` Julien Grall
@ 2024-02-29 13:49   ` Jan Beulich
  2024-02-29 13:56     ` Juergen Gross
  1 sibling, 1 reply; 73+ messages in thread
From: Jan Beulich @ 2024-02-29 13:49 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Stefano Stabellini, Julien Grall, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Wei Liu,
	Roger Pau Monné,
	Tamas K Lengyel, Lukasz Hawrylko, Daniel P. Smith,
	Mateusz Mówka, xen-devel

On 12.12.2023 10:47, Juergen Gross wrote:
> In order to prepare a type-safe recursive spinlock structure, add
> explicitly non-recursive locking functions to be used for non-recursive
> locking of spinlocks, which are used recursively, too.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>

Acked-by: Jan Beulich <jbeulich@suse.com>
preferably with ...

> --- a/xen/include/xen/spinlock.h
> +++ b/xen/include/xen/spinlock.h
> @@ -101,6 +101,8 @@ struct lock_profile_qhead {
>  };
>  
>  #define _LOCK_PROFILE(lockname) { .name = #lockname, .lock = &lockname, }
> +#define _RLOCK_PROFILE(lockname) { .name = #lockname, .rlock = &lockname,     \
> +    .is_rlock = 1, }

... "true" used here, ...

> @@ -133,13 +135,16 @@ struct lock_profile_qhead {
>              break;                                                            \
>          }                                                                     \
>          prof->name = #l;                                                      \
> -        prof->lock = &(s)->l;                                                 \
> +        prof->lockptr = &(s)->l;                                              \
> +        prof->is_rlock = isr;                                                 \
>          prof->next = (s)->profile_head.elem_q;                                \
>          (s)->profile_head.elem_q = prof;                                      \
>      } while( 0 )
>  
> -#define spin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, spinlock_t)
> -#define rspin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, rspinlock_t)
> +#define spin_lock_init_prof(s, l)                                             \
> +    __spin_lock_init_prof(s, l, lock, spinlock_t, 0)

... "false" here, ...

> +#define rspin_lock_init_prof(s, l)                                            \
> +    __spin_lock_init_prof(s, l, rlock, rspinlock_t, 1)

... "true" again here, and ...

> @@ -174,6 +179,7 @@ struct lock_profile_qhead { };
>  
>  #endif
>  
> +
>  typedef union {
>      uint32_t head_tail;
>      struct {

... definitely with this hunk dropped.

Jan


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

* Re: [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions
  2024-02-29 13:49   ` Jan Beulich
@ 2024-02-29 13:56     ` Juergen Gross
  0 siblings, 0 replies; 73+ messages in thread
From: Juergen Gross @ 2024-02-29 13:56 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Stefano Stabellini, Julien Grall, Bertrand Marquis, Michal Orzel,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Wei Liu,
	Roger Pau Monné,
	Tamas K Lengyel, Lukasz Hawrylko, Daniel P. Smith,
	Mateusz Mówka, xen-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 2333 bytes --]

On 29.02.24 14:49, Jan Beulich wrote:
> On 12.12.2023 10:47, Juergen Gross wrote:
>> In order to prepare a type-safe recursive spinlock structure, add
>> explicitly non-recursive locking functions to be used for non-recursive
>> locking of spinlocks, which are used recursively, too.
>>
>> Signed-off-by: Juergen Gross <jgross@suse.com>
> 
> Acked-by: Jan Beulich <jbeulich@suse.com>
> preferably with ...
> 
>> --- a/xen/include/xen/spinlock.h
>> +++ b/xen/include/xen/spinlock.h
>> @@ -101,6 +101,8 @@ struct lock_profile_qhead {
>>   };
>>   
>>   #define _LOCK_PROFILE(lockname) { .name = #lockname, .lock = &lockname, }
>> +#define _RLOCK_PROFILE(lockname) { .name = #lockname, .rlock = &lockname,     \
>> +    .is_rlock = 1, }
> 
> ... "true" used here, ...
> 
>> @@ -133,13 +135,16 @@ struct lock_profile_qhead {
>>               break;                                                            \
>>           }                                                                     \
>>           prof->name = #l;                                                      \
>> -        prof->lock = &(s)->l;                                                 \
>> +        prof->lockptr = &(s)->l;                                              \
>> +        prof->is_rlock = isr;                                                 \
>>           prof->next = (s)->profile_head.elem_q;                                \
>>           (s)->profile_head.elem_q = prof;                                      \
>>       } while( 0 )
>>   
>> -#define spin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, spinlock_t)
>> -#define rspin_lock_init_prof(s, l) __spin_lock_init_prof(s, l, rspinlock_t)
>> +#define spin_lock_init_prof(s, l)                                             \
>> +    __spin_lock_init_prof(s, l, lock, spinlock_t, 0)
> 
> ... "false" here, ...
> 
>> +#define rspin_lock_init_prof(s, l)                                            \
>> +    __spin_lock_init_prof(s, l, rlock, rspinlock_t, 1)
> 
> ... "true" again here, and ...
> 
>> @@ -174,6 +179,7 @@ struct lock_profile_qhead { };
>>   
>>   #endif
>>   
>> +
>>   typedef union {
>>       uint32_t head_tail;
>>       struct {
> 
> ... definitely with this hunk dropped.

I'm fine with all of above.


Juergen


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 08/12] xen/spinlock: add another function level
  2023-12-12  9:47 ` [PATCH v4 08/12] xen/spinlock: add another function level Juergen Gross
  2023-12-12 19:10   ` Julien Grall
@ 2024-02-29 13:59   ` Jan Beulich
  1 sibling, 0 replies; 73+ messages in thread
From: Jan Beulich @ 2024-02-29 13:59 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

On 12.12.2023 10:47, Juergen Gross wrote:
> @@ -377,25 +388,25 @@ void _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
>      local_irq_restore(flags);
>  }
>  
> +static int always_inline spin_is_locked_common(const spinlock_tickets_t *t)
> +{
> +    return t->head != t->tail;
> +}
> +
>  int _spin_is_locked(const spinlock_t *lock)
>  {
> -    /*
> -     * Recursive locks may be locked by another CPU, yet we return
> -     * "false" here, making this function suitable only for use in
> -     * ASSERT()s and alike.
> -     */
> -    return lock->recurse_cpu == SPINLOCK_NO_CPU
> -           ? lock->tickets.head != lock->tickets.tail
> -           : lock->recurse_cpu == smp_processor_id();
> +    return spin_is_locked_common(&lock->tickets);
>  }

This looks like a functional change. I haven't spotted an adjustment in an
earlier patch that would make the lost case unnecessary, but even if there
was one, the removal thereof would then also want doing there, I think.

Jan


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

* Re: [PATCH v4 09/12] xen/spinlock: add missing rspin_is_locked() and rspin_barrier()
  2023-12-12  9:47 ` [PATCH v4 09/12] xen/spinlock: add missing rspin_is_locked() and rspin_barrier() Juergen Gross
@ 2024-02-29 14:14   ` Jan Beulich
  2024-02-29 14:18     ` Jürgen Groß
  0 siblings, 1 reply; 73+ messages in thread
From: Jan Beulich @ 2024-02-29 14:14 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Roger Pau Monné,
	Wei Liu, Julien Grall, Stefano Stabellini, Paul Durrant,
	xen-devel

On 12.12.2023 10:47, Juergen Gross wrote:
> --- a/xen/common/spinlock.c
> +++ b/xen/common/spinlock.c
> @@ -458,6 +458,23 @@ void _spin_barrier(spinlock_t *lock)
>      spin_barrier_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
>  }
>  
> +int rspin_is_locked(const rspinlock_t *lock)
> +{
> +    /*
> +     * Recursive locks may be locked by another CPU, yet we return
> +     * "false" here, making this function suitable only for use in
> +     * ASSERT()s and alike.
> +     */
> +    return lock->recurse_cpu == SPINLOCK_NO_CPU
> +           ? spin_is_locked_common(&lock->tickets)
> +           : lock->recurse_cpu == smp_processor_id();
> +}
> +
> +void rspin_barrier(rspinlock_t *lock)
> +{
> +    spin_barrier_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
> +}

Ah, here we go. Looks all okay to me, but needs re-ordering such that the
earlier patch won't transiently introduce a regression.

Jan


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

* Re: [PATCH v4 09/12] xen/spinlock: add missing rspin_is_locked() and rspin_barrier()
  2024-02-29 14:14   ` Jan Beulich
@ 2024-02-29 14:18     ` Jürgen Groß
  0 siblings, 0 replies; 73+ messages in thread
From: Jürgen Groß @ 2024-02-29 14:18 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Roger Pau Monné,
	Wei Liu, Julien Grall, Stefano Stabellini, Paul Durrant,
	xen-devel

On 29.02.24 15:14, Jan Beulich wrote:
> On 12.12.2023 10:47, Juergen Gross wrote:
>> --- a/xen/common/spinlock.c
>> +++ b/xen/common/spinlock.c
>> @@ -458,6 +458,23 @@ void _spin_barrier(spinlock_t *lock)
>>       spin_barrier_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
>>   }
>>   
>> +int rspin_is_locked(const rspinlock_t *lock)
>> +{
>> +    /*
>> +     * Recursive locks may be locked by another CPU, yet we return
>> +     * "false" here, making this function suitable only for use in
>> +     * ASSERT()s and alike.
>> +     */
>> +    return lock->recurse_cpu == SPINLOCK_NO_CPU
>> +           ? spin_is_locked_common(&lock->tickets)
>> +           : lock->recurse_cpu == smp_processor_id();
>> +}
>> +
>> +void rspin_barrier(rspinlock_t *lock)
>> +{
>> +    spin_barrier_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
>> +}
> 
> Ah, here we go. Looks all okay to me, but needs re-ordering such that the
> earlier patch won't transiently introduce a regression.

Yes, just wanted to answer something similar to your remark on patch 8.


Juergen


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

* Re: [PATCH v4 10/12] xen/spinlock: split recursive spinlocks from normal ones
  2023-12-12  9:47 ` [PATCH v4 10/12] xen/spinlock: split recursive spinlocks from normal ones Juergen Gross
@ 2024-02-29 15:32   ` Jan Beulich
  2024-02-29 15:45     ` Jürgen Groß
  2024-03-01 14:37     ` Juergen Gross
  0 siblings, 2 replies; 73+ messages in thread
From: Jan Beulich @ 2024-02-29 15:32 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

On 12.12.2023 10:47, Juergen Gross wrote:
> --- a/xen/common/spinlock.c
> +++ b/xen/common/spinlock.c
> @@ -541,6 +541,55 @@ void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags)
>      local_irq_restore(flags);
>  }
>  
> +int nrspin_trylock(rspinlock_t *lock)
> +{
> +    check_lock(&lock->debug, true);
> +
> +    if ( unlikely(lock->recurse_cpu != SPINLOCK_NO_CPU) )
> +        return 0;
> +
> +    return spin_trylock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
> +}

I wonder if we shouldn't take the opportunity and stop having trylock
functions have "int" return type. Perhaps already spin_trylock_common()
when introduced could use "bool" instead, then here following suit.

> +void nrspin_lock(rspinlock_t *lock)
> +{
> +    spin_lock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR, NULL,
> +                     NULL);
> +}
> +
> +void nrspin_unlock(rspinlock_t *lock)
> +{
> +    spin_unlock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
> +}
> +
> +void nrspin_lock_irq(rspinlock_t *lock)
> +{
> +    ASSERT(local_irq_is_enabled());
> +    local_irq_disable();
> +    nrspin_lock(lock);
> +}
> +
> +void nrspin_unlock_irq(rspinlock_t *lock)
> +{
> +    nrspin_unlock(lock);
> +    local_irq_enable();
> +}
> +
> +unsigned long __nrspin_lock_irqsave(rspinlock_t *lock)
> +{
> +    unsigned long flags;
> +
> +    local_irq_save(flags);
> +    nrspin_lock(lock);
> +    return flags;

Nit: Strictly speaking we want a blank line ahead of this "return".

> @@ -166,11 +172,15 @@ struct lock_profile_qhead { };
>  struct lock_profile { };
>  
>  #define SPIN_LOCK_UNLOCKED {                                                  \
> +    .debug =_LOCK_DEBUG,                                                      \
> +}
> +#define RSPIN_LOCK_UNLOCKED {                                                 \
> +    .debug =_LOCK_DEBUG,                                                      \
>      .recurse_cpu = SPINLOCK_NO_CPU,                                           \
>      .debug =_LOCK_DEBUG,                                                      \
>  }

Initializing .debug twice?

> @@ -180,7 +190,6 @@ struct lock_profile { };
>  
>  #endif
>  
> -
>  typedef union {
>      uint32_t head_tail;
>      struct {

Looks like this might be undoing what the earlier patch isn't going to
do anymore?

> @@ -242,6 +257,19 @@ void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags);
>  int rspin_is_locked(const rspinlock_t *lock);
>  void rspin_barrier(rspinlock_t *lock);
>  
> +int nrspin_trylock(rspinlock_t *lock);
> +void nrspin_lock(rspinlock_t *lock);
> +void nrspin_unlock(rspinlock_t *lock);
> +void nrspin_lock_irq(rspinlock_t *lock);
> +void nrspin_unlock_irq(rspinlock_t *lock);
> +#define nrspin_lock_irqsave(l, f)                               \
> +    ({                                                          \
> +        BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long));       \
> +        ((f) = __nrspin_lock_irqsave(l));                       \

I don't think the outer pair of parentheses is needed here. As to the
leading double underscores, see comments elsewhere.

Jan


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

* Re: [PATCH v4 11/12] xen/spinlock: remove indirection through macros for spin_*() functions
  2023-12-12  9:47 ` [PATCH v4 11/12] xen/spinlock: remove indirection through macros for spin_*() functions Juergen Gross
@ 2024-02-29 15:35   ` Jan Beulich
  0 siblings, 0 replies; 73+ messages in thread
From: Jan Beulich @ 2024-02-29 15:35 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

On 12.12.2023 10:47, Juergen Gross wrote:
> In reality all spin_*() functions are macros which are defined to just
> call a related real function.
> 
> Remove this macro layer, as it is adding complexity without any gain.
> 
> Signed-off-by: Juergen Gross <jgross@suse.com>

Acked-by: Jan Beulich <jbeulich@suse.com>
with the same remark as on patch 04.

Jan


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

* Re: [PATCH v4 10/12] xen/spinlock: split recursive spinlocks from normal ones
  2024-02-29 15:32   ` Jan Beulich
@ 2024-02-29 15:45     ` Jürgen Groß
  2024-03-01 14:37     ` Juergen Gross
  1 sibling, 0 replies; 73+ messages in thread
From: Jürgen Groß @ 2024-02-29 15:45 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

On 29.02.24 16:32, Jan Beulich wrote:
> On 12.12.2023 10:47, Juergen Gross wrote:
>> --- a/xen/common/spinlock.c
>> +++ b/xen/common/spinlock.c
>> @@ -541,6 +541,55 @@ void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags)
>>       local_irq_restore(flags);
>>   }
>>   
>> +int nrspin_trylock(rspinlock_t *lock)
>> +{
>> +    check_lock(&lock->debug, true);
>> +
>> +    if ( unlikely(lock->recurse_cpu != SPINLOCK_NO_CPU) )
>> +        return 0;
>> +
>> +    return spin_trylock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
>> +}
> 
> I wonder if we shouldn't take the opportunity and stop having trylock
> functions have "int" return type. Perhaps already spin_trylock_common()
> when introduced could use "bool" instead, then here following suit.

Fine with me.

> 
>> +void nrspin_lock(rspinlock_t *lock)
>> +{
>> +    spin_lock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR, NULL,
>> +                     NULL);
>> +}
>> +
>> +void nrspin_unlock(rspinlock_t *lock)
>> +{
>> +    spin_unlock_common(&lock->tickets, &lock->debug, LOCK_PROFILE_PAR);
>> +}
>> +
>> +void nrspin_lock_irq(rspinlock_t *lock)
>> +{
>> +    ASSERT(local_irq_is_enabled());
>> +    local_irq_disable();
>> +    nrspin_lock(lock);
>> +}
>> +
>> +void nrspin_unlock_irq(rspinlock_t *lock)
>> +{
>> +    nrspin_unlock(lock);
>> +    local_irq_enable();
>> +}
>> +
>> +unsigned long __nrspin_lock_irqsave(rspinlock_t *lock)
>> +{
>> +    unsigned long flags;
>> +
>> +    local_irq_save(flags);
>> +    nrspin_lock(lock);
>> +    return flags;
> 
> Nit: Strictly speaking we want a blank line ahead of this "return".

Okay, will add it.

> 
>> @@ -166,11 +172,15 @@ struct lock_profile_qhead { };
>>   struct lock_profile { };
>>   
>>   #define SPIN_LOCK_UNLOCKED {                                                  \
>> +    .debug =_LOCK_DEBUG,                                                      \
>> +}
>> +#define RSPIN_LOCK_UNLOCKED {                                                 \
>> +    .debug =_LOCK_DEBUG,                                                      \
>>       .recurse_cpu = SPINLOCK_NO_CPU,                                           \
>>       .debug =_LOCK_DEBUG,                                                      \
>>   }
> 
> Initializing .debug twice?

Oh, right. Will drop one.

> 
>> @@ -180,7 +190,6 @@ struct lock_profile { };
>>   
>>   #endif
>>   
>> -
>>   typedef union {
>>       uint32_t head_tail;
>>       struct {
> 
> Looks like this might be undoing what the earlier patch isn't going to
> do anymore?

Yes, seen it already.

> 
>> @@ -242,6 +257,19 @@ void rspin_unlock_irqrestore(rspinlock_t *lock, unsigned long flags);
>>   int rspin_is_locked(const rspinlock_t *lock);
>>   void rspin_barrier(rspinlock_t *lock);
>>   
>> +int nrspin_trylock(rspinlock_t *lock);
>> +void nrspin_lock(rspinlock_t *lock);
>> +void nrspin_unlock(rspinlock_t *lock);
>> +void nrspin_lock_irq(rspinlock_t *lock);
>> +void nrspin_unlock_irq(rspinlock_t *lock);
>> +#define nrspin_lock_irqsave(l, f)                               \
>> +    ({                                                          \
>> +        BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long));       \
>> +        ((f) = __nrspin_lock_irqsave(l));                       \
> 
> I don't think the outer pair of parentheses is needed here. As to the
> leading double underscores, see comments elsewhere.

Okay.


Juergen


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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2023-12-12  9:47 ` [PATCH v4 12/12] xen/spinlock: support higher number of cpus Juergen Gross
  2023-12-12 10:10   ` Julien Grall
  2023-12-12 12:39   ` Julien Grall
@ 2024-02-29 15:46   ` Jan Beulich
  2024-02-29 16:29     ` Jürgen Groß
  2 siblings, 1 reply; 73+ messages in thread
From: Jan Beulich @ 2024-02-29 15:46 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

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


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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2024-02-29 15:46   ` Jan Beulich
@ 2024-02-29 16:29     ` Jürgen Groß
  2024-02-29 16:31       ` Jan Beulich
  0 siblings, 1 reply; 73+ messages in thread
From: Jürgen Groß @ 2024-02-29 16:29 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

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


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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2024-02-29 16:29     ` Jürgen Groß
@ 2024-02-29 16:31       ` Jan Beulich
  2024-02-29 16:45         ` Juergen Gross
  0 siblings, 1 reply; 73+ messages in thread
From: Jan Beulich @ 2024-02-29 16:31 UTC (permalink / raw)
  To: Jürgen Groß
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

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


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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2024-02-29 16:31       ` Jan Beulich
@ 2024-02-29 16:45         ` Juergen Gross
  2024-02-29 16:54           ` Jan Beulich
  0 siblings, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2024-02-29 16:45 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 1888 bytes --]

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


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2024-02-29 16:45         ` Juergen Gross
@ 2024-02-29 16:54           ` Jan Beulich
  2024-02-29 17:04             ` Jürgen Groß
  0 siblings, 1 reply; 73+ messages in thread
From: Jan Beulich @ 2024-02-29 16:54 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

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


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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2024-02-29 16:54           ` Jan Beulich
@ 2024-02-29 17:04             ` Jürgen Groß
  2024-02-29 17:07               ` Jan Beulich
  0 siblings, 1 reply; 73+ messages in thread
From: Jürgen Groß @ 2024-02-29 17:04 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

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


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

* Re: [PATCH v4 12/12] xen/spinlock: support higher number of cpus
  2024-02-29 17:04             ` Jürgen Groß
@ 2024-02-29 17:07               ` Jan Beulich
  0 siblings, 0 replies; 73+ messages in thread
From: Jan Beulich @ 2024-02-29 17:07 UTC (permalink / raw)
  To: Jürgen Groß
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

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


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

* Re: [PATCH v4 10/12] xen/spinlock: split recursive spinlocks from normal ones
  2024-02-29 15:32   ` Jan Beulich
  2024-02-29 15:45     ` Jürgen Groß
@ 2024-03-01 14:37     ` Juergen Gross
  2024-03-04  7:25       ` Jan Beulich
  1 sibling, 1 reply; 73+ messages in thread
From: Juergen Gross @ 2024-03-01 14:37 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel


[-- Attachment #1.1.1: Type: text/plain, Size: 614 bytes --]

On 29.02.24 16:32, Jan Beulich wrote:
> On 12.12.2023 10:47, Juergen Gross wrote:
>> +#define nrspin_lock_irqsave(l, f)                               \
>> +    ({                                                          \
>> +        BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long));       \
>> +        ((f) = __nrspin_lock_irqsave(l));                       \
> 
> I don't think the outer pair of parentheses is needed here.

Turns out it is needed. Otherwise something like:


if ( a )
     nrspin_lock_irqsave(l, f);
else
     ...

will fail with "else without a previous if".


Juergen


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

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

* Re: [PATCH v4 10/12] xen/spinlock: split recursive spinlocks from normal ones
  2024-03-01 14:37     ` Juergen Gross
@ 2024-03-04  7:25       ` Jan Beulich
  2024-03-04  7:43         ` Jürgen Groß
  0 siblings, 1 reply; 73+ messages in thread
From: Jan Beulich @ 2024-03-04  7:25 UTC (permalink / raw)
  To: Juergen Gross
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

On 01.03.2024 15:37, Juergen Gross wrote:
> On 29.02.24 16:32, Jan Beulich wrote:
>> On 12.12.2023 10:47, Juergen Gross wrote:
>>> +#define nrspin_lock_irqsave(l, f)                               \
>>> +    ({                                                          \
>>> +        BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long));       \
>>> +        ((f) = __nrspin_lock_irqsave(l));                       \
>>
>> I don't think the outer pair of parentheses is needed here.
> 
> Turns out it is needed. Otherwise something like:
> 
> 
> if ( a )
>      nrspin_lock_irqsave(l, f);
> else
>      ...
> 
> will fail with "else without a previous if".

That's for "outer" in the whole #define I suppose, when I commented on
just a specific line inside the construct. The ({ ... }) may better be
avoided here too, for there being no reason to use a compiler
extension when do { ... } while ( false ) would also do. Things would
be different in the construct "returned" the flags value, in a more
function-like manner. But that would be inconsistent with related
similar functions.

Jan


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

* Re: [PATCH v4 10/12] xen/spinlock: split recursive spinlocks from normal ones
  2024-03-04  7:25       ` Jan Beulich
@ 2024-03-04  7:43         ` Jürgen Groß
  0 siblings, 0 replies; 73+ messages in thread
From: Jürgen Groß @ 2024-03-04  7:43 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Andrew Cooper, George Dunlap, Julien Grall, Stefano Stabellini,
	Wei Liu, xen-devel

On 04.03.24 08:25, Jan Beulich wrote:
> On 01.03.2024 15:37, Juergen Gross wrote:
>> On 29.02.24 16:32, Jan Beulich wrote:
>>> On 12.12.2023 10:47, Juergen Gross wrote:
>>>> +#define nrspin_lock_irqsave(l, f)                               \
>>>> +    ({                                                          \
>>>> +        BUILD_BUG_ON(sizeof(f) != sizeof(unsigned long));       \
>>>> +        ((f) = __nrspin_lock_irqsave(l));                       \
>>>
>>> I don't think the outer pair of parentheses is needed here.
>>
>> Turns out it is needed. Otherwise something like:
>>
>>
>> if ( a )
>>       nrspin_lock_irqsave(l, f);
>> else
>>       ...
>>
>> will fail with "else without a previous if".
> 
> That's for "outer" in the whole #define I suppose, when I commented on
> just a specific line inside the construct.

Sorry, I applied your remark to the wrong context.

Yes, one level of parentheses can be removed from this line.


Juergen


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

end of thread, other threads:[~2024-03-04  7:43 UTC | newest]

Thread overview: 73+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-12  9:47 [PATCH v4 00/12] xen/spinlock: make recursive spinlocks a dedicated type Juergen Gross
2023-12-12  9:47 ` [PATCH v4 01/12] xen/spinlock: reduce lock profile ifdefs Juergen Gross
2023-12-12 12:44   ` Julien Grall
2023-12-12  9:47 ` [PATCH v4 02/12] xen/spinlock: make spinlock initializers more readable Juergen Gross
2023-12-12  9:47 ` [PATCH v4 03/12] xen/spinlock: introduce new type for recursive spinlocks Juergen Gross
2023-12-12 12:57   ` Julien Grall
2023-12-12 13:04     ` Juergen Gross
2023-12-12 13:07       ` Julien Grall
2023-12-21 10:34     ` Jan Beulich
2023-12-21 11:06       ` Juergen Gross
2023-12-21 11:07         ` Jan Beulich
2023-12-12  9:47 ` [PATCH v4 04/12] xen/spinlock: rename recursive lock functions Juergen Gross
2023-12-12 12:59   ` Julien Grall
2024-02-28 14:59   ` Jan Beulich
2023-12-12  9:47 ` [PATCH v4 05/12] xen/spinlock: add rspin_[un]lock_irq[save|restore]() Juergen Gross
2023-12-12 13:03   ` Julien Grall
2023-12-12 14:16     ` Juergen Gross
2024-02-28 15:09   ` Jan Beulich
2024-02-28 15:21     ` Jürgen Groß
2023-12-12  9:47 ` [PATCH v4 06/12] xen/spinlock: make struct lock_profile rspinlock_t aware Juergen Gross
2023-12-12 18:42   ` Julien Grall
2023-12-13  6:05     ` Juergen Gross
2023-12-13  8:32       ` Julien Grall
2023-12-13  8:36       ` Jan Beulich
2023-12-13  9:07         ` Juergen Gross
2024-02-28 15:19   ` Jan Beulich
2024-02-28 15:43     ` Jürgen Groß
2024-02-28 16:02       ` Jan Beulich
2024-02-28 16:22         ` Jürgen Groß
2023-12-12  9:47 ` [PATCH v4 07/12] xen/spinlock: add explicit non-recursive locking functions Juergen Gross
2023-12-12 18:49   ` Julien Grall
2023-12-13  6:17     ` Juergen Gross
2023-12-13  8:36       ` Julien Grall
2023-12-13  9:11         ` Juergen Gross
2024-02-29 13:49   ` Jan Beulich
2024-02-29 13:56     ` Juergen Gross
2023-12-12  9:47 ` [PATCH v4 08/12] xen/spinlock: add another function level Juergen Gross
2023-12-12 19:10   ` Julien Grall
2023-12-13  6:23     ` Juergen Gross
2023-12-13  8:43       ` Julien Grall
2023-12-13  9:17         ` Juergen Gross
2023-12-13  9:48           ` Julien Grall
2023-12-13  9:55             ` Juergen Gross
2023-12-13 10:06               ` Jan Beulich
2023-12-13 10:04             ` Jan Beulich
2024-02-29 13:59   ` Jan Beulich
2023-12-12  9:47 ` [PATCH v4 09/12] xen/spinlock: add missing rspin_is_locked() and rspin_barrier() Juergen Gross
2024-02-29 14:14   ` Jan Beulich
2024-02-29 14:18     ` Jürgen Groß
2023-12-12  9:47 ` [PATCH v4 10/12] xen/spinlock: split recursive spinlocks from normal ones Juergen Gross
2024-02-29 15:32   ` Jan Beulich
2024-02-29 15:45     ` Jürgen Groß
2024-03-01 14:37     ` Juergen Gross
2024-03-04  7:25       ` Jan Beulich
2024-03-04  7:43         ` Jürgen Groß
2023-12-12  9:47 ` [PATCH v4 11/12] xen/spinlock: remove indirection through macros for spin_*() functions Juergen Gross
2024-02-29 15:35   ` Jan Beulich
2023-12-12  9:47 ` [PATCH v4 12/12] xen/spinlock: support higher number of cpus Juergen Gross
2023-12-12 10:10   ` Julien Grall
2023-12-12 11:09     ` Juergen Gross
2023-12-12 11:40       ` Julien Grall
2023-12-12 12:11         ` Juergen Gross
2023-12-12 12:22           ` Julien Grall
2023-12-12 12:39   ` Julien Grall
2023-12-12 13:08     ` Juergen Gross
2023-12-12 14:04       ` Julien Grall
2024-02-29 15:46   ` Jan Beulich
2024-02-29 16:29     ` Jürgen Groß
2024-02-29 16:31       ` Jan Beulich
2024-02-29 16:45         ` Juergen Gross
2024-02-29 16:54           ` Jan Beulich
2024-02-29 17:04             ` Jürgen Groß
2024-02-29 17:07               ` Jan Beulich

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.