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