Print this page
10139 smatch fixes for usr/src/cmd/stat
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/stat/common/acquire_iodevs.c
+++ new/usr/src/cmd/stat/common/acquire_iodevs.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 #include "statcommon.h"
26 26 #include "dsr.h"
27 27
28 28 #include <sys/dklabel.h>
29 29 #include <sys/dktp/fdisk.h>
30 30 #include <stdlib.h>
31 31 #include <stdarg.h>
32 32 #include <stddef.h>
33 33 #include <unistd.h>
34 34 #include <strings.h>
35 35 #include <errno.h>
36 36 #include <limits.h>
37 37
38 38 static void insert_iodev(struct snapshot *ss, struct iodev_snapshot *iodev);
39 39
40 40 static struct iodev_snapshot *
41 41 make_controller(int cid)
42 42 {
43 43 struct iodev_snapshot *new;
44 44
45 45 new = safe_alloc(sizeof (struct iodev_snapshot));
46 46 (void) memset(new, 0, sizeof (struct iodev_snapshot));
47 47 new->is_type = IODEV_CONTROLLER;
48 48 new->is_id.id = cid;
49 49 new->is_parent_id.id = IODEV_NO_ID;
50 50
51 51 (void) snprintf(new->is_name, sizeof (new->is_name), "c%d", cid);
52 52
53 53 return (new);
54 54 }
55 55
56 56 static struct iodev_snapshot *
57 57 find_iodev_by_name(struct iodev_snapshot *list, const char *name)
58 58 {
59 59 struct iodev_snapshot *pos;
60 60 struct iodev_snapshot *pos2;
61 61
62 62 for (pos = list; pos; pos = pos->is_next) {
63 63 if (strcmp(pos->is_name, name) == 0)
64 64 return (pos);
65 65
66 66 pos2 = find_iodev_by_name(pos->is_children, name);
67 67 if (pos2 != NULL)
68 68 return (pos2);
69 69 }
70 70
71 71 return (NULL);
72 72 }
73 73
74 74 static enum iodev_type
75 75 parent_iodev_type(enum iodev_type type)
76 76 {
77 77 switch (type) {
78 78 case IODEV_CONTROLLER: return (0);
79 79 case IODEV_IOPATH_LT: return (0);
80 80 case IODEV_IOPATH_LI: return (0);
81 81 case IODEV_NFS: return (0);
82 82 case IODEV_TAPE: return (0);
83 83 case IODEV_IOPATH_LTI: return (IODEV_DISK);
84 84 case IODEV_DISK: return (IODEV_CONTROLLER);
85 85 case IODEV_PARTITION: return (IODEV_DISK);
86 86 }
87 87 return (IODEV_UNKNOWN);
88 88 }
89 89
90 90 static int
91 91 id_match(struct iodev_id *id1, struct iodev_id *id2)
92 92 {
93 93 return (id1->id == id2->id &&
94 94 strcmp(id1->tid, id2->tid) == 0);
95 95 }
96 96
97 97 static struct iodev_snapshot *
98 98 find_parent(struct snapshot *ss, struct iodev_snapshot *iodev)
99 99 {
100 100 enum iodev_type parent_type = parent_iodev_type(iodev->is_type);
101 101 struct iodev_snapshot *pos;
102 102 struct iodev_snapshot *pos2;
103 103
104 104 if (parent_type == 0 || parent_type == IODEV_UNKNOWN)
105 105 return (NULL);
106 106
107 107 if (iodev->is_parent_id.id == IODEV_NO_ID &&
108 108 iodev->is_parent_id.tid[0] == '\0')
109 109 return (NULL);
110 110
111 111 if (parent_type == IODEV_CONTROLLER) {
112 112 for (pos = ss->s_iodevs; pos; pos = pos->is_next) {
113 113 if (pos->is_type != IODEV_CONTROLLER)
114 114 continue;
115 115 if (pos->is_id.id != iodev->is_parent_id.id)
116 116 continue;
117 117 return (pos);
118 118 }
119 119
120 120 if (!(ss->s_types & SNAP_CONTROLLERS))
121 121 return (NULL);
122 122
123 123 pos = make_controller(iodev->is_parent_id.id);
124 124 insert_iodev(ss, pos);
125 125 return (pos);
126 126 }
127 127
128 128 /* IODEV_DISK parent */
129 129 for (pos = ss->s_iodevs; pos; pos = pos->is_next) {
130 130 if (id_match(&iodev->is_parent_id, &pos->is_id) &&
131 131 pos->is_type == IODEV_DISK)
132 132 return (pos);
133 133 if (pos->is_type != IODEV_CONTROLLER)
134 134 continue;
135 135 for (pos2 = pos->is_children; pos2; pos2 = pos2->is_next) {
136 136 if (pos2->is_type != IODEV_DISK)
137 137 continue;
138 138 if (id_match(&iodev->is_parent_id, &pos2->is_id))
139 139 return (pos2);
140 140 }
141 141 }
142 142
143 143 return (NULL);
144 144 }
145 145
146 146 /*
147 147 * Introduce an index into the list to speed up insert_into looking for the
148 148 * right position in the list. This index is an AVL tree of all the
149 149 * iodev_snapshot in the list.
150 150 */
151 151 static int
152 152 avl_iodev_cmp(const void* is1, const void* is2)
153 153 {
154 154 int c = iodev_cmp((struct iodev_snapshot *)is1,
155 155 (struct iodev_snapshot *)is2);
156 156
157 157 if (c > 0)
158 158 return (1);
159 159
160 160 if (c < 0)
161 161 return (-1);
162 162
163 163 return (0);
164 164 }
165 165
166 166 static void
167 167 ix_new_list(struct iodev_snapshot *elem)
168 168 {
169 169 avl_tree_t *l = malloc(sizeof (avl_tree_t));
170 170
171 171 elem->avl_list = l;
172 172 if (l == NULL)
173 173 return;
174 174
175 175 avl_create(l, avl_iodev_cmp, sizeof (struct iodev_snapshot),
176 176 offsetof(struct iodev_snapshot, avl_link));
177 177
178 178 avl_add(l, elem);
179 179 }
180 180
181 181 static void
182 182 ix_list_del(struct iodev_snapshot *elem)
183 183 {
184 184 avl_tree_t *l = elem->avl_list;
185 185
186 186 if (l == NULL)
187 187 return;
188 188
189 189 elem->avl_list = NULL;
190 190
191 191 avl_remove(l, elem);
192 192 if (avl_numnodes(l) == 0) {
193 193 avl_destroy(l);
194 194 free(l);
195 195 }
196 196 }
197 197
198 198 static void
199 199 ix_insert_here(struct iodev_snapshot *pos, struct iodev_snapshot *elem, int ba)
200 200 {
201 201 avl_tree_t *l = pos->avl_list;
202 202 elem->avl_list = l;
203 203
204 204 if (l == NULL)
205 205 return;
206 206
207 207 avl_insert_here(l, elem, pos, ba);
208 208 }
209 209
210 210 static void
211 211 list_del(struct iodev_snapshot **list, struct iodev_snapshot *pos)
212 212 {
213 213 ix_list_del(pos);
214 214
215 215 if (*list == pos)
216 216 *list = pos->is_next;
217 217 if (pos->is_next)
218 218 pos->is_next->is_prev = pos->is_prev;
219 219 if (pos->is_prev)
220 220 pos->is_prev->is_next = pos->is_next;
221 221 pos->is_prev = pos->is_next = NULL;
222 222 }
223 223
224 224 static void
225 225 insert_before(struct iodev_snapshot **list, struct iodev_snapshot *pos,
226 226 struct iodev_snapshot *new)
227 227 {
228 228 if (pos == NULL) {
229 229 new->is_prev = new->is_next = NULL;
230 230 *list = new;
231 231 ix_new_list(new);
232 232 return;
233 233 }
234 234
235 235 new->is_next = pos;
236 236 new->is_prev = pos->is_prev;
237 237 if (pos->is_prev)
238 238 pos->is_prev->is_next = new;
239 239 else
240 240 *list = new;
241 241 pos->is_prev = new;
242 242
243 243 ix_insert_here(pos, new, AVL_BEFORE);
244 244 }
245 245
246 246 static void
247 247 insert_after(struct iodev_snapshot **list, struct iodev_snapshot *pos,
248 248 struct iodev_snapshot *new)
249 249 {
250 250 if (pos == NULL) {
251 251 new->is_prev = new->is_next = NULL;
252 252 *list = new;
253 253 ix_new_list(new);
254 254 return;
255 255 }
256 256
257 257 new->is_next = pos->is_next;
258 258 new->is_prev = pos;
259 259 if (pos->is_next)
260 260 pos->is_next->is_prev = new;
261 261 pos->is_next = new;
262 262
263 263 ix_insert_here(pos, new, AVL_AFTER);
264 264 }
265 265
266 266 static void
267 267 insert_into(struct iodev_snapshot **list, struct iodev_snapshot *iodev)
268 268 {
269 269 struct iodev_snapshot *tmp = *list;
270 270 avl_tree_t *l;
271 271 void *p;
272 272 avl_index_t where;
273 273
274 274 if (*list == NULL) {
275 275 *list = iodev;
276 276 ix_new_list(iodev);
277 277 return;
278 278 }
279 279
280 280 /*
281 281 * Optimize the search: instead of walking the entire list
282 282 * (which can contain thousands of nodes), search in the AVL
283 283 * tree the nearest node and reposition the startup point to
284 284 * this node rather than always starting from the beginning
285 285 * of the list.
286 286 */
287 287 l = tmp->avl_list;
288 288 if (l != NULL) {
289 289 p = avl_find(l, iodev, &where);
290 290 if (p == NULL) {
291 291 p = avl_nearest(l, where, AVL_BEFORE);
292 292 }
293 293 if (p != NULL) {
294 294 tmp = (struct iodev_snapshot *)p;
295 295 }
296 296 }
297 297
298 298 for (;;) {
299 299 if (iodev_cmp(tmp, iodev) > 0) {
300 300 insert_before(list, tmp, iodev);
301 301 return;
302 302 }
303 303
304 304 if (tmp->is_next == NULL)
305 305 break;
306 306
307 307 tmp = tmp->is_next;
308 308 }
309 309
310 310 insert_after(list, tmp, iodev);
311 311 }
312 312
313 313 static int
314 314 disk_or_partition(enum iodev_type type)
315 315 {
316 316 return (type == IODEV_DISK || type == IODEV_PARTITION);
317 317 }
318 318
319 319 static int
320 320 disk_or_partition_or_iopath(enum iodev_type type)
321 321 {
322 322 return (type == IODEV_DISK || type == IODEV_PARTITION ||
323 323 type == IODEV_IOPATH_LTI);
324 324 }
325 325
326 326 static void
327 327 insert_iodev(struct snapshot *ss, struct iodev_snapshot *iodev)
328 328 {
329 329 struct iodev_snapshot *parent = find_parent(ss, iodev);
330 330 struct iodev_snapshot **list;
331 331
332 332 if (parent != NULL) {
333 333 list = &parent->is_children;
334 334 parent->is_nr_children++;
335 335 } else {
336 336 list = &ss->s_iodevs;
337 337 ss->s_nr_iodevs++;
338 338 }
339 339
340 340 insert_into(list, iodev);
341 341 }
342 342
343 343 /* return 1 if dev passes filter */
344 344 static int
345 345 iodev_match(struct iodev_snapshot *dev, struct iodev_filter *df)
346 346 {
347 347 int is_floppy = (strncmp(dev->is_name, "fd", 2) == 0);
348 348 char *isn, *ispn, *ifn;
349 349 char *path;
350 350 int ifnl;
351 351 size_t i;
352 352
353 353 /* no filter, pass */
354 354 if (df == NULL)
355 355 return (1); /* pass */
356 356
357 357 /* no filtered names, pass if not floppy and skipped */
358 358 if (df->if_nr_names == NULL)
359 359 return (!(df->if_skip_floppy && is_floppy));
360 360
361 361 isn = dev->is_name;
362 362 ispn = dev->is_pretty;
363 363 for (i = 0; i < df->if_nr_names; i++) {
364 364 ifn = df->if_names[i];
365 365 ifnl = strlen(ifn);
366 366 path = strchr(ifn, '.');
367 367
368 368 if ((strcmp(isn, ifn) == 0) ||
369 369 (ispn && (strcmp(ispn, ifn) == 0)))
370 370 return (1); /* pass */
371 371
372 372 /* if filter is a path allow partial match */
373 373 if (path &&
374 374 ((strncmp(isn, ifn, ifnl) == 0) ||
375 375 (ispn && (strncmp(ispn, ifn, ifnl) == 0))))
376 376 return (1); /* pass */
377 377 }
378 378
379 379 return (0); /* fail */
380 380 }
381 381
382 382 /* return 1 if path is an mpxio path associated with dev */
383 383 static int
384 384 iodev_path_match(struct iodev_snapshot *dev, struct iodev_snapshot *path)
385 385 {
386 386 char *dn, *pn;
387 387 int dnl;
388 388
389 389 dn = dev->is_name;
390 390 pn = path->is_name;
391 391 dnl = strlen(dn);
392 392
393 393 if ((strncmp(pn, dn, dnl) == 0) && (pn[dnl] == '.'))
394 394 return (1); /* yes */
395 395
396 396 return (0); /* no */
397 397 }
398 398
399 399 /* select which I/O devices to collect stats for */
400 400 static void
401 401 choose_iodevs(struct snapshot *ss, struct iodev_snapshot *iodevs,
402 402 struct iodev_filter *df)
403 403 {
404 404 struct iodev_snapshot *pos, *ppos, *tmp, *ptmp;
405 405 int nr_iodevs;
406 406 int nr_iodevs_orig;
407 407
408 408 nr_iodevs = df ? df->if_max_iodevs : UNLIMITED_IODEVS;
409 409 nr_iodevs_orig = nr_iodevs;
410 410
411 411 if (nr_iodevs == UNLIMITED_IODEVS)
412 412 nr_iodevs = INT_MAX;
413 413
414 414 /* add the full matches */
415 415 pos = iodevs;
416 416 while (pos && nr_iodevs) {
417 417 tmp = pos;
418 418 pos = pos->is_next;
419 419
420 420 if (!iodev_match(tmp, df))
421 421 continue; /* failed full match */
422 422
423 423 list_del(&iodevs, tmp);
424 424 insert_iodev(ss, tmp);
425 425
426 426 /*
427 427 * Add all mpxio paths associated with match above. Added
428 428 * paths don't count against nr_iodevs.
429 429 */
430 430 if (strchr(tmp->is_name, '.') == NULL) {
431 431 ppos = iodevs;
432 432 while (ppos) {
433 433 ptmp = ppos;
434 434 ppos = ppos->is_next;
435 435
436 436 if (!iodev_path_match(tmp, ptmp))
437 437 continue; /* not an mpxio path */
438 438
439 439 list_del(&iodevs, ptmp);
440 440 insert_iodev(ss, ptmp);
441 441 if (pos == ptmp)
442 442 pos = ppos;
443 443 }
444 444 }
445 445
446 446 nr_iodevs--;
447 447 }
448 448
449 449 /*
450 450 * If we had a filter, and *nothing* passed the filter then we
↓ open down ↓ |
450 lines elided |
↑ open up ↑ |
451 451 * don't want to fill the remaining slots - it is just confusing
452 452 * if we don that, it makes it look like the filter code is broken.
453 453 */
454 454 if ((df->if_nr_names == NULL) || (nr_iodevs != nr_iodevs_orig)) {
455 455 /* now insert any iodevs into the remaining slots */
456 456 pos = iodevs;
457 457 while (pos && nr_iodevs) {
458 458 tmp = pos;
459 459 pos = pos->is_next;
460 460
461 - if (df && df->if_skip_floppy &&
461 + if (df->if_skip_floppy &&
462 462 strncmp(tmp->is_name, "fd", 2) == 0)
463 463 continue;
464 464
465 465 list_del(&iodevs, tmp);
466 466 insert_iodev(ss, tmp);
467 467
468 468 --nr_iodevs;
469 469 }
470 470 }
471 471
472 472 /* clear the unwanted ones */
473 473 pos = iodevs;
474 474 while (pos) {
475 475 struct iodev_snapshot *tmp = pos;
476 476 pos = pos->is_next;
477 477 free_iodev(tmp);
478 478 }
479 479 }
480 480
481 481 static int
482 482 collate_controller(struct iodev_snapshot *controller,
483 483 struct iodev_snapshot *disk)
484 484 {
485 485 controller->is_stats.nread += disk->is_stats.nread;
486 486 controller->is_stats.nwritten += disk->is_stats.nwritten;
487 487 controller->is_stats.reads += disk->is_stats.reads;
488 488 controller->is_stats.writes += disk->is_stats.writes;
489 489 controller->is_stats.wtime += disk->is_stats.wtime;
490 490 controller->is_stats.wlentime += disk->is_stats.wlentime;
491 491 controller->is_stats.rtime += disk->is_stats.rtime;
492 492 controller->is_stats.rlentime += disk->is_stats.rlentime;
493 493 controller->is_crtime += disk->is_crtime;
494 494 controller->is_snaptime += disk->is_snaptime;
495 495 if (kstat_add(&disk->is_errors, &controller->is_errors))
496 496 return (errno);
497 497 return (0);
498 498 }
499 499
500 500 static int
501 501 acquire_iodev_stats(struct iodev_snapshot *list, kstat_ctl_t *kc)
502 502 {
503 503 struct iodev_snapshot *pos;
504 504 int err = 0;
505 505
506 506 for (pos = list; pos; pos = pos->is_next) {
507 507 /* controllers don't have stats (yet) */
508 508 if (pos->is_ksp != NULL) {
509 509 if (kstat_read(kc, pos->is_ksp, &pos->is_stats) == -1)
510 510 return (errno);
511 511 /* make sure crtime/snaptime is updated */
512 512 pos->is_crtime = pos->is_ksp->ks_crtime;
513 513 pos->is_snaptime = pos->is_ksp->ks_snaptime;
514 514 }
515 515
516 516 if ((err = acquire_iodev_stats(pos->is_children, kc)))
517 517 return (err);
518 518
519 519 if (pos->is_type == IODEV_CONTROLLER) {
520 520 struct iodev_snapshot *pos2 = pos->is_children;
521 521
522 522 for (; pos2; pos2 = pos2->is_next) {
523 523 if ((err = collate_controller(pos, pos2)))
524 524 return (err);
525 525 }
526 526 }
527 527 }
528 528
529 529 return (0);
530 530 }
531 531
532 532 static int
533 533 acquire_iodev_errors(struct snapshot *ss, kstat_ctl_t *kc)
534 534 {
535 535 kstat_t *ksp;
536 536
537 537 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
538 538 char kstat_name[KSTAT_STRLEN];
539 539 char *dname = kstat_name;
540 540 char *ename = ksp->ks_name;
541 541 struct iodev_snapshot *iodev;
542 542
543 543 if (ksp->ks_type != KSTAT_TYPE_NAMED)
544 544 continue;
545 545 if (strncmp(ksp->ks_class, "device_error", 12) != 0 &&
546 546 strncmp(ksp->ks_class, "iopath_error", 12) != 0)
547 547 continue;
548 548
549 549 /*
550 550 * Some drivers may not follow the naming convention
551 551 * for error kstats (i.e., drivername,err) so
552 552 * be sure we don't walk off the end.
553 553 */
554 554 while (*ename && *ename != ',') {
555 555 *dname = *ename;
556 556 dname++;
557 557 ename++;
558 558 }
559 559 *dname = '\0';
560 560
561 561 iodev = find_iodev_by_name(ss->s_iodevs, kstat_name);
562 562
563 563 if (iodev == NULL)
564 564 continue;
565 565
566 566 if (kstat_read(kc, ksp, NULL) == -1)
567 567 return (errno);
568 568 if (kstat_copy(ksp, &iodev->is_errors) == -1)
569 569 return (errno);
570 570 }
571 571
572 572 return (0);
573 573 }
574 574
575 575 static void
576 576 get_ids(struct iodev_snapshot *iodev, const char *pretty)
577 577 {
578 578 int ctr, disk, slice, ret;
579 579 char *target;
580 580 const char *p1;
581 581 const char *p2;
582 582
583 583 if (pretty == NULL)
584 584 return;
585 585
586 586 if (sscanf(pretty, "c%d", &ctr) != 1)
587 587 return;
588 588
589 589 p1 = pretty;
590 590 while (*p1 && *p1 != 't')
591 591 ++p1;
592 592
593 593 if (!*p1)
594 594 return;
595 595 ++p1;
596 596
597 597 p2 = p1;
598 598 while (*p2 && *p2 != 'd')
599 599 ++p2;
600 600
601 601 if (!*p2 || p2 == p1)
602 602 return;
603 603
604 604 target = safe_alloc(1 + p2 - p1);
605 605 (void) strlcpy(target, p1, 1 + p2 - p1);
606 606
607 607 ret = sscanf(p2, "d%d%*[sp]%d", &disk, &slice);
608 608
609 609 if (ret == 2 && iodev->is_type == IODEV_PARTITION) {
610 610 iodev->is_id.id = slice;
611 611 iodev->is_parent_id.id = disk;
612 612 (void) strlcpy(iodev->is_parent_id.tid, target, KSTAT_STRLEN);
613 613 } else if (ret == 1) {
614 614 if (iodev->is_type == IODEV_DISK) {
615 615 iodev->is_id.id = disk;
616 616 (void) strlcpy(iodev->is_id.tid, target, KSTAT_STRLEN);
617 617 iodev->is_parent_id.id = ctr;
618 618 } else if (iodev->is_type == IODEV_IOPATH_LTI) {
619 619 iodev->is_parent_id.id = disk;
620 620 (void) strlcpy(iodev->is_parent_id.tid,
621 621 target, KSTAT_STRLEN);
622 622 }
623 623 }
624 624
625 625 free(target);
626 626 }
627 627
628 628 static void
629 629 get_pretty_name(enum snapshot_types types, struct iodev_snapshot *iodev,
630 630 kstat_ctl_t *kc)
631 631 {
632 632 disk_list_t *dl;
633 633 char *pretty = NULL;
634 634
635 635 if (iodev->is_type == IODEV_NFS) {
636 636 if (!(types & SNAP_IODEV_PRETTY))
637 637 return;
638 638
639 639 iodev->is_pretty = lookup_nfs_name(iodev->is_name, kc);
640 640 return;
641 641 }
642 642
643 643 /* lookup/translate the kstat name */
644 644 dl = lookup_ks_name(iodev->is_name, (types & SNAP_IODEV_DEVID) ? 1 : 0);
645 645 if (dl == NULL)
646 646 return;
647 647
648 648 if (dl->dsk)
649 649 pretty = safe_strdup(dl->dsk);
650 650
651 651 if (types & SNAP_IODEV_PRETTY) {
652 652 if (dl->dname)
653 653 iodev->is_dname = safe_strdup(dl->dname);
654 654 }
655 655
656 656 if (dl->devidstr)
657 657 iodev->is_devid = safe_strdup(dl->devidstr);
658 658
659 659 get_ids(iodev, pretty);
660 660
661 661 /*
662 662 * we fill in pretty name wether it is asked for or not because
663 663 * it could be used in a filter by match_iodevs.
664 664 */
665 665 iodev->is_pretty = pretty;
666 666 }
667 667
668 668 static enum iodev_type
669 669 get_iodev_type(kstat_t *ksp)
670 670 {
671 671 if (strcmp(ksp->ks_class, "disk") == 0)
672 672 return (IODEV_DISK);
673 673 if (strcmp(ksp->ks_class, "partition") == 0)
674 674 return (IODEV_PARTITION);
675 675 if (strcmp(ksp->ks_class, "nfs") == 0)
676 676 return (IODEV_NFS);
677 677 if (strcmp(ksp->ks_class, "iopath") == 0)
678 678 return (IODEV_IOPATH_LTI);
679 679 if (strcmp(ksp->ks_class, "tape") == 0)
680 680 return (IODEV_TAPE);
681 681 return (IODEV_UNKNOWN);
682 682 }
683 683
684 684 /* get the lun/target/initiator from the name, return 1 on success */
685 685 static int
686 686 get_lti(char *s,
687 687 char *lname, int *l, char *tname, int *t, char *iname, int *i)
688 688 {
689 689 int num = 0;
690 690
691 691 num = sscanf(s, "%[a-z]%d%*[.]%[a-z]%d%*[.]%[a-z_]%d", lname, l,
692 692 tname, t, iname, i);
693 693 return ((num == 6) ? 1 : 0);
694 694 }
695 695
696 696
697 697 /* get the lun, target, and initiator name and instance */
698 698 static void
699 699 get_path_info(struct iodev_snapshot *io, char *mod, size_t modlen, int *type,
700 700 int *inst, char *name, size_t size)
701 701 {
702 702
703 703 /*
704 704 * If it is iopath or ssd then pad the name with i/t/l so we can sort
705 705 * by alpha order and set type for IOPATH to DISK since we want to
706 706 * have it grouped with its ssd parent. The lun can be 5 digits,
707 707 * the target can be 4 digits, and the initiator can be 3 digits and
708 708 * the padding is done appropriately for string comparisons.
709 709 */
710 710 if (disk_or_partition_or_iopath(io->is_type)) {
711 711 int i1, t1, l1;
712 712 char tname[KSTAT_STRLEN], iname[KSTAT_STRLEN];
713 713 char *ptr, lname[KSTAT_STRLEN];
714 714
715 715 i1 = t1 = l1 = 0;
716 716 (void) get_lti(io->is_name, lname, &l1, tname, &t1, iname, &i1);
717 717 *type = io->is_type;
718 718 if (io->is_type == IODEV_DISK) {
719 719 (void) snprintf(name, size, "%s%05d", lname, l1);
720 720 } else if (io->is_type == IODEV_PARTITION) {
721 721 ptr = strchr(io->is_name, ',');
722 722 (void) snprintf(name, size, "%s%05d%s", lname, l1, ptr);
723 723 } else {
724 724 (void) snprintf(name, size, "%s%05d.%s%04d.%s%03d",
725 725 lname, l1, tname, t1, iname, i1);
726 726 /* set to disk so we sort with disks */
727 727 *type = IODEV_DISK;
728 728 }
729 729 (void) strlcpy(mod, lname, modlen);
730 730 *inst = l1;
731 731 } else {
732 732 (void) strlcpy(mod, io->is_module, modlen);
733 733 (void) strlcpy(name, io->is_name, size);
734 734 *type = io->is_type;
735 735 *inst = io->is_instance;
736 736 }
737 737 }
738 738
739 739 int
740 740 iodev_cmp(struct iodev_snapshot *io1, struct iodev_snapshot *io2)
741 741 {
742 742 int type1, type2;
743 743 int inst1, inst2;
744 744 char name1[KSTAT_STRLEN], name2[KSTAT_STRLEN];
745 745 char mod1[KSTAT_STRLEN], mod2[KSTAT_STRLEN];
746 746
747 747 get_path_info(io1, mod1, sizeof (mod1), &type1, &inst1, name1,
748 748 sizeof (name1));
749 749 get_path_info(io2, mod2, sizeof (mod2), &type2, &inst2, name2,
750 750 sizeof (name2));
751 751 if ((!disk_or_partition(type1)) ||
752 752 (!disk_or_partition(type2))) {
753 753 /* neutral sort order between disk and part */
754 754 if (type1 < type2) {
755 755 return (-1);
756 756 }
757 757 if (type1 > type2) {
758 758 return (1);
759 759 }
760 760 }
761 761
762 762 /* controller doesn't have ksp */
763 763 if (io1->is_ksp && io2->is_ksp) {
764 764 if (strcmp(mod1, mod2) != 0) {
765 765 return (strcmp(mod1, mod2));
766 766 }
767 767 if (inst1 < inst2) {
768 768 return (-1);
769 769 }
770 770 if (inst1 > inst2) {
771 771 return (1);
772 772 }
773 773 } else {
774 774 if (io1->is_id.id < io2->is_id.id) {
775 775 return (-1);
776 776 }
777 777 if (io1->is_id.id > io2->is_id.id) {
778 778 return (1);
779 779 }
780 780 }
781 781
782 782 return (strcmp(name1, name2));
783 783 }
784 784
785 785 /* update the target reads and writes */
786 786 static void
787 787 update_target(struct iodev_snapshot *tgt, struct iodev_snapshot *path)
788 788 {
789 789 tgt->is_stats.reads += path->is_stats.reads;
790 790 tgt->is_stats.writes += path->is_stats.writes;
791 791 tgt->is_stats.nread += path->is_stats.nread;
792 792 tgt->is_stats.nwritten += path->is_stats.nwritten;
793 793 tgt->is_stats.wcnt += path->is_stats.wcnt;
794 794 tgt->is_stats.rcnt += path->is_stats.rcnt;
795 795
796 796 /*
797 797 * Stash the t_delta in the crtime for use in show_disk
798 798 * NOTE: this can't be done in show_disk because the
799 799 * itl entry is removed for the old format
800 800 */
801 801 tgt->is_crtime += hrtime_delta(path->is_crtime, path->is_snaptime);
802 802 tgt->is_snaptime += path->is_snaptime;
803 803 tgt->is_nr_children += 1;
804 804 }
805 805
806 806 /*
807 807 * Create a new synthetic device entry of the specified type. The supported
808 808 * synthetic types are IODEV_IOPATH_LT and IODEV_IOPATH_LI.
809 809 */
810 810 static struct iodev_snapshot *
811 811 make_extended_device(int type, struct iodev_snapshot *old)
812 812 {
813 813 struct iodev_snapshot *tptr = NULL;
814 814 char *ptr;
815 815 int lun, tgt, initiator;
816 816 char lun_name[KSTAT_STRLEN];
817 817 char tgt_name[KSTAT_STRLEN];
818 818 char initiator_name[KSTAT_STRLEN];
819 819
820 820 if (old == NULL)
821 821 return (NULL);
822 822 if (get_lti(old->is_name,
823 823 lun_name, &lun, tgt_name, &tgt, initiator_name, &initiator) != 1) {
824 824 return (NULL);
825 825 }
826 826 tptr = safe_alloc(sizeof (*old));
827 827 bzero(tptr, sizeof (*old));
828 828 if (old->is_pretty != NULL) {
829 829 tptr->is_pretty = safe_alloc(strlen(old->is_pretty) + 1);
830 830 (void) strcpy(tptr->is_pretty, old->is_pretty);
831 831 }
832 832 bcopy(&old->is_parent_id, &tptr->is_parent_id,
833 833 sizeof (old->is_parent_id));
834 834
835 835 tptr->is_type = type;
836 836
837 837 if (type == IODEV_IOPATH_LT) {
838 838 /* make new synthetic entry that is the LT */
839 839 /* set the id to the target id */
840 840 tptr->is_id.id = tgt;
841 841 (void) snprintf(tptr->is_id.tid, sizeof (tptr->is_id.tid),
842 842 "%s%d", tgt_name, tgt);
843 843 (void) snprintf(tptr->is_name, sizeof (tptr->is_name),
844 844 "%s%d.%s%d", lun_name, lun, tgt_name, tgt);
845 845
846 846 if (old->is_pretty) {
847 847 ptr = strrchr(tptr->is_pretty, '.');
848 848 if (ptr)
849 849 *ptr = '\0';
850 850 }
851 851 } else if (type == IODEV_IOPATH_LI) {
852 852 /* make new synthetic entry that is the LI */
853 853 /* set the id to the initiator number */
854 854 tptr->is_id.id = initiator;
855 855 (void) snprintf(tptr->is_id.tid, sizeof (tptr->is_id.tid),
856 856 "%s%d", initiator_name, initiator);
857 857 (void) snprintf(tptr->is_name, sizeof (tptr->is_name),
858 858 "%s%d.%s%d", lun_name, lun, initiator_name, initiator);
859 859
860 860 if (old->is_pretty) {
861 861 ptr = strchr(tptr->is_pretty, '.');
862 862 if (ptr)
863 863 (void) snprintf(ptr + 1,
864 864 strlen(tptr->is_pretty) + 1,
865 865 "%s%d", initiator_name, initiator);
866 866 }
867 867 }
868 868 return (tptr);
869 869 }
870 870
871 871 /*
872 872 * This is to get the original -X LI format (e.g. ssd1.fp0). When an LTI kstat
873 873 * is found - traverse the children looking for the same initiator and sum
874 874 * them up. Add an LI entry and delete all of the LTI entries with the same
875 875 * initiator.
876 876 */
877 877 static int
878 878 create_li_delete_lti(struct snapshot *ss, struct iodev_snapshot *list)
879 879 {
880 880 struct iodev_snapshot *pos, *entry, *parent;
881 881 int lun, tgt, initiator;
882 882 char lun_name[KSTAT_STRLEN];
883 883 char tgt_name[KSTAT_STRLEN];
884 884 char initiator_name[KSTAT_STRLEN];
885 885 int err;
886 886
887 887 for (entry = list; entry; entry = entry->is_next) {
888 888 if ((err = create_li_delete_lti(ss, entry->is_children)) != 0)
889 889 return (err);
890 890
891 891 if (entry->is_type == IODEV_IOPATH_LTI) {
892 892 parent = find_parent(ss, entry);
893 893 if (get_lti(entry->is_name, lun_name, &lun,
894 894 tgt_name, &tgt, initiator_name, &initiator) != 1) {
895 895 return (1);
896 896 }
897 897
898 898 pos = (parent == NULL) ? NULL : parent->is_children;
899 899 for (; pos; pos = pos->is_next) {
900 900 if (pos->is_id.id != -1 &&
901 901 pos->is_id.id == initiator &&
902 902 pos->is_type == IODEV_IOPATH_LI) {
903 903 /* found the same initiator */
904 904 update_target(pos, entry);
905 905 list_del(&parent->is_children, entry);
906 906 free_iodev(entry);
907 907 parent->is_nr_children--;
908 908 entry = pos;
909 909 break;
910 910 }
911 911 }
912 912
913 913 if (!pos) {
914 914 /* make the first LI entry */
915 915 pos = make_extended_device(
916 916 IODEV_IOPATH_LI, entry);
917 917 update_target(pos, entry);
918 918
919 919 if (parent) {
920 920 insert_before(&parent->is_children,
921 921 entry, pos);
922 922 list_del(&parent->is_children, entry);
923 923 free_iodev(entry);
924 924 } else {
925 925 insert_before(&ss->s_iodevs, entry,
926 926 pos);
927 927 list_del(&ss->s_iodevs, entry);
928 928 free_iodev(entry);
929 929 }
930 930 entry = pos;
931 931 }
932 932 }
933 933 }
934 934 return (0);
935 935 }
936 936
937 937 /*
938 938 * We have the LTI kstat, now add an entry for the LT that sums up all of
939 939 * the LTI's with the same target(t).
940 940 */
941 941 static int
942 942 create_lt(struct snapshot *ss, struct iodev_snapshot *list)
943 943 {
944 944 struct iodev_snapshot *entry, *parent, *pos;
945 945 int lun, tgt, initiator;
946 946 char lun_name[KSTAT_STRLEN];
947 947 char tgt_name[KSTAT_STRLEN];
948 948 char initiator_name[KSTAT_STRLEN];
949 949 int err;
950 950
951 951 for (entry = list; entry; entry = entry->is_next) {
952 952 if ((err = create_lt(ss, entry->is_children)) != 0)
953 953 return (err);
954 954
955 955 if (entry->is_type == IODEV_IOPATH_LTI) {
956 956 parent = find_parent(ss, entry);
957 957 if (get_lti(entry->is_name, lun_name, &lun,
958 958 tgt_name, &tgt, initiator_name, &initiator) != 1) {
959 959 return (1);
960 960 }
961 961
962 962 pos = (parent == NULL) ? NULL : parent->is_children;
963 963 for (; pos; pos = pos->is_next) {
964 964 if (pos->is_id.id != -1 &&
965 965 pos->is_id.id == tgt &&
966 966 pos->is_type == IODEV_IOPATH_LT) {
967 967 /* found the same target */
968 968 update_target(pos, entry);
969 969 break;
970 970 }
971 971 }
972 972
973 973 if (!pos) {
974 974 pos = make_extended_device(
975 975 IODEV_IOPATH_LT, entry);
976 976 update_target(pos, entry);
977 977
978 978 if (parent) {
979 979 insert_before(&parent->is_children,
980 980 entry, pos);
981 981 parent->is_nr_children++;
982 982 } else {
983 983 insert_before(&ss->s_iodevs,
984 984 entry, pos);
985 985 }
986 986 }
987 987 }
988 988 }
989 989 return (0);
990 990 }
991 991
992 992 /* Find the longest is_name field to aid formatting of output */
993 993 static int
994 994 iodevs_is_name_maxlen(struct iodev_snapshot *list)
995 995 {
996 996 struct iodev_snapshot *entry;
997 997 int max = 0, cmax, len;
998 998
999 999 for (entry = list; entry; entry = entry->is_next) {
1000 1000 cmax = iodevs_is_name_maxlen(entry->is_children);
1001 1001 max = (cmax > max) ? cmax : max;
1002 1002 len = strlen(entry->is_name);
1003 1003 max = (len > max) ? len : max;
1004 1004 }
1005 1005 return (max);
1006 1006 }
1007 1007
1008 1008 int
1009 1009 acquire_iodevs(struct snapshot *ss, kstat_ctl_t *kc, struct iodev_filter *df)
1010 1010 {
1011 1011 kstat_t *ksp;
1012 1012 struct iodev_snapshot *pos;
1013 1013 struct iodev_snapshot *list = NULL;
1014 1014 int err = 0;
1015 1015
1016 1016 ss->s_nr_iodevs = 0;
1017 1017 ss->s_iodevs_is_name_maxlen = 0;
1018 1018
1019 1019 /*
1020 1020 * Call cleanup_iodevs_snapshot() so that a cache miss in
1021 1021 * lookup_ks_name() will result in a fresh snapshot.
1022 1022 */
1023 1023 cleanup_iodevs_snapshot();
1024 1024
1025 1025 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
1026 1026 enum iodev_type type;
1027 1027
1028 1028 if (ksp->ks_type != KSTAT_TYPE_IO)
1029 1029 continue;
1030 1030
1031 1031 /* e.g. "usb_byte_count" is not handled */
1032 1032 if ((type = get_iodev_type(ksp)) == IODEV_UNKNOWN)
1033 1033 continue;
1034 1034
1035 1035 if (df && !(type & df->if_allowed_types))
1036 1036 continue;
1037 1037
1038 1038 if ((pos = malloc(sizeof (struct iodev_snapshot))) == NULL) {
1039 1039 err = errno;
1040 1040 goto out;
1041 1041 }
1042 1042
1043 1043 (void) memset(pos, 0, sizeof (struct iodev_snapshot));
1044 1044
1045 1045 pos->is_type = type;
1046 1046 pos->is_crtime = ksp->ks_crtime;
1047 1047 pos->is_snaptime = ksp->ks_snaptime;
1048 1048 pos->is_id.id = IODEV_NO_ID;
1049 1049 pos->is_parent_id.id = IODEV_NO_ID;
1050 1050 pos->is_ksp = ksp;
1051 1051 pos->is_instance = ksp->ks_instance;
1052 1052
1053 1053 (void) strlcpy(pos->is_module, ksp->ks_module, KSTAT_STRLEN);
1054 1054 (void) strlcpy(pos->is_name, ksp->ks_name, KSTAT_STRLEN);
1055 1055 get_pretty_name(ss->s_types, pos, kc);
1056 1056
1057 1057 /*
1058 1058 * We must insert in sort order so e.g. vmstat -l
1059 1059 * chooses in order.
1060 1060 */
1061 1061 insert_into(&list, pos);
1062 1062 }
1063 1063
1064 1064 choose_iodevs(ss, list, df);
1065 1065
1066 1066 /* before acquire_stats for collate_controller()'s benefit */
1067 1067 if (ss->s_types & SNAP_IODEV_ERRORS) {
1068 1068 if ((err = acquire_iodev_errors(ss, kc)) != 0)
1069 1069 goto out;
1070 1070 }
1071 1071
1072 1072 if ((err = acquire_iodev_stats(ss->s_iodevs, kc)) != 0)
1073 1073 goto out;
1074 1074
1075 1075 if (ss->s_types & SNAP_IOPATHS_LTI) {
1076 1076 /*
1077 1077 * -Y: kstats are LTI, need to create a synthetic LT
1078 1078 * for -Y output.
1079 1079 */
1080 1080 if ((err = create_lt(ss, ss->s_iodevs)) != 0) {
1081 1081 return (err);
1082 1082 }
1083 1083 }
1084 1084 if (ss->s_types & SNAP_IOPATHS_LI) {
1085 1085 /*
1086 1086 * -X: kstats are LTI, need to create a synthetic LI and
1087 1087 * delete the LTI for -X output
1088 1088 */
1089 1089 if ((err = create_li_delete_lti(ss, ss->s_iodevs)) != 0) {
1090 1090 return (err);
1091 1091 }
1092 1092 }
1093 1093
1094 1094 /* determine width of longest is_name */
1095 1095 ss->s_iodevs_is_name_maxlen = iodevs_is_name_maxlen(ss->s_iodevs);
1096 1096
1097 1097 err = 0;
1098 1098 out:
1099 1099 return (err);
1100 1100 }
1101 1101
1102 1102 void
1103 1103 free_iodev(struct iodev_snapshot *iodev)
1104 1104 {
1105 1105 while (iodev->is_children) {
1106 1106 struct iodev_snapshot *tmp = iodev->is_children;
1107 1107 iodev->is_children = iodev->is_children->is_next;
1108 1108 free_iodev(tmp);
1109 1109 }
1110 1110
1111 1111 if (iodev->avl_list) {
1112 1112 avl_remove(iodev->avl_list, iodev);
1113 1113 if (avl_numnodes(iodev->avl_list) == 0) {
1114 1114 avl_destroy(iodev->avl_list);
1115 1115 free(iodev->avl_list);
1116 1116 }
1117 1117 }
1118 1118
1119 1119 free(iodev->is_errors.ks_data);
1120 1120 free(iodev->is_pretty);
1121 1121 free(iodev->is_dname);
1122 1122 free(iodev->is_devid);
1123 1123 free(iodev);
1124 1124 }
↓ open down ↓ |
653 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX