Serialize access to UID data with a rwlock.
authormpi <mpi@openbsd.org>
Mon, 26 Feb 2018 13:43:51 +0000 (13:43 +0000)
committermpi <mpi@openbsd.org>
Mon, 26 Feb 2018 13:43:51 +0000 (13:43 +0000)
Caller must call uid_release() after making whatever change they needed
on the result of uid_find().

Adapted from guenther@'s proctree diff, ok dlg@, visa@

sys/kern/kern_proc.c
sys/kern/vfs_lockf.c
sys/sys/proc.h

index 8ba1222..45e84d8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_proc.c,v 1.81 2018/02/20 12:38:58 mpi Exp $      */
+/*     $OpenBSD: kern_proc.c,v 1.82 2018/02/26 13:43:51 mpi Exp $      */
 /*     $NetBSD: kern_proc.c,v 1.14 1996/02/09 18:59:41 christos Exp $  */
 
 /*
@@ -39,6 +39,7 @@
 #include <sys/buf.h>
 #include <sys/acct.h>
 #include <sys/wait.h>
+#include <sys/rwlock.h>
 #include <ufs/ufs/quota.h>
 #include <sys/uio.h>
 #include <sys/malloc.h>
@@ -49,6 +50,7 @@
 #include <sys/pool.h>
 #include <sys/vnode.h>
 
+struct rwlock uidinfolk;
 #define        UIHASH(uid)     (&uihashtbl[(uid) & uihash])
 LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
 u_long uihash;         /* size of hash table - 1 */
@@ -91,6 +93,7 @@ procinit(void)
        LIST_INIT(&zombprocess);
        LIST_INIT(&allproc);
 
+       rw_init(&uidinfolk, "uidinfo");
 
        tidhashtbl = hashinit(maxthread / 4, M_PROC, M_NOWAIT, &tidhash);
        pidhashtbl = hashinit(maxprocess / 4, M_PROC, M_NOWAIT, &pidhash);
@@ -113,6 +116,10 @@ procinit(void)
            PR_WAITOK, "sessionpl", NULL);
 }
 
+/*
+ * This returns with `uidinfolk' held: caller must call uid_release()
+ * after making whatever change they needed.
+ */
 struct uidinfo *
 uid_find(uid_t uid)
 {
@@ -120,12 +127,15 @@ uid_find(uid_t uid)
        struct uihashhead *uipp;
 
        uipp = UIHASH(uid);
+       rw_enter_write(&uidinfolk);
        LIST_FOREACH(uip, uipp, ui_hash)
                if (uip->ui_uid == uid)
                        break;
        if (uip)
                return (uip);
+       rw_exit_write(&uidinfolk);
        nuip = malloc(sizeof(*nuip), M_PROC, M_WAITOK|M_ZERO);
+       rw_enter_write(&uidinfolk);
        LIST_FOREACH(uip, uipp, ui_hash)
                if (uip->ui_uid == uid)
                        break;
@@ -139,6 +149,12 @@ uid_find(uid_t uid)
        return (nuip);
 }
 
+void
+uid_release(struct uidinfo *uip)
+{
+       rw_exit_write(&uidinfolk);
+}
+
 /*
  * Change the count associated with number of threads
  * a given user is using.
@@ -147,12 +163,14 @@ int
 chgproccnt(uid_t uid, int diff)
 {
        struct uidinfo *uip;
+       long count;
 
        uip = uid_find(uid);
-       uip->ui_proccnt += diff;
-       if (uip->ui_proccnt < 0)
+       count = (uip->ui_proccnt += diff);
+       uid_release(uip);
+       if (count < 0)
                panic("chgproccnt: procs < 0");
-       return (uip->ui_proccnt);
+       return count;
 }
 
 /*
index 0190900..9bd95ae 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: vfs_lockf.c,v 1.24 2016/11/07 00:26:33 guenther Exp $ */
+/*     $OpenBSD: vfs_lockf.c,v 1.25 2018/02/26 13:43:51 mpi Exp $      */
 /*     $NetBSD: vfs_lockf.c,v 1.7 1996/02/04 02:18:21 christos Exp $   */
 
 /*
@@ -106,9 +106,12 @@ lf_alloc(uid_t uid, int allowfail)
 
        uip = uid_find(uid);
        if (uid && allowfail && uip->ui_lockcnt >
-           (allowfail == 1 ? maxlocksperuid : (maxlocksperuid * 2)))
+           (allowfail == 1 ? maxlocksperuid : (maxlocksperuid * 2))) {
+               uid_release(uip);
                return (NULL);
+       }
        uip->ui_lockcnt++;
+       uid_release(uip);
        lock = pool_get(&lockfpool, PR_WAITOK);
        lock->lf_uid = uid;
        return (lock);
@@ -121,6 +124,7 @@ lf_free(struct lockf *lock)
 
        uip = uid_find(lock->lf_uid);
        uip->ui_lockcnt--;
+       uid_release(uip);
        pool_put(&lockfpool, lock);
 }
 
index fd0e46e..edcaf7c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: proc.h,v 1.246 2018/02/20 12:38:58 mpi Exp $  */
+/*     $OpenBSD: proc.h,v 1.247 2018/02/26 13:43:51 mpi Exp $  */
 /*     $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $       */
 
 /*-
@@ -408,6 +408,7 @@ struct uidinfo {
 };
 
 struct uidinfo *uid_find(uid_t);
+void uid_release(struct uidinfo *);
 
 /*
  * We use process IDs <= PID_MAX; PID_MAX + 1 must also fit in a pid_t,