All of lore.kernel.org
 help / color / mirror / Atom feed
From: Roger Pau Monne <roger.pau@citrix.com>
To: <xen-devel@lists.xenproject.org>
Cc: "Jürgen Groß" <jgross@suse.com>,
	"Stefano Stabellini" <sstabellini@kernel.org>,
	"Julien Grall" <julien@xen.org>, "Wei Liu" <wl@xen.org>,
	"Konrad Rzeszutek Wilk" <konrad.wilk@oracle.com>,
	"George Dunlap" <George.Dunlap@eu.citrix.com>,
	"Andrew Cooper" <andrew.cooper3@citrix.com>,
	"Ian Jackson" <ian.jackson@eu.citrix.com>,
	"Jan Beulich" <jbeulich@suse.com>,
	"Roger Pau Monne" <roger.pau@citrix.com>
Subject: [Xen-devel] [PATCH v2] rwlock: allow recursive read locking when already locked in write mode
Date: Thu, 20 Feb 2020 18:31:16 +0100	[thread overview]
Message-ID: <20200220173116.88915-1-roger.pau@citrix.com> (raw)

Allow a CPU already holding the lock in write mode to also lock it in
read mode. There's no harm in allowing read locking a rwlock that's
already owned by the caller (ie: CPU) in write mode. Allowing such
accesses is required at least for the CPU maps use-case.

In order to do this reserve 14bits of the lock, this allows to support
up to 16384 CPUs. Also reduce the write lock mask to 2 bits: one to
signal there are pending writers waiting on the lock and the other to
signal the lock is owned in write mode. Note the write related data
is using 16bits, this is done in order to be able to clear it (and
thus release the lock) using a 16bit atomic write.

This reduces the maximum number of concurrent readers from 16777216 to
65536, I think this should still be enough, or else the lock field
can be expanded from 32 to 64bits if all architectures support atomic
operations on 64bit integers.

Fixes: 5872c83b42c608 ('smp: convert the cpu maps lock into a rw lock')
Reported-by: Jan Beulich <jbeulich@suse.com>
Reported-by: Jürgen Groß <jgross@suse.com>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v1:
 - Move the processor ID field to start at bit 0 and hence avoid the
   shift when checking it.
 - Enlarge write related structures to use 16bit, and hence allow them
   to be cleared using an atomic write.
---
 xen/common/rwlock.c      |  4 +--
 xen/include/xen/rwlock.h | 53 +++++++++++++++++++++++++---------------
 2 files changed, 35 insertions(+), 22 deletions(-)

diff --git a/xen/common/rwlock.c b/xen/common/rwlock.c
index d568bbf6de..dadab372b5 100644
--- a/xen/common/rwlock.c
+++ b/xen/common/rwlock.c
@@ -69,7 +69,7 @@ void queue_write_lock_slowpath(rwlock_t *lock)
 
     /* Try to acquire the lock directly if no reader is present. */
     if ( !atomic_read(&lock->cnts) &&
-         (atomic_cmpxchg(&lock->cnts, 0, _QW_LOCKED) == 0) )
+         (atomic_cmpxchg(&lock->cnts, 0, _write_lock_val()) == 0) )
         goto unlock;
 
     /*
@@ -93,7 +93,7 @@ void queue_write_lock_slowpath(rwlock_t *lock)
         cnts = atomic_read(&lock->cnts);
         if ( (cnts == _QW_WAITING) &&
              (atomic_cmpxchg(&lock->cnts, _QW_WAITING,
-                             _QW_LOCKED) == _QW_WAITING) )
+                             _write_lock_val()) == _QW_WAITING) )
             break;
 
         cpu_relax();
diff --git a/xen/include/xen/rwlock.h b/xen/include/xen/rwlock.h
index 3dfea1ac2a..59f0d21075 100644
--- a/xen/include/xen/rwlock.h
+++ b/xen/include/xen/rwlock.h
@@ -20,21 +20,30 @@ typedef struct {
 #define DEFINE_RWLOCK(l) rwlock_t l = RW_LOCK_UNLOCKED
 #define rwlock_init(l) (*(l) = (rwlock_t)RW_LOCK_UNLOCKED)
 
-/*
- * Writer states & reader shift and bias.
- *
- * Writer field is 8 bit to allow for potential optimisation, see
- * _write_unlock().
- */
-#define    _QW_WAITING  1               /* A writer is waiting     */
-#define    _QW_LOCKED   0xff            /* A writer holds the lock */
-#define    _QW_WMASK    0xff            /* Writer mask.*/
-#define    _QR_SHIFT    8               /* Reader count shift      */
+/* Writer states & reader shift and bias. */
+#define    _QW_CPUMASK  0x3fff              /* Writer CPU mask */
+#define    _QW_SHIFT    14                  /* Writer flags shift */
+#define    _QW_WAITING  (1u << _QW_SHIFT)   /* A writer is waiting */
+#define    _QW_LOCKED   (3u << _QW_SHIFT)   /* A writer holds the lock */
+#define    _QW_WMASK    (3u << _QW_SHIFT)   /* Writer mask */
+#define    _QR_SHIFT    16                  /* Reader count shift */
 #define    _QR_BIAS     (1U << _QR_SHIFT)
 
 void queue_read_lock_slowpath(rwlock_t *lock);
 void queue_write_lock_slowpath(rwlock_t *lock);
 
