The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=9b6b793bd79521edc082a89b264a30881cb65e22

commit 9b6b793bd79521edc082a89b264a30881cb65e22
Author:     Konstantin Belousov <k...@freebsd.org>
AuthorDate: 2021-07-19 15:40:38 +0000
Commit:     Konstantin Belousov <k...@freebsd.org>
CommitDate: 2021-07-28 10:21:12 +0000

    Revert most of ce42e793100b460f597e4c85ec0da12e274f9394
    
    to restore ABI compatibility for pre-10.x binaries.
    
    It restores _umtx_lock() and _umtx_unlock() syscalls, and UMTX_OP_LOCK/
    UMTX_OP_UNLOCK umtx_op(2) operations. UMUTEX_ERROR_CHECK flag is left
    out for now, I do not think it makes a difference.
    
    PR:     218571
    Reviewed by:    brooks (previous version)
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D31220
---
 sys/compat/freebsd32/syscalls.master |   6 +-
 sys/kern/kern_umtx.c                 | 446 ++++++++++++++++++++++++++++++++++-
 sys/kern/syscalls.master             |  14 +-
 sys/sys/_umtx.h                      |   4 +
 sys/sys/umtx.h                       |   7 +-
 5 files changed, 467 insertions(+), 10 deletions(-)

diff --git a/sys/compat/freebsd32/syscalls.master 
b/sys/compat/freebsd32/syscalls.master
index 93d5a251d8ab..aac788bf3956 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -789,8 +789,10 @@
 431    AUE_THR_EXIT    NOPROTO { void thr_exit(long *state); }
 432    AUE_NULL        NOPROTO { int thr_self(long *id); }
 433    AUE_THR_KILL    NOPROTO { int thr_kill(long id, int sig); }
