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 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <strings.h> 31 #include "rcapd.h" 32 #include "utils.h" 33 34 /* 35 * An abstract "collection" of processes. Multiple types of collections can 36 * exist, one of which is selected at run-time. Currently, the only one 37 * defined corresponds to project(4)s. 38 */ 39 40 #define MAX(x, y) (((x) > (y)) ? (x) : (y)) 41 42 typedef struct { 43 rcid_t *lfa_colidp; 44 lcollection_t *lfa_found; 45 } lcollection_find_arg_t; 46 47 extern void lcollection_update_project(lcollection_update_type_t, 48 void(*)(char *, char *, int, uint64_t, int)); 49 extern void lcollection_update_zone(lcollection_update_type_t, 50 void(*)(char *, char *, int, uint64_t, int)); 51 static void lcollection_update_notification_cb(char *, char *, int, uint64_t, 52 int); 53 54 rcid_t(*rc_getidbypsinfo)(psinfo_t *); 55 uint64_t phys_total = 0; 56 static lcollection_t *lcollection_head = NULL; 57 58 void 59 lcollection_update(lcollection_update_type_t ut) 60 { 61 lcollection_update_zone(ut, lcollection_update_notification_cb); 62 lcollection_update_project(ut, lcollection_update_notification_cb); 63 } 64 65 /* 66 * Inserts a collection with the supplied identity, or updates the caps of an 67 * existing one. The return value will have these bits set, depending on the 68 * previous and new cap values. If no cap was displaced, and the requested cap 69 * is 0, no collection will be added, and the applicable *ZERO flags will be 70 * set. 71 * 72 * LCST_CAP_CHANGED 73 * LCST_CAP_REMOVED 74 * LCSS_CAP_ZERO 75 */ 76 lcollection_t * 77 lcollection_insert_update(rcid_t *colidp, uint64_t rss_cap, char *name, 78 int *changes) 79 { 80 lcollection_t *lcol; 81 82 *changes = 0; 83 84 if (rss_cap == 0) 85 *changes |= LCST_CAP_ZERO; 86 87 lcol = lcollection_find(colidp); 88 89 /* 90 * If the specified collection is capped, add it to lcollection. 91 */ 92 if (lcol == NULL) { 93 /* 94 * If the cap has been zeroed and the collection doesn't exist, 95 * don't create the collection just to remvoe the cap later. 96 */ 97 if (rss_cap == 0) 98 return (NULL); 99 100 *changes |= LCST_CAP_CHANGED; 101 lcol = malloc(sizeof (*lcol)); 102 if (lcol == NULL) { 103 debug("not enough memory to monitor %s %s", 104 (colidp->rcid_type == RCIDT_PROJECT ? 105 "project" : "zone"), name); 106 return (NULL); 107 } 108 (void) bzero(lcol, sizeof (*lcol)); 109 110 lcol->lcol_id = *colidp; 111 debug("added collection %s\n", name); 112 lcol->lcol_prev = NULL; 113 lcol->lcol_next = lcollection_head; 114 lcol->lcol_stat.lcols_min_rss = (uint64_t)-1; 115 if (lcollection_head != NULL) 116 lcollection_head->lcol_prev = lcol; 117 lcollection_head = lcol; 118 } 119 120 /* 121 * Set/update the collection's name. 122 */ 123 (void) strlcpy(lcol->lcol_name, name, sizeof (lcol->lcol_name)); 124 125 /* 126 * Set cap flags. 127 */ 128 if (rss_cap != lcol->lcol_rss_cap) { 129 *changes |= LCST_CAP_CHANGED; 130 lcol->lcol_rss_cap = rss_cap; 131 if (lcol->lcol_rss_cap == 0) 132 *changes |= LCST_CAP_REMOVED; 133 } 134 135 if (rss_cap > 0) 136 lcol->lcol_mark++; 137 138 return (lcol); 139 } 140 141 static void 142 lcollection_update_notification_cb(char *col_type, char *name, int changes, 143 uint64_t rss_cap, int mark) 144 { 145 /* 146 * Assume the collection has been updated redundantly if its mark count 147 * exceeds 1, and that another notification is unnecessary. 148 */ 149 if (mark > 1) 150 return; 151 152 if (changes & LCST_CAP_ZERO) 153 debug("%s %s: %s\n", col_type, name, 154 (changes & LCST_CAP_REMOVED) ? "cap removed" : "uncapped"); 155 else 156 debug("%s %s: cap: %llukB\n", col_type, name, 157 (unsigned long long)rss_cap); 158 } 159 160 /* 161 * Function to walk list of collections and invoke the specified callback with 162 * the specified argument. Callbacks are allowed to change the linkage of the 163 * collection on which they act. 164 */ 165 void 166 list_walk_collection(int (*cb)(lcollection_t *, void *), void *arg) 167 { 168 lcollection_t *lcol; 169 lcollection_t *next; 170 171 lcol = lcollection_head; 172 while (lcol != NULL) { 173 next = lcol->lcol_next; 174 if (cb(lcol, arg) != 0) 175 return; 176 lcol = next; 177 } 178 } 179 180 /* 181 * Returns a nonzero value if an lprocess_t is still a valid member of a given 182 * collection. 183 */ 184 int 185 lcollection_member(lcollection_t *lcol, lprocess_t *lpc) 186 { 187 lprocess_t *cur = lcol->lcol_lprocess; 188 189 while (cur != NULL) 190 if (cur == lpc) 191 return (1); 192 else 193 cur = cur->lpc_next; 194 return (0); 195 } 196 197 static int 198 lcollection_find_cb(lcollection_t *lcol, void *arg) 199 { 200 rcid_t *colidp = ((lcollection_find_arg_t *)arg)->lfa_colidp; 201 202 if (lcol->lcol_id.rcid_type == colidp->rcid_type && 203 lcol->lcol_id.rcid_val == colidp->rcid_val) { 204 ((lcollection_find_arg_t *)arg)->lfa_found = lcol; 205 return (1); 206 } 207 208 return (0); 209 } 210 211 lcollection_t * 212 lcollection_find(rcid_t *colidp) 213 { 214 lcollection_find_arg_t lfa; 215 216 lfa.lfa_colidp = colidp; 217 lfa.lfa_found = NULL; 218 list_walk_collection(lcollection_find_cb, &lfa); 219 220 return (lfa.lfa_found); 221 } 222 223 /* 224 * Unlinks a collection from lcollection. 225 */ 226 void 227 lcollection_free(lcollection_t *lcol) 228 { 229 lprocess_t *lpc; 230 lprocess_t *next; 231 232 lpc = lcol->lcol_lprocess; 233 while (lpc != NULL) { 234 next = lpc->lpc_next; 235 if (lpc->lpc_collection == lcol) 236 lprocess_free(lpc); 237 lpc = next; 238 } 239 240 /* 241 * Unlink the collection. 242 */ 243 if (lcol->lcol_prev != NULL) 244 lcol->lcol_prev->lcol_next = lcol->lcol_next; 245 if (lcol->lcol_next != NULL) 246 lcol->lcol_next->lcol_prev = lcol->lcol_prev; 247 if (lcollection_head == lcol) 248 lcollection_head = lcol->lcol_next; 249 lcol->lcol_next = lcol->lcol_prev = NULL; 250 251 free(lcol); 252 } 253