The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_uidinfo.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: kern_uidinfo.c,v 1.13 2021/12/28 13:28:24 riastradh Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 1982, 1986, 1991, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  * (c) UNIX System Laboratories, Inc.
    7  * All or some portions of this file are derived from material licensed
    8  * to the University of California by American Telephone and Telegraph
    9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   10  * the permission of UNIX System Laboratories, Inc.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. Neither the name of the University nor the names of its contributors
   21  *    may be used to endorse or promote products derived from this software
   22  *    without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   34  * SUCH DAMAGE.
   35  */
   36 
   37 #include <sys/cdefs.h>
   38 __KERNEL_RCSID(0, "$NetBSD: kern_uidinfo.c,v 1.13 2021/12/28 13:28:24 riastradh Exp $");
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kmem.h>
   43 #include <sys/proc.h>
   44 #include <sys/atomic.h>
   45 #include <sys/uidinfo.h>
   46 #include <sys/sysctl.h>
   47 #include <sys/kauth.h>
   48 #include <sys/cpu.h>
   49 
   50 static SLIST_HEAD(uihashhead, uidinfo) *uihashtbl;
   51 static u_long           uihash;
   52 
   53 #define UIHASH(uid)     (&uihashtbl[(uid) & uihash])
   54 
   55 static int
   56 sysctl_kern_uidinfo_cnt(SYSCTLFN_ARGS)
   57 {
   58         static const struct {
   59                 const char *name;
   60                 u_int value;
   61         } nv[] = {
   62 #define _MEM(n) { # n, offsetof(struct uidinfo, ui_ ## n) }
   63                 _MEM(proccnt),
   64                 _MEM(lwpcnt),
   65                 _MEM(lockcnt),
   66                 _MEM(semcnt),
   67                 _MEM(sbsize),
   68 #undef _MEM
   69         };
   70 
   71         for (size_t i = 0; i < __arraycount(nv); i++)
   72                 if (strcmp(nv[i].name, rnode->sysctl_name) == 0) {
   73                         uint64_t cnt;
   74                         struct sysctlnode node = *rnode;
   75                         struct uidinfo *uip;
   76 
   77                         node.sysctl_data = &cnt;
   78                         uip = uid_find(kauth_cred_geteuid(l->l_cred));
   79 
   80                         *(uint64_t *)node.sysctl_data =
   81                             *(u_long *)((char *)uip + nv[i].value);
   82 
   83                         return sysctl_lookup(SYSCTLFN_CALL(&node));
   84                 }
   85 
   86         return EINVAL;
   87 }
   88 
   89 static struct sysctllog *kern_uidinfo_sysctllog;
   90 
   91 static void
   92 sysctl_kern_uidinfo_setup(void)
   93 {
   94         const struct sysctlnode *rnode, *cnode;
   95 
   96         sysctl_createv(&kern_uidinfo_sysctllog, 0, NULL, &rnode,
   97                        CTLFLAG_PERMANENT,
   98                        CTLTYPE_NODE, "uidinfo",
   99                        SYSCTL_DESCR("Resource usage per uid"),
  100                        NULL, 0, NULL, 0,
  101                        CTL_KERN, CTL_CREATE, CTL_EOL);
  102 
  103         sysctl_createv(&kern_uidinfo_sysctllog, 0, &rnode, &cnode,
  104                        CTLFLAG_PERMANENT,
  105                        CTLTYPE_QUAD, "proccnt",
  106                        SYSCTL_DESCR("Number of processes for the current user"),
  107                        sysctl_kern_uidinfo_cnt, 0, NULL, 0,
  108                        CTL_CREATE, CTL_EOL);
  109         sysctl_createv(&kern_uidinfo_sysctllog, 0, &rnode, &cnode,
  110                        CTLFLAG_PERMANENT,
  111                        CTLTYPE_QUAD, "lwpcnt",
  112                        SYSCTL_DESCR("Number of lwps for the current user"),
  113                        sysctl_kern_uidinfo_cnt, 0, NULL, 0,
  114                        CTL_CREATE, CTL_EOL);
  115         sysctl_createv(&kern_uidinfo_sysctllog, 0, &rnode, &cnode,
  116                        CTLFLAG_PERMANENT,
  117                        CTLTYPE_QUAD, "lockcnt",
  118                        SYSCTL_DESCR("Number of locks for the current user"),
  119                        sysctl_kern_uidinfo_cnt, 0, NULL, 0,
  120                        CTL_CREATE, CTL_EOL);
  121         sysctl_createv(&kern_uidinfo_sysctllog, 0, &rnode, &cnode,
  122                        CTLFLAG_PERMANENT,
  123                        CTLTYPE_QUAD, "semcnt",
  124                        SYSCTL_DESCR("Number of semaphores used for the current user"),
  125                        sysctl_kern_uidinfo_cnt, 0, NULL, 0,
  126                        CTL_CREATE, CTL_EOL);
  127         sysctl_createv(&kern_uidinfo_sysctllog, 0, &rnode, &cnode,
  128                        CTLFLAG_PERMANENT,
  129                        CTLTYPE_QUAD, "sbsize",
  130                        SYSCTL_DESCR("Socket buffers used for the current user"),
  131                        sysctl_kern_uidinfo_cnt, 0, NULL, 0,
  132                        CTL_CREATE, CTL_EOL);
  133 }
  134 
  135 static int
  136 uid_stats(struct hashstat_sysctl *hs, bool fill)
  137 {
  138         struct uidinfo *uip;
  139         uint64_t chain;
  140 
  141         strlcpy(hs->hash_name, "uihash", sizeof(hs->hash_name));
  142         strlcpy(hs->hash_desc, "user info (uid->used proc) hash",
  143             sizeof(hs->hash_desc));
  144         if (!fill)
  145                 return 0;
  146 
  147         hs->hash_size = uihash + 1;
  148 
  149         for (size_t i = 0; i < hs->hash_size; i++) {
  150                 chain = 0;
  151                 SLIST_FOREACH(uip, &uihashtbl[i], ui_hash) {
  152                         membar_datadep_consumer();
  153                         chain++;
  154                 }
  155                 if (chain > 0) {
  156                         hs->hash_used++;
  157                         hs->hash_items += chain;
  158                         if (chain > hs->hash_maxchain)
  159                                 hs->hash_maxchain = chain;
  160                 }
  161         }
  162 
  163         return 0;
  164 }
  165 
  166 void
  167 uid_init(void)
  168 {
  169 
  170         /*
  171          * In case of MP system, SLIST_FOREACH would force a cache line
  172          * write-back for every modified 'uidinfo', thus we try to keep the
  173          * lists short.
  174          */
  175         const u_int uihash_sz = (maxcpus > 1 ? 1024 : 64);
  176 
  177         uihashtbl = hashinit(uihash_sz, HASH_SLIST, true, &uihash);
  178 
  179         /*
  180          * Ensure that uid 0 is always in the user hash table, as
  181          * sbreserve() expects it available from interrupt context.
  182          */
  183         (void)uid_find(0);
  184         sysctl_kern_uidinfo_setup();
  185         hashstat_register("uihash", uid_stats);
  186 }
  187 
  188 struct uidinfo *
  189 uid_find(uid_t uid)
  190 {
  191         struct uidinfo *uip, *uip_first, *newuip;
  192         struct uihashhead *uipp;
  193 
  194         uipp = UIHASH(uid);
  195         newuip = NULL;
  196 
  197         /*
  198          * To make insertion atomic, abstraction of SLIST will be violated.
  199          */
  200         uip_first = uipp->slh_first;
  201  again:
  202         SLIST_FOREACH(uip, uipp, ui_hash) {
  203                 membar_datadep_consumer();
  204                 if (uip->ui_uid != uid)
  205                         continue;
  206                 if (newuip != NULL)
  207                         kmem_free(newuip, sizeof(*newuip));
  208                 return uip;
  209         }
  210         if (newuip == NULL)
  211                 newuip = kmem_zalloc(sizeof(*newuip), KM_SLEEP);
  212         newuip->ui_uid = uid;
  213 
  214         /*
  215          * If atomic insert is unsuccessful, another thread might be
  216          * allocated this 'uid', thus full re-check is needed.
  217          */
  218         newuip->ui_hash.sle_next = uip_first;
  219         membar_producer();
  220         uip = atomic_cas_ptr(&uipp->slh_first, uip_first, newuip);
  221         if (uip != uip_first) {
  222                 uip_first = uip;
  223                 goto again;
  224         }
  225 
  226         return newuip;
  227 }
  228 
  229 /*
  230  * Change the count associated with number of processes
  231  * a given user is using.
  232  */
  233 int
  234 chgproccnt(uid_t uid, int diff)
  235 {
  236         struct uidinfo *uip;
  237         long proccnt;
  238 
  239         uip = uid_find(uid);
  240         proccnt = atomic_add_long_nv(&uip->ui_proccnt, diff);
  241         KASSERTMSG(proccnt >= 0, "uid=%d diff=%d proccnt=%ld",
  242             uid, diff, proccnt);
  243         return proccnt;
  244 }
  245 
  246 /*
  247  * Change the count associated with number of lwps
  248  * a given user is using.
  249  */
  250 int
  251 chglwpcnt(uid_t uid, int diff)
  252 {
  253         struct uidinfo *uip;
  254         long lwpcnt;
  255 
  256         uip = uid_find(uid);
  257         lwpcnt = atomic_add_long_nv(&uip->ui_lwpcnt, diff);
  258         KASSERTMSG(lwpcnt >= 0, "uid=%d diff=%d lwpcnt=%ld",
  259             uid, diff, lwpcnt);
  260         return lwpcnt;
  261 }
  262 
  263 /*
  264  * Change the count associated with number of semaphores
  265  * a given user is using.
  266  */
  267 int
  268 chgsemcnt(uid_t uid, int diff)
  269 {
  270         struct uidinfo *uip;
  271         long semcnt;
  272 
  273         uip = uid_find(uid);
  274         semcnt = atomic_add_long_nv(&uip->ui_semcnt, diff);
  275         KASSERTMSG(semcnt >= 0, "uid=%d diff=%d semcnt=%ld",
  276             uid, diff, semcnt);
  277         return semcnt;
  278 }
  279 
  280 int
  281 chgsbsize(struct uidinfo *uip, u_long *hiwat, u_long to, rlim_t xmax)
  282 {
  283         rlim_t nsb;
  284         const long diff = to - *hiwat;
  285 
  286         nsb = (rlim_t)atomic_add_long_nv((long *)&uip->ui_sbsize, diff);
  287         if (diff > 0 && nsb > xmax) {
  288                 atomic_add_long((long *)&uip->ui_sbsize, -diff);
  289                 return 0;
  290         }
  291         *hiwat = to;
  292         return 1;
  293 }

Cache object: 1bd8b4287bc8fda37c667ca940f9e5bb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.