-434    AUE_NULL        UNIMPL  nosys
-435    AUE_NULL        UNIMPL  nosys
+434    AUE_NULL        COMPAT10 { int freebsd32_umtx_lock( \
+                                   struct umtx *umtx); }
+435    AUE_NULL        COMPAT10 { int freebsd32_umtx_unlock( \
+                                   struct umtx *umtx); }
 436    AUE_JAIL_ATTACH NOPROTO { int jail_attach(int jid); }
 437    AUE_EXTATTR_LIST_FD     NOPROTO { ssize_t extattr_list_fd(int fd, \
                                    int attrnamespace, void *data, \
diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c
index a1dca77fe991..b76d080b8e06 100644
--- a/sys/kern/kern_umtx.c
+++ b/sys/kern/kern_umtx.c
@@ -908,6 +908,369 @@ umtx_key_release(struct umtx_key *key)
                vm_object_deallocate(key->info.shared.object);
 }
 
+#ifdef COMPAT_FREEBSD10
+/*
+ * Lock a umtx object.
+ */
+static int
+do_lock_umtx(struct thread *td, struct umtx *umtx, u_long id,
+    const struct timespec *timeout)
+{
+       struct abs_timeout timo;
+       struct umtx_q *uq;
+       u_long owner;
+       u_long old;
+       int error = 0;
+
+       uq = td->td_umtxq;
+       if (timeout != NULL)
+               abs_timeout_init(&timo, CLOCK_REALTIME, 0, timeout);
+
+       /*
+        * Care must be exercised when dealing with umtx structure. It
+        * can fault on any access.
+        */
+       for (;;) {
+               /*
+                * Try the uncontested case.  This should be done in userland.
+                */
+               owner = casuword(&umtx->u_owner, UMTX_UNOWNED, id);
+
+               /* The acquire succeeded. */
+               if (owner == UMTX_UNOWNED)
+                       return (0);
+
+               /* The address was invalid. */
+               if (owner == -1)
+                       return (EFAULT);
+
+               /* If no one owns it but it is contested try to acquire it. */
+               if (owner == UMTX_CONTESTED) {
+                       owner = casuword(&umtx->u_owner,
+                           UMTX_CONTESTED, id | UMTX_CONTESTED);
+
+                       if (owner == UMTX_CONTESTED)
+                               return (0);
+
+                       /* The address was invalid. */
+                       if (owner == -1)
+                               return (EFAULT);
+
+                       error = thread_check_susp(td, false);
+                       if (error != 0)
+                               break;
+
+                       /* If this failed the lock has changed, restart. */
+                       continue;
+               }
+
+               /*
+                * If we caught a signal, we have retried and now
+                * exit immediately.
+                */
+               if (error != 0)
+                       break;
+
+               if ((error = umtx_key_get(umtx, TYPE_SIMPLE_LOCK,
+                       AUTO_SHARE, &uq->uq_key)) != 0)
+                       return (error);
+
+               umtxq_lock(&uq->uq_key);
+               umtxq_busy(&uq->uq_key);
+               umtxq_insert(uq);
+               umtxq_unbusy(&uq->uq_key);
+               umtxq_unlock(&uq->uq_key);
+
+               /*
+                * Set the contested bit so that a release in user space
+                * knows to use the system call for unlock.  If this fails
+                * either some one else has acquired the lock or it has been
+                * released.
+                */
+               old = casuword(&umtx->u_owner, owner, owner | UMTX_CONTESTED);
+
+               /* The address was invalid. */
+               if (old == -1) {
+                       umtxq_lock(&uq->uq_key);
+                       umtxq_remove(uq);
+                       umtxq_unlock(&uq->uq_key);
+                       umtx_key_release(&uq->uq_key);
+                       return (EFAULT);
+               }
+
+               /*
+                * We set the contested bit, sleep. Otherwise the lock changed
+                * and we need to retry or we lost a race to the thread
+                * unlocking the umtx.
+                */
+               umtxq_lock(&uq->uq_key);
+               if (old == owner)
+                       error = umtxq_sleep(uq, "umtx", timeout == NULL ? NULL :
+                           &timo);
+               umtxq_remove(uq);
+               umtxq_unlock(&uq->uq_key);
+               umtx_key_release(&uq->uq_key);
+
+               if (error == 0)
+                       error = thread_check_susp(td, false);
+       }
+
+       if (timeout == NULL) {
+               /* Mutex locking is restarted if it is interrupted. */
+               if (error == EINTR)
+                       error = ERESTART;
+       } else {
+               /* Timed-locking is not restarted. */
+               if (error == ERESTART)
+                       error = EINTR;
+       }
+       return (error);
+}
+
+/*
+ * Unlock a umtx object.
+ */
+static int
+do_unlock_umtx(struct thread *td, struct umtx *umtx, u_long id)
+{
+       struct umtx_key key;
+       u_long owner;
+       u_long old;
+       int error;
+       int count;
+
+       /*
+        * Make sure we own this mtx.
+        */
+       owner = fuword(__DEVOLATILE(u_long *, &umtx->u_owner));
+       if (owner == -1)
+               return (EFAULT);
+
+       if ((owner & ~UMTX_CONTESTED) != id)
+               return (EPERM);
+
+       /* This should be done in userland */
+       if ((owner & UMTX_CONTESTED) == 0) {
+               old = casuword(&umtx->u_owner, owner, UMTX_UNOWNED);
+               if (old == -1)
+                       return (EFAULT);
+               if (old == owner)
+                       return (0);
+               owner = old;
+       }
+
+       /* We should only ever be in here for contested locks */
+       if ((error = umtx_key_get(umtx, TYPE_SIMPLE_LOCK, AUTO_SHARE,
+           &key)) != 0)
+               return (error);
+
+       umtxq_lock(&key);
+       umtxq_busy(&key);
+       count = umtxq_count(&key);
+       umtxq_unlock(&key);
+
+       /*
+        * When unlocking the umtx, it must be marked as unowned if
+        * there is zero or one thread only waiting for it.
+        * Otherwise, it must be marked as contested.
+        */
+       old = casuword(&umtx->u_owner, owner,
+           count <= 1 ? UMTX_UNOWNED : UMTX_CONTESTED);
+       umtxq_lock(&key);
+       umtxq_signal(&key,1);
+       umtxq_unbusy(&key);
+       umtxq_unlock(&key);
+       umtx_key_release(&key);
+       if (old == -1)
+               return (EFAULT);
+       if (old != owner)
+               return (EINVAL);
+       return (0);
+}
+
+#ifdef COMPAT_FREEBSD32
+
+/*
+ * Lock a umtx object.
+ */
+static int
+do_lock_umtx32(struct thread *td, uint32_t *m, uint32_t id,
+       const struct timespec *timeout)
+{
+       struct abs_timeout timo;
+       struct umtx_q *uq;
+       uint32_t owner;
+       uint32_t old;
+       int error = 0;
+
+       uq = td->td_umtxq;
+
+       if (timeout != NULL)
+               abs_timeout_init(&timo, CLOCK_REALTIME, 0, timeout);
+
+       /*
+        * Care must be exercised when dealing with umtx structure. It
+        * can fault on any access.
+        */
+       for (;;) {
+               /*
+                * Try the uncontested case.  This should be done in userland.
+                */
+               owner = casuword32(m, UMUTEX_UNOWNED, id);
+
+               /* The acquire succeeded. */
+               if (owner == UMUTEX_UNOWNED)
+                       return (0);
+
+               /* The address was invalid. */
+               if (owner == -1)
+                       return (EFAULT);
+
+               /* If no one owns it but it is contested try to acquire it. */
+               if (owner == UMUTEX_CONTESTED) {
+                       owner = casuword32(m,
+                           UMUTEX_CONTESTED, id | UMUTEX_CONTESTED);
+                       if (owner == UMUTEX_CONTESTED)
+                               return (0);
+
+                       /* The address was invalid. */
+                       if (owner == -1)
+                               return (EFAULT);
+
+                       error = thread_check_susp(td, false);
+                       if (error != 0)
+                               break;
+
+                       /* If this failed the lock has changed, restart. */
+                       continue;
+               }
+
+               /*
+                * If we caught a signal, we have retried and now
+                * exit immediately.
+                */
+               if (error != 0)
+                       return (error);
+
+               if ((error = umtx_key_get(m, TYPE_SIMPLE_LOCK,
+                       AUTO_SHARE, &uq->uq_key)) != 0)
+                       return (error);
+
+               umtxq_lock(&uq->uq_key);
+               umtxq_busy(&uq->uq_key);
+               umtxq_insert(uq);
+               umtxq_unbusy(&uq->uq_key);
+               umtxq_unlock(&uq->uq_key);
+
+               /*
+                * Set the contested bit so that a release in user space
+                * knows to use the system call for unlock.  If this fails
+                * either some one else has acquired the lock or it has been
+                * released.
+                */
+               old = casuword32(m, owner, owner | UMUTEX_CONTESTED);
+
+               /* The address was invalid. */
+               if (old == -1) {
+                       umtxq_lock(&uq->uq_key);
+                       umtxq_remove(uq);
+                       umtxq_unlock(&uq->uq_key);
+                       umtx_key_release(&uq->uq_key);
+                       return (EFAULT);
+               }
+
+               /*
+                * We set the contested bit, sleep. Otherwise the lock changed
+                * and we need to retry or we lost a race to the thread
+                * unlocking the umtx.
+                */
+               umtxq_lock(&uq->uq_key);
+               if (old == owner)
+                       error = umtxq_sleep(uq, "umtx", timeout == NULL ?
+                           NULL : &timo);
+               umtxq_remove(uq);
+               umtxq_unlock(&uq->uq_key);
+               umtx_key_release(&uq->uq_key);
+
+               if (error == 0)
+                       error = thread_check_susp(td, false);
+       }
+
+       if (timeout == NULL) {
+               /* Mutex locking is restarted if it is interrupted. */
+               if (error == EINTR)
+                       error = ERESTART;
+       } else {
+               /* Timed-locking is not restarted. */
+               if (error == ERESTART)
+                       error = EINTR;
+       }
+       return (error);
+}
+
+/*
+ * Unlock a umtx object.
+ */
+static int
+do_unlock_umtx32(struct thread *td, uint32_t *m, uint32_t id)
+{
+       struct umtx_key key;
+       uint32_t owner;
+       uint32_t old;
+       int error;
+       int count;
+
+       /*
+        * Make sure we own this mtx.
+        */
+       owner = fuword32(m);
+       if (owner == -1)
+               return (EFAULT);
+
+       if ((owner & ~UMUTEX_CONTESTED) != id)
+               return (EPERM);
+
+       /* This should be done in userland */
+       if ((owner & UMUTEX_CONTESTED) == 0) {
+               old = casuword32(m, owner, UMUTEX_UNOWNED);
+               if (old == -1)
+                       return (EFAULT);
+               if (old == owner)
+                       return (0);
+               owner = old;
+       }
+
+       /* We should only ever be in here for contested locks */
+       if ((error = umtx_key_get(m, TYPE_SIMPLE_LOCK, AUTO_SHARE,
+               &key)) != 0)
+               return (error);
+
+       umtxq_lock(&key);
+       umtxq_busy(&key);
+       count = umtxq_count(&key);
+       umtxq_unlock(&key);
+
+       /*
+        * When unlocking the umtx, it must be marked as unowned if
+        * there is zero or one thread only waiting for it.
+        * Otherwise, it must be marked as contested.
+        */
+       old = casuword32(m, owner,
+               count <= 1 ? UMUTEX_UNOWNED : UMUTEX_CONTESTED);
+       umtxq_lock(&key);
+       umtxq_signal(&key,1);
+       umtxq_unbusy(&key);
+       umtxq_unlock(&key);
+       umtx_key_release(&key);
+       if (old == -1)
+               return (EFAULT);
+       if (old != owner)
+               return (EINVAL);
+       return (0);
+}
+#endif /* COMPAT_FREEBSD32 */
+#endif /* COMPAT_FREEBSD10 */
+
 /*
  * Fetch and compare value, sleep on the address if value is not changed.
  */
@@ -3397,6 +3760,21 @@ do_sem2_wake(struct thread *td, struct _usem2 *sem)
        return (error);
 }
 
