summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.pm9
-rw-r--r--usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.xs8
-rw-r--r--usr/src/cmd/projadd/projmod.pl91
-rw-r--r--usr/src/cmd/truss/codes.c1
-rw-r--r--usr/src/cmd/truss/expound.c15
-rw-r--r--usr/src/cmd/truss/print.c16
-rw-r--r--usr/src/cmd/truss/print.h5
-rw-r--r--usr/src/cmd/truss/systable.c1
-rw-r--r--usr/src/lib/common/inc/c_synonyms.h3
-rw-r--r--usr/src/lib/libc/inc/synonyms.h3
-rw-r--r--usr/src/lib/libc/port/llib-lc3
-rw-r--r--usr/src/lib/libc/port/mapfile-vers2
-rw-r--r--usr/src/lib/libc/port/sys/rctlsys.c15
-rw-r--r--usr/src/lib/libproc/common/libproc.h4
-rw-r--r--usr/src/lib/libproc/common/llib-lproc9
-rw-r--r--usr/src/lib/libproc/common/mapfile-vers3
-rw-r--r--usr/src/lib/libproc/common/pr_getrctl.c85
-rw-r--r--usr/src/lib/libproject/common/setproject.c169
-rw-r--r--usr/src/uts/common/os/project.c4
-rw-r--r--usr/src/uts/common/os/rctl.c291
-rw-r--r--usr/src/uts/common/sys/rctl.h10
-rw-r--r--usr/src/uts/common/sys/rctl_impl.h12
-rw-r--r--usr/src/uts/common/sys/task.h11
-rw-r--r--usr/src/uts/common/syscall/rctlsys.c161
24 files changed, 823 insertions, 108 deletions
diff --git a/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.pm b/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.pm
index bb7c72700a..9dbdf26274 100644
--- a/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.pm
+++ b/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.pm
@@ -1,13 +1,12 @@
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
@@ -38,7 +37,7 @@ use XSLoader;
XSLoader::load(__PACKAGE__, $VERSION);
our (@EXPORT_OK, %EXPORT_TAGS);
-my @constants = qw(TASK_NORMAL TASK_FINAL);
+my @constants = qw(TASK_NORMAL TASK_FINAL TASK_PROJ_PURGE);
my @syscalls = qw(settaskid gettaskid);
@EXPORT_OK = (@constants, @syscalls);
%EXPORT_TAGS = (CONSTANTS => \@constants, SYSCALLS => \@syscalls,
diff --git a/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.xs b/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.xs
index b18968440d..8cdbb9e403 100644
--- a/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.xs
+++ b/usr/src/cmd/perl/contrib/Sun/Solaris/Task/Task.xs
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Task.xs contains XS wrappers for the task maniplulation functions.
@@ -58,6 +57,7 @@ BOOT:
stash = gv_stashpv("Sun::Solaris::Task", TRUE);
newCONSTSUB(stash, "TASK_NORMAL", newSViv(TASK_NORMAL));
newCONSTSUB(stash, "TASK_FINAL", newSViv(TASK_FINAL));
+ newCONSTSUB(stash, "TASK_PROJ_PURGE", newSViv(TASK_PROJ_PURGE));
}
taskid_t
diff --git a/usr/src/cmd/projadd/projmod.pl b/usr/src/cmd/projadd/projmod.pl
index e522747629..2d3f07e1a2 100644
--- a/usr/src/cmd/projadd/projmod.pl
+++ b/usr/src/cmd/projadd/projmod.pl
@@ -3,9 +3,8 @@
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License"). You may not use this file except in compliance
-# with the License.
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
@@ -21,7 +20,7 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#ident "%Z%%M% %I% %E% SMI"
@@ -38,6 +37,7 @@ use Getopt::Long qw(:config no_ignore_case bundling);
use POSIX qw(locale_h);
use Sun::Solaris::Utils qw(textdomain gettext);
use Sun::Solaris::Project qw(:ALL :PRIVATE);
+use Sun::Solaris::Task qw(:ALL);
#
# Print a usage message and exit.
@@ -51,7 +51,7 @@ sub usage
printf(STDERR gettext(
"Usage: %s [-n] [-f filename]\n"), $prog);
printf(STDERR gettext(
- " %s [-n] [-f filename] [-p projid [-o]] [-c comment]\n".
+ " %s [-n] [-A|-f filename] [-p projid [-o]] [-c comment]\n".
" %s [-a|-s|-r] [-U user[,user...]] [-G group[,group...]]\n".
" %s [-K name[=value[,value...]]] [-l new_projectname] ".
"project\n"), $prog, $space, $space, $space);
@@ -360,7 +360,7 @@ my ($pname, $flags);
$flags = {};
my $modify = 0;
-my $projfile = &PROJF_PATH;
+my $projfile;
my $opt_n;
my $opt_c;
my $opt_o;
@@ -372,6 +372,7 @@ my $opt_s;
my $opt_U;
my $opt_G;
my @opt_K;
+my $opt_A;
GetOptions("f=s" => \$projfile,
"n" => \$opt_n,
@@ -384,11 +385,12 @@ GetOptions("f=s" => \$projfile,
"a" => \$opt_a,
"U=s" => \$opt_U,
"G=s" => \$opt_G,
- "K=s" => \@opt_K) || usage();
+ "K=s" => \@opt_K,
+ "A" => \$opt_A) || usage();
usage(gettext('Invalid command-line arguments')) if (@ARGV > 1);
-if ($opt_c || $opt_G || $opt_l || $opt_p || $opt_U || @opt_K) {
+if ($opt_c || $opt_G || $opt_l || $opt_p || $opt_U || @opt_K || $opt_A) {
$modify = 1;
if (! defined($ARGV[0])) {
usage(gettext('No project name specified'));
@@ -399,6 +401,14 @@ if (!$modify && defined($ARGV[0])) {
usage(gettext('missing -c, -G, -l, -p, -U, or -K'));
}
+if (defined($opt_A) && defined($projfile)) {
+ usage(gettext('-A and -f are mutually exclusive'));
+}
+
+if (! defined($projfile)) {
+ $projfile = &PROJF_PATH;
+}
+
if ($modify && $projfile eq '-') {
usage(gettext('Cannot modify standard input'));
}
@@ -654,8 +664,69 @@ if ($modify) {
}
-exit(0);
-
+if (defined($opt_A)) {
+ my $error;
+
+ if (($error = setproject($pname, "root", TASK_FINAL|TASK_PROJ_PURGE)) != 0) {
+
+ if ($error == SETPROJ_ERR_TASK) {
+ if ($!{EAGAIN}) {
+ error([5, gettext("resource control limit has ".
+ "been reached\n")]);
+ } elsif ($!{ESRCH}) {
+ error([5, gettext("user \"%s\" is not a member ".
+ "of project \"%s\"\n"), "root", $pname]);
+ } elsif ($!{EACCES}) {
+ error([5, gettext("the invoking task is final\n"
+ )]);
+ } else {
+ error([5, gettext("could not join project \"%s".
+ "\"\n"), $pname]);
+ }
+ } elsif ($error == SETPROJ_ERR_POOL) {
+ if ($!{EACCES}) {
+ error([5, gettext("no resource pool accepting ".
+ "default bindings exists for project \"%s".
+ "\"\n"), $pname]);
+ } elsif ($!{ESRCH}) {
+ error([5, gettext("specified resource pool ".
+ "does not exist for project \"%s\"\n"),
+ $pname]);
+ } else {
+ error([5, gettext("could not bind to default ".
+ "resource pool for project \"%s\"\n"),
+ $pname]);
+ }
+ } else {
+ #
+ # $error represents the position - within the semi-colon
+ # delimited $attribute - that generated the error
+ #
+ if ($error <= 0) {
+ error([5, gettext("setproject failed for ".
+ "project \"%s\"\n"), $pname]);
+ } else {
+ my ($name, $projid, $comment, $users_ref,
+ $groups_ref, $attr) = getprojbyname($pname);
+ my $attribute = ($attr =~
+ /(\S+?)=\S+?(?:;|\z)/g)[$error - 1];
+
+ if (!$attribute) {
+ error([5, gettext("warning, resource ".
+ "control assignment failed for ".
+ "project \"%s\" attribute %d\n"),
+ $pname, $error]);
+ } else {
+ error([5, gettext("warning, %s ".
+ "resource control assignment ".
+ "failed for project \"%s\"\n"),
+ $attribute, $pname]);
+ }
+ }
+ }
+ }
+}
+exit(0);
diff --git a/usr/src/cmd/truss/codes.c b/usr/src/cmd/truss/codes.c
index b3867d52ee..1e734fd926 100644
--- a/usr/src/cmd/truss/codes.c
+++ b/usr/src/cmd/truss/codes.c
@@ -1129,6 +1129,7 @@ rctlsyscode(int code)
case 1: str = "SETRCTL"; break;
case 2: str = "RCTLSYS_LST"; break;
case 3: str = "RCTLSYS_CTL"; break;
+ case 4: str = "RCTLSYS_SETPROJ"; break;
default: str = "UNKNOWN"; break;
}
return (str);
diff --git a/usr/src/cmd/truss/expound.c b/usr/src/cmd/truss/expound.c
index e5213b88d5..e158f96343 100644
--- a/usr/src/cmd/truss/expound.c
+++ b/usr/src/cmd/truss/expound.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -93,6 +93,7 @@
#include <tsol/label.h>
#include <sys/nvpair.h>
#include <libnvpair.h>
+#include <sys/rctl_impl.h>
#include "ramdata.h"
#include "systable.h"
@@ -4687,6 +4688,8 @@ show_rctlblk(private_t *pri, long _rctlblk)
static void
show_rctls(private_t *pri)
{
+ int entry;
+
switch (pri->sys_args[0]) {
case 0: /* getrctl */
case 1: /* setrctl */
@@ -4705,6 +4708,16 @@ show_rctls(private_t *pri)
show_rctlblk(pri, pri->sys_args[3]);
}
break;
+ case 4: /* setprojrctl */
+ for (entry = 0; entry < pri->sys_args[4]; entry++) {
+ (void) printf("%s\tNew rctlblk[%d]: 0x%lx\n",
+ pri->pname, entry,
+ (long)RCTLBLK_INC(pri->sys_args[3], entry));
+ if (RCTLBLK_INC(pri->sys_args[3], entry) != NULL) {
+ show_rctlblk(pri,
+ (long)RCTLBLK_INC(pri->sys_args[3], entry));
+ }
+ }
}
}
diff --git a/usr/src/cmd/truss/print.c b/usr/src/cmd/truss/print.c
index 09dec70e82..8bdc4134e0 100644
--- a/usr/src/cmd/truss/print.c
+++ b/usr/src/cmd/truss/print.c
@@ -80,6 +80,7 @@
#include <sys/rctl.h>
#include <sys/rctl_impl.h>
#include <sys/fork.h>
+#include <sys/task.h>
#include "ramdata.h"
#include "print.h"
#include "proto.h"
@@ -2542,6 +2543,20 @@ prt_rcf(private_t *pri, int raw, long val)
}
/*
+ * Print setprojrctl flags
+ */
+void
+prt_spf(private_t *pri, int raw, long val)
+{
+ long action = val & TASK_PROJ_MASK;
+
+ if (!raw && (action == TASK_PROJ_PURGE))
+ outstring(pri, "TASK_PROJ_PURGE");
+ else
+ prt_hex(pri, 0, val);
+}
+
+/*
* Print forkx() flags
*/
void
@@ -2664,5 +2679,6 @@ void (* const Print[])() = {
prt_rsf, /* RSF -- print setrctl() flags */
prt_rcf, /* RCF -- print rctlsys_ctl() flags */
prt_fxf, /* FXF -- print forkx() flags */
+ prt_spf, /* SPF -- print rctlsys_projset() flags */
prt_dec, /* HID -- hidden argument, make this the last one */
};
diff --git a/usr/src/cmd/truss/print.h b/usr/src/cmd/truss/print.h
index 9a4482139e..9d4239cce8 100644
--- a/usr/src/cmd/truss/print.h
+++ b/usr/src/cmd/truss/print.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -133,7 +133,8 @@ extern "C" {
#define RSF 91 /* print rctlsys_set flags */
#define RCF 92 /* print rctlsys_ctl flags */
#define FXF 93 /* print forkx flags */
-#define HID 94 /* hidden argument, don't print */
+#define SPF 94 /* print rctlsys_projset flags */
+#define HID 95 /* hidden argument, don't print */
/* make sure HID is always the last member */
/*
diff --git a/usr/src/cmd/truss/systable.c b/usr/src/cmd/truss/systable.c
index e9b8c6a6e5..61ff8cb7dc 100644
--- a/usr/src/cmd/truss/systable.c
+++ b/usr/src/cmd/truss/systable.c
@@ -578,6 +578,7 @@ const struct systable rctltable[] = {
{"setrctl", 6, DEC, NOV, HID, STG, HEX, HEX, HID, RSF}, /* 1 */
{"rctlsys_lst", 6, DEC, NOV, HID, HID, HEX, HID, HEX, HID}, /* 2 */
{"rctlsys_ctl", 6, DEC, NOV, HID, STG, HEX, HID, HID, RCF}, /* 3 */
+{"setprojrctl", 6, DEC, NOV, HID, STG, HID, HEX, HEX, SPF}, /* 4 */
};
#define NRCTLCODE (sizeof (rctltable) / sizeof (struct systable))
diff --git a/usr/src/lib/common/inc/c_synonyms.h b/usr/src/lib/common/inc/c_synonyms.h
index 581f55150f..d652cc06c2 100644
--- a/usr/src/lib/common/inc/c_synonyms.h
+++ b/usr/src/lib/common/inc/c_synonyms.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -800,6 +800,7 @@ extern "C" {
#define setppriv _setppriv
#define setpwent _setpwent
#define setrctl _setrctl
+#define setprojrctl _setprojrctl
#define setregid _setregid
#define setreuid _setreuid
#define setrlimit _setrlimit
diff --git a/usr/src/lib/libc/inc/synonyms.h b/usr/src/lib/libc/inc/synonyms.h
index faa9d33034..209d7f6063 100644
--- a/usr/src/lib/libc/inc/synonyms.h
+++ b/usr/src/lib/libc/inc/synonyms.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -917,6 +917,7 @@ extern "C" {
#define setpgid _setpgid
#define setpgrp _setpgrp
#define setppriv _setppriv
+#define setprojrctl _setprojrctl
#define setpwent _setpwent
#define setrctl _setrctl
#define setregid _setregid
diff --git a/usr/src/lib/libc/port/llib-lc b/usr/src/lib/libc/port/llib-lc
index 169b444f6a..cff6f24c5d 100644
--- a/usr/src/lib/libc/port/llib-lc
+++ b/usr/src/lib/libc/port/llib-lc
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1348,6 +1348,7 @@ int getrctl(const char *name, rctlblk_t *old_rblk, rctlblk_t *new_rblk,
int setrctl(const char *name, rctlblk_t *old_rblk, rctlblk_t *new_rblk,
int flags);
/* (private functions) */
+int setprojrctl(const char *name, rctlblk_t *new_rblk, size_t size, int flags);
int rctlctl(const char *, rctlblk_t *, int);
size_t rctllist(char *, size_t);
diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers
index 560ac9d878..1f3fdc9d6a 100644
--- a/usr/src/lib/libc/port/mapfile-vers
+++ b/usr/src/lib/libc/port/mapfile-vers
@@ -1989,6 +1989,8 @@ SUNWprivate_1.1 {
_setgrent;
_setlogmask;
_setpwent;
+ setprojrctl;
+ _setprojrctl;
_setregid;
_setreuid;
setsigacthandler;
diff --git a/usr/src/lib/libc/port/sys/rctlsys.c b/usr/src/lib/libc/port/sys/rctlsys.c
index e47511ac2a..9e395d3048 100644
--- a/usr/src/lib/libc/port/sys/rctlsys.c
+++ b/usr/src/lib/libc/port/sys/rctlsys.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -30,6 +29,7 @@
#pragma weak getrctl = _getrctl
#pragma weak rctllist = _rctllist
#pragma weak rctlctl = _rctlctl
+#pragma weak setprojrctl = _setprojrctl
#include "synonyms.h"
#include <sys/types.h>
@@ -71,3 +71,10 @@ rctlctl(const char *name, rctlblk_t *rblk, int flags)
{
return (syscall(SYS_rctlsys, 3, name, rblk, NULL, 0, flags));
}
+
+int
+setprojrctl(const char *name, rctlblk_t *new_rblk, size_t size, int flags)
+{
+ return (syscall(SYS_rctlsys,
+ 4, name, NULL, new_rblk, size, flags));
+}
diff --git a/usr/src/lib/libproc/common/libproc.h b/usr/src/lib/libproc/common/libproc.h
index 07e58fa05c..d12fda05e3 100644
--- a/usr/src/lib/libproc/common/libproc.h
+++ b/usr/src/lib/libproc/common/libproc.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -325,6 +325,8 @@ extern int pr_getrlimit(struct ps_prochandle *,
int, struct rlimit *);
extern int pr_setrlimit(struct ps_prochandle *,
int, const struct rlimit *);
+extern int pr_setprojrctl(struct ps_prochandle *, const char *,
+ rctlblk_t *, size_t, int);
#if defined(_LARGEFILE64_SOURCE)
extern int pr_getrlimit64(struct ps_prochandle *,
int, struct rlimit64 *);
diff --git a/usr/src/lib/libproc/common/llib-lproc b/usr/src/lib/libproc/common/llib-lproc
index 015de9ca0e..b9eff09617 100644
--- a/usr/src/lib/libproc/common/llib-lproc
+++ b/usr/src/lib/libproc/common/llib-lproc
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -23,7 +22,7 @@
/* PROTOLIB1 */
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -248,6 +247,8 @@ int pr_getrctl(struct ps_prochandle *Pr, const char *rname,
rctlblk_t *old_blk, rctlblk_t *new_blk, int rflag);
int pr_setrctl(struct ps_prochandle *Pr, const char *rname,
rctlblk_t *old_blk, rctlblk_t *new_blk, int rflag);
+int pr_setprojrctl(struct ps_prochandle *Pr, const char *rname,
+ rctlblk_t *new_blk, size_t size, int rflag);
/* pr_getrlimit.c */
int pr_getrlimit(struct ps_prochandle *Pr,
diff --git a/usr/src/lib/libproc/common/mapfile-vers b/usr/src/lib/libproc/common/mapfile-vers
index ef256570ce..758f43d99f 100644
--- a/usr/src/lib/libproc/common/mapfile-vers
+++ b/usr/src/lib/libproc/common/mapfile-vers
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -208,6 +208,7 @@ SUNWprivate_1.1 {
pr_pset_bind;
pr_rename;
pr_setitimer;
+ pr_setprojrctl;
pr_setrctl;
pr_setrlimit;
pr_setrlimit64;
diff --git a/usr/src/lib/libproc/common/pr_getrctl.c b/usr/src/lib/libproc/common/pr_getrctl.c
index d54fc228a6..9cbf7dfa0c 100644
--- a/usr/src/lib/libproc/common/pr_getrctl.c
+++ b/usr/src/lib/libproc/common/pr_getrctl.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,8 +19,8 @@
* CDDL HEADER END
*/
/*
- * Copyright (c) 2001 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -33,6 +32,7 @@
#include <errno.h>
#include <strings.h>
#include "libproc.h"
+#include <sys/rctl_impl.h>
/*
* getrctl() system call -- executed by subject process
@@ -197,3 +197,78 @@ pr_setrctl(struct ps_prochandle *Pr, const char *rname,
}
return (rval.sys_rval1);
}
+
+/*
+ * setprojrctl() system call -- executed by subject process
+ */
+int
+pr_setprojrctl(struct ps_prochandle *Pr, const char *rname,
+ rctlblk_t *new_blk, size_t size, int rflag)
+{
+ sysret_t rval;
+ argdes_t argd[6];
+ argdes_t *adp;
+ int error;
+
+ if (Pr == NULL) /* no subject process */
+ return (setprojrctl(rname, new_blk, size, rflag));
+
+ adp = &argd[0];
+ adp->arg_value = 4; /* switch for setprojrctls in rctlsys */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++;
+ adp->arg_value = 0;
+ adp->arg_object = (void *)rname;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = strlen(rname) + 1;
+
+ adp++;
+ adp->arg_value = 0; /* old_blk is not used by setprojrctls() */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+
+ adp++;
+ if (new_blk == NULL) {
+ adp->arg_value = 0;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+ } else {
+ adp->arg_value = 0;
+ adp->arg_object = new_blk;
+ adp->arg_type = AT_BYREF;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = rctlblk_size() * size;
+ }
+
+ adp++;
+ adp->arg_value = size; /* obufsz is used by setrctls() */
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ adp++;
+ adp->arg_value = rflag;
+ adp->arg_object = NULL;
+ adp->arg_type = AT_BYVAL;
+ adp->arg_inout = AI_INPUT;
+ adp->arg_size = 0;
+
+ error = Psyscall(Pr, &rval, SYS_rctlsys, 6, &argd[0]);
+
+ if (error) {
+ errno = (error > 0) ? error : ENOSYS;
+ return (-1);
+ }
+ return (rval.sys_rval1);
+}
diff --git a/usr/src/lib/libproject/common/setproject.c b/usr/src/lib/libproject/common/setproject.c
index d22878a36f..e15c719c5c 100644
--- a/usr/src/lib/libproject/common/setproject.c
+++ b/usr/src/lib/libproject/common/setproject.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -36,6 +36,7 @@
#include <signal.h>
#include <stdlib.h>
#include <string.h>
+#include <strings.h>
#include <nss_dbdefs.h>
#include <pwd.h>
#include <pool.h>
@@ -45,6 +46,7 @@
#include <zone.h>
#include <sys/pool.h>
#include <sys/pool_impl.h>
+#include <sys/rctl_impl.h>
static void
xstrtolower(char *s)
@@ -177,7 +179,7 @@ build_rctlblk(rctlblk_t *blk, int comp_num, char *component)
#define BADSPEC 5
static int
-rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr)
+rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr, int flags)
{
int error = 0;
uint_t component = 0;
@@ -185,18 +187,68 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr)
uint_t state = 0;
char *component_head;
rctlblk_t *blk;
-
- remove_spaces(val);
- if ((blk = malloc(rctlblk_size())) == NULL) {
+ rctlblk_t *ablk;
+ int project_entity = 0;
+ int count = 0;
+ char *tmp;
+ int local_action;
+
+ /* We cannot modify a zone resource control */
+ if (strncmp(ctl_name, "zone.", strlen("zone.")) == 0) {
return (SETFAILED);
}
+ remove_spaces(val);
+
/*
- * Tear down everything with this ctl name.
+ * As we are operating in a new task, both process and task
+ * rctls are referenced by this process alone. Tear down
+ * matching process and task rctls only.
+ *
+ * blk will be the RCPRIV_SYSTEM for this resource control,
+ * populated by the last pr_setrctl().
*/
- while (pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST) != -1 &&
- rctlblk_get_privilege(blk) != RCPRIV_SYSTEM) {
- (void) pr_setrctl(Pr, ctl_name, NULL, blk, RCTL_DELETE);
+ if ((strncmp(ctl_name, "process.", strlen("process.")) == 0) ||
+ (strncmp(ctl_name, "task.", strlen("task.")) == 0)) {
+
+ if ((blk = (rctlblk_t *)malloc(rctlblk_size())) == NULL) {
+ return (SETFAILED);
+ }
+
+
+ while (pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST) != -1 &&
+ rctlblk_get_privilege(blk) != RCPRIV_SYSTEM) {
+ (void) pr_setrctl(Pr, ctl_name, NULL, blk, RCTL_DELETE);
+ }
+
+ } else if (strncmp(ctl_name, "project.", strlen("project.")) == 0) {
+ project_entity = 1;
+
+ /* Determine how many attributes we'll be setting */
+ for (tmp = val; *tmp != '\0'; tmp++) {
+ if (*tmp == '(')
+ count++;
+ }
+
+ /* Allocate sufficient memory for rctl blocks */
+ if ((count == 0) || ((ablk =
+ (rctlblk_t *)malloc(rctlblk_size() * count)) == NULL)) {
+ return (SETFAILED);
+ }
+ blk = ablk;
+
+ /*
+ * In order to set the new rctl's local_action, we'll need the
+ * current value of global_flags. We obtain global_flags by
+ * performing a pr_getrctl().
+ *
+ * The ctl_name has been verified as valid, so we have no reason
+ * to suspect that pr_getrctl() will return an error.
+ */
+ (void) pr_getrctl(Pr, ctl_name, NULL, blk, RCTL_FIRST);
+
+ } else {
+ return (SETFAILED);
}
/*
@@ -205,11 +257,13 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr)
rctlblk_set_privilege(blk, RCPRIV_PRIVILEGED);
rctlblk_set_value(blk, 0);
rctlblk_set_local_flags(blk, 0);
+
if (rctlblk_get_global_flags(blk) & RCTL_GLOBAL_DENY_ALWAYS)
- rctlblk_set_local_action(blk, RCTL_LOCAL_DENY, 0);
+ local_action = RCTL_LOCAL_DENY;
else
- rctlblk_set_local_action(blk, RCTL_LOCAL_NOACTION, 0);
+ local_action = RCTL_LOCAL_NOACTION;
+ rctlblk_set_local_action(blk, local_action, 0);
for (; ; val++) {
switch (*val) {
@@ -238,22 +292,35 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr)
state &= ~INPAREN;
component = 0;
valuecount++;
- if (pr_setrctl(Pr, ctl_name, NULL, blk,
- RCTL_INSERT) == -1)
+
+ if (project_entity &&
+ (rctlblk_get_privilege(blk) ==
+ RCPRIV_BASIC)) {
error = SETFAILED;
+ } else if (project_entity) {
+ if (valuecount > count)
+ return (SETFAILED);
+
+ if (valuecount != count)
+ blk = RCTLBLK_INC(ablk,
+ valuecount);
+ } else {
+ if (pr_setrctl(Pr, ctl_name,
+ NULL, blk, RCTL_INSERT) ==
+ -1)
+ error = SETFAILED;
+ }
/* re-initialize block */
- rctlblk_set_privilege(blk,
- RCPRIV_PRIVILEGED);
- rctlblk_set_value(blk, 0);
- rctlblk_set_local_flags(blk, 0);
- if (rctlblk_get_global_flags(blk) &
- RCTL_GLOBAL_DENY_ALWAYS)
- rctlblk_set_local_action(blk,
- RCTL_LOCAL_DENY, 0);
- else
+ if (!project_entity ||
+ (valuecount != count)) {
+ rctlblk_set_privilege(blk,
+ RCPRIV_PRIVILEGED);
+ rctlblk_set_value(blk, 0);
+ rctlblk_set_local_flags(blk, 0);
rctlblk_set_local_action(blk,
- RCTL_LOCAL_NOACTION, 0);
+ local_action, 0);
+ }
} else {
error = CLOSEBEFOREOPEN;
}
@@ -288,6 +355,12 @@ rctl_set(char *ctl_name, char *val, struct ps_prochandle *Pr)
break;
}
+ if (project_entity) {
+ blk = ablk;
+ if (pr_setprojrctl(Pr, ctl_name, blk, count, flags) == -1)
+ error = SETFAILED;
+ }
+
free(blk);
if (valuecount == 0)
@@ -465,6 +538,7 @@ setproject_proc(const char *project_name, const char *user_name, int flags,
int ret = 0;
kva_t *kv_array;
struct project local_proj; /* space to store proj if not provided */
+ const char *pool_name = NULL;
if (project_name != NULL) {
/*
@@ -508,45 +582,37 @@ setproject_proc(const char *project_name, const char *user_name, int flags,
projid = getprojid();
}
+
+ if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN,
+ KV_DELIMITER)) != NULL) {
+ for (i = 0; i < kv_array->length; i++) {
+ if (strcmp(kv_array->data[i].key,
+ "project.pool") == 0) {
+ pool_name = kv_array->data[i].value;
+ }
+ if (strcmp(kv_array->data[i].key, "task.final") == 0) {
+ flags |= TASK_FINAL;
+ }
+ }
+ }
+
/*
- * Only bind to a pool if pools are configured.
+ * Bind process to a pool only if pools are configured
*/
if (pools_enabled() == 1) {
- const char *pool_name = NULL;
char *old_pool_name;
- int taskflags = flags;
/*
* Attempt to bind to pool before calling
* settaskid().
*/
- if ((kv_array = _str2kva(proj->pj_attr, KV_ASSIGN,
- KV_DELIMITER)) != NULL) {
- for (i = 0; i < kv_array->length; i++) {
- if (strcmp(kv_array->data[i].key,
- "project.pool") == 0) {
- pool_name = kv_array->data[i].value;
- break;
- }
- if (strcmp(kv_array->data[i].key,
- "task.final") == 0) {
- taskflags |= TASK_FINAL;
- }
- }
- }
-
old_pool_name = pool_get_binding(pid);
-
- /*
- * If parent is not bound to the default pool, then we want
- * to preserve same binding as parent.
- */
- if (pool_name != NULL && bind_to_pool(pool_name, pid, 0) != 0) {
+ if (bind_to_pool(pool_name, pid, 0) != 0) {
if (old_pool_name)
free(old_pool_name);
_kva_free(kv_array);
return (SETPROJ_ERR_POOL);
}
- if (pr_settaskid(Pr, projid, taskflags) == -1) {
+ if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
int saved_errno = errno;
/*
@@ -568,9 +634,10 @@ setproject_proc(const char *project_name, const char *user_name, int flags,
/*
* Pools are not configured, so simply create new task.
*/
- if (pr_settaskid(Pr, projid, flags) == -1)
+ if (pr_settaskid(Pr, projid, flags & TASK_MASK) == -1) {
+ _kva_free(kv_array);
return (SETPROJ_ERR_TASK);
- kv_array = _str2kva(proj->pj_attr, KV_ASSIGN, KV_DELIMITER);
+ }
}
if (project_name == NULL) {
@@ -612,7 +679,7 @@ setproject_proc(const char *project_name, const char *user_name, int flags,
}
ret = rctl_set(kv_array->data[i].key,
- kv_array->data[i].value, Pr);
+ kv_array->data[i].value, Pr, flags & TASK_PROJ_MASK);
if (ret && unknown == 0) {
/*
diff --git a/usr/src/uts/common/os/project.c b/usr/src/uts/common/os/project.c
index c17ba2b414..3c17a0dc38 100644
--- a/usr/src/uts/common/os/project.c
+++ b/usr/src/uts/common/os/project.c
@@ -905,8 +905,8 @@ project_init(void)
* Per project limit on contracts.
*/
rc_project_contract = rctl_register("project.max-contracts",
- RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_COUNT,
- INT_MAX, INT_MAX, &project_contract_ops);
+ RCENTITY_PROJECT, RCTL_GLOBAL_DENY_ALWAYS | RCTL_GLOBAL_NOBASIC |
+ RCTL_GLOBAL_COUNT, INT_MAX, INT_MAX, &project_contract_ops);
rctl_add_default_limit("project.max-contracts", 10000,
RCPRIV_PRIVILEGED, RCTL_LOCAL_DENY);
diff --git a/usr/src/uts/common/os/rctl.c b/usr/src/uts/common/os/rctl.c
index 026d6b13ed..3aa6e7b6cc 100644
--- a/usr/src/uts/common/os/rctl.c
+++ b/usr/src/uts/common/os/rctl.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -150,6 +150,41 @@
*
* The locking subsequence of interest is: p_lock, rctl_dict_lock,
* rctl_lists_lock, entity->rcs_lock.
+ *
+ * The projects(4) database and project entity resource controls
+ * A special case is made for RCENTITY_PROJECT values set through the
+ * setproject(3PROJECT) interface. setproject() makes use of a private
+ * interface, setprojrctl(), which passes through an array of resource control
+ * blocks that need to be set while holding the entity->rcs_lock. This
+ * ensures that the act of modifying a project's resource controls is
+ * "atomic" within the kernel.
+ *
+ * Within the rctl sub-system, we provide two interfaces that are only used by
+ * the setprojrctl() code path - rctl_local_insert_all() and
+ * rctl_local_replace_all(). rctl_local_insert_all() will ensure that the
+ * resource values specified in *new_values are applied.
+ * rctl_local_replace_all() will purge the current rctl->rc_projdb and
+ * rctl->rc_values entries, and apply the *new_values.
+ *
+ * These functions modify not only the linked list of active resource controls
+ * (rctl->rc_values), but also a "cached" linked list (rctl->rc_projdb) of
+ * values set through these interfaces. To clarify:
+ *
+ * rctl->rc_values - a linked list of rctl_val_t. These are the active
+ * resource values associated with this rctl, and may have been set by
+ * setrctl() - via prctl(1M), or by setprojrctl() - via
+ * setproject(3PROJECT).
+ *
+ * rctl->rc_projdb - a linked list of rctl_val_t. These reflect the
+ * resource values set by the setprojrctl() code path. rc_projdb is not
+ * referenced by any other component of the rctl sub-system.
+ *
+ * As various locks are held when calling these functions, we ensure that all
+ * the possible memory allocations are performed prior to calling the
+ * function. *alloc_values is a linked list of uninitialized rctl_val_t,
+ * which may be used to duplicate a new resource control value (passed in as
+ * one of the members of the *new_values linked list), in order to populate
+ * rctl->rc_values.
*/
id_t max_rctl_hndl = 32768;
@@ -1081,6 +1116,7 @@ rctl_set_init(rctl_entity_t entity, struct proc *p, rctl_entity_p_t *e,
rctl->rc_dict_entry = rde;
rctl->rc_id = rde->rcd_id;
+ rctl->rc_projdb = NULL;
rctl->rc_values = rctl_val_list_dup(rde->rcd_default_value,
ragp, NULL, p);
@@ -1688,6 +1724,259 @@ rctl_local_insert(rctl_hndl_t hndl, rctl_val_t *val, struct proc *p)
return (rctl_local_op(hndl, NULL, val, rctl_local_insert_cb, p));
}
+/*
+ * rctl_local_insert_all_cb()
+ *
+ * Overview
+ * Called for RCENTITY_PROJECT rctls only, via rctlsys_projset().
+ *
+ * Inserts new values from the project database (new_values). alloc_values
+ * should be a linked list of pre-allocated rctl_val_t, which are used to
+ * populate (rc_projdb).
+ *
+ * Should the *new_values linked list match the contents of the rctl's
+ * rp_projdb then we do nothing.
+ *
+ * Return Values
+ * 0 is always returned.
+ */
+/*ARGSUSED*/
+static int
+rctl_local_insert_all_cb(rctl_hndl_t hndl, struct proc *p, rctl_entity_p_t *e,
+ rctl_t *rctl, rctl_val_t *new_values, rctl_val_t *alloc_values)
+{
+ rctl_val_t *val;
+ rctl_val_t *tmp_val;
+ rctl_val_t *next;
+ int modified = 0;
+
+ /*
+ * If this the first time we've set this project rctl, then we delete
+ * all the privilege values. These privilege values have been set by
+ * rctl_add_default_limit().
+ *
+ * We save some cycles here by not calling rctl_val_list_delete().
+ */
+ if (rctl->rc_projdb == NULL) {
+ val = rctl->rc_values;
+
+ while (val != NULL) {
+ if (val->rcv_privilege == RCPRIV_PRIVILEGED) {
+ if (val->rcv_prev != NULL)
+ val->rcv_prev->rcv_next = val->rcv_next;
+ else
+ rctl->rc_values = val->rcv_next;
+
+ if (val->rcv_next != NULL)
+ val->rcv_next->rcv_prev = val->rcv_prev;
+
+ tmp_val = val;
+ val = val->rcv_next;
+ kmem_cache_free(rctl_val_cache, tmp_val);
+ } else {
+ val = val->rcv_next;
+ }
+ }
+ modified = 1;
+ }
+
+ /*
+ * Delete active values previously set through the project database.
+ */
+ val = rctl->rc_projdb;
+
+ while (val != NULL) {
+
+ /* Is the old value found in the new values? */
+ if (rctl_val_list_find(&new_values, val) == NULL) {
+
+ /*
+ * Delete from the active values if it originated from
+ * the project database.
+ */
+ if (((tmp_val = rctl_val_list_find(&rctl->rc_values,
+ val)) != NULL) &&
+ (tmp_val->rcv_flagaction & RCTL_LOCAL_PROJDB)) {
+ (void) rctl_val_list_delete(&rctl->rc_values,
+ tmp_val);
+ }
+
+ tmp_val = val->rcv_next;
+ (void) rctl_val_list_delete(&rctl->rc_projdb, val);
+ val = tmp_val;
+ modified = 1;
+
+ } else
+ val = val->rcv_next;
+ }
+
+ /*
+ * Insert new values from the project database.
+ */
+ while (new_values != NULL) {
+ next = new_values->rcv_next;
+
+ /*
+ * Insert this new value into the rc_projdb, and duplicate this
+ * entry to the active list.
+ */
+ if (rctl_val_list_insert(&rctl->rc_projdb, new_values) == 0) {
+
+ tmp_val = alloc_values->rcv_next;
+ bcopy(new_values, alloc_values, sizeof (rctl_val_t));
+ alloc_values->rcv_next = tmp_val;
+
+ if (rctl_val_list_insert(&rctl->rc_values,
+ alloc_values) == 0) {
+ /* inserted move alloc_values on */
+ alloc_values = tmp_val;
+ modified = 1;
+ }
+ } else {
+ /*
+ * Unlike setrctl() we don't want to return an error on
+ * a duplicate entry; we are concerned solely with
+ * ensuring that all the values specified are set.
+ */
+ kmem_cache_free(rctl_val_cache, new_values);
+ }
+ new_values = next;
+ }
+
+ /* Teardown any unused rctl_val_t */
+ while (alloc_values != NULL) {
+ tmp_val = alloc_values;
+ alloc_values = alloc_values->rcv_next;
+ kmem_cache_free(rctl_val_cache, tmp_val);
+ }
+
+ /* Reset the cursor if rctl values have been modified */
+ if (modified) {
+ rctl->rc_cursor = rctl->rc_values;
+ rctl_val_list_reset(rctl->rc_cursor);
+ RCTLOP_SET(rctl, p, e, rctl_model_value(rctl->rc_dict_entry, p,
+ rctl->rc_cursor->rcv_value));
+ }
+
+ return (0);
+}
+
+int
+rctl_local_insert_all(rctl_hndl_t hndl, rctl_val_t *new_values,
+ rctl_val_t *alloc_values, struct proc *p)
+{
+ return (rctl_local_op(hndl, new_values, alloc_values,
+ rctl_local_insert_all_cb, p));
+}
+
+/*
+ * rctl_local_replace_all_cb()
+ *
+ * Overview
+ * Called for RCENTITY_PROJECT rctls only, via rctlsys_projset().
+ *
+ * Clears the active rctl values (rc_values), and stored values from the
+ * previous insertions from the project database (rc_projdb).
+ *
+ * Inserts new values from the project database (new_values). alloc_values
+ * should be a linked list of pre-allocated rctl_val_t, which are used to
+ * populate (rc_projdb).
+ *
+ * Return Values
+ * 0 is always returned.
+ */
+/*ARGSUSED*/
+static int
+rctl_local_replace_all_cb(rctl_hndl_t hndl, struct proc *p, rctl_entity_p_t *e,
+ rctl_t *rctl, rctl_val_t *new_values, rctl_val_t *alloc_values)
+{
+ rctl_val_t *val;
+ rctl_val_t *next;
+ rctl_val_t *tmp_val;
+
+ /* Delete all the privilege vaules */
+ val = rctl->rc_values;
+
+ while (val != NULL) {
+ if (val->rcv_privilege == RCPRIV_PRIVILEGED) {
+ if (val->rcv_prev != NULL)
+ val->rcv_prev->rcv_next = val->rcv_next;
+ else
+ rctl->rc_values = val->rcv_next;
+
+ if (val->rcv_next != NULL)
+ val->rcv_next->rcv_prev = val->rcv_prev;
+
+ tmp_val = val;
+ val = val->rcv_next;
+ kmem_cache_free(rctl_val_cache, tmp_val);
+ } else {
+ val = val->rcv_next;
+ }
+ }
+
+ /* Delete the contents of rc_projdb */
+ val = rctl->rc_projdb;
+ while (val != NULL) {
+
+ tmp_val = val;
+ val = val->rcv_next;
+ kmem_cache_free(rctl_val_cache, tmp_val);
+ }
+ rctl->rc_projdb = NULL;
+
+ /*
+ * Insert new values from the project database.
+ */
+ while (new_values != NULL) {
+ next = new_values->rcv_next;
+
+ if (rctl_val_list_insert(&rctl->rc_projdb, new_values) == 0) {
+ tmp_val = alloc_values->rcv_next;
+ bcopy(new_values, alloc_values, sizeof (rctl_val_t));
+ alloc_values->rcv_next = tmp_val;
+
+ if (rctl_val_list_insert(&rctl->rc_values,
+ alloc_values) == 0) {
+ /* inserted, so move alloc_values on */
+ alloc_values = tmp_val;
+ }
+ } else {
+ /*
+ * Unlike setrctl() we don't want to return an error on
+ * a duplicate entry; we are concerned solely with
+ * ensuring that all the values specified are set.
+ */
+ kmem_cache_free(rctl_val_cache, new_values);
+ }
+
+ new_values = next;
+ }
+
+ /* Teardown any unused rctl_val_t */
+ while (alloc_values != NULL) {
+ tmp_val = alloc_values;
+ alloc_values = alloc_values->rcv_next;
+ kmem_cache_free(rctl_val_cache, tmp_val);
+ }
+
+ /* Always reset the cursor */
+ rctl->rc_cursor = rctl->rc_values;
+ rctl_val_list_reset(rctl->rc_cursor);
+ RCTLOP_SET(rctl, p, e, rctl_model_value(rctl->rc_dict_entry, p,
+ rctl->rc_cursor->rcv_value));
+
+ return (0);
+}
+
+int
+rctl_local_replace_all(rctl_hndl_t hndl, rctl_val_t *new_values,
+ rctl_val_t *alloc_values, struct proc *p)
+{
+ return (rctl_local_op(hndl, new_values, alloc_values,
+ rctl_local_replace_all_cb, p));
+}
+
static int
rctl_local_replace_cb(rctl_hndl_t hndl, struct proc *p, rctl_entity_p_t *e,
rctl_t *rctl, rctl_val_t *oval, rctl_val_t *nval)
diff --git a/usr/src/uts/common/sys/rctl.h b/usr/src/uts/common/sys/rctl.h
index a8480c2768..2061398fba 100644
--- a/usr/src/uts/common/sys/rctl.h
+++ b/usr/src/uts/common/sys/rctl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -44,9 +44,10 @@ extern "C" {
#define RCTL_LOCAL_DENY 0x00000002
#define RCTL_LOCAL_MAXIMAL 0x80000000
+#define RCTL_LOCAL_PROJDB 0x40000000
#define RCTL_LOCAL_ACTION_MASK 0xffff0000
-#define RCTL_LOCAL_MASK 0x80000003
+#define RCTL_LOCAL_MASK 0xc0000003
/*
* Available global actions and flags.
@@ -216,6 +217,7 @@ typedef struct rctl {
rctl_val_t *rc_cursor; /* currently enforced value */
struct rctl_dict_entry *rc_dict_entry; /* global control properties */
rctl_hndl_t rc_id; /* control handle (hash key) */
+ rctl_val_t *rc_projdb; /* project database rctls */
} rctl_t;
/*
@@ -309,6 +311,10 @@ int rctl_global_set(const char *name, rctl_dict_entry_t *);
int rctl_local_delete(rctl_hndl_t, rctl_val_t *, struct proc *p);
int rctl_local_insert(rctl_hndl_t, rctl_val_t *, struct proc *p);
+int rctl_local_insert_all(rctl_hndl_t, rctl_val_t *, rctl_val_t *,
+ struct proc *p);
+int rctl_local_replace_all(rctl_hndl_t, rctl_val_t *, rctl_val_t *,
+ struct proc *p);
int rctl_local_get(rctl_hndl_t, rctl_val_t *, rctl_val_t *, struct proc *p);
int rctl_local_replace(rctl_hndl_t, rctl_val_t *, rctl_val_t *,
struct proc *p);
diff --git a/usr/src/uts/common/sys/rctl_impl.h b/usr/src/uts/common/sys/rctl_impl.h
index c3d7d118ce..c37f9879e7 100644
--- a/usr/src/uts/common/sys/rctl_impl.h
+++ b/usr/src/uts/common/sys/rctl_impl.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -44,6 +43,7 @@ extern "C" {
extern int rctlctl(const char *, rctlblk_t *, int);
extern size_t rctllist(char *, size_t);
+extern int setprojrctl(const char *, rctlblk_t *, size_t, int);
#endif /* _KERNEL */
@@ -62,6 +62,10 @@ typedef struct rctl_opaque {
extern uint_t rlim_fd_cur;
extern uint_t rlim_fd_max;
+/* Given an array of rctlblk_t calculate the address of the n'th element */
+#define RCTLBLK_INC(blk, n) (rctlblk_t *)(((char *)blk) \
+ + (n * rctlblk_size()))
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/sys/task.h b/usr/src/uts/common/sys/task.h
index f009b5e5a7..87cc94cbd0 100644
--- a/usr/src/uts/common/sys/task.h
+++ b/usr/src/uts/common/sys/task.h
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -39,6 +38,10 @@ extern "C" {
#define TASK_NORMAL 0x0 /* task may create tasks via settaskid() */
#define TASK_FINAL 0x1 /* task finalized, settaskid() will fail */
+#define TASK_MASK 0x1 /* task flags mask */
+
+#define TASK_PROJ_PURGE 0x100000 /* purge project.* rctl entities */
+#define TASK_PROJ_MASK 0x100000
#ifdef _KERNEL
diff --git a/usr/src/uts/common/syscall/rctlsys.c b/usr/src/uts/common/syscall/rctlsys.c
index 03617b5d44..b82f4b0566 100644
--- a/usr/src/uts/common/syscall/rctlsys.c
+++ b/usr/src/uts/common/syscall/rctlsys.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -843,6 +842,155 @@ rctlsys_ctl(char *name, rctl_opaque_t *rblk, int flags)
return (0);
}
+/*
+ * The arbitrary maximum number of rctl_opaque_t that we can pass to
+ * rctl_projset().
+ */
+#define RCTL_PROJSET_MAXSIZE 1024
+
+static long
+rctlsys_projset(char *name, rctl_opaque_t *rblk, size_t size, int flags)
+{
+ rctl_dict_entry_t *krde;
+ rctl_opaque_t *krblk;
+ char *kname;
+ size_t klen;
+ rctl_hndl_t hndl;
+ rctl_val_t *new_values = NULL;
+ rctl_val_t *alloc_values = NULL;
+ rctl_val_t *new_val;
+ rctl_val_t *alloc_val;
+ int error = 0;
+ int count;
+
+ kname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+
+ if (name == NULL || copyinstr(name, kname, MAXPATHLEN, &klen) != 0) {
+ kmem_free(kname, MAXPATHLEN);
+ return (set_errno(EFAULT));
+ }
+
+ if (secpolicy_rctlsys(CRED(), B_TRUE) != 0) {
+ kmem_free(kname, MAXPATHLEN);
+ return (set_errno(EPERM));
+ }
+
+ if (size > RCTL_PROJSET_MAXSIZE) {
+ kmem_free(kname, MAXPATHLEN);
+ return (set_errno(EINVAL));
+ }
+
+ if ((hndl = rctl_hndl_lookup(kname)) == -1) {
+ kmem_free(kname, MAXPATHLEN);
+ return (set_errno(EINVAL));
+ }
+
+ krde = rctl_dict_lookup_hndl(hndl);
+
+ /* If not a project entity then exit */
+ if ((krde->rcd_entity != RCENTITY_PROJECT) || (size <= 0)) {
+ kmem_free(kname, MAXPATHLEN);
+ return (set_errno(EINVAL));
+ }
+
+ /* Allocate an array large enough for all resource control blocks */
+ krblk = kmem_zalloc(sizeof (rctl_opaque_t) * size, KM_SLEEP);
+
+ if (copyin(rblk, krblk, sizeof (rctl_opaque_t) * size) == 0) {
+
+ for (count = 0; (count < size) && (error == 0); count++) {
+ new_val = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
+ alloc_val = kmem_cache_alloc(rctl_val_cache, KM_SLEEP);
+
+ rctlsys_rblk_xfrm(&krblk[count], NULL, new_val,
+ RBX_FROM_BLK | RBX_VAL);
+
+ /*
+ * Project entity resource control values should always
+ * be privileged
+ */
+ if (new_val->rcv_privilege != RCPRIV_PRIVILEGED) {
+ kmem_cache_free(rctl_val_cache, new_val);
+ kmem_cache_free(rctl_val_cache, alloc_val);
+
+ error = EPERM;
+ } else if (rctl_invalid_value(krde, new_val) == 0) {
+
+ /*
+ * This is a project entity; we do not set
+ * rcv_action_recipient or rcv_action_recip_pid
+ */
+ new_val->rcv_action_recipient = NULL;
+ new_val->rcv_action_recip_pid = -1;
+ new_val->rcv_flagaction |= RCTL_LOCAL_PROJDB;
+ new_val->rcv_firing_time = 0;
+
+ new_val->rcv_prev = NULL;
+ new_val->rcv_next = new_values;
+ new_values = new_val;
+
+ /*
+ * alloc_val is left largely uninitialized, it
+ * is a pre-allocated rctl_val_t which is used
+ * later in rctl_local_replace_all() /
+ * rctl_local_insert_all().
+ */
+ alloc_val->rcv_prev = NULL;
+ alloc_val->rcv_next = alloc_values;
+ alloc_values = alloc_val;
+ } else {
+ kmem_cache_free(rctl_val_cache, new_val);
+ kmem_cache_free(rctl_val_cache, alloc_val);
+
+ error = EINVAL;
+ }
+ }
+
+ kmem_free(krblk, sizeof (rctl_opaque_t) * size);
+ } else {
+ error = EFAULT;
+ }
+
+ kmem_free(kname, MAXPATHLEN);
+
+ if (error) {
+ /*
+ * We will have the same number of items in the alloc_values
+ * linked list, as we have in new_values. However, we remain
+ * cautious, and teardown the linked lists individually.
+ */
+ while (new_values != NULL) {
+ new_val = new_values;
+ new_values = new_values->rcv_next;
+ kmem_cache_free(rctl_val_cache, new_val);
+ }
+
+ while (alloc_values != NULL) {
+ alloc_val = alloc_values;
+ alloc_values = alloc_values->rcv_next;
+ kmem_cache_free(rctl_val_cache, alloc_val);
+ }
+
+ return (set_errno(error));
+ }
+
+ /*
+ * We take the p_lock here to maintain consistency with other functions
+ * - rctlsys_get() and rctlsys_set()
+ */
+ mutex_enter(&curproc->p_lock);
+ if (flags & TASK_PROJ_PURGE) {
+ (void) rctl_local_replace_all(hndl, new_values, alloc_values,
+ curproc);
+ } else {
+ (void) rctl_local_insert_all(hndl, new_values, alloc_values,
+ curproc);
+ }
+ mutex_exit(&curproc->p_lock);
+
+ return (0);
+}
+
long
rctlsys(int code, char *name, void *obuf, void *nbuf, size_t obufsz, int flags)
{
@@ -864,6 +1012,11 @@ rctlsys(int code, char *name, void *obuf, void *nbuf, size_t obufsz, int flags)
* Private code for rctladm(1M): "rctlctl".
*/
return (rctlsys_ctl(name, obuf, flags));
+ case 4:
+ /*
+ * Private code for setproject(3PROJECT).
+ */
+ return (rctlsys_projset(name, nbuf, obufsz, flags));
default:
return (set_errno(EINVAL));