1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <procfs.h>
30*0Sstevel@tonic-gate #include <project.h>
31*0Sstevel@tonic-gate #include <stdlib.h>
32*0Sstevel@tonic-gate #include <strings.h>
33*0Sstevel@tonic-gate #include "rcapd.h"
34*0Sstevel@tonic-gate #include "utils.h"
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate 				/* absolute cap name */
37*0Sstevel@tonic-gate #define	PJ_ABS_ATTR_NAME	"rcap.max-rss"
38*0Sstevel@tonic-gate 				/* round up to next y = 2^n */
39*0Sstevel@tonic-gate #define	ROUNDUP(x, y)		(((x) + ((y) - 1)) & ~((y) - 1))
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate static rcid_t rc_proj_getidbypsinfo(psinfo_t *);
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate void
44*0Sstevel@tonic-gate lcollection_set_type_project(void)
45*0Sstevel@tonic-gate {
46*0Sstevel@tonic-gate 	rc_getidbypsinfo = rc_proj_getidbypsinfo;
47*0Sstevel@tonic-gate }
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate static int
50*0Sstevel@tonic-gate lcollection_update_project_cb(const struct project *proj, void *walk_data)
51*0Sstevel@tonic-gate {
52*0Sstevel@tonic-gate 	void(*update_notification_cb)(char *, int, uint64_t, int) =
53*0Sstevel@tonic-gate 	    (void(*)(char *, int, uint64_t, int))walk_data;
54*0Sstevel@tonic-gate 	char *capattr_abs;
55*0Sstevel@tonic-gate 	char *end;
56*0Sstevel@tonic-gate 	int changes;
57*0Sstevel@tonic-gate 	int64_t max_rss;
58*0Sstevel@tonic-gate 	lcollection_t *lcol;
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate 	capattr_abs = strstr(proj->pj_attr, PJ_ABS_ATTR_NAME "=");
61*0Sstevel@tonic-gate 	if (capattr_abs != NULL) {
62*0Sstevel@tonic-gate 		if (capattr_abs > proj->pj_attr)
63*0Sstevel@tonic-gate 			if (*(capattr_abs - 1) != ';') {
64*0Sstevel@tonic-gate 				/*
65*0Sstevel@tonic-gate 				 * PJ_ABS_ATTR_NAME only matched part
66*0Sstevel@tonic-gate 				 * of an attribute.
67*0Sstevel@tonic-gate 				 */
68*0Sstevel@tonic-gate 				return (0);
69*0Sstevel@tonic-gate 			}
70*0Sstevel@tonic-gate 		capattr_abs += strlen(PJ_ABS_ATTR_NAME "=");
71*0Sstevel@tonic-gate 		max_rss = ROUNDUP(strtoll(capattr_abs, &end, 10), 1024) / 1024;
72*0Sstevel@tonic-gate 		if (end == capattr_abs || *end != ';' && *end != 0)
73*0Sstevel@tonic-gate 			warn(gettext("%s %s: malformed %s value "
74*0Sstevel@tonic-gate 			    "'%s'\n"), rcfg.rcfg_mode_name, proj->pj_name,
75*0Sstevel@tonic-gate 			    PJ_ABS_ATTR_NAME, capattr_abs);
76*0Sstevel@tonic-gate 	} else
77*0Sstevel@tonic-gate 		max_rss = 0;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	lcol = lcollection_insert_update(proj->pj_projid, max_rss,
80*0Sstevel@tonic-gate 	    proj->pj_name, &changes);
81*0Sstevel@tonic-gate 	if (update_notification_cb != NULL)
82*0Sstevel@tonic-gate 		update_notification_cb(proj->pj_name, changes, max_rss, (lcol !=
83*0Sstevel@tonic-gate 		    NULL) ? lcol->lcol_mark : 0);
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	return (0);
86*0Sstevel@tonic-gate }
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate static int
89*0Sstevel@tonic-gate lcollection_update_project_byid_cb(const projid_t id, void *walk_data)
90*0Sstevel@tonic-gate {
91*0Sstevel@tonic-gate 	char buf[PROJECT_BUFSZ];
92*0Sstevel@tonic-gate 	struct project proj;
93*0Sstevel@tonic-gate 
94*0Sstevel@tonic-gate 	if (getprojbyid(id, &proj, buf, sizeof (buf)) != NULL && proj.pj_attr !=
95*0Sstevel@tonic-gate 	    NULL)
96*0Sstevel@tonic-gate 		return (lcollection_update_project_cb(&proj, walk_data));
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	return (0);
99*0Sstevel@tonic-gate }
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate static int
102*0Sstevel@tonic-gate lcollection_update_onceactive_cb(lcollection_t *lcol, void *walk_data)
103*0Sstevel@tonic-gate {
104*0Sstevel@tonic-gate 	void(*update_notification_cb)(char *, int, uint64_t, int) =
105*0Sstevel@tonic-gate 	    (void(*)(char *, int, uint64_t, int))walk_data;
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	return (lcollection_update_project_byid_cb(lcol->lcol_id,
108*0Sstevel@tonic-gate 	    (void *)update_notification_cb));
109*0Sstevel@tonic-gate }
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate static int
112*0Sstevel@tonic-gate project_walk_all(int(*cb)(const struct project *, void *), void *walk_data)
113*0Sstevel@tonic-gate {
114*0Sstevel@tonic-gate 	char buf[PROJECT_BUFSZ];
115*0Sstevel@tonic-gate 	struct project proj;
116*0Sstevel@tonic-gate 	int res = 0;
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 	setprojent();
119*0Sstevel@tonic-gate 	while (getprojent(&proj, buf, sizeof (buf)) != NULL && res == 0)
120*0Sstevel@tonic-gate 		res = cb(&proj, walk_data);
121*0Sstevel@tonic-gate 	endprojent();
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	return (res);
124*0Sstevel@tonic-gate }
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate void
127*0Sstevel@tonic-gate lcollection_update_project(lcollection_update_type_t ut,
128*0Sstevel@tonic-gate     void(*update_notification_cb)(char *, int, uint64_t, int))
129*0Sstevel@tonic-gate {
130*0Sstevel@tonic-gate 	switch (ut) {
131*0Sstevel@tonic-gate 	case LCU_ACTIVE_ONLY:
132*0Sstevel@tonic-gate 		/*
133*0Sstevel@tonic-gate 		 * Enumerate active projects.  This is much faster than
134*0Sstevel@tonic-gate 		 * enumerating all projects (as is done below, in the default
135*0Sstevel@tonic-gate 		 * case), and is done to efficiently and incrementally update
136*0Sstevel@tonic-gate 		 * lcollection with capped projects.  The default case performs
137*0Sstevel@tonic-gate 		 * the initialization.
138*0Sstevel@tonic-gate 		 */
139*0Sstevel@tonic-gate 		(void) project_walk(lcollection_update_project_byid_cb,
140*0Sstevel@tonic-gate 		    (void *)update_notification_cb);
141*0Sstevel@tonic-gate 		/*
142*0Sstevel@tonic-gate 		 * Enumerate once-active projects, including the active
143*0Sstevel@tonic-gate 		 * projects just enumerated, meaning active projects will be
144*0Sstevel@tonic-gate 		 * updated and marked twice.
145*0Sstevel@tonic-gate 		 */
146*0Sstevel@tonic-gate 		list_walk_collection(lcollection_update_onceactive_cb,
147*0Sstevel@tonic-gate 		    (void *)update_notification_cb);
148*0Sstevel@tonic-gate 		break;
149*0Sstevel@tonic-gate 	default:
150*0Sstevel@tonic-gate 		/*
151*0Sstevel@tonic-gate 		 * Enumerate all projects.
152*0Sstevel@tonic-gate 		 */
153*0Sstevel@tonic-gate 		(void) project_walk_all(lcollection_update_project_cb,
154*0Sstevel@tonic-gate 		    (void *)update_notification_cb);
155*0Sstevel@tonic-gate 	}
156*0Sstevel@tonic-gate }
157*0Sstevel@tonic-gate 
158*0Sstevel@tonic-gate static rcid_t
159*0Sstevel@tonic-gate rc_proj_getidbypsinfo(psinfo_t *psinfo)
160*0Sstevel@tonic-gate {
161*0Sstevel@tonic-gate 	return (psinfo->pr_projid);
162*0Sstevel@tonic-gate }
163