+#ifdef COMPAT_FREEBSD10
+int
+freebsd10__umtx_lock(struct thread *td, struct freebsd10__umtx_lock_args *uap)
+{
+       return (do_lock_umtx(td, uap->umtx, td->td_tid, 0));
+}
+
+int
+freebsd10__umtx_unlock(struct thread *td,
+    struct freebsd10__umtx_unlock_args *uap)
+{
+       return (do_unlock_umtx(td, uap->umtx, td->td_tid));
+}
+#endif
+
 inline int
 umtx_copyin_timeout(const void *uaddr, struct timespec *tsp)
 {
@@ -3456,13 +3834,50 @@ umtx_copyout_timeout(void *uaddr, size_t sz, struct 
timespec *tsp)
        return (copyout(tsp, uaddr, sizeof(*tsp)));
 }
 
+#ifdef COMPAT_FREEBSD10
 static int
-__umtx_op_unimpl(struct thread *td, struct _umtx_op_args *uap,
-    const struct umtx_copyops *ops __unused)
+__umtx_op_lock_umtx(struct thread *td, struct _umtx_op_args *uap,
+    const struct umtx_copyops *ops)
+{
+       struct timespec *ts, timeout;
+       int error;
+
+       /* Allow a null timespec (wait forever). */
+       if (uap->uaddr2 == NULL)
+               ts = NULL;
+       else {
+               error = ops->copyin_timeout(uap->uaddr2, &timeout);
+               if (error != 0)
+                       return (error);
+               ts = &timeout;
+       }
+#ifdef COMPAT_FREEBSD32
+       if (ops->compat32)
+               return (do_lock_umtx32(td, uap->obj, uap->val, ts));
+#endif
+       return (do_lock_umtx(td, uap->obj, uap->val, ts));
+}
+
+static int
+__umtx_op_unlock_umtx(struct thread *td, struct _umtx_op_args *uap,
+    const struct umtx_copyops *ops)
 {
+#ifdef COMPAT_FREEBSD32
+       if (ops->compat32)
+               return (do_unlock_umtx32(td, uap->obj, uap->val));
+#endif
+       return (do_unlock_umtx(td, uap->obj, uap->val));
+}
+#endif /* COMPAT_FREEBSD10 */
 
