xref: /illumos-gate/usr/src/cmd/stat/common/walkers.c (revision 2bbdd445a21f9d61f4a0ca0faf05d5ceb2bd91f3)
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
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
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
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
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
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_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
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
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
368 dummy_cb(void *v1, void *v2, void *data)
369 {
370 }
371 
372 int
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