xref: /titanic_44/usr/src/cmd/stat/common/walkers.c (revision 37fbbce5257519d600faa3d23d464b42b71c1605)
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