+#if !defined(COMPAT_FREEBSD10)
+static int
+__umtx_op_unimpl(struct thread *td __unused, struct _umtx_op_args *uap 
__unused,
+    const struct umtx_copyops *ops __unused)
+{
        return (EOPNOTSUPP);
 }
+#endif /* COMPAT_FREEBSD10 */
 
 static int
 __umtx_op_wait(struct thread *td, struct _umtx_op_args *uap,
@@ -4358,8 +4773,13 @@ typedef int (*_umtx_op_func)(struct thread *td, struct 
_umtx_op_args *uap,
     const struct umtx_copyops *umtx_ops);
 
 static const _umtx_op_func op_table[] = {
-       [UMTX_OP_RESERVED0]     = __umtx_op_unimpl,
-       [UMTX_OP_RESERVED1]     = __umtx_op_unimpl,
+#ifdef COMPAT_FREEBSD10
+       [UMTX_OP_LOCK]          = __umtx_op_lock_umtx,
+       [UMTX_OP_UNLOCK]        = __umtx_op_unlock_umtx,
+#else
+       [UMTX_OP_LOCK]          = __umtx_op_unimpl,
+       [UMTX_OP_UNLOCK]        = __umtx_op_unimpl,
+#endif
        [UMTX_OP_WAIT]          = __umtx_op_wait,
        [UMTX_OP_WAKE]          = __umtx_op_wake,
        [UMTX_OP_MUTEX_TRYLOCK] = __umtx_op_trylock_umutex,
@@ -4480,6 +4900,22 @@ sys__umtx_op(struct thread *td, struct _umtx_op_args 
*uap)
 }
 
 #ifdef COMPAT_FREEBSD32
+#ifdef COMPAT_FREEBSD10
+int
+freebsd10_freebsd32_umtx_lock(struct thread *td,
+    struct freebsd10_freebsd32_umtx_lock_args *uap)
+{
+       return (do_lock_umtx32(td, (uint32_t *)uap->umtx, td->td_tid, NULL));
+}
+
+int
+freebsd10_freebsd32_umtx_unlock(struct thread *td,
+    struct freebsd10_freebsd32_umtx_unlock_args *uap)
+{
+       return (do_unlock_umtx32(td, (uint32_t *)uap->umtx, td->td_tid));
+}
+#endif /* COMPAT_FREEBSD10 */
+
 int
 freebsd32__umtx_op(struct thread *td, struct freebsd32__umtx_op_args *uap)
 {
@@ -4487,7 +4923,7 @@ freebsd32__umtx_op(struct thread *td, struct 
freebsd32__umtx_op_args *uap)
        return (kern__umtx_op(td, uap->obj, uap->op, uap->val, uap->uaddr,
            uap->uaddr2, &umtx_native_ops32));
 }
-#endif
+#endif /* COMPAT_FREEBSD32 */
 
 void
 umtx_thread_init(struct thread *td)
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 69a82d642d79..af787908451a 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -2270,7 +2270,19 @@
                    int sig
                );
        }
