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 "statcommon.h"
27
28 #include <string.h>
29 #include <errno.h>
30
31 /* max size of report change annotations */
32 #define LIST_SIZE 512
33
34 static char cpus_added[LIST_SIZE];
35 static char cpus_removed[LIST_SIZE];
36
37 static int
cpu_walk(struct snapshot * old,struct snapshot * new,snapshot_cb cb,void * data)38 cpu_walk(struct snapshot *old, struct snapshot *new,
39 snapshot_cb cb, void *data)
40 {
41 int changed = 0;
42 int i;
43
44 /* CPUs can change state but not re-order */
45 for (i = 0; i < new->s_nr_cpus; i++) {
46 struct cpu_snapshot *cpu = NULL;
47 struct cpu_snapshot *newcpu = &new->s_cpus[i];
48 if (old)
49 cpu = &old->s_cpus[i];
50 cb(cpu, newcpu, data);
51 if (cpu == NULL)
52 changed = 1;
53 else {
54 /*
55 * We only care about off/on line transitions
56 */
57 if ((CPU_ACTIVE(cpu) && !CPU_ACTIVE(newcpu)) ||
58 (!CPU_ACTIVE(cpu) && CPU_ACTIVE(newcpu)))
59 changed = 1;
60 if ((new->s_types & SNAP_PSETS) &&
61 cpu->cs_pset_id != newcpu->cs_pset_id)
62 changed = 1;
63 }
64
65 }
66
67 return (changed);
68 }
69
70 static int
pset_walk(struct snapshot * old,struct snapshot * new,snapshot_cb cb,void * data)71 pset_walk(struct snapshot *old, struct snapshot *new,
72 snapshot_cb cb, void *data)
73 {
74 int i = 0;
75 int j = 0;
76 int changed = 0;
77
78 while (old && i < old->s_nr_psets && j < new->s_nr_psets) {
79 if (old->s_psets[i].ps_id < new->s_psets[j].ps_id) {
80 cb(&old->s_psets[i], NULL, data);
81 i++;
82 changed = 1;
83 } else if (old->s_psets[i].ps_id > new->s_psets[j].ps_id) {
84 cb(NULL, &new->s_psets[j], data);
85 j++;
86 changed = 1;
87 } else {
88 cb(&old->s_psets[i], &new->s_psets[j], data);
89 i++;
90 j++;
91 }
92 }
93
94 while (old && i < old->s_nr_psets) {
95 cb(&old->s_psets[i], NULL, data);
96 i++;
97 changed = 1;
98 }
99
100 while (j < new->s_nr_psets) {
101 cb(NULL, &new->s_psets[j], data);
102 j++;
103 changed = 1;
104 }
105
106 return (changed);
107 }
108
109 static int
iodev_walk(struct iodev_snapshot * d1,struct iodev_snapshot * d2,snapshot_cb cb,void * data)110 iodev_walk(struct iodev_snapshot *d1, struct iodev_snapshot *d2,
111 snapshot_cb cb, void *data)
112 {
113 int changed = 0;
114
115 while (d1 && d2) {
116 if (strcmp(d1->is_name, d2->is_name) < 0) {
117 changed = 1;
118 cb(d1, NULL, data);
119 (void) iodev_walk(d1->is_children, NULL, cb, data);
120 d1 = d1->is_next;
121 } else if (strcmp(d1->is_name, d2->is_name) > 0) {
122 changed = 1;
123 cb(NULL, d2, data);
124 (void) iodev_walk(NULL, d2->is_children, cb, data);
125 d2 = d2->is_next;
126 } else {
127 cb(d1, d2, data);
128 changed |= iodev_walk(d1->is_children,
129 d2->is_children, cb, data);
130 d1 = d1->is_next;
131 d2 = d2->is_next;
132 }
133 }
134
135 while (d1) {
136 changed = 1;
137 cb(d1, NULL, data);
138 (void) iodev_walk(d1->is_children, NULL, cb, data);
139 d1 = d1->is_next;
140 }
141
142 while (d2) {
143 changed = 1;
144 cb(NULL, d2, data);
145 (void) iodev_walk(NULL, d2->is_children, cb, data);
146 d2 = d2->is_next;
147 }
148
149 return (changed);
150 }
151
152 int
snapshot_walk(enum snapshot_types type,struct snapshot * old,struct snapshot * new,snapshot_cb cb,void * data)153 snapshot_walk(enum snapshot_types type, struct snapshot *old,
154 struct snapshot *new, snapshot_cb cb, void *data)
155 {
156 int changed = 0;
157
158 switch (type) {
159 case SNAP_CPUS:
160 changed = cpu_walk(old, new, cb, data);
161 break;
162
163 case SNAP_PSETS:
164 changed = pset_walk(old, new, cb, data);
165 break;
166
167 case SNAP_CONTROLLERS:
168 case SNAP_IODEVS:
169 case SNAP_IOPATHS_LI:
170 case SNAP_IOPATHS_LTI:
171 changed = iodev_walk(old ? old->s_iodevs : NULL,
172 new->s_iodevs, cb, data);
173 break;
174
175 default:
176 break;
177 }
178
179 return (changed);
180 }
181
182 static void
add_nr_to_list(char * buf,unsigned long nr)183 add_nr_to_list(char *buf, unsigned long nr)
184 {
185 char tmp[LIST_SIZE];
186
187 (void) snprintf(tmp, LIST_SIZE, "%lu", nr);
188
189 if (strlen(buf))
190 (void) strlcat(buf, ", ", LIST_SIZE);
191
192 (void) strlcat(buf, tmp, LIST_SIZE);
193 }
194
195 static void
cpu_report(void * v1,void * v2,void * data)196 cpu_report(void *v1, void *v2, void *data)
197 {
198 int *pset = (int *)data;
199 struct cpu_snapshot *c1 = (struct cpu_snapshot *)v1;
200 struct cpu_snapshot *c2 = (struct cpu_snapshot *)v2;
201
202 if (*pset && c1->cs_pset_id != c2->cs_pset_id) {
203 (void) printf("<<processor %d moved from pset: %d to: %d>>\n",
204 c1->cs_id, c1->cs_pset_id, c2->cs_pset_id);
205 }
206
207 if (c1->cs_state == c2->cs_state)
208 return;
209
210 if (CPU_ONLINE(c1->cs_state) && !CPU_ONLINE(c2->cs_state))
211 add_nr_to_list(cpus_removed, c1->cs_id);
212
213 if (!CPU_ONLINE(c1->cs_state) && CPU_ONLINE(c2->cs_state))
214 add_nr_to_list(cpus_added, c2->cs_id);
215 }
216
217 /*ARGSUSED*/
218 static void
pset_report(void * v1,void * v2,void * data)219 pset_report(void *v1, void *v2, void *data)
220 {
221 struct pset_snapshot *p1 = (struct pset_snapshot *)v1;
222 struct pset_snapshot *p2 = (struct pset_snapshot *)v2;
223
224 if (p2 == NULL) {
225 (void) printf("<<pset destroyed: %u>>\n", p1->ps_id);
226 return;
227 }
228
229 if (p1 == NULL)
230 (void) printf("<<pset created: %u>>\n", p2->ps_id);
231 }
232
233 static void
get_child_list(struct iodev_snapshot * iodev,char * buf)234 get_child_list(struct iodev_snapshot *iodev, char *buf)
235 {
236 char tmp[LIST_SIZE];
237 struct iodev_snapshot *pos = iodev->is_children;
238
239 while (pos) {
240 if (pos->is_type == IODEV_PARTITION) {
241 add_nr_to_list(buf, pos->is_id.id);
242 } else if (pos->is_type == IODEV_DISK) {
243 if (strlen(buf))
244 (void) strlcat(buf, ", ", LIST_SIZE);
245 (void) strlcat(buf, "t", LIST_SIZE);
246 (void) strlcat(buf, pos->is_id.tid, LIST_SIZE);
247 (void) strlcat(buf, "d", LIST_SIZE);
248 *tmp = '\0';
249 add_nr_to_list(tmp, pos->is_id.id);
250 (void) strlcat(buf, tmp, LIST_SIZE);
251 }
252 pos = pos->is_next;
253 }
254 }
255
256 static void
iodev_changed(struct iodev_snapshot * iodev,int added)257 iodev_changed(struct iodev_snapshot *iodev, int added)
258 {
259 char tmp[LIST_SIZE];
260 int is_disk = iodev->is_type == IODEV_DISK;
261 char *name = iodev->is_name;
262
263 if (iodev->is_pretty)
264 name = iodev->is_pretty;
265
266 switch (iodev->is_type) {
267 case IODEV_IOPATH_LT:
268 case IODEV_IOPATH_LI:
269 case IODEV_IOPATH_LTI:
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
iodev_report(struct iodev_snapshot * d1,struct iodev_snapshot * d2)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
snapshot_report_changes(struct snapshot * old,struct snapshot * new)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
dummy_cb(void * v1,void * v2,void * data)366 dummy_cb(void *v1, void *v2, void *data)
367 {
368 }
369
370 int
snapshot_has_changed(struct snapshot * old,struct snapshot * new)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 |
376 SNAP_IOPATHS_LI | SNAP_IOPATHS_LTI;
377
378 if (old == NULL)
379 return (1);
380
381 if (new == NULL)
382 return (EINVAL);
383
384 if (old->s_types != new->s_types)
385 return (EINVAL);
386
387 if (!ret && (old->s_types & cpu_mask))
388 ret = snapshot_walk(SNAP_CPUS, old, new, dummy_cb, NULL);
389 if (!ret && (old->s_types & SNAP_PSETS))
390 ret = snapshot_walk(SNAP_PSETS, old, new, dummy_cb, NULL);
391 if (!ret && (old->s_types & iodev_mask))
392 ret = snapshot_walk(SNAP_IODEVS, old, new, dummy_cb, NULL);
393
394 return (ret);
395 }
396