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 "statcommon.h"
29
30 #include <string.h>
31 #include <errno.h>
32
33 /* max size of report change annotations */
34 #define LIST_SIZE 512
35
36 static char cpus_added[LIST_SIZE];
37 static char cpus_removed[LIST_SIZE];
38
39 static int
cpu_walk(struct snapshot * old,struct snapshot * new,snapshot_cb cb,void * data)40 cpu_walk(struct snapshot *old, struct snapshot *new,
41 snapshot_cb cb, void *data)
42 {
43 int changed = 0;
44 int i;
45
46 /* CPUs can change state but not re-order */
47 for (i = 0; i < new->s_nr_cpus; i++) {
48 struct cpu_snapshot *cpu = NULL;
49 struct cpu_snapshot *newcpu = &new->s_cpus[i];
50 if (old)
51 cpu = &old->s_cpus[i];
52 cb(cpu, newcpu, data);
53 if (cpu == NULL)
54 changed = 1;
55 else {
56 /*
57 * We only care about off/on line transitions
58 */
59 if ((CPU_ACTIVE(cpu) && !CPU_ACTIVE(newcpu)) ||
60 (!CPU_ACTIVE(cpu) && CPU_ACTIVE(newcpu)))
61 changed = 1;
62 if ((new->s_types & SNAP_PSETS) &&
63 cpu->cs_pset_id != newcpu->cs_pset_id)
64 changed = 1;
65 }
66
67 }
68
69 return (changed);
70 }
71
72 static int
pset_walk(struct snapshot * old,struct snapshot * new,snapshot_cb cb,void * data)73 pset_walk(struct snapshot *old, struct snapshot *new,
74 snapshot_cb cb, void *data)
75 {
76 int i = 0;
77 int j = 0;
78 int changed = 0;
79
80 while (old && i < old->s_nr_psets && j < new->s_nr_psets) {
81 if (old->s_psets[i].ps_id < new->s_psets[j].ps_id) {
82 cb(&old->s_psets[i], NULL, data);
83 i++;
84 changed = 1;
85 } else if (old->s_psets[i].ps_id > new->s_psets[j].ps_id) {
86 cb(NULL, &new->s_psets[j], data);
87 j++;
88 changed = 1;
89 } else {
90 cb(&old->s_psets[i], &new->s_psets[j], data);
91 i++;
92 j++;
93 }
94 }
95
96 while (old && i < old->s_nr_psets) {
97 cb(&old->s_psets[i], NULL, data);
98 i++;
99 changed = 1;
100 }
101
102 while (j < new->s_nr_psets) {
103 cb(NULL, &new->s_psets[j], data);
104 j++;
105 changed = 1;
106 }
107
108 return (changed);
109 }
110
111 static int
iodev_walk(struct iodev_snapshot * d1,struct iodev_snapshot * d2,snapshot_cb cb,void * data)112 iodev_walk(struct iodev_snapshot *d1, struct iodev_snapshot *d2,
113 snapshot_cb cb, void *data)
114 {
115 int changed = 0;
116
117 while (d1 && d2) {
118 if (strcmp(d1->is_name, d2->is_name) < 0) {
119 changed = 1;
120 cb(d1, NULL, data);
121 (void) iodev_walk(d1->is_children, NULL, cb, data);
122 d1 = d1->is_next;
123 } else if (strcmp(d1->is_name, d2->is_name) > 0) {
124 changed = 1;
125 cb(NULL, d2, data);
126 (void) iodev_walk(NULL, d2->is_children, cb, data);
127 d2 = d2->is_next;
128 } else {
129 cb(d1, d2, data);
130 changed |= iodev_walk(d1->is_children,
131 d2->is_children, cb, data);
132 d1 = d1->is_next;
133 d2 = d2->is_next;
134 }
135 }
136
137 while (d1) {
138 changed = 1;
139 cb(d1, NULL, data);
140 (void) iodev_walk(d1->is_children, NULL, cb, data);
141 d1 = d1->is_next;
142 }
143
144 while (d2) {
145 changed = 1;
146 cb(NULL, d2, data);
147 (void) iodev_walk(NULL, d2->is_children, cb, data);
148 d2 = d2->is_next;
149 }
150
151 return (changed);
152 }
153
154 int
snapshot_walk(enum snapshot_types type,struct snapshot * old,struct snapshot * new,snapshot_cb cb,void * data)155 snapshot_walk(enum snapshot_types type, struct snapshot *old,
156 struct snapshot *new, snapshot_cb cb, void *data)
157 {
158 int changed = 0;
159
160 switch (type) {
161 case SNAP_CPUS:
162 changed = cpu_walk(old, new, cb, data);
163 break;
164
165 case SNAP_PSETS:
166 changed = pset_walk(old, new, cb, data);
167 break;
168
169 case SNAP_CONTROLLERS:
170 case SNAP_IODEVS:
171 case SNAP_IOPATHS_LI:
172 case SNAP_IOPATHS_LTI:
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
add_nr_to_list(char * buf,unsigned long nr)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
cpu_report(void * v1,void * v2,void * data)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
pset_report(void * v1,void * v2,void * data)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
get_child_list(struct iodev_snapshot * iodev,char * buf)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
iodev_changed(struct iodev_snapshot * iodev,int added)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_LT:
270 case IODEV_IOPATH_LI:
271 case IODEV_IOPATH_LTI:
272 (void) printf("<<multi-path %s: %s>>\n",
273 added ? "added" : "removed", name);
274 break;
275 case IODEV_PARTITION:
276 (void) printf("<<partition %s: %s>>\n",
277 added ? "added" : "removed", name);
278 break;
279 case IODEV_NFS:
280 (void) printf("<<NFS %s: %s>>\n",
281 added ? "mounted" : "unmounted", name);
282 break;
283 case IODEV_TAPE:
284 (void) printf("<<device %s: %s>>\n",
285 added ? "added" : "removed", name);
286 break;
287 case IODEV_CONTROLLER:
288 case IODEV_DISK:
289 *tmp = '\0';
290 get_child_list(iodev, tmp);
291 (void) printf("<<%s %s: %s", is_disk ? "disk" : "controller",
292 added ? "added" : "removed", name);
293 if (!*tmp) {
294 (void) printf(">>\n");
295 return;
296 }
297 (void) printf(" (%s %s)>>\n", is_disk ? "slices" : "disks",
298 tmp);
299 break;
300 };
301 }
302
303 static void
iodev_report(struct iodev_snapshot * d1,struct iodev_snapshot * d2)304 iodev_report(struct iodev_snapshot *d1, struct iodev_snapshot *d2)
305 {
306 while (d1 && d2) {
307 if (iodev_cmp(d1, d2) < 0) {
308 iodev_changed(d1, 0);
309 d1 = d1->is_next;
310 } else if (iodev_cmp(d1, d2) > 0) {
311 iodev_changed(d2, 1);
312 d2 = d2->is_next;
313 } else {
314 iodev_report(d1->is_children, d2->is_children);
315 d1 = d1->is_next;
316 d2 = d2->is_next;
317 }
318 }
319
320 while (d1) {
321 iodev_changed(d1, 0);
322 d1 = d1->is_next;
323 }
324
325 while (d2) {
326 iodev_changed(d2, 1);
327 d2 = d2->is_next;
328 }
329 }
330
331 void
snapshot_report_changes(struct snapshot * old,struct snapshot * new)332 snapshot_report_changes(struct snapshot *old, struct snapshot *new)
333 {
334 int pset;
335
336 if (old == NULL || new == NULL)
337 return;
338
339 if (old->s_types != new->s_types)
340 return;
341
342 pset = old->s_types & SNAP_PSETS;
343
344 cpus_removed[0] = '\0';
345 cpus_added[0] = '\0';
346
347 if (old->s_types & SNAP_CPUS)
348 (void) snapshot_walk(SNAP_CPUS, old, new, cpu_report, &pset);
349
350 if (cpus_added[0]) {
351 (void) printf("<<processors added: %s>>\n",
352 cpus_added);
353 }
354 if (cpus_removed[0]) {
355 (void) printf("<<processors removed: %s>>\n",
356 cpus_removed);
357 }
358 if (pset) {
359 (void) snapshot_walk(SNAP_PSETS, old, new,
360 pset_report, NULL);
361 }
362
363 iodev_report(old->s_iodevs, new->s_iodevs);
364 }
365
366 /*ARGSUSED*/
367 static void
dummy_cb(void * v1,void * v2,void * data)368 dummy_cb(void *v1, void *v2, void *data)
369 {
370 }
371
372 int
snapshot_has_changed(struct snapshot * old,struct snapshot * new)373 snapshot_has_changed(struct snapshot *old, struct snapshot *new)
374 {
375 int ret = 0;
376 int cpu_mask = SNAP_CPUS | SNAP_PSETS | SNAP_SYSTEM;
377 int iodev_mask = SNAP_CONTROLLERS | SNAP_IODEVS |
378 SNAP_IOPATHS_LI | SNAP_IOPATHS_LTI;
379
380 if (old == NULL)
381 return (1);
382
383 if (new == NULL)
384 return (EINVAL);
385
386 if (old->s_types != new->s_types)
387 return (EINVAL);
388
389 if (!ret && (old->s_types & cpu_mask))
390 ret = snapshot_walk(SNAP_CPUS, old, new, dummy_cb, NULL);
391 if (!ret && (old->s_types & SNAP_PSETS))
392 ret = snapshot_walk(SNAP_PSETS, old, new, dummy_cb, NULL);
393 if (!ret && (old->s_types & iodev_mask))
394 ret = snapshot_walk(SNAP_IODEVS, old, new, dummy_cb, NULL);
395
396 return (ret);
397 }
398