summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_resource.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_resource.c')
-rw-r--r--sys/kern/kern_resource.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/sys/kern/kern_resource.c b/sys/kern/kern_resource.c
index b3c2ec6..4956e51 100644
--- a/sys/kern/kern_resource.c
+++ b/sys/kern/kern_resource.c
@@ -46,6 +46,7 @@
#include <sys/systm.h>
#include <sys/sysproto.h>
#include <sys/file.h>
+#include <sys/kernel.h>
#include <sys/resourcevar.h>
#include <sys/malloc.h>
#include <sys/proc.h>
@@ -61,6 +62,14 @@ static int donice __P((struct proc *curp, struct proc *chgp, int n));
/* dosetrlimit non-static: Needed by SysVR4 emulator */
int dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
+static MALLOC_DEFINE(M_UIDINFO, "uidinfo", "uidinfo structures");
+#define UIHASH(uid) (&uihashtbl[(uid) & uihash])
+static LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
+static u_long uihash; /* size of hash table - 1 */
+
+static struct uidinfo *uicreate __P((uid_t uid));
+static struct uidinfo *uilookup __P((uid_t uid));
+
/*
* Resource controls and accounting.
*/
@@ -641,3 +650,136 @@ limcopy(lim)
copy->p_refcnt = 1;
return (copy);
}
+
+/*
+ * Find the uidinfo structure for a uid. This structure is used to
+ * track the total resource consumption (process count, socket buffer
+ * size, etc.) for the uid and impose limits.
+ */
+void
+uihashinit()
+{
+ uihashtbl = hashinit(maxproc / 16, M_UIDINFO, &uihash);
+}
+
+static struct uidinfo *
+uilookup(uid)
+ uid_t uid;
+{
+ struct uihashhead *uipp;
+ struct uidinfo *uip;
+
+ uipp = UIHASH(uid);
+ LIST_FOREACH(uip, uipp, ui_hash)
+ if (uip->ui_uid == uid)
+ break;
+
+ return (uip);
+}
+
+static struct uidinfo *
+uicreate(uid)
+ uid_t uid;
+{
+ struct uidinfo *uip, *norace;
+
+ MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_NOWAIT);
+ if (uip == NULL) {
+ MALLOC(uip, struct uidinfo *, sizeof(*uip), M_UIDINFO, M_WAITOK);
+ /*
+ * if we M_WAITOK we must look afterwards or risk
+ * redundant entries
+ */
+ norace = uilookup(uid);
+ if (norace != NULL) {
+ FREE(uip, M_UIDINFO);
+ return (norace);
+ }
+ }
+ LIST_INSERT_HEAD(UIHASH(uid), uip, ui_hash);
+ uip->ui_uid = uid;
+ uip->ui_proccnt = 0;
+ uip->ui_sbsize = 0;
+ uip->ui_ref = 0;
+ return (uip);
+}
+
+struct uidinfo *
+uifind(uid)
+ uid_t uid;
+{
+ struct uidinfo *uip;
+
+ uip = uilookup(uid);
+ if (uip == NULL)
+ uip = uicreate(uid);
+ uip->ui_ref++;
+ return (uip);
+}
+
+int
+uifree(uip)
+ struct uidinfo *uip;
+{
+
+ if (--uip->ui_ref == 0) {
+ if (uip->ui_sbsize != 0)
+ /* XXX no %qd in kernel. Truncate. */
+ panic("freeing uidinfo: uid = %d, sbsize = %ld",
+ uip->ui_uid, (long)uip->ui_sbsize);
+ if (uip->ui_proccnt != 0)
+ panic("freeing uidinfo: uid = %d, proccnt = %ld",
+ uip->ui_uid, uip->ui_proccnt);
+ LIST_REMOVE(uip, ui_hash);
+ FREE(uip, M_UIDINFO);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Change the count associated with number of processes
+ * a given user is using. When 'max' is 0, don't enforce a limit
+ */
+int
+chgproccnt(uip, diff, max)
+ struct uidinfo *uip;
+ int diff;
+ int max;
+{
+ /* don't allow them to exceed max, but allow subtraction */
+ if (diff > 0 && uip->ui_proccnt + diff > max && max != 0)
+ return (0);
+ uip->ui_proccnt += diff;
+ if (uip->ui_proccnt < 0)
+ panic("negative proccnt for uid = %d", uip->ui_uid);
+ return (1);
+}
+
+/*
+ * Change the total socket buffer size a user has used.
+ */
+int
+chgsbsize(uip, hiwat, to, max)
+ struct uidinfo *uip;
+ u_long *hiwat;
+ u_long to;
+ rlim_t max;
+{
+ rlim_t new;
+ int s;
+
+ s = splnet();
+ new = uip->ui_sbsize + to - *hiwat;
+ /* don't allow them to exceed max, but allow subtraction */
+ if (to > *hiwat && new > max) {
+ splx(s);
+ return (0);
+ }
+ uip->ui_sbsize = new;
+ *hiwat = to;
+ if (uip->ui_sbsize < 0)
+ panic("negative sbsize for uid = %d", uip->ui_uid);
+ splx(s);
+ return (1);
+}
OpenPOWER on IntegriCloud