diff options
Diffstat (limited to 'usr/src')
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)); |