+static inline bool _is_write_locked_by_me(uint32_t cnts)
+{
+    BUILD_BUG_ON(_QW_CPUMASK < NR_CPUS);
+    return (cnts & _QW_WMASK) == _QW_LOCKED &&
+           (cnts & _QW_CPUMASK) == smp_processor_id();
+}
+
+static inline bool _can_read_lock(uint32_t cnts)
+{
+    return !(cnts & _QW_WMASK) || _is_write_locked_by_me(cnts);
+}
+
 /*
  * _read_trylock - try to acquire read lock of a queue rwlock.
  * @lock : Pointer to queue rwlock structure.
@@ -45,10 +54,10 @@ static inline int _read_trylock(rwlock_t *lock)
     u32 cnts;
 
     cnts = atomic_read(&lock->cnts);
-    if ( likely(!(cnts & _QW_WMASK)) )
+    if ( likely(_can_read_lock(cnts)) )
     {
         cnts = (u32)atomic_add_return(_QR_BIAS, &lock->cnts);
-        if ( likely(!(cnts & _QW_WMASK)) )
+        if ( likely(_can_read_lock(cnts)) )
             return 1;
         atomic_sub(_QR_BIAS, &lock->cnts);
     }
@@ -64,7 +73,7 @@ static inline void _read_lock(rwlock_t *lock)
     u32 cnts;
 
     cnts = atomic_add_return(_QR_BIAS, &lock->cnts);
-    if ( likely(!(cnts & _QW_WMASK)) )
+    if ( likely(_can_read_lock(cnts)) )
         return;
 
     /* The slowpath will decrement the reader count, if necessary. */
@@ -115,6 +124,11 @@ static inline int _rw_is_locked(rwlock_t *lock)
     return atomic_read(&lock->cnts);
 }
 
+static inline uint32_t _write_lock_val(void)
+{
+    return _QW_LOCKED | smp_processor_id();
+}
+
 /*
  * queue_write_lock - acquire write lock of a queue rwlock.
  * @lock : Pointer to queue rwlock structure.
@@ -122,7 +136,7 @@ static inline int _rw_is_locked(rwlock_t *lock)
 static inline void _write_lock(rwlock_t *lock)
 {
     /* Optimize for the unfair lock case where the fair flag is 0. */
-    if ( atomic_cmpxchg(&lock->cnts, 0, _QW_LOCKED) == 0 )
+    if ( atomic_cmpxchg(&lock->cnts, 0, _write_lock_val()) == 0 )
         return;
 
     queue_write_lock_slowpath(lock);
@@ -157,16 +171,15 @@ static inline int _write_trylock(rwlock_t *lock)
     if ( unlikely(cnts) )
         return 0;
 
-    return likely(atomic_cmpxchg(&lock->cnts, 0, _QW_LOCKED) == 0);
+    return likely(atomic_cmpxchg(&lock->cnts, 0, _write_lock_val()) == 0);
 }
 
 static inline void _write_unlock(rwlock_t *lock)
 {
-    /*
-     * If the writer field is atomic, it can be cleared directly.
-     * Otherwise, an atomic subtraction will be used to clear it.
-     */
-    atomic_sub(_QW_LOCKED, &lock->cnts);
+    /* Since the writer field is atomic, it can be cleared directly. */
+    ASSERT(_is_write_locked_by_me(atomic_read(&lock->cnts)));
+    BUILD_BUG_ON(_QR_SHIFT != 16);
+    write_atomic((uint16_t *)&lock->cnts, 0);
 }
 
 static inline void _write_unlock_irq(rwlock_t *lock)
-- 
2.25.0


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

             reply	other threads:[~2020-02-20 17:31 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-20 17:31 Roger Pau Monne [this message]
2020-02-20 19:20 ` [Xen-devel] [PATCH v2] rwlock: allow recursive read locking when already locked in write mode Julien Grall
2020-02-21  9:10   ` Roger Pau Monné
2020-02-21 12:42     ` Julien Grall
2020-02-21 13:36     ` Jan Beulich
2020-02-21 13:46       ` Jürgen Groß
2020-02-21 13:49         ` Julien Grall
2020-02-21 14:06           ` Jürgen Groß
2020-02-21 14:11             ` Julien Grall
2020-02-21 14:16               ` Jürgen Groß
2020-02-21 14:17                 ` Jan Beulich
2020-02-21 14:24                   ` Jürgen Groß
2020-02-21 14:37                     ` Jan Beulich
2020-02-21 14:32                 ` Julien Grall
2020-02-21 14:35                   ` Jürgen Groß
2020-02-21 14:51                     ` Julien Grall
2020-02-21 15:13                       ` Jürgen Groß
2020-02-21 15:17                         ` Jan Beulich
2020-02-21 15:23                           ` Jürgen Groß
2020-02-21 15:27                             ` Jan Beulich
2020-02-21 15:33                               ` Jürgen Groß
2020-02-21 14:16             ` Jan Beulich
2020-02-21 14:19               ` Jürgen Groß
2020-02-21 14:50                 ` Jan Beulich
2020-02-21 14:06         ` Jan Beulich
2020-02-21 14:26       ` Roger Pau Monné
2020-02-21 14:32         ` Roger Pau Monné
2020-02-21 14:41         ` Jan Beulich
2020-02-21 14:49           ` Roger Pau Monné
2020-02-21 14:52             ` Jan Beulich
2020-02-21 14:58               ` Roger Pau Monné
2020-02-21 15:15                 ` Jan Beulich
2020-02-21 16:22                   ` Roger Pau Monné
2020-02-21 14:56             ` Julien Grall
2020-02-21 14:59               ` Roger Pau Monné
2020-02-21 15:02                 ` Julien Grall
2020-02-21 15:11               ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200220173116.88915-1-roger.pau@citrix.com \
    --to=roger.pau@citrix.com \
    --cc=George.Dunlap@eu.citrix.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=jbeulich@suse.com \
    --cc=jgross@suse.com \
    --cc=julien@xen.org \
    --cc=konrad.wilk@oracle.com \
    --cc=sstabellini@kernel.org \
    --cc=wl@xen.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.