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