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