xref: /illumos-gate/usr/src/cmd/stat/common/walkers.c (revision 4de2612967d06c4fdbf524a62556a1e8118a006f)
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