-434-435        AUE_NULL        RESERVED
+
+434    AUE_NULL        COMPAT10 {
+               int _umtx_lock(
+                   _Inout_ struct umtx *umtx
+               );
+       }
+
+435    AUE_NULL        COMPAT10 {
+               int _umtx_unlock(
+                   _Inout_ struct umtx *umtx
+               );
+       }
+
 436    AUE_JAIL_ATTACH STD {
                int jail_attach(
                    int jid
diff --git a/sys/sys/_umtx.h b/sys/sys/_umtx.h
index b9d10b756a0c..d280c7d3db19 100644
--- a/sys/sys/_umtx.h
+++ b/sys/sys/_umtx.h
@@ -35,6 +35,10 @@
 #include <sys/_types.h>
 #include <sys/_timespec.h>
 
+struct umtx {
+       volatile unsigned long  u_owner;        /* Owner of the mutex. */
+};
+
 struct umutex {
        volatile __lwpid_t      m_owner;        /* Owner of the mutex */
        __uint32_t              m_flags;        /* Flags of the mutex */
diff --git a/sys/sys/umtx.h b/sys/sys/umtx.h
index 6753a6217688..60e9dccdad91 100644
--- a/sys/sys/umtx.h
+++ b/sys/sys/umtx.h
@@ -34,6 +34,9 @@
 
 #include <sys/_umtx.h>
 
+#define        UMTX_UNOWNED            0x0
+#define        UMTX_CONTESTED          LONG_MIN
+
 /* Common lock flags */
 #define USYNC_PROCESS_SHARED   0x0001  /* Process shared sync objs */
 
@@ -73,8 +76,8 @@
 #define        USEM_COUNT(c)           ((c) & USEM_MAX_COUNT)
 
 /* op code for _umtx_op */
-#define        UMTX_OP_RESERVED0       0
-#define        UMTX_OP_RESERVED1       1
+#define        UMTX_OP_LOCK            0       /* COMPAT10 */
+#define        UMTX_OP_UNLOCK          1       /* COMPAT10 */
 #define        UMTX_OP_WAIT            2
 #define        UMTX_OP_WAKE            3
 #define        UMTX_OP_MUTEX_TRYLOCK   4
_______________________________________________
dev-commits-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "dev-commits-src-all-unsubscr...@freebsd.org"

Reply via email to