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