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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "statcommon.h" 30 31 #include <string.h> 32 #include <errno.h> 33 34 /* max size of report change annotations */ 35 #define LIST_SIZE 512 36 37 static char cpus_added[LIST_SIZE]; 38 static char cpus_removed[LIST_SIZE]; 39 40 static int 41 cpu_walk(struct snapshot *old, struct snapshot *new, 42 snapshot_cb cb, void *data) 43 { 44 int changed = 0; 45 int i; 46 47 /* CPUs can change state but not re-order */ 48 for (i = 0; i < new->s_nr_cpus; i++) { 49 struct cpu_snapshot *cpu = NULL; 50 struct cpu_snapshot *newcpu = &new->s_cpus[i]; 51 if (old) 52 cpu = &old->s_cpus[i]; 53 cb(cpu, newcpu, data); 54 if (cpu == NULL) 55 changed = 1; 56 else { 57 /* 58 * We only care about off/on line transitions 59 */ 60 if ((CPU_ACTIVE(cpu) && !CPU_ACTIVE(newcpu)) || 61 (!CPU_ACTIVE(cpu) && CPU_ACTIVE(newcpu))) 62 changed = 1; 63 if ((new->s_types & SNAP_PSETS) && 64 cpu->cs_pset_id != newcpu->cs_pset_id) 65 changed = 1; 66 } 67 68 } 69 70 return (changed); 71 } 72 73 static int 74 pset_walk(struct snapshot *old, struct snapshot *new, 75 snapshot_cb cb, void *data) 76 { 77 int i = 0; 78 int j = 0; 79 int changed = 0; 80 81 while (old && i < old->s_nr_psets && j < new->s_nr_psets) { 82 if (old->s_psets[i].ps_id < new->s_psets[j].ps_id) { 83 cb(&old->s_psets[i], NULL, data); 84 i++; 85 changed = 1; 86 } else if (old->s_psets[i].ps_id > new->s_psets[j].ps_id) { 87 cb(NULL, &new->s_psets[j], data); 88 j++; 89 changed = 1; 90 } else { 91 cb(&old->s_psets[i], &new->s_psets[j], data); 92 i++; 93 j++; 94 } 95 } 96 97 while (old && i < old->s_nr_psets) { 98 cb(&old->s_psets[i], NULL, data); 99 i++; 100 changed = 1; 101 } 102 103 while (j < new->s_nr_psets) { 104 cb(NULL, &new->s_psets[j], data); 105 j++; 106 changed = 1; 107 } 108 109 return (changed); 110 } 111 112 static int 113 iodev_walk(struct iodev_snapshot *d1, struct iodev_snapshot *d2, 114 snapshot_cb cb, void *data) 115 { 116 int changed = 0; 117 118 while (d1 && d2) { 119 if (strcmp(d1->is_name, d2->is_name) < 0) { 120 changed = 1; 121 cb(d1, NULL, data); 122 (void) iodev_walk(d1->is_children, NULL, cb, data); 123 d1 = d1->is_next; 124 } else if (strcmp(d1->is_name, d2->is_name) > 0) { 125 changed = 1; 126 cb(NULL, d2, data); 127 (void) iodev_walk(NULL, d2->is_children, cb, data); 128 d2 = d2->is_next; 129 } else { 130 cb(d1, d2, data); 131 changed |= iodev_walk(d1->is_children, 132 d2->is_children, cb, data); 133 d1 = d1->is_next; 134 d2 = d2->is_next; 135 } 136 } 137 138 while (d1) { 139 changed = 1; 140 cb(d1, NULL, data); 141 (void) iodev_walk(d1->is_children, NULL, cb, data); 142 d1 = d1->is_next; 143 } 144 145 while (d2) { 146 changed = 1; 147 cb(NULL, d2, data); 148 (void) iodev_walk(NULL, d2->is_children, cb, data); 149 d2 = d2->is_next; 150 } 151 152 return (changed); 153 } 154 155 int 156 snapshot_walk(enum snapshot_types type, struct snapshot *old, 157 struct snapshot *new, snapshot_cb cb, void *data) 158 { 159 int changed = 0; 160 161 switch (type) { 162 case SNAP_CPUS: 163 changed = cpu_walk(old, new, cb, data); 164 break; 165 166 case SNAP_PSETS: 167 changed = pset_walk(old, new, cb, data); 168 break; 169 170 case SNAP_CONTROLLERS: 171 case SNAP_IODEVS: 172 case SNAP_IOPATHS: 173 changed = iodev_walk(old ? old->s_iodevs : NULL, 174 new->s_iodevs, cb, data); 175 break; 176 177 default: 178 break; 179 } 180 181 return (changed); 182 } 183 184 static void 185 add_nr_to_list(char *buf, unsigned long nr) 186 { 187 char tmp[LIST_SIZE]; 188 189 (void) snprintf(tmp, LIST_SIZE, "%lu", nr); 190 191 if (strlen(buf)) 192 (void) strlcat(buf, ", ", LIST_SIZE); 193 194 (void) strlcat(buf, tmp, LIST_SIZE); 195 } 196 197 static void 198 cpu_report(void *v1, void *v2, void *data) 199 { 200 int *pset = (int *)data; 201 struct cpu_snapshot *c1 = (struct cpu_snapshot *)v1; 202 struct cpu_snapshot *c2 = (struct cpu_snapshot *)v2; 203 204 if (*pset && c1->cs_pset_id != c2->cs_pset_id) { 205 (void) printf("<<processor %d moved from pset: %d to: %d>>\n", 206 c1->cs_id, c1->cs_pset_id, c2->cs_pset_id); 207 } 208 209 if (c1->cs_state == c2->cs_state) 210 return; 211 212 if (CPU_ONLINE(c1->cs_state) && !CPU_ONLINE(c2->cs_state)) 213 add_nr_to_list(cpus_removed, c1->cs_id); 214 215 if (!CPU_ONLINE(c1->cs_state) && CPU_ONLINE(c2->cs_state)) 216 add_nr_to_list(cpus_added, c2->cs_id); 217 } 218 219 /*ARGSUSED*/ 220 static void 221 pset_report(void *v1, void *v2, void *data) 222 { 223 struct pset_snapshot *p1 = (struct pset_snapshot *)v1; 224 struct pset_snapshot *p2 = (struct pset_snapshot *)v2; 225 226 if (p2 == NULL) { 227 (void) printf("<<pset destroyed: %u>>\n", p1->ps_id); 228 return; 229 } 230 231 if (p1 == NULL) 232 (void) printf("<<pset created: %u>>\n", p2->ps_id); 233 } 234 235 static void 236 get_child_list(struct iodev_snapshot *iodev, char *buf) 237 { 238 char tmp[LIST_SIZE]; 239 struct iodev_snapshot *pos = iodev->is_children; 240 241 while (pos) { 242 if (pos->is_type == IODEV_PARTITION) { 243 add_nr_to_list(buf, pos->is_id.id); 244 } else if (pos->is_type == IODEV_DISK) { 245 if (strlen(buf)) 246 (void) strlcat(buf, ", ", LIST_SIZE); 247 (void) strlcat(buf, "t", LIST_SIZE); 248 (void) strlcat(buf, pos->is_id.tid, LIST_SIZE); 249 (void) strlcat(buf, "d", LIST_SIZE); 250 *tmp = '\0'; 251 add_nr_to_list(tmp, pos->is_id.id); 252 (void) strlcat(buf, tmp, LIST_SIZE); 253 } 254 pos = pos->is_next; 255 } 256 } 257 258 static void 259 iodev_changed(struct iodev_snapshot *iodev, int added) 260 { 261 char tmp[LIST_SIZE]; 262 int is_disk = iodev->is_type == IODEV_DISK; 263 char *name = iodev->is_name; 264 265 if (iodev->is_pretty) 266 name = iodev->is_pretty; 267 268 switch (iodev->is_type) { 269 case IODEV_IOPATH: 270 (void) printf("<<multi-path %s: %s>>\n", 271 added ? "added" : "removed", name); 272 break; 273 case IODEV_PARTITION: 274 (void) printf("<<partition %s: %s>>\n", 275 added ? "added" : "removed", name); 276 break; 277 case IODEV_NFS: 278 (void) printf("<<NFS %s: %s>>\n", 279 added ? "mounted" : "unmounted", name); 280 break; 281 case IODEV_TAPE: 282 (void) printf("<<device %s: %s>>\n", 283 added ? "added" : "removed", name); 284 break; 285 case IODEV_CONTROLLER: 286 case IODEV_DISK: 287 *tmp = '\0'; 288 get_child_list(iodev, tmp); 289 (void) printf("<<%s %s: %s", is_disk ? "disk" : "controller", 290 added ? "added" : "removed", name); 291 if (!*tmp) { 292 (void) printf(">>\n"); 293 return; 294 } 295 (void) printf(" (%s %s)>>\n", is_disk ? "slices" : "disks", 296 tmp); 297 break; 298 }; 299 } 300 301 static void 302 iodev_report(struct iodev_snapshot *d1, struct iodev_snapshot *d2) 303 { 304 while (d1 && d2) { 305 if (iodev_cmp(d1, d2) < 0) { 306 iodev_changed(d1, 0); 307 d1 = d1->is_next; 308 } else if (iodev_cmp(d1, d2) > 0) { 309 iodev_changed(d2, 1); 310 d2 = d2->is_next; 311 } else { 312 iodev_report(d1->is_children, d2->is_children); 313 d1 = d1->is_next; 314 d2 = d2->is_next; 315 } 316 } 317 318 while (d1) { 319 iodev_changed(d1, 0); 320 d1 = d1->is_next; 321 } 322 323 while (d2) { 324 iodev_changed(d2, 1); 325 d2 = d2->is_next; 326 } 327 } 328 329 void 330 snapshot_report_changes(struct snapshot *old, struct snapshot *new) 331 { 332 int pset; 333 334 if (old == NULL || new == NULL) 335 return; 336 337 if (old->s_types != new->s_types) 338 return; 339 340 pset = old->s_types & SNAP_PSETS; 341 342 cpus_removed[0] = '\0'; 343 cpus_added[0] = '\0'; 344 345 if (old->s_types & SNAP_CPUS) 346 (void) snapshot_walk(SNAP_CPUS, old, new, cpu_report, &pset); 347 348 if (cpus_added[0]) { 349 (void) printf("<<processors added: %s>>\n", 350 cpus_added); 351 } 352 if (cpus_removed[0]) { 353 (void) printf("<<processors removed: %s>>\n", 354 cpus_removed); 355 } 356 if (pset) { 357 (void) snapshot_walk(SNAP_PSETS, old, new, 358 pset_report, NULL); 359 } 360 361 iodev_report(old->s_iodevs, new->s_iodevs); 362 } 363 364 /*ARGSUSED*/ 365 static void 366 dummy_cb(void *v1, void *v2, void *data) 367 { 368 } 369 370 int 371 snapshot_has_changed(struct snapshot *old, struct snapshot *new) 372 { 373 int ret = 0; 374 int cpu_mask = SNAP_CPUS | SNAP_PSETS | SNAP_SYSTEM; 375 int iodev_mask = SNAP_CONTROLLERS | SNAP_IODEVS | SNAP_IOPATHS; 376 377 if (old == NULL) 378 return (1); 379 380 if (new == NULL) 381 return (EINVAL); 382 383 if (old->s_types != new->s_types) 384 return (EINVAL); 385 386 if (!ret && (old->s_types & cpu_mask)) 387 ret = snapshot_walk(SNAP_CPUS, old, new, dummy_cb, NULL); 388 if (!ret && (old->s_types & SNAP_PSETS)) 389 ret = snapshot_walk(SNAP_PSETS, old, new, dummy_cb, NULL); 390 if (!ret && (old->s_types & iodev_mask)) 391 ret = snapshot_walk(SNAP_IODEVS, old, new, dummy_cb, NULL); 392 393 return (ret); 